Unverified Commit 687553a4 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #67576 from yue9944882/externalize-secret-serviceaccount-informer

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Externalize serviceaacount admission controller ref: #66680 this pull externalizes serviceaccount admission controller in which secret & serviceaccount informers will be completely replaced. /sig api-machinery **Release note**: ```release-note NONE ```
parents 70e7a7d1 17306b54
......@@ -20,7 +20,6 @@ import (
"k8s.io/api/core/v1"
apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
"k8s.io/apiserver/pkg/authentication/user"
api "k8s.io/kubernetes/pkg/apis/core"
)
// UserInfo returns a user.Info interface for the given namespace, service account name and UID
......@@ -51,24 +50,3 @@ func IsServiceAccountToken(secret *v1.Secret, sa *v1.ServiceAccount) bool {
return true
}
// TODO: remove the duplicate code
// InternalIsServiceAccountToken returns true if the secret is a valid api token for the service account
func InternalIsServiceAccountToken(secret *api.Secret, sa *api.ServiceAccount) bool {
if secret.Type != api.SecretTypeServiceAccountToken {
return false
}
name := secret.Annotations[api.ServiceAccountNameKey]
uid := secret.Annotations[api.ServiceAccountUIDKey]
if name != sa.Name {
// Name must match
return false
}
if len(uid) > 0 && uid != string(sa.UID) {
// If UID is specified, it must match
return false
}
return true
}
......@@ -16,19 +16,20 @@ go_library(
deps = [
"//pkg/api/pod:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/core/internalversion:go_default_library",
"//pkg/kubeapiserver/admission: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",
"//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/labels:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_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/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",
],
)
......@@ -38,16 +39,18 @@ go_test(
embed = [":go_default_library"],
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/client/listers/core/internalversion:go_default_library",
"//pkg/controller: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/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",
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
],
)
......
......@@ -23,19 +23,20 @@ import (
"strconv"
"time"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/admission"
genericadmissioninitializer "k8s.io/apiserver/pkg/admission/initializer"
"k8s.io/apiserver/pkg/storage/names"
"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"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
corelisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
"k8s.io/kubernetes/pkg/kubeapiserver/admission/util"
"k8s.io/kubernetes/pkg/serviceaccount"
)
......@@ -74,16 +75,16 @@ type serviceAccount struct {
// MountServiceAccountToken creates Volume and VolumeMounts for the first referenced ServiceAccountToken for the pod's service account
MountServiceAccountToken bool
client internalclientset.Interface
client kubernetes.Interface
serviceAccountLister corelisters.ServiceAccountLister
secretLister corelisters.SecretLister
serviceAccountLister corev1listers.ServiceAccountLister
secretLister corev1listers.SecretLister
}
var _ admission.MutationInterface = &serviceAccount{}
var _ admission.ValidationInterface = &serviceAccount{}
var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&serviceAccount{})
var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&serviceAccount{})
var _ = genericadmissioninitializer.WantsExternalKubeClientSet(&serviceAccount{})
var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&serviceAccount{})
// NewServiceAccount returns an admission.Interface implementation which limits admission of Pod CREATE requests based on the pod's ServiceAccount:
// 1. If the pod does not specify a ServiceAccount, it sets the pod's ServiceAccount to "default"
......@@ -103,15 +104,15 @@ func NewServiceAccount() *serviceAccount {
}
}
func (a *serviceAccount) SetInternalKubeClientSet(cl internalclientset.Interface) {
func (a *serviceAccount) SetExternalKubeClientSet(cl kubernetes.Interface) {
a.client = cl
}
func (a *serviceAccount) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) {
serviceAccountInformer := f.Core().InternalVersion().ServiceAccounts()
func (a *serviceAccount) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
serviceAccountInformer := f.Core().V1().ServiceAccounts()
a.serviceAccountLister = serviceAccountInformer.Lister()
secretInformer := f.Core().InternalVersion().Secrets()
secretInformer := f.Core().V1().Secrets()
a.secretLister = secretInformer.Lister()
a.SetReadyFunc(func() bool {
......@@ -174,7 +175,9 @@ func (s *serviceAccount) Admit(a admission.Attributes) (err error) {
}
if len(pod.Spec.ImagePullSecrets) == 0 {
pod.Spec.ImagePullSecrets = make([]api.LocalObjectReference, len(serviceAccount.ImagePullSecrets))
copy(pod.Spec.ImagePullSecrets, serviceAccount.ImagePullSecrets)
for i := 0; i < len(serviceAccount.ImagePullSecrets); i++ {
pod.Spec.ImagePullSecrets[i].Name = serviceAccount.ImagePullSecrets[i].Name
}
}
return s.Validate(a)
......@@ -251,7 +254,7 @@ func shouldIgnore(a admission.Attributes) bool {
return false
}
func shouldAutomount(sa *api.ServiceAccount, pod *api.Pod) bool {
func shouldAutomount(sa *corev1.ServiceAccount, pod *api.Pod) bool {
// Pod's preference wins
if pod.Spec.AutomountServiceAccountToken != nil {
return *pod.Spec.AutomountServiceAccountToken
......@@ -266,7 +269,7 @@ func shouldAutomount(sa *api.ServiceAccount, pod *api.Pod) bool {
// enforceMountableSecrets indicates whether mountable secrets should be enforced for a particular service account
// A global setting of true will override any flag set on the individual service account
func (s *serviceAccount) enforceMountableSecrets(serviceAccount *api.ServiceAccount) bool {
func (s *serviceAccount) enforceMountableSecrets(serviceAccount *corev1.ServiceAccount) bool {
if s.LimitSecretReferences {
return true
}
......@@ -280,7 +283,7 @@ func (s *serviceAccount) enforceMountableSecrets(serviceAccount *api.ServiceAcco
}
// getServiceAccount returns the ServiceAccount for the given namespace and name if it exists
func (s *serviceAccount) getServiceAccount(namespace string, name string) (*api.ServiceAccount, error) {
func (s *serviceAccount) getServiceAccount(namespace string, name string) (*corev1.ServiceAccount, error) {
serviceAccount, err := s.serviceAccountLister.ServiceAccounts(namespace).Get(name)
if err == nil {
return serviceAccount, nil
......@@ -313,7 +316,7 @@ func (s *serviceAccount) getServiceAccount(namespace string, name string) (*api.
}
// getReferencedServiceAccountToken returns the name of the first referenced secret which is a ServiceAccountToken for the service account
func (s *serviceAccount) getReferencedServiceAccountToken(serviceAccount *api.ServiceAccount) (string, error) {
func (s *serviceAccount) getReferencedServiceAccountToken(serviceAccount *corev1.ServiceAccount) (string, error) {
if len(serviceAccount.Secrets) == 0 {
return "", nil
}
......@@ -338,27 +341,27 @@ func (s *serviceAccount) getReferencedServiceAccountToken(serviceAccount *api.Se
}
// getServiceAccountTokens returns all ServiceAccountToken secrets for the given ServiceAccount
func (s *serviceAccount) getServiceAccountTokens(serviceAccount *api.ServiceAccount) ([]*api.Secret, error) {
func (s *serviceAccount) getServiceAccountTokens(serviceAccount *corev1.ServiceAccount) ([]*corev1.Secret, error) {
secrets, err := s.secretLister.Secrets(serviceAccount.Namespace).List(labels.Everything())
if err != nil {
return nil, err
}
tokens := []*api.Secret{}
tokens := []*corev1.Secret{}
for _, secret := range secrets {
if secret.Type != api.SecretTypeServiceAccountToken {
if secret.Type != corev1.SecretTypeServiceAccountToken {
continue
}
if serviceaccount.InternalIsServiceAccountToken(secret, serviceAccount) {
if serviceaccount.IsServiceAccountToken(secret, serviceAccount) {
tokens = append(tokens, secret)
}
}
return tokens, nil
}
func (s *serviceAccount) limitSecretReferences(serviceAccount *api.ServiceAccount, pod *api.Pod) error {
func (s *serviceAccount) limitSecretReferences(serviceAccount *corev1.ServiceAccount, pod *api.Pod) error {
// Ensure all secrets the pod references are allowed by the service account
mountableSecrets := sets.NewString()
for _, s := range serviceAccount.Secrets {
......@@ -408,7 +411,7 @@ func (s *serviceAccount) limitSecretReferences(serviceAccount *api.ServiceAccoun
return nil
}
func (s *serviceAccount) mountServiceAccountToken(serviceAccount *api.ServiceAccount, pod *api.Pod) error {
func (s *serviceAccount) mountServiceAccountToken(serviceAccount *corev1.ServiceAccount, pod *api.Pod) error {
// Find the name of a referenced ServiceAccountToken secret we can mount
serviceAccountToken, err := s.getReferencedServiceAccountToken(serviceAccount)
if err != nil {
......
......@@ -14,8 +14,6 @@ go_test(
],
tags = ["integration"],
deps = [
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/controller:go_default_library",
"//pkg/controller/serviceaccount:go_default_library",
"//pkg/serviceaccount:go_default_library",
......
......@@ -43,10 +43,9 @@ import (
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
clientset "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
internalinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
"k8s.io/kubernetes/pkg/controller"
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
"k8s.io/kubernetes/pkg/serviceaccount"
......@@ -362,7 +361,7 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
// Root client
// TODO: remove rootClient after we refactor pkg/admission to use the clientset.
rootClientset := clientset.NewForConfigOrDie(&restclient.Config{Host: apiServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}, BearerToken: rootToken})
internalRootClientset := internalclientset.NewForConfigOrDie(&restclient.Config{Host: apiServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}, BearerToken: rootToken})
externalRootClientset := kubernetes.NewForConfigOrDie(&restclient.Config{Host: apiServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}, BearerToken: rootToken})
// Set up two authenticators:
// 1. A token authenticator that maps the rootToken to the "root" user
// 2. A ServiceAccountToken authenticator that validates ServiceAccount tokens
......@@ -417,9 +416,9 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
// Set up admission plugin to auto-assign serviceaccounts to pods
serviceAccountAdmission := serviceaccountadmission.NewServiceAccount()
serviceAccountAdmission.SetInternalKubeClientSet(internalRootClientset)
internalInformers := internalinformers.NewSharedInformerFactory(internalRootClientset, controller.NoResyncPeriodFunc())
serviceAccountAdmission.SetInternalKubeInformerFactory(internalInformers)
serviceAccountAdmission.SetExternalKubeClientSet(externalRootClientset)
externalInformers := informers.NewSharedInformerFactory(externalRootClientset, controller.NoResyncPeriodFunc())
serviceAccountAdmission.SetExternalKubeInformerFactory(externalInformers)
informers := informers.NewSharedInformerFactory(rootClientset, controller.NoResyncPeriodFunc())
masterConfig := framework.NewMasterConfig()
......@@ -457,7 +456,7 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
return rootClientset, clientConfig, stop, err
}
informers.Start(stopCh)
internalInformers.Start(stopCh)
externalInformers.Start(stopCh)
go serviceAccountController.Run(5, stopCh)
return rootClientset, clientConfig, stop, nil
......
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