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