diff --git a/pkg/apis/kops/validation/validation.go b/pkg/apis/kops/validation/validation.go index 35b613e298f0b..4774af410102d 100644 --- a/pkg/apis/kops/validation/validation.go +++ b/pkg/apis/kops/validation/validation.go @@ -454,12 +454,33 @@ func validateKubeAPIServer(v *kops.KubeAPIServerConfig, c *kops.Cluster, fldPath } } - if v.AuthorizationMode != nil && strings.Contains(*v.AuthorizationMode, "Webhook") { - if v.AuthorizationWebhookConfigFile == nil { - allErrs = append(allErrs, field.Required(fldPath.Child("authorizationWebhookConfigFile"), "Authorization mode Webhook requires authorizationWebhookConfigFile to be specified")) + if v.AuthorizationMode != nil { + if strings.Contains(*v.AuthorizationMode, "Webhook") { + if v.AuthorizationWebhookConfigFile == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("authorizationWebhookConfigFile"), "Authorization mode Webhook requires authorizationWebhookConfigFile to be specified")) + } } - } + if c.Spec.Authorization != nil && c.Spec.Authorization.RBAC != nil { + + var hasNode, hasRBAC bool + for _, mode := range strings.Split(*v.AuthorizationMode, ",") { + switch mode { + case "Node": + hasNode = true + case "RBAC": + hasRBAC = true + default: + allErrs = append(allErrs, IsValidValue(fldPath.Child("authorizationMode"), &mode, []string{"ABAC", "Webhook", "Node", "RBAC", "AlwaysAllow", "AlwaysDeny"})...) + } + } + if kops.CloudProviderID(c.Spec.CloudProvider) == kops.CloudProviderAWS && c.IsKubernetesGTE("1.19") { + if !hasNode || !hasRBAC { + allErrs = append(allErrs, field.Required(fldPath.Child("authorizationMode"), "As of kubernetes 1.19 on AWS, authorizationMode must include RBAC and Node")) + } + } + } + } return allErrs } diff --git a/pkg/apis/kops/validation/validation_test.go b/pkg/apis/kops/validation/validation_test.go index 99ea847d0b6a5..9fc1df432a6a1 100644 --- a/pkg/apis/kops/validation/validation_test.go +++ b/pkg/apis/kops/validation/validation_test.go @@ -169,6 +169,7 @@ func TestValidateKubeAPIServer(t *testing.T) { grid := []struct { Input kops.KubeAPIServerConfig + Cluster *kops.Cluster ExpectedErrors []string ExpectedDetail string }{ @@ -207,14 +208,64 @@ func TestValidateKubeAPIServer(t *testing.T) { }, ExpectedDetail: "Authorization mode Webhook requires authorizationWebhookConfigFile to be specified", }, + { + Input: kops.KubeAPIServerConfig{ + AuthorizationMode: fi.String("RBAC"), + }, + Cluster: &kops.Cluster{ + Spec: kops.ClusterSpec{ + Authorization: &kops.AuthorizationSpec{ + RBAC: &kops.RBACAuthorizationSpec{}, + }, + KubernetesVersion: "1.19.0", + CloudProvider: "aws", + }, + }, + ExpectedErrors: []string{ + "Required value::KubeAPIServer.authorizationMode", + }, + }, + { + Input: kops.KubeAPIServerConfig{ + AuthorizationMode: fi.String("RBAC,Node"), + }, + Cluster: &kops.Cluster{ + Spec: kops.ClusterSpec{ + Authorization: &kops.AuthorizationSpec{ + RBAC: &kops.RBACAuthorizationSpec{}, + }, + KubernetesVersion: "1.19.0", + CloudProvider: "aws", + }, + }, + }, + { + Input: kops.KubeAPIServerConfig{ + AuthorizationMode: fi.String("RBAC,Node,Bogus"), + }, + Cluster: &kops.Cluster{ + Spec: kops.ClusterSpec{ + Authorization: &kops.AuthorizationSpec{ + RBAC: &kops.RBACAuthorizationSpec{}, + }, + KubernetesVersion: "1.19.0", + CloudProvider: "aws", + }, + }, + ExpectedErrors: []string{ + "Unsupported value::KubeAPIServer.authorizationMode", + }, + }, } for _, g := range grid { - cluster := &kops.Cluster{ - Spec: kops.ClusterSpec{ - KubernetesVersion: "1.16.0", - }, + if g.Cluster == nil { + g.Cluster = &kops.Cluster{ + Spec: kops.ClusterSpec{ + KubernetesVersion: "1.16.0", + }, + } } - errs := validateKubeAPIServer(&g.Input, cluster, field.NewPath("KubeAPIServer")) + errs := validateKubeAPIServer(&g.Input, g.Cluster, field.NewPath("KubeAPIServer")) testErrors(t, g.Input, errs, g.ExpectedErrors)