Unverified Commit ca696fef authored by k8s-ci-robot's avatar k8s-ci-robot Committed by GitHub

Merge pull request #69848 from mikedanese/projadmission

migrate service account volume to a projected volume when BoundServiceAccountTokenVolumes are enabled
parents 9bd9bf71 1244ee66
......@@ -17,19 +17,22 @@ spec:
scheduler.alpha.kubernetes.io/critical-pod: ''
spec:
priorityClassName: system-cluster-critical
securityContext:
supplementalGroups: [ 65534 ]
fsGroup: 65534
containers:
- image: k8s.gcr.io/cluster-proportional-autoscaler-amd64:1.1.2-r2
name: autoscaler
command:
- /cluster-proportional-autoscaler
- --namespace=kube-system
- --configmap=calico-typha-horizontal-autoscaler
- --target=deployment/calico-typha
- --logtostderr=true
- --v=2
resources:
requests:
cpu: 10m
limits:
cpu: 10m
- image: k8s.gcr.io/cluster-proportional-autoscaler-amd64:1.1.2-r2
name: autoscaler
command:
- /cluster-proportional-autoscaler
- --namespace=kube-system
- --configmap=calico-typha-horizontal-autoscaler
- --target=deployment/calico-typha
- --logtostderr=true
- --v=2
resources:
requests:
cpu: 10m
limits:
cpu: 10m
serviceAccountName: typha-cpha
......@@ -59,6 +59,9 @@ spec:
seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
spec:
priorityClassName: system-cluster-critical
securityContext:
supplementalGroups: [ 65534 ]
fsGroup: 65534
containers:
- image: k8s.gcr.io/heapster-amd64:v1.6.0-beta.1
name: heapster
......
......@@ -59,6 +59,9 @@ spec:
seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
spec:
priorityClassName: system-cluster-critical
securityContext:
supplementalGroups: [ 65534 ]
fsGroup: 65534
containers:
- image: k8s.gcr.io/heapster-amd64:v1.6.0-beta.1
name: heapster
......
......@@ -59,6 +59,9 @@ spec:
seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
spec:
priorityClassName: system-cluster-critical
securityContext:
supplementalGroups: [ 65534 ]
fsGroup: 65534
containers:
- image: k8s.gcr.io/heapster-amd64:v1.6.0-beta.1
name: heapster
......
......@@ -46,6 +46,9 @@ spec:
seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
spec:
priorityClassName: system-cluster-critical
securityContext:
supplementalGroups: [ 65534 ]
fsGroup: 65534
containers:
- image: k8s.gcr.io/heapster-amd64:v1.6.0-beta.1
name: heapster
......
......@@ -46,6 +46,9 @@ spec:
seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
spec:
priorityClassName: system-cluster-critical
securityContext:
supplementalGroups: [ 65534 ]
fsGroup: 65534
containers:
- image: k8s.gcr.io/heapster-amd64:v1.6.0-beta.1
name: heapster
......
......@@ -80,6 +80,9 @@ spec:
seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
spec:
priorityClassName: system-cluster-critical
securityContext:
supplementalGroups: [ 65534 ]
fsGroup: 65534
containers:
- name: autoscaler
image: k8s.gcr.io/cluster-proportional-autoscaler-amd64:1.3.0
......
......@@ -86,6 +86,9 @@ spec:
seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
spec:
priorityClassName: system-cluster-critical
securityContext:
supplementalGroups: [ 65534 ]
fsGroup: 65534
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
......
......@@ -86,6 +86,9 @@ spec:
seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
spec:
priorityClassName: system-cluster-critical
securityContext:
supplementalGroups: [ 65534 ]
fsGroup: 65534
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
......
......@@ -86,6 +86,9 @@ spec:
seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
spec:
priorityClassName: system-cluster-critical
securityContext:
supplementalGroups: [ 65534 ]
fsGroup: 65534
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
......
......@@ -19,6 +19,7 @@ spec:
volumes:
- 'hostPath'
- 'secret'
- 'projected'
# TODO: This only needs a hostPath to read /etc/ssl/certs,
# but it should be able to just include these in the image.
allowedHostPaths:
......
......@@ -20,6 +20,7 @@ spec:
- 'configMap'
- 'hostPath'
- 'secret'
- 'projected'
allowedHostPaths:
- pathPrefix: /var/log
- pathPrefix: /var/lib/docker/containers
......
......@@ -15,6 +15,7 @@ spec:
volumes:
- 'nfs'
- 'secret' # Required for service account credentials.
- 'projected'
hostNetwork: false
hostIPC: false
hostPID: false
......
......@@ -39,6 +39,7 @@ spec:
- 'emptyDir'
- 'configMap'
- 'secret'
- 'projected'
hostNetwork: false
hostIPC: false
hostPID: false
......
......@@ -16,6 +16,7 @@ go_library(
deps = [
"//pkg/api/pod:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/features:go_default_library",
"//pkg/kubeapiserver/admission/util:go_default_library",
"//pkg/serviceaccount:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
......@@ -27,6 +28,7 @@ go_library(
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/initializer:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/client-go/informers:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/listers/core/v1:go_default_library",
......@@ -40,12 +42,14 @@ go_test(
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/controller:go_default_library",
"//pkg/features:go_default_library",
"//pkg/kubelet/types:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/client-go/informers:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/listers/core/v1:go_default_library",
......
......@@ -21,6 +21,7 @@ import (
"io"
"math/rand"
"strconv"
"strings"
"time"
corev1 "k8s.io/api/core/v1"
......@@ -32,28 +33,34 @@ import (
"k8s.io/apiserver/pkg/admission"
genericadmissioninitializer "k8s.io/apiserver/pkg/admission/initializer"
"k8s.io/apiserver/pkg/storage/names"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
corev1listers "k8s.io/client-go/listers/core/v1"
podutil "k8s.io/kubernetes/pkg/api/pod"
api "k8s.io/kubernetes/pkg/apis/core"
kubefeatures "k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/kubeapiserver/admission/util"
"k8s.io/kubernetes/pkg/serviceaccount"
)
// DefaultServiceAccountName is the name of the default service account to set on pods which do not specify a service account
const DefaultServiceAccountName = "default"
const (
// DefaultServiceAccountName is the name of the default service account to set on pods which do not specify a service account
DefaultServiceAccountName = "default"
// EnforceMountableSecretsAnnotation is a default annotation that indicates that a service account should enforce mountable secrets.
// The value must be true to have this annotation take effect
const EnforceMountableSecretsAnnotation = "kubernetes.io/enforce-mountable-secrets"
// EnforceMountableSecretsAnnotation is a default annotation that indicates that a service account should enforce mountable secrets.
// The value must be true to have this annotation take effect
EnforceMountableSecretsAnnotation = "kubernetes.io/enforce-mountable-secrets"
// DefaultAPITokenMountPath is the path that ServiceAccountToken secrets are automounted to.
// The token file would then be accessible at /var/run/secrets/kubernetes.io/serviceaccount
const DefaultAPITokenMountPath = "/var/run/secrets/kubernetes.io/serviceaccount"
ServiceAccountVolumeName = "kube-api-access"
// PluginName is the name of this admission plugin
const PluginName = "ServiceAccount"
// DefaultAPITokenMountPath is the path that ServiceAccountToken secrets are automounted to.
// The token file would then be accessible at /var/run/secrets/kubernetes.io/serviceaccount
DefaultAPITokenMountPath = "/var/run/secrets/kubernetes.io/serviceaccount"
// PluginName is the name of this admission plugin
PluginName = "ServiceAccount"
)
// Register registers a plugin
func Register(plugins *admission.Plugins) {
......@@ -79,6 +86,10 @@ type serviceAccount struct {
serviceAccountLister corev1listers.ServiceAccountLister
secretLister corev1listers.SecretLister
generateName func(string) string
featureGate utilfeature.FeatureGate
}
var _ admission.MutationInterface = &serviceAccount{}
......@@ -101,6 +112,10 @@ func NewServiceAccount() *serviceAccount {
MountServiceAccountToken: true,
// Reject pod creation until a service account token is available
RequireAPIToken: true,
generateName: names.SimpleNameGenerator.GenerateName,
featureGate: utilfeature.DefaultFeatureGate,
}
}
......@@ -434,7 +449,8 @@ func (s *serviceAccount) mountServiceAccountToken(serviceAccount *corev1.Service
allVolumeNames := sets.NewString()
for _, volume := range pod.Spec.Volumes {
allVolumeNames.Insert(volume.Name)
if volume.Secret != nil && volume.Secret.SecretName == serviceAccountToken {
if (!s.featureGate.Enabled(kubefeatures.BoundServiceAccountTokenVolume) && volume.Secret != nil && volume.Secret.SecretName == serviceAccountToken) ||
(s.featureGate.Enabled(kubefeatures.BoundServiceAccountTokenVolume) && strings.HasPrefix(volume.Name, ServiceAccountVolumeName+"-")) {
tokenVolumeName = volume.Name
hasTokenVolume = true
break
......@@ -443,10 +459,14 @@ func (s *serviceAccount) mountServiceAccountToken(serviceAccount *corev1.Service
// Determine a volume name for the ServiceAccountTokenSecret in case we need it
if len(tokenVolumeName) == 0 {
// Try naming the volume the same as the serviceAccountToken, and uniquify if needed
tokenVolumeName = serviceAccountToken
if allVolumeNames.Has(tokenVolumeName) {
tokenVolumeName = names.SimpleNameGenerator.GenerateName(fmt.Sprintf("%s-", serviceAccountToken))
if s.featureGate.Enabled(kubefeatures.BoundServiceAccountTokenVolume) {
tokenVolumeName = s.generateName(ServiceAccountVolumeName + "-")
} else {
// Try naming the volume the same as the serviceAccountToken, and uniquify if needed
tokenVolumeName = serviceAccountToken
if allVolumeNames.Has(tokenVolumeName) {
tokenVolumeName = s.generateName(fmt.Sprintf("%s-", serviceAccountToken))
}
}
}
......@@ -490,15 +510,61 @@ func (s *serviceAccount) mountServiceAccountToken(serviceAccount *corev1.Service
// Add the volume if a container needs it
if !hasTokenVolume && needsTokenVolume {
volume := api.Volume{
pod.Spec.Volumes = append(pod.Spec.Volumes, s.createVolume(tokenVolumeName, serviceAccountToken))
}
return nil
}
func (s *serviceAccount) createVolume(tokenVolumeName, secretName string) api.Volume {
if s.featureGate.Enabled(kubefeatures.BoundServiceAccountTokenVolume) {
return api.Volume{
Name: tokenVolumeName,
VolumeSource: api.VolumeSource{
Secret: &api.SecretVolumeSource{
SecretName: serviceAccountToken,
Projected: &api.ProjectedVolumeSource{
Sources: []api.VolumeProjection{
{
ServiceAccountToken: &api.ServiceAccountTokenProjection{
Path: "token",
ExpirationSeconds: 60 * 60,
},
},
{
ConfigMap: &api.ConfigMapProjection{
LocalObjectReference: api.LocalObjectReference{
Name: "kube-root-ca.crt",
},
Items: []api.KeyToPath{
{
Key: "ca.crt",
Path: "ca.crt",
},
},
},
},
{
DownwardAPI: &api.DownwardAPIProjection{
Items: []api.DownwardAPIVolumeFile{
{
Path: "namespace",
FieldRef: &api.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.namespace",
},
},
},
},
},
},
},
},
}
pod.Spec.Volumes = append(pod.Spec.Volumes, volume)
}
return nil
return api.Volume{
Name: tokenVolumeName,
VolumeSource: api.VolumeSource{
Secret: &api.SecretVolumeSource{
SecretName: secretName,
},
},
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment