mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 03:11:40 +00:00
Merge pull request #92006 from zshihang/master
allow projected in psp when secret is allowed and boundedserviceaccounttoken is enabled
This commit is contained in:
commit
00cf315f3c
@ -32,6 +32,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/api/policy/v1beta1:go_default_library",
|
"//staging/src/k8s.io/api/policy/v1beta1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||||
],
|
],
|
||||||
@ -48,6 +49,7 @@ go_test(
|
|||||||
"//pkg/security/apparmor:go_default_library",
|
"//pkg/security/apparmor:go_default_library",
|
||||||
"//pkg/security/podsecuritypolicy/seccomp:go_default_library",
|
"//pkg/security/podsecuritypolicy/seccomp:go_default_library",
|
||||||
"//pkg/security/podsecuritypolicy/util:go_default_library",
|
"//pkg/security/podsecuritypolicy/util:go_default_library",
|
||||||
|
"//plugin/pkg/admission/serviceaccount:go_default_library",
|
||||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/api/policy/v1beta1:go_default_library",
|
"//staging/src/k8s.io/api/policy/v1beta1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
policy "k8s.io/api/policy/v1beta1"
|
policy "k8s.io/api/policy/v1beta1"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
podutil "k8s.io/kubernetes/pkg/api/pod"
|
podutil "k8s.io/kubernetes/pkg/api/pod"
|
||||||
@ -259,7 +260,7 @@ func (s *simpleProvider) validatePodVolumes(pod *api.Pod) field.ErrorList {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !allowsAllVolumeTypes && !allowedVolumes.Has(string(fsType)) {
|
if !allowsAllVolumeTypes && !allowsVolumeType(allowedVolumes, fsType, v) {
|
||||||
allErrs = append(allErrs, field.Invalid(
|
allErrs = append(allErrs, field.Invalid(
|
||||||
field.NewPath("spec", "volumes").Index(i), string(fsType),
|
field.NewPath("spec", "volumes").Index(i), string(fsType),
|
||||||
fmt.Sprintf("%s volumes are not allowed to be used", string(fsType))))
|
fmt.Sprintf("%s volumes are not allowed to be used", string(fsType))))
|
||||||
@ -449,3 +450,15 @@ func validateRuntimeClassName(actual *string, validNames []string) field.ErrorLi
|
|||||||
}
|
}
|
||||||
return field.ErrorList{field.Invalid(field.NewPath("spec", "runtimeClassName"), *actual, "")}
|
return field.ErrorList{field.Invalid(field.NewPath("spec", "runtimeClassName"), *actual, "")}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func allowsVolumeType(allowedVolumes sets.String, fsType policy.FSType, volume api.Volume) bool {
|
||||||
|
if allowedVolumes.Has(string(fsType)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// if secret volume is allowed, all the projected volume sources that projected service account token volumes expose are allowed, regardless of psp.
|
||||||
|
if allowedVolumes.Has(string(policy.Secret)) && fsType == policy.Projected && psputil.IsOnlyServiceAccountTokenSources(volume.VolumeSource.Projected) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -37,6 +37,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/security/apparmor"
|
"k8s.io/kubernetes/pkg/security/apparmor"
|
||||||
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp"
|
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp"
|
||||||
psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
|
psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
|
||||||
|
"k8s.io/kubernetes/plugin/pkg/admission/serviceaccount"
|
||||||
"k8s.io/utils/pointer"
|
"k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1373,6 +1374,66 @@ func TestValidateAllowedVolumes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateProjectedVolume(t *testing.T) {
|
||||||
|
pod := defaultPod()
|
||||||
|
psp := defaultPSP()
|
||||||
|
provider, err := NewSimpleProvider(psp, "namespace", NewSimpleStrategyFactory())
|
||||||
|
require.NoError(t, err, "error creating provider")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
allowedFSTypes []policy.FSType
|
||||||
|
projectedVolumeSource *api.ProjectedVolumeSource
|
||||||
|
wantAllow bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "deny if secret is not allowed",
|
||||||
|
allowedFSTypes: []policy.FSType{policy.EmptyDir},
|
||||||
|
projectedVolumeSource: serviceaccount.TokenVolumeSource(),
|
||||||
|
wantAllow: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "deny if the projected volume has volume source other than the ones in projected volume injected by service account token admission plugin",
|
||||||
|
allowedFSTypes: []policy.FSType{policy.Secret},
|
||||||
|
projectedVolumeSource: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{
|
||||||
|
ConfigMap: &api.ConfigMapProjection{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{
|
||||||
|
Name: "foo-ca.crt",
|
||||||
|
},
|
||||||
|
Items: []api.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "ca.crt",
|
||||||
|
Path: "ca.crt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
wantAllow: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "allow if secret is allowed and the projected volume sources equals to the ones injected by service account admission plugin",
|
||||||
|
allowedFSTypes: []policy.FSType{policy.Secret},
|
||||||
|
projectedVolumeSource: serviceaccount.TokenVolumeSource(),
|
||||||
|
wantAllow: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
pod.Spec.Volumes = []api.Volume{{VolumeSource: api.VolumeSource{Projected: test.projectedVolumeSource}}}
|
||||||
|
psp.Spec.Volumes = test.allowedFSTypes
|
||||||
|
errs := provider.ValidatePod(pod)
|
||||||
|
if test.wantAllow {
|
||||||
|
assert.Empty(t, errs, "projected volumes are allowed if secret volumes is allowed and BoundServiceAccountTokenVolume is enabled")
|
||||||
|
} else {
|
||||||
|
assert.Contains(t, errs.ToAggregate().Error(), fmt.Sprintf("projected volumes are not allowed to be used"), "did not find the expected error")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAllowPrivilegeEscalation(t *testing.T) {
|
func TestAllowPrivilegeEscalation(t *testing.T) {
|
||||||
ptr := pointer.BoolPtr
|
ptr := pointer.BoolPtr
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
@ -26,6 +26,7 @@ go_test(
|
|||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
|
"//pkg/serviceaccount:go_default_library",
|
||||||
"//staging/src/k8s.io/api/policy/v1beta1:go_default_library",
|
"//staging/src/k8s.io/api/policy/v1beta1:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -242,3 +242,28 @@ func EqualStringSlices(a, b []string) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsOnlyServiceAccountTokenSources(v *api.ProjectedVolumeSource) bool {
|
||||||
|
for _, s := range v.Sources {
|
||||||
|
// reject any projected source that does not match any of our expected source types
|
||||||
|
if s.ServiceAccountToken == nil && s.ConfigMap == nil && s.DownwardAPI == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if t := s.ServiceAccountToken; t != nil && (t.Path != "token" || t.Audience != "") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.ConfigMap != nil && s.ConfigMap.LocalObjectReference.Name != "kube-root-ca.crt" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.DownwardAPI != nil {
|
||||||
|
for _, d := range s.DownwardAPI.Items {
|
||||||
|
if d.Path != "namespace" || d.FieldRef == nil || d.FieldRef.APIVersion != "v1" || d.FieldRef.FieldPath != "metadata.namespace" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
|
|
||||||
policy "k8s.io/api/policy/v1beta1"
|
policy "k8s.io/api/policy/v1beta1"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
|
"k8s.io/kubernetes/pkg/serviceaccount"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestVolumeSourceFSTypeDrift ensures that for every known type of volume source (by the fields on
|
// TestVolumeSourceFSTypeDrift ensures that for every known type of volume source (by the fields on
|
||||||
@ -251,3 +252,220 @@ func TestEqualStringSlices(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsOnlyServiceAccountTokenSources(t *testing.T) {
|
||||||
|
serviceAccountToken := api.VolumeProjection{
|
||||||
|
ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
||||||
|
Path: "token",
|
||||||
|
ExpirationSeconds: serviceaccount.WarnOnlyBoundTokenExpirationSeconds,
|
||||||
|
}}
|
||||||
|
configMap := api.VolumeProjection{
|
||||||
|
ConfigMap: &api.ConfigMapProjection{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{
|
||||||
|
Name: "kube-root-ca.crt",
|
||||||
|
},
|
||||||
|
Items: []api.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "ca.crt",
|
||||||
|
Path: "ca.crt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
downwardAPI := api.VolumeProjection{
|
||||||
|
DownwardAPI: &api.DownwardAPIProjection{
|
||||||
|
Items: []api.DownwardAPIVolumeFile{
|
||||||
|
{
|
||||||
|
Path: "namespace",
|
||||||
|
FieldRef: &api.ObjectFieldSelector{
|
||||||
|
APIVersion: "v1",
|
||||||
|
FieldPath: "metadata.namespace",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
volume *api.ProjectedVolumeSource
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "deny if ServiceAccountToken has wrong path",
|
||||||
|
volume: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
||||||
|
Path: "notatoken",
|
||||||
|
ExpirationSeconds: serviceaccount.WarnOnlyBoundTokenExpirationSeconds,
|
||||||
|
}},
|
||||||
|
configMap,
|
||||||
|
downwardAPI,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "deny if ServiceAccountToken has wrong audience",
|
||||||
|
volume: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
||||||
|
Path: "token",
|
||||||
|
Audience: "not api server",
|
||||||
|
ExpirationSeconds: serviceaccount.WarnOnlyBoundTokenExpirationSeconds,
|
||||||
|
}},
|
||||||
|
configMap,
|
||||||
|
downwardAPI,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "deny if CondigMap has wrong LocalObjectReference.Name",
|
||||||
|
volume: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
serviceAccountToken,
|
||||||
|
{
|
||||||
|
ConfigMap: &api.ConfigMapProjection{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{
|
||||||
|
Name: "foo-ca.crt",
|
||||||
|
},
|
||||||
|
Items: []api.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "ca.crt",
|
||||||
|
Path: "ca.crt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
downwardAPI,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "deny if DownwardAPI has wrong path",
|
||||||
|
volume: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
serviceAccountToken,
|
||||||
|
configMap,
|
||||||
|
{
|
||||||
|
DownwardAPI: &api.DownwardAPIProjection{
|
||||||
|
Items: []api.DownwardAPIVolumeFile{
|
||||||
|
{
|
||||||
|
Path: "foo",
|
||||||
|
FieldRef: &api.ObjectFieldSelector{
|
||||||
|
APIVersion: "v1",
|
||||||
|
FieldPath: "metadata.namespace",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "deny if DownwardAPI has nil field ref",
|
||||||
|
volume: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
serviceAccountToken,
|
||||||
|
configMap,
|
||||||
|
{
|
||||||
|
DownwardAPI: &api.DownwardAPIProjection{
|
||||||
|
Items: []api.DownwardAPIVolumeFile{
|
||||||
|
{
|
||||||
|
Path: "namespace",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "deny if DownwardAPI has wrong api version",
|
||||||
|
volume: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
serviceAccountToken,
|
||||||
|
configMap,
|
||||||
|
{
|
||||||
|
DownwardAPI: &api.DownwardAPIProjection{
|
||||||
|
Items: []api.DownwardAPIVolumeFile{
|
||||||
|
{
|
||||||
|
Path: "namespace",
|
||||||
|
FieldRef: &api.ObjectFieldSelector{
|
||||||
|
APIVersion: "v1beta1",
|
||||||
|
FieldPath: "metadata.namespace",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "deny if DownwardAPI has wrong field path",
|
||||||
|
volume: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
serviceAccountToken,
|
||||||
|
configMap,
|
||||||
|
{
|
||||||
|
DownwardAPI: &api.DownwardAPIProjection{
|
||||||
|
Items: []api.DownwardAPIVolumeFile{
|
||||||
|
{
|
||||||
|
Path: "namespace",
|
||||||
|
FieldRef: &api.ObjectFieldSelector{
|
||||||
|
APIVersion: "v1",
|
||||||
|
FieldPath: "metadata.foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "deny if Secret exists",
|
||||||
|
volume: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{
|
||||||
|
Secret: &api.SecretProjection{},
|
||||||
|
},
|
||||||
|
configMap,
|
||||||
|
downwardAPI,
|
||||||
|
serviceAccountToken,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "deny if none of ServiceAccountToken, ConfigMap and DownwardAPI exist",
|
||||||
|
volume: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "allow if any of ServiceAccountToken, ConfigMap and DownwardAPI matches",
|
||||||
|
volume: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
configMap,
|
||||||
|
downwardAPI,
|
||||||
|
serviceAccountToken,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
if got := IsOnlyServiceAccountTokenSources(test.volume); got != test.want {
|
||||||
|
t.Errorf("IsOnlyServiceAccountTokenSources(%+v) = %v, want %v", test.volume, got, test.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -525,42 +525,7 @@ func (s *Plugin) createVolume(tokenVolumeName, secretName string) api.Volume {
|
|||||||
return api.Volume{
|
return api.Volume{
|
||||||
Name: tokenVolumeName,
|
Name: tokenVolumeName,
|
||||||
VolumeSource: api.VolumeSource{
|
VolumeSource: api.VolumeSource{
|
||||||
Projected: &api.ProjectedVolumeSource{
|
Projected: TokenVolumeSource(),
|
||||||
Sources: []api.VolumeProjection{
|
|
||||||
{
|
|
||||||
ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
|
||||||
Path: "token",
|
|
||||||
ExpirationSeconds: serviceaccount.WarnOnlyBoundTokenExpirationSeconds,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -573,3 +538,43 @@ func (s *Plugin) createVolume(tokenVolumeName, secretName string) api.Volume {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TokenVolumeSource returns the projected volume source for service account token.
|
||||||
|
func TokenVolumeSource() *api.ProjectedVolumeSource {
|
||||||
|
return &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{
|
||||||
|
ServiceAccountToken: &api.ServiceAccountTokenProjection{
|
||||||
|
Path: "token",
|
||||||
|
ExpirationSeconds: serviceaccount.WarnOnlyBoundTokenExpirationSeconds,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user