mirror of https://github.com/kubernetes/kops.git
Validate external IAM policies
This commit is contained in:
parent
4ef7ee1cb9
commit
4579a1bcdc
|
|
@ -248,7 +248,7 @@ func validateInstanceProfile(v *kops.IAMProfileSpec, fldPath *field.Path) field.
|
||||||
if v != nil && v.Profile != nil {
|
if v != nil && v.Profile != nil {
|
||||||
instanceProfileARN := *v.Profile
|
instanceProfileARN := *v.Profile
|
||||||
parsedARN, err := arn.Parse(instanceProfileARN)
|
parsedARN, err := arn.Parse(instanceProfileARN)
|
||||||
if err != nil || !strings.HasPrefix(parsedARN.Resource, "instance-profile") {
|
if err != nil || !strings.HasPrefix(parsedARN.Resource, "instance-profile/") {
|
||||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("profile"), instanceProfileARN,
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("profile"), instanceProfileARN,
|
||||||
"Instance Group IAM Instance Profile must be a valid aws arn such as arn:aws:iam::123456789012:instance-profile/KopsExampleRole"))
|
"Instance Group IAM Instance Profile must be a valid aws arn such as arn:aws:iam::123456789012:instance-profile/KopsExampleRole"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,21 +23,21 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/arn"
|
||||||
"github.com/blang/semver/v4"
|
"github.com/blang/semver/v4"
|
||||||
"golang.org/x/net/ipv4"
|
"golang.org/x/net/ipv4"
|
||||||
"golang.org/x/net/ipv6"
|
"golang.org/x/net/ipv6"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
|
||||||
"k8s.io/kops/pkg/featureflag"
|
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/validation"
|
"k8s.io/apimachinery/pkg/api/validation"
|
||||||
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
|
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
"k8s.io/kops/pkg/apis/kops"
|
"k8s.io/kops/pkg/apis/kops"
|
||||||
|
"k8s.io/kops/pkg/featureflag"
|
||||||
"k8s.io/kops/pkg/model/components"
|
"k8s.io/kops/pkg/model/components"
|
||||||
"k8s.io/kops/pkg/model/iam"
|
"k8s.io/kops/pkg/model/iam"
|
||||||
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newValidateCluster(cluster *kops.Cluster) field.ErrorList {
|
func newValidateCluster(cluster *kops.Cluster) field.ErrorList {
|
||||||
|
|
@ -158,12 +158,18 @@ func validateClusterSpec(spec *kops.ClusterSpec, c *kops.Cluster, fieldPath *fie
|
||||||
allErrs = append(allErrs, validateNodeTerminationHandler(c, spec.NodeTerminationHandler, fieldPath.Child("nodeTerminationHandler"))...)
|
allErrs = append(allErrs, validateNodeTerminationHandler(c, spec.NodeTerminationHandler, fieldPath.Child("nodeTerminationHandler"))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IAM additionalPolicies
|
// IAM additional policies
|
||||||
if spec.AdditionalPolicies != nil {
|
if spec.AdditionalPolicies != nil {
|
||||||
for k, v := range *spec.AdditionalPolicies {
|
for k, v := range *spec.AdditionalPolicies {
|
||||||
allErrs = append(allErrs, validateAdditionalPolicy(k, v, fieldPath.Child("additionalPolicies"))...)
|
allErrs = append(allErrs, validateAdditionalPolicy(k, v, fieldPath.Child("additionalPolicies"))...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// IAM external policies
|
||||||
|
if spec.ExternalPolicies != nil {
|
||||||
|
for k, v := range *spec.ExternalPolicies {
|
||||||
|
allErrs = append(allErrs, validateExternalPolicies(k, v, fieldPath.Child("externalPolicies"))...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// EtcdClusters
|
// EtcdClusters
|
||||||
{
|
{
|
||||||
|
|
@ -795,31 +801,51 @@ func validateNetworkingGCE(c *kops.ClusterSpec, v *kops.GCENetworkingSpec, fldPa
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateAdditionalPolicy(role string, policy string, fldPath *field.Path) field.ErrorList {
|
func validateAdditionalPolicy(role string, policy string, fldPath *field.Path) field.ErrorList {
|
||||||
errs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
var valid []string
|
var valid []string
|
||||||
for _, r := range kops.AllInstanceGroupRoles {
|
for _, r := range kops.AllInstanceGroupRoles {
|
||||||
valid = append(valid, strings.ToLower(string(r)))
|
valid = append(valid, strings.ToLower(string(r)))
|
||||||
}
|
}
|
||||||
errs = append(errs, IsValidValue(fldPath, &role, valid)...)
|
allErrs = append(allErrs, IsValidValue(fldPath, &role, valid)...)
|
||||||
|
|
||||||
statements, err := iam.ParseStatements(policy)
|
statements, err := iam.ParseStatements(policy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, field.Invalid(fldPath.Key(role), policy, "policy was not valid JSON: "+err.Error()))
|
allErrs = append(allErrs, field.Invalid(fldPath.Key(role), policy, "policy was not valid JSON: "+err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trivial validation of policy, mostly to make sure it isn't some other random object
|
// Trivial validation of policy, mostly to make sure it isn't some other random object
|
||||||
for i, statement := range statements {
|
for i, statement := range statements {
|
||||||
fldEffect := fldPath.Key(role).Index(i).Child("Effect")
|
fldEffect := fldPath.Key(role).Index(i).Child("Effect")
|
||||||
if statement.Effect == "" {
|
if statement.Effect == "" {
|
||||||
errs = append(errs, field.Required(fldEffect, "Effect must be specified for IAM policy"))
|
allErrs = append(allErrs, field.Required(fldEffect, "Effect must be specified for IAM policy"))
|
||||||
} else {
|
} else {
|
||||||
value := string(statement.Effect)
|
value := string(statement.Effect)
|
||||||
errs = append(errs, IsValidValue(fldEffect, &value, []string{"Allow", "Deny"})...)
|
allErrs = append(allErrs, IsValidValue(fldEffect, &value, []string{"Allow", "Deny"})...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errs
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateExternalPolicies(role string, policies []string, fldPath *field.Path) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
|
var valid []string
|
||||||
|
for _, r := range kops.AllInstanceGroupRoles {
|
||||||
|
valid = append(valid, strings.ToLower(string(r)))
|
||||||
|
}
|
||||||
|
allErrs = append(allErrs, IsValidValue(fldPath, &role, valid)...)
|
||||||
|
|
||||||
|
for _, policy := range policies {
|
||||||
|
parsedARN, err := arn.Parse(policy)
|
||||||
|
if err != nil || !strings.HasPrefix(parsedARN.Resource, "policy/") {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child(role), policy,
|
||||||
|
"Policy must be a valid AWS ARN such as arn:aws:iam::123456789012:policy/KopsExamplePolicy"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateEtcdClusterSpec(spec kops.EtcdClusterSpec, c *kops.Cluster, fieldPath *field.Path) field.ErrorList {
|
func validateEtcdClusterSpec(spec kops.EtcdClusterSpec, c *kops.Cluster, fieldPath *field.Path) field.ErrorList {
|
||||||
|
|
|
||||||
|
|
@ -50,11 +50,11 @@ spec:
|
||||||
nodes: public
|
nodes: public
|
||||||
externalPolicies:
|
externalPolicies:
|
||||||
node:
|
node:
|
||||||
- aws:arn:iam:123456789000:policy:test-policy
|
- arn:aws:iam::123456789000:policy/test-policy
|
||||||
master:
|
master:
|
||||||
- aws:arn:iam:123456789000:policy:test-policy
|
- arn:aws:iam::123456789000:policy/test-policy
|
||||||
bastion:
|
bastion:
|
||||||
- aws:arn:iam:123456789000:policy:test-policy
|
- arn:aws:iam::123456789000:policy/test-policy
|
||||||
subnets:
|
subnets:
|
||||||
- cidr: 172.20.32.0/19
|
- cidr: 172.20.32.0/19
|
||||||
name: us-test-1a
|
name: us-test-1a
|
||||||
|
|
|
||||||
|
|
@ -268,13 +268,13 @@ resource "aws_iam_instance_profile" "nodes-externalpolicies-example-com" {
|
||||||
role = aws_iam_role.nodes-externalpolicies-example-com.name
|
role = aws_iam_role.nodes-externalpolicies-example-com.name
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_role_policy_attachment" "master-policyoverride-1178482798" {
|
resource "aws_iam_role_policy_attachment" "master-policyoverride-1242070525" {
|
||||||
policy_arn = "aws:arn:iam:123456789000:policy:test-policy"
|
policy_arn = "arn:aws:iam::123456789000:policy/test-policy"
|
||||||
role = aws_iam_role.masters-externalpolicies-example-com.name
|
role = aws_iam_role.masters-externalpolicies-example-com.name
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_role_policy_attachment" "node-policyoverride-1178482798" {
|
resource "aws_iam_role_policy_attachment" "node-policyoverride-1242070525" {
|
||||||
policy_arn = "aws:arn:iam:123456789000:policy:test-policy"
|
policy_arn = "arn:aws:iam::123456789000:policy/test-policy"
|
||||||
role = aws_iam_role.nodes-externalpolicies-example-com.name
|
role = aws_iam_role.nodes-externalpolicies-example-com.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue