diff --git a/docs/clusterdefinition.md b/docs/clusterdefinition.md index 9cb8e06b9..456bc277e 100644 --- a/docs/clusterdefinition.md +++ b/docs/clusterdefinition.md @@ -313,7 +313,8 @@ Below is a list of apiserver options that acs-engine will configure by default: |apiserver option|default value| |---|---| -|"--admission-control"|"NamespaceLifecycle, LimitRanger, ServiceAccount, DefaultStorageClass, ResourceQuota, DenyEscalatingExec, AlwaysPullImages"| +|"--admission-control"|"NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota,DenyEscalatingExec,AlwaysPullImages" (Kubernetes versions prior to 1.9.0| +|"--enable-admission-plugins"`*`|"NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,DenyEscalatingExec,AlwaysPullImages" (Kubernetes versions 1.9.0 and later| |"--authorization-mode"|"Node", "RBAC" (*the latter if enabledRbac is true*)| |"--audit-log-maxage"|"30"| |"--audit-log-maxbackup"|"10"| @@ -324,6 +325,8 @@ Below is a list of apiserver options that acs-engine will configure by default: |"--oidc-client-id"|*calculated value that represents OID client ID* (*if has AADProfile*)| |"--oidc-issuer-url"|*calculated value that represents OID issuer URL* (*if has AADProfile*)| +`*` In Kubernetes versions 1.10.0 and later the `--admission-control` flag is deprecated and `--enable-admission-plugins` is used in its stead. + Below is a list of apiserver options that are *not* currently user-configurable, either because a higher order configuration vector is available that enforces apiserver configuration, or because a static configuration is required to build a functional cluster: diff --git a/pkg/acsengine/defaults-apiserver.go b/pkg/acsengine/defaults-apiserver.go index 3b7c7edb6..620cbfda0 100644 --- a/pkg/acsengine/defaults-apiserver.go +++ b/pkg/acsengine/defaults-apiserver.go @@ -45,7 +45,6 @@ func setAPIServerConfig(cs *api.ContainerService) { // Default apiserver config defaultAPIServerConfig := map[string]string{ - "--admission-control": "NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota,DenyEscalatingExec,AlwaysPullImages", "--audit-log-maxage": "30", "--audit-log-maxbackup": "10", "--audit-log-maxsize": "100", @@ -104,10 +103,9 @@ func setAPIServerConfig(cs *api.ContainerService) { } } - // Pod Security Policy configuration - if helpers.IsTrueBoolPointer(o.KubernetesConfig.EnablePodSecurityPolicy) { - defaultAPIServerConfig["--admission-control"] = defaultAPIServerConfig["--admission-control"] + ",PodSecurityPolicy" - } + // Set default admission controllers + admissionControlKey, admissionControlValues := getDefaultAdmissionControls(cs) + defaultAPIServerConfig[admissionControlKey] = admissionControlValues // If no user-configurable apiserver config values exists, use the defaults if o.KubernetesConfig.APIServerConfig == nil { @@ -141,3 +139,29 @@ func setAPIServerConfig(cs *api.ContainerService) { } } } + +func getDefaultAdmissionControls(cs *api.ContainerService) (string, string) { + o := cs.Properties.OrchestratorProfile + admissionControlKey := "--enable-admission-plugins" + var admissionControlValues string + + // --admission-control was used in v1.9 and earlier and was deprecated in 1.10 + if !common.IsKubernetesVersionGe(o.OrchestratorVersion, "1.10.0") { + admissionControlKey = "--admission-control" + } + + // Add new version case when applying admission controllers only available in that version or later + switch { + case common.IsKubernetesVersionGe(o.OrchestratorVersion, "1.9.0"): + admissionControlValues = "NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,DenyEscalatingExec,AlwaysPullImages" + default: + admissionControlValues = "NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota,DenyEscalatingExec,AlwaysPullImages" + } + + // Pod Security Policy configuration + if helpers.IsTrueBoolPointer(o.KubernetesConfig.EnablePodSecurityPolicy) { + admissionControlValues += ",PodSecurityPolicy" + } + + return admissionControlKey, admissionControlValues +} diff --git a/pkg/acsengine/defaults-apiserver_test.go b/pkg/acsengine/defaults-apiserver_test.go index f3ed27c5f..791170caa 100644 --- a/pkg/acsengine/defaults-apiserver_test.go +++ b/pkg/acsengine/defaults-apiserver_test.go @@ -291,6 +291,43 @@ func TestAPIServerConfigEnableSecureKubelet(t *testing.T) { } } +func TestAPIServerConfigDefaultAdmissionControls(t *testing.T) { + // Test --enable-admission-plugins for v1.10 and above + version := "1.10.0" + cs := createContainerService("testcluster", version, 3, 2) + setAPIServerConfig(cs) + a := cs.Properties.OrchestratorProfile.KubernetesConfig.APIServerConfig + + enableAdmissionPluginsKey := "--enable-admission-plugins" + admissonControlKey := "--admission-control" + + // --enable-admission-plugins should be set for v1.10 and above + if _, found := a[enableAdmissionPluginsKey]; !found { + t.Fatalf("Admission control key '%s' not set in API server config for version %s", enableAdmissionPluginsKey, version) + } + + // --admission-control was deprecated in v1.10 + if _, found := a[admissonControlKey]; found { + t.Fatalf("Deprecated admission control key '%s' set in API server config for version %s", admissonControlKey, version) + } + + // Test --admission-control for v1.9 and below + version = "1.9.0" + cs = createContainerService("testcluster", version, 3, 2) + setAPIServerConfig(cs) + a = cs.Properties.OrchestratorProfile.KubernetesConfig.APIServerConfig + + // --enable-admission-plugins is available for v1.10 and above and should not be set here + if _, found := a[enableAdmissionPluginsKey]; found { + t.Fatalf("Unknown admission control key '%s' set in API server config for version %s", enableAdmissionPluginsKey, version) + } + + // --admission-control is used for v1.9 and below + if _, found := a[admissonControlKey]; !found { + t.Fatalf("Admission control key '%s' not set in API server config for version %s", enableAdmissionPluginsKey, version) + } +} + func createContainerService(containerServiceName string, orchestratorVersion string, masterCount int, agentCount int) *api.ContainerService { cs := api.ContainerService{} cs.ID = uuid.NewV4().String()