Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

generic Kubernetes API server config interface #2012

Merged
merged 10 commits into from Jan 9, 2018
57 changes: 55 additions & 2 deletions docs/clusterdefinition.md
Expand Up @@ -209,7 +209,7 @@ Below is a list of controller-manager options that acs-engine will configure by
|"--route-reconciliation-period"|"10s"|


Below is a list of kubelet options that are *not* currently user-configurable, either because a higher order configuration vector is available that enforces kubelet configuration, or because a static configuration is required to build a functional cluster:
Below is a list of controller-manager options that are *not* currently user-configurable, either because a higher order configuration vector is available that enforces controller-manager configuration, or because a static configuration is required to build a functional cluster:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correcting copy/paste errors from a prior, related PR.


|controller-manager option|default value|
|---|---|
Expand All @@ -228,7 +228,60 @@ Below is a list of kubelet options that are *not* currently user-configurable, e
|"--profiling"|"false"|
|"--use-service-account-credentials"|"false" ("true" if kubernetesConfig.enableRbac is true)|

We consider `kubeletConfig` and `controllerManagerConfig` to be generic conveniences that add power/flexibility to cluster deployments. Their usage comes with no operational guarantees! They are manual tuning features that enable low-level configuration of a kubernetes cluster.
#### apiServerConfig

`apiServerConfig` declares runtime configuration for the kube-apiserver daemon running on all master nodes. Like `kubeletConfig` and `controllerManagerConfig` it is a generic key/value object, and a child property of `kubernetesConfig`. An example custom apiserver config:

```
"kubernetesConfig": {
"apiServerConfig": {
"--request-timeout": "30s"
}
}
```

See [here](https://kubernetes.io/docs/reference/generated/kube-apiserver/) for a reference of supported apiserver options.

Below is a list of apiserver options that are *not* currently user-configurable, either because a higher order configuration vector is available that enforces kubelet configuration, or because a static configuration is required to build a functional cluster:

|apiserver option|default value|
|---|---|
|"--admission-control"|"NamespaceLifecycle, LimitRanger, ServiceAccount, DefaultStorageClass, ResourceQuota, DenyEscalatingExec"|
|"--address"|"0.0.0.0"|
|"--advertise-address"|*calculated value that represents listening URI for API server*|
|"--allow-privileged"|"true"|
|"--insecure-port"|"8080"|
|"--secure-port"|"443"|
|"--etcd-cafile"|"/etc/kubernetes/certs/ca.crt"|
|"--etcd-certfile"|"/etc/kubernetes/certs/etcdclient.crt"|
|"--etcd-keyfile"|"/etc/kubernetes/certs/etcdclient.key"|
|"--etcd-servers"|*calculated value that represents etcd servers*|
|"--etcd-quorum-read"|"true"|
|"--tls-cert-file"|"/etc/kubernetes/certs/apiserver.crt"|
|"--tls-private-key-file"|"/etc/kubernetes/certs/apiserver.key"|
|"--client-ca-file"|"/etc/kubernetes/certs/ca.crt"|
|"--service-account-key-file"|"/etc/kubernetes/certs/apiserver.key"|
|"--kubelet-client-certificate"|"/etc/kubernetes/certs/client.crt"|
|"--kubelet-client-key"|"/etc/kubernetes/certs/client.key"|
|"--service-cluster-ip-range"|*see serviceCIDR*|
|"--storage-backend"|*calculated value that represents etcd version*|
|"--v"|"4"|
|"--authorization-mode"|"RBAC" (*if enabledRbac is true*)|
|"--experimental-encryption-provider-config"|"/etc/kubernetes/encryption-config.yaml" (*if enableDataEncryptionAtRest is true*)|
|"--requestheader-client-ca-file"|"/etc/kubernetes/certs/proxy-ca.crt" (*if enableAggregatedAPIs is true*)|
|"--proxy-client-cert-file"|"/etc/kubernetes/certs/proxy.crt" (*if enableAggregatedAPIs is true*)|
|"--proxy-client-key-file"|"/etc/kubernetes/certs/proxy.key" (*if enableAggregatedAPIs is true*)|
|"--requestheader-allowed-names"|"" (*if enableAggregatedAPIs is true*)|
|"--requestheader-extra-headers-prefix"|"X-Remote-Extra-" (*if enableAggregatedAPIs is true*)|
|"--requestheader-group-headers"|"X-Remote-Group" (*if enableAggregatedAPIs is true*)|
|"--requestheader-username-headers"|"X-Remote-User" (*if enableAggregatedAPIs is true*)|
|"--cloud-provider"|"azure" (*unless useCloudControllerManager is true*)|
|"--cloud-config"|"/etc/kubernetes/azure.json" (*unless useCloudControllerManager is true*)|
|"--oidc-username-claim"|"oid" (*if has AADProfile*)|
|"--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*)|

We consider `kubeletConfig`, `controllerManagerConfig`, and `apiServerConfig` to be generic conveniences that add power/flexibility to cluster deployments. Their usage comes with no operational guarantees! They are manual tuning features that enable low-level configuration of a kubernetes cluster.

### masterProfile
`masterProfile` describes the settings for master configuration.
Expand Down
38 changes: 3 additions & 35 deletions parts/k8s/kubernetesmastercustomdata.yml
Expand Up @@ -182,23 +182,13 @@ MASTER_ARTIFACTS_CONFIG_PLACEHOLDER
{{end}}

{{ if .HasAadProfile }}
OIDC_CLIENT_ID=spn:{{WrapAsVariable "aadServerAppId"}}
VAR_AAD_TENANT_ID={{WrapAsVariable "aadTenantId"}}
VAR_TENANT_ID={{WrapAsVariable "tenantId"}}
VAR_TARGET_ENV={{WrapAsVariable "targetEnvironment"}}
AAD_TENANT_ID=${VAR_AAD_TENANT_ID:-$VAR_TENANT_ID}
AAD_ISSUER_HOST="sts.windows.net"
if [ "$VAR_TARGET_ENV" = "AzureChinaCloud" ]; then
AAD_ISSUER_HOST="sts.chinacloudapi.cn"
fi

OIDC_ISSUER_URL="https://$AAD_ISSUER_HOST/$AAD_TENANT_ID/"
perl -pi -e "s|--oidc-client-id=\K(?=\")|$OIDC_CLIENT_ID| || s|--oidc-issuer-url=\K(?=\")|$OIDC_ISSUER_URL|" "/etc/kubernetes/manifests/kube-apiserver.yaml"
{{else}}
sed -i "/--oidc-client-id\|--oidc-issuer-url\|--oidc-username-claim/d" "/etc/kubernetes/manifests/kube-apiserver.yaml"
sed -i "/--oidc-issuer-url/s/$/$AAD_TENANT_ID/" "/etc/kubernetes/manifests/kube-apiserver.yaml"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to do this post-deployment transformation because I'm not aware of any other way to implement the fallback tenantID assignment. The one here uses this kubernetesmastervars.t statement:

"tenantId": "[subscription().tenantId]",

Which gives us our fallback tenantId value (see AAD_TENANT_ID=${VAR_AAD_TENANT_ID:-$VAR_TENANT_ID} above). My understanding is that subscription() is an ARM function that we won't have access to anywhere else.

{{end}}
sed -i "s|<kubernetesAddonManagerSpec>|{{WrapAsVariable "kubernetesAddonManagerSpec"}}|g" "/etc/kubernetes/manifests/kube-addon-manager.yaml"
sed -i "s|<kubernetesHyperkubeSpec>|{{WrapAsVariable "kubernetesHyperkubeSpec"}}|g; s|<kubeServiceCidr>|{{WrapAsVariable "kubeServiceCidr"}}|g; s|<masterEtcdClientPort>|{{WrapAsVariable "masterEtcdClientPort"}}|g; s|<kubernetesAPIServerIP>|{{WrapAsVariable "kubernetesAPIServerIP"}}|g" "/etc/kubernetes/manifests/kube-apiserver.yaml"
sed -i "s|<kubernetesHyperkubeSpec>|{{WrapAsVariable "kubernetesHyperkubeSpec"}}|g; s|<kubernetesAPIServerIP>|{{WrapAsVariable "kubernetesAPIServerIP"}}|g" "/etc/kubernetes/manifests/kube-apiserver.yaml"
sed -i "s|<kubernetesHyperkubeSpec>|{{WrapAsVariable "kubernetesHyperkubeSpec"}}|g" "/etc/kubernetes/manifests/kube-controller-manager.yaml"
sed -i "s|<kubernetesHyperkubeSpec>|{{WrapAsVariable "kubernetesHyperkubeSpec"}}|g" "/etc/kubernetes/manifests/kube-scheduler.yaml"
sed -i "s|<kubernetesHyperkubeSpec>|{{WrapAsVariable "kubernetesHyperkubeSpec"}}|g; s|<kubeClusterCidr>|{{WrapAsVariable "kubeClusterCidr"}}|g" "/etc/kubernetes/addons/kube-proxy-daemonset.yaml"
Expand Down Expand Up @@ -245,47 +235,25 @@ MASTER_ARTIFACTS_CONFIG_PLACEHOLDER
sed -i "s|<kubernetesReschedulerMemoryLimit>|{{WrapAsVariable "kubernetesReschedulerMemoryLimit"}}|g" "/etc/kubernetes/addons/kube-rescheduler-deployment.yaml"
{{end}}

{{if .OrchestratorProfile.KubernetesConfig.EnableRbac }}
# If RBAC enabled then add parameters to API server and Controller manager configuration
sed -i "s|<kubernetesEnableRbac>|--authorization-mode=RBAC|g" "/etc/kubernetes/manifests/kube-apiserver.yaml"
{{else}}
sed -i "/<kubernetesEnableRbac>/d" "/etc/kubernetes/manifests/kube-apiserver.yaml"
{{end}}

{{if EnableDataEncryptionAtRest }}
ETCD_ENCRYPTION_SECRET="$(head -c 32 /dev/urandom | base64)"
sed -i "s|<etcdEncryptionSecret>|$ETCD_ENCRYPTION_SECRET|g" "/etc/kubernetes/encryption-config.yaml"
sed -i "s|<kubernetesEnableEtcdEncryption>|--experimental-encryption-provider-config=/etc/kubernetes/encryption-config.yaml|g" "/etc/kubernetes/manifests/kube-apiserver.yaml"
{{else}}
sed -i "/<kubernetesEnableEtcdEncryption>/d" "/etc/kubernetes/manifests/kube-apiserver.yaml"
{{end}}

{{if eq .OrchestratorProfile.KubernetesConfig.NetworkPolicy "calico"}}
# If Calico Policy enabled then update Cluster Cidr
sed -i "s|<kubeClusterCidr>|{{WrapAsVariable "kubeClusterCidr"}}|g" "/etc/kubernetes/addons/calico-daemonset.yaml"
{{end}}

{{if not .OrchestratorProfile.KubernetesConfig.EnableAggregatedAPIs}}
sed -i "/requestheader-client-ca-file/d" "/etc/kubernetes/manifests/kube-apiserver.yaml"
sed -i "/proxy-client-cert-file/d" "/etc/kubernetes/manifests/kube-apiserver.yaml"
sed -i "/proxy-client-key-file/d" "/etc/kubernetes/manifests/kube-apiserver.yaml"
sed -i "/requestheader-allowed-names/d" "/etc/kubernetes/manifests/kube-apiserver.yaml"
sed -i "/requestheader-extra-headers-prefix/d" "/etc/kubernetes/manifests/kube-apiserver.yaml"
sed -i "/requestheader-group-headers/d" "/etc/kubernetes/manifests/kube-apiserver.yaml"
sed -i "/requestheader-username-headers/d" "/etc/kubernetes/manifests/kube-apiserver.yaml"
{{end}}
sed -i "s|<etcdApiVersion>|{{ .OrchestratorProfile.GetAPIServerEtcdAPIVersion }}|g" "/etc/kubernetes/manifests/kube-apiserver.yaml"

{{if UseCloudControllerManager }}
sed -i "s|<kubernetesCcmImageSpec>|{{WrapAsVariable "kubernetesCcmImageSpec"}}|g; s|<masterFqdnPrefix>|{{WrapAsVariable "masterFqdnPrefix"}}|g; s|<allocateNodeCidrs>|{{WrapAsVariable "allocateNodeCidrs"}}|g; s|<kubeClusterCidr>|{{WrapAsVariable "kubeClusterCidr"}}|g; s|<kubernetesCtrlMgrRouteReconciliationPeriod>|{{GetCloudControllerManagerRouteReconciliationPeriod .OrchestratorProfile.KubernetesConfig}}|g" \
/etc/kubernetes/manifests/cloud-controller-manager.yaml

sed -i "/--\(cloud-config\|cloud-provider\|route-reconciliation-period\)=/d" \
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have been removed in #1960, doing so now.

/etc/kubernetes/manifests/kube-controller-manager.yaml
sed -i "/--\(cloud-config\|cloud-provider\)=/d" \
/etc/kubernetes/manifests/kube-apiserver.yaml
{{end}}
sed -i "s|<kubernetesControllerManagerConfig>|{{GetControllerManagerConfigKeyVals .OrchestratorProfile.KubernetesConfig}}|g" "/etc/kubernetes/manifests/kube-controller-manager.yaml"
sed -i "s|<kubernetesAPIServerConfig>|{{GetAPIServerConfigKeyVals .OrchestratorProfile.KubernetesConfig}}|g" "/etc/kubernetes/manifests/kube-apiserver.yaml"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is probably better to take APIServerConfig (instead of KubernetesConfig) as argument for GetAPIServerConfigKeyVals.

The original code logic is pretty tangled here and I have not dig very deep, I assume GetAPIServerConfigKeyVals will return the already processed argument map. Please just confirm it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good feedback. Let's do this: after all of these config refactors are done, we can optimize the number of key/val getter functions in engine.go (we have two types, I think, which is better than having one function per config file). A part of that improvement would be passing in the specific config as the arg instead of kubernetesConfig.


- path: "/opt/azure/containers/provision.sh"
permissions: "0744"
Expand Down
5 changes: 2 additions & 3 deletions parts/k8s/kubernetesmastervars.t
Expand Up @@ -109,7 +109,6 @@
{{end}}
"sshPublicKeyData": "[parameters('sshRSAPublicKey')]",
{{if .HasAadProfile}}
"aadServerAppId": "[parameters('aadServerAppId')]",
"aadTenantId": "[parameters('aadTenantId')]",
{{end}}
{{if not IsHostedMaster}}
Expand Down Expand Up @@ -267,8 +266,8 @@
"[concat(variables('masterFirstAddrPrefix'), add(3, int(variables('masterFirstAddrOctet4'))))]",
"[concat(variables('masterFirstAddrPrefix'), add(4, int(variables('masterFirstAddrOctet4'))))]"
],
"masterEtcdServerPort": 2380,
"masterEtcdClientPort": 2379,
"masterEtcdServerPort": "[parameters('masterEtcdServerPort')]",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved these vals to pkg/acsengine/const.go (and added appropriate changes elswhere).

"masterEtcdClientPort": "[parameters('masterEtcdClientPort')]",
"masterEtcdPeerURLs":[
"[concat('https://', variables('masterPrivateIpAddrs')[0], ':', variables('masterEtcdServerPort'))]",
"[concat('https://', variables('masterPrivateIpAddrs')[1], ':', variables('masterEtcdServerPort'))]",
Expand Down
6 changes: 0 additions & 6 deletions parts/k8s/kubernetesparams.t
@@ -1,10 +1,4 @@
{{if .HasAadProfile}}
"aadServerAppId": {
"metadata": {
"description": "The server AAD application ID"
},
"type": "string"
},
"aadTenantId": {
"defaultValue": "",
"metadata": {
Expand Down
Expand Up @@ -21,7 +21,6 @@ spec:
- "--cloud-config=/etc/kubernetes/azure.json"
- "--leader-elect=true"
# TODO: RBAC support
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to remove RBAC placeholder here? Seems not related to this PR. If so, remove the above TODO comment too?

# - "<kubernetesEnableRbac>"
- "--route-reconciliation-period=<kubernetesCtrlMgrRouteReconciliationPeriod>"
- "--v=2"
volumeMounts:
Expand Down
39 changes: 2 additions & 37 deletions parts/k8s/manifests/kubernetesmaster-kube-apiserver.yaml
Expand Up @@ -11,43 +11,8 @@ spec:
containers:
- name: "kube-apiserver"
image: "<kubernetesHyperkubeSpec>"
command:
- "/hyperkube"
- "apiserver"
- "--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota,DenyEscalatingExec"
- "--address=0.0.0.0"
- "--allow-privileged"
- "--insecure-port=8080"
- "--secure-port=443"
- "--cloud-provider=azure"
- "--cloud-config=/etc/kubernetes/azure.json"
- "--service-cluster-ip-range=<kubeServiceCidr>"
- "--etcd-cafile=/etc/kubernetes/certs/ca.crt"
- "--etcd-certfile=/etc/kubernetes/certs/etcdclient.crt"
- "--etcd-keyfile=/etc/kubernetes/certs/etcdclient.key"
- "--etcd-servers=https://127.0.0.1:<masterEtcdClientPort>"
- "--etcd-quorum-read=true"
- "--advertise-address=<kubernetesAPIServerIP>"
- "--tls-cert-file=/etc/kubernetes/certs/apiserver.crt"
- "--tls-private-key-file=/etc/kubernetes/certs/apiserver.key"
- "--client-ca-file=/etc/kubernetes/certs/ca.crt"
- "--requestheader-client-ca-file=/etc/kubernetes/certs/proxy-ca.crt"
- "--proxy-client-cert-file=/etc/kubernetes/certs/proxy.crt"
- "--proxy-client-key-file=/etc/kubernetes/certs/proxy.key"
- "--service-account-key-file=/etc/kubernetes/certs/apiserver.key"
- "--kubelet-client-certificate=/etc/kubernetes/certs/client.crt"
- "--kubelet-client-key=/etc/kubernetes/certs/client.key"
- "--oidc-client-id="
- "--oidc-issuer-url="
- "--oidc-username-claim=oid"
- "--storage-backend=<etcdApiVersion>"
- "--v=4"
- "<kubernetesEnableRbac>"
- "<kubernetesEnableEtcdEncryption>"
- "--requestheader-allowed-names="
- "--requestheader-extra-headers-prefix=X-Remote-Extra-"
- "--requestheader-group-headers=X-Remote-Group"
- "--requestheader-username-headers=X-Remote-User"
command: ["/hyperkube", "apiserver"]
args: [<kubernetesAPIServerConfig>]
volumeMounts:
- name: "etc-kubernetes"
mountPath: "/etc/kubernetes"
Expand Down
4 changes: 4 additions & 0 deletions pkg/acsengine/const.go
Expand Up @@ -105,6 +105,10 @@ const (
DefaultReschedulerAddonName = "rescheduler"
// DefaultKubernetesKubeletMaxPods is the max pods per kubelet
DefaultKubernetesKubeletMaxPods = 110
// DefaultMasterEtcdClientPort is the etcd client port for master nodes
DefaultMasterEtcdClientPort = 2379
// DefaultMasterEtcdServerPort is the etcd server port for master nodes
DefaultMasterEtcdServerPort = 2380
)

const (
Expand Down
102 changes: 102 additions & 0 deletions pkg/acsengine/defaults-apiserver.go
@@ -0,0 +1,102 @@
package acsengine

import (
"strconv"

"github.com/Azure/acs-engine/pkg/api"
"github.com/Azure/acs-engine/pkg/helpers"
)

func setAPIServerConfig(cs *api.ContainerService) {
o := cs.Properties.OrchestratorProfile
staticLinuxAPIServerConfig := map[string]string{
"--admission-control": "NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota,DenyEscalatingExec",
"--address": "0.0.0.0",
"--advertise-address": "<kubernetesAPIServerIP>",
"--allow-privileged": "true",
"--insecure-port": "8080",
"--secure-port": "443",
"--etcd-cafile": "/etc/kubernetes/certs/ca.crt",
"--etcd-certfile": "/etc/kubernetes/certs/etcdclient.crt",
"--etcd-keyfile": "/etc/kubernetes/certs/etcdclient.key",
"--etcd-servers": "https://127.0.0.1:" + strconv.Itoa(DefaultMasterEtcdClientPort),
"--etcd-quorum-read": "true",
"--tls-cert-file": "/etc/kubernetes/certs/apiserver.crt",
"--tls-private-key-file": "/etc/kubernetes/certs/apiserver.key",
"--client-ca-file": "/etc/kubernetes/certs/ca.crt",
"--service-account-key-file": "/etc/kubernetes/certs/apiserver.key",
"--kubelet-client-certificate": "/etc/kubernetes/certs/client.crt",
"--kubelet-client-key": "/etc/kubernetes/certs/client.key",
"--service-cluster-ip-range": o.KubernetesConfig.ServiceCIDR,
"--storage-backend": o.GetAPIServerEtcdAPIVersion(),
"--v": "4",
}

if helpers.IsTrueBoolPointer(o.KubernetesConfig.EnableRbac) {
staticLinuxAPIServerConfig["--authorization-mode"] = "RBAC"
}

if helpers.IsTrueBoolPointer(o.KubernetesConfig.EnableDataEncryptionAtRest) {
staticLinuxAPIServerConfig["--experimental-encryption-provider-config"] = "/etc/kubernetes/encryption-config.yaml"
}

if o.KubernetesConfig.EnableAggregatedAPIs {
staticLinuxAPIServerConfig["--requestheader-client-ca-file"] = "/etc/kubernetes/certs/proxy-ca.crt"
staticLinuxAPIServerConfig["--proxy-client-cert-file"] = "/etc/kubernetes/certs/proxy.crt"
staticLinuxAPIServerConfig["--proxy-client-key-file"] = "/etc/kubernetes/certs/proxy.key"
staticLinuxAPIServerConfig["--requestheader-allowed-names"] = ""
staticLinuxAPIServerConfig["--requestheader-extra-headers-prefix"] = "X-Remote-Extra-"
staticLinuxAPIServerConfig["--requestheader-group-headers"] = "X-Remote-Group"
staticLinuxAPIServerConfig["--requestheader-username-headers"] = "X-Remote-User"
}

if !helpers.IsTrueBoolPointer(o.KubernetesConfig.UseCloudControllerManager) {
staticLinuxAPIServerConfig["--cloud-provider"] = "azure"
staticLinuxAPIServerConfig["--cloud-config"] = "/etc/kubernetes/azure.json"
}

if cs.Properties.HasAadProfile() {
staticLinuxAPIServerConfig["--oidc-username-claim"] = "oid"
staticLinuxAPIServerConfig["--oidc-client-id"] = "spn:" + cs.Properties.AADProfile.ServerAppID
issuerHost := "sts.windows.net"
if GetCloudTargetEnv(cs.Location) == "AzureChinaCloud" {
issuerHost = "sts.chinacloudapi.cn"
}
staticLinuxAPIServerConfig["--oidc-issuer-url"] = "https://" + issuerHost + "/"
}

staticWindowsAPIServerConfig := make(map[string]string)
for key, val := range staticLinuxAPIServerConfig {
staticWindowsAPIServerConfig[key] = val
}
// Windows apiserver config overrides
// TODO placeholder for specific config overrides for Windows clusters

// Default apiserver config
defaultAPIServerConfig := map[string]string{}

// If no user-configurable apiserver config values exists, use the defaults
if o.KubernetesConfig.APIServerConfig == nil {
o.KubernetesConfig.APIServerConfig = defaultAPIServerConfig
} else {
for key, val := range defaultAPIServerConfig {
// If we don't have a user-configurable apiserver config for each option
if _, ok := o.KubernetesConfig.APIServerConfig[key]; !ok {
// then assign the default value
o.KubernetesConfig.APIServerConfig[key] = val
}
}
}

// We don't support user-configurable values for the following,
// so any of the value assignments below will override user-provided values
var overrideAPIServerConfig map[string]string
if cs.Properties.HasWindows() {
overrideAPIServerConfig = staticWindowsAPIServerConfig
} else {
overrideAPIServerConfig = staticLinuxAPIServerConfig
}
for key, val := range overrideAPIServerConfig {
o.KubernetesConfig.APIServerConfig[key] = val
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some argument like "--admission-control" and "--authorization-mode" takes a list of features, and probably should allow feature addition (as long as static config is a subset of the user input config), instead of override. It can be done in a later change if needed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this would be a useful addition to this surface area. Feature gates also are special, in that they essentially contain key/vals themselves. Yeah, I'd prefer a follow-up PR for that.

}
}
2 changes: 2 additions & 0 deletions pkg/acsengine/defaults.go
Expand Up @@ -403,6 +403,8 @@ func setOrchestratorDefaults(cs *api.ContainerService) {
setKubeletConfig(cs)
// Configure controller-manager
setControllerManagerConfig(cs)
// Configure apiserver
setAPIServerConfig(cs)

} else if o.OrchestratorType == api.DCOS {
if o.DcosConfig == nil {
Expand Down