mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Do not require token secrets when using bound service account tokens
This commit is contained in:
parent
79bb357193
commit
39e373fc45
@ -46,6 +46,7 @@ go_test(
|
|||||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors: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/apis/meta/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission/testing:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission/testing:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/informers:go_default_library",
|
"//staging/src/k8s.io/client-go/informers:go_default_library",
|
||||||
|
@ -424,12 +424,19 @@ func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, po
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Plugin) mountServiceAccountToken(serviceAccount *corev1.ServiceAccount, pod *api.Pod) error {
|
func (s *Plugin) mountServiceAccountToken(serviceAccount *corev1.ServiceAccount, pod *api.Pod) error {
|
||||||
// Find the name of a referenced ServiceAccountToken secret we can mount
|
var (
|
||||||
serviceAccountToken, err := s.getReferencedServiceAccountToken(serviceAccount)
|
// serviceAccountToken holds the name of a secret containing a legacy service account token
|
||||||
if err != nil {
|
serviceAccountToken string
|
||||||
return fmt.Errorf("Error looking up service account token for %s/%s: %v", serviceAccount.Namespace, serviceAccount.Name, err)
|
err error
|
||||||
|
)
|
||||||
|
if !s.boundServiceAccountTokenVolume {
|
||||||
|
// Find the name of a referenced ServiceAccountToken secret we can mount
|
||||||
|
serviceAccountToken, err = s.getReferencedServiceAccountToken(serviceAccount)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error looking up service account token for %s/%s: %v", serviceAccount.Namespace, serviceAccount.Name, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(serviceAccountToken) == 0 {
|
if len(serviceAccountToken) == 0 && !s.boundServiceAccountTokenVolume {
|
||||||
// We don't have an API token to mount, so return
|
// We don't have an API token to mount, so return
|
||||||
if s.RequireAPIToken {
|
if s.RequireAPIToken {
|
||||||
// If a token is required, this is considered an error
|
// If a token is required, this is considered an error
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/apimachinery/pkg/util/diff"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
admissiontesting "k8s.io/apiserver/pkg/admission/testing"
|
admissiontesting "k8s.io/apiserver/pkg/admission/testing"
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
@ -217,6 +218,73 @@ func TestAssignsDefaultServiceAccountAndRejectsMissingAPIToken(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAssignsDefaultServiceAccountAndBoundTokenWithNoSecretTokens(t *testing.T) {
|
||||||
|
ns := "myns"
|
||||||
|
|
||||||
|
admit := NewServiceAccount()
|
||||||
|
informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
|
||||||
|
admit.SetExternalKubeInformerFactory(informerFactory)
|
||||||
|
admit.MountServiceAccountToken = true
|
||||||
|
admit.RequireAPIToken = true
|
||||||
|
admit.boundServiceAccountTokenVolume = true
|
||||||
|
|
||||||
|
// Add the default service account for the ns into the cache
|
||||||
|
informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(&corev1.ServiceAccount{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: DefaultServiceAccountName,
|
||||||
|
Namespace: ns,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
pod := &api.Pod{
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{{}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
|
||||||
|
err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Expected success, got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedVolumes := []api.Volume{{
|
||||||
|
Name: "cleared",
|
||||||
|
VolumeSource: api.VolumeSource{
|
||||||
|
Projected: &api.ProjectedVolumeSource{
|
||||||
|
Sources: []api.VolumeProjection{
|
||||||
|
{ServiceAccountToken: &api.ServiceAccountTokenProjection{ExpirationSeconds: 3600, Path: "token"}},
|
||||||
|
{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"}}}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
expectedVolumeMounts := []api.VolumeMount{{
|
||||||
|
Name: "cleared",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/var/run/secrets/kubernetes.io/serviceaccount",
|
||||||
|
}}
|
||||||
|
|
||||||
|
// clear generated volume names
|
||||||
|
for i := range pod.Spec.Volumes {
|
||||||
|
if len(pod.Spec.Volumes[i].Name) > 0 {
|
||||||
|
pod.Spec.Volumes[i].Name = "cleared"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := range pod.Spec.Containers[0].VolumeMounts {
|
||||||
|
if len(pod.Spec.Containers[0].VolumeMounts[i].Name) > 0 {
|
||||||
|
pod.Spec.Containers[0].VolumeMounts[i].Name = "cleared"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expectedVolumes, pod.Spec.Volumes) {
|
||||||
|
t.Errorf("unexpected volumes: %s", diff.ObjectReflectDiff(expectedVolumes, pod.Spec.Volumes))
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(expectedVolumeMounts, pod.Spec.Containers[0].VolumeMounts) {
|
||||||
|
t.Errorf("unexpected volumes: %s", diff.ObjectReflectDiff(expectedVolumeMounts, pod.Spec.Containers[0].VolumeMounts))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFetchesUncachedServiceAccount(t *testing.T) {
|
func TestFetchesUncachedServiceAccount(t *testing.T) {
|
||||||
ns := "myns"
|
ns := "myns"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user