// 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" // 2. It ensures the ServiceAccount referenced by the pod exists // 3. If LimitSecretReferences is true, it rejects the pod if the pod references Secret objects which the pod's ServiceAccount does not reference // 4. If the pod does not contain any ImagePullSecrets, the ImagePullSecrets of the service account are added. // 5. If MountServiceAccountToken is true, it adds a VolumeMount with the pod's ServiceAccount's api token secret to containers func NewServiceAccount(cl clientset.Interface) *serviceAccount { serviceAccountsIndexer, serviceAccountsReflector := cache.NewNamespaceKeyedIndexerAndReflector( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) return cl.Core().ServiceAccounts(api.NamespaceAll).List(internalOptions) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) return cl.Core().ServiceAccounts(api.NamespaceAll).Watch(internalOptions) }, }, &api.ServiceAccount{}, 0, ) tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(api.SecretTypeServiceAccountToken)}) secretsIndexer, secretsReflector := cache.NewNamespaceKeyedIndexerAndReflector( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) internalOptions.FieldSelector = tokenSelector return cl.Core().Secrets(api.NamespaceAll).List(internalOptions) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) internalOptions.FieldSelector = tokenSelector return cl.Core().Secrets(api.NamespaceAll).Watch(internalOptions) }, }, &api.Secret{}, 0, ) return &serviceAccount{ Handler: admission.NewHandler(admission.Create), // TODO: enable this once we've swept secret usage to account for adding secret references to service accounts LimitSecretReferences: false, // Auto mount service account API token secrets MountServiceAccountToken: true, // Reject pod creation until a service account token is available RequireAPIToken: true, client: cl, serviceAccounts: serviceAccountsIndexer, serviceAccountsReflector: serviceAccountsReflector, secrets: secretsIndexer, secretsReflector: secretsReflector, } }
// NewLimitRanger returns an object that enforces limits based on the supplied limit function func NewLimitRanger(client clientset.Interface, actions LimitRangerActions) (admission.Interface, error) { liveLookupCache, err := lru.New(10000) if err != nil { return nil, err } lw := &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return client.Core().LimitRanges(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return client.Core().LimitRanges(api.NamespaceAll).Watch(options) }, } indexer, reflector := cache.NewNamespaceKeyedIndexerAndReflector(lw, &api.LimitRange{}, 0) reflector.Run() if actions == nil { actions = &DefaultLimitRangerActions{} } return &limitRanger{ Handler: admission.NewHandler(admission.Create, admission.Update), client: client, actions: actions, indexer: indexer, liveLookupCache: liveLookupCache, liveTTL: time.Duration(30 * time.Second), }, nil }
// newQuotaAccessor creates an object that conforms to the QuotaAccessor interface to be used to retrieve quota objects. func newQuotaAccessor(client clientset.Interface) (*quotaAccessor, error) { liveLookupCache, err := lru.New(100) if err != nil { return nil, err } updatedCache, err := lru.New(100) if err != nil { return nil, err } lw := &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) return client.Core().ResourceQuotas(api.NamespaceAll).List(internalOptions) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) return client.Core().ResourceQuotas(api.NamespaceAll).Watch(internalOptions) }, } indexer, reflector := cache.NewNamespaceKeyedIndexerAndReflector(lw, &api.ResourceQuota{}, 0) return "aAccessor{ client: client, indexer: indexer, reflector: reflector, liveLookupCache: liveLookupCache, liveTTL: time.Duration(30 * time.Second), updatedQuotas: updatedCache, }, nil }
// newQuotaEvaluator configures an admission controller that can enforce quota constraints // using the provided registry. The registry must have the capability to handle group/kinds that // are persisted by the server this admission controller is intercepting func newQuotaEvaluator(client clientset.Interface, registry quota.Registry) (*quotaEvaluator, error) { liveLookupCache, err := lru.New(100) if err != nil { return nil, err } updatedCache, err := lru.New(100) if err != nil { return nil, err } lw := &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return client.Core().ResourceQuotas(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return client.Core().ResourceQuotas(api.NamespaceAll).Watch(options) }, } indexer, reflector := cache.NewNamespaceKeyedIndexerAndReflector(lw, &api.ResourceQuota{}, 0) reflector.Run() return "aEvaluator{ client: client, indexer: indexer, registry: registry, liveLookupCache: liveLookupCache, liveTTL: time.Duration(30 * time.Second), updatedQuotas: updatedCache, queue: workqueue.New(), work: map[string][]*admissionWaiter{}, dirtyWork: map[string][]*admissionWaiter{}, inProgress: sets.String{}, }, nil }
// 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" // 2. It ensures the ServiceAccount referenced by the pod exists // 3. If LimitSecretReferences is true, it rejects the pod if the pod references Secret objects which the pod's ServiceAccount does not reference // 4. If the pod does not contain any ImagePullSecrets, the ImagePullSecrets of the service account are added. // 5. If MountServiceAccountToken is true, it adds a VolumeMount with the pod's ServiceAccount's api token secret to containers func NewServiceAccount(cl client.Interface) *serviceAccount { serviceAccountsIndexer, serviceAccountsReflector := cache.NewNamespaceKeyedIndexerAndReflector( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return cl.ServiceAccounts(api.NamespaceAll).List(labels.Everything(), fields.Everything()) }, WatchFunc: func(resourceVersion string) (watch.Interface, error) { options := api.ListOptions{ResourceVersion: resourceVersion} return cl.ServiceAccounts(api.NamespaceAll).Watch(labels.Everything(), fields.Everything(), options) }, }, &api.ServiceAccount{}, 0, ) tokenSelector := fields.SelectorFromSet(map[string]string{client.SecretType: string(api.SecretTypeServiceAccountToken)}) secretsIndexer, secretsReflector := cache.NewNamespaceKeyedIndexerAndReflector( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return cl.Secrets(api.NamespaceAll).List(labels.Everything(), tokenSelector) }, WatchFunc: func(resourceVersion string) (watch.Interface, error) { options := api.ListOptions{ResourceVersion: resourceVersion} return cl.Secrets(api.NamespaceAll).Watch(labels.Everything(), tokenSelector, options) }, }, &api.Secret{}, 0, ) return &serviceAccount{ Handler: admission.NewHandler(admission.Create), // TODO: enable this once we've swept secret usage to account for adding secret references to service accounts LimitSecretReferences: false, // Auto mount service account API token secrets MountServiceAccountToken: true, // Reject pod creation until a service account token is available RequireAPIToken: true, client: cl, serviceAccounts: serviceAccountsIndexer, serviceAccountsReflector: serviceAccountsReflector, secrets: secretsIndexer, secretsReflector: secretsReflector, } }
func (a *serviceAccount) SetInternalClientSet(cl internalclientset.Interface) { a.client = cl a.serviceAccounts, a.serviceAccountsReflector = cache.NewNamespaceKeyedIndexerAndReflector( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) return cl.Core().ServiceAccounts(api.NamespaceAll).List(internalOptions) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) return cl.Core().ServiceAccounts(api.NamespaceAll).Watch(internalOptions) }, }, &api.ServiceAccount{}, 0, ) tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(api.SecretTypeServiceAccountToken)}) a.secrets, a.secretsReflector = cache.NewNamespaceKeyedIndexerAndReflector( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) internalOptions.FieldSelector = tokenSelector return cl.Core().Secrets(api.NamespaceAll).List(internalOptions) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) internalOptions.FieldSelector = tokenSelector return cl.Core().Secrets(api.NamespaceAll).Watch(internalOptions) }, }, &api.Secret{}, 0, ) if cl != nil { a.Run() } }
// NewResourceQuota creates a new resource quota admission control handler func NewResourceQuota(client client.Interface) admission.Interface { lw := &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return client.ResourceQuotas(api.NamespaceAll).List(labels.Everything(), fields.Everything()) }, WatchFunc: func(resourceVersion string) (watch.Interface, error) { return client.ResourceQuotas(api.NamespaceAll).Watch(labels.Everything(), fields.Everything(), resourceVersion) }, } indexer, reflector := cache.NewNamespaceKeyedIndexerAndReflector(lw, &api.ResourceQuota{}, 0) reflector.Run() return createResourceQuota(client, indexer) }
// NewResourceQuota creates a new resource quota admission control handler func NewResourceQuota(client clientset.Interface) admission.Interface { lw := &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return client.Core().ResourceQuotas(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return client.Core().ResourceQuotas(api.NamespaceAll).Watch(options) }, } indexer, reflector := cache.NewNamespaceKeyedIndexerAndReflector(lw, &api.ResourceQuota{}, 0) reflector.Run() return createResourceQuota(client, indexer) }
func NewLimitVerifier(client kclient.LimitRangesNamespacer) LimitVerifier { lw := &cache.ListWatch{ ListFunc: func(options kapi.ListOptions) (runtime.Object, error) { return client.LimitRanges(kapi.NamespaceAll).List(options) }, WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) { return client.LimitRanges(kapi.NamespaceAll).Watch(options) }, } indexer, reflector := cache.NewNamespaceKeyedIndexerAndReflector(lw, &kapi.LimitRange{}, 0) reflector.Run() return &limitVerifier{ client: client, indexer: indexer, } }
// NewLimitRanger returns an object that enforces limits based on the supplied limit function func NewLimitRanger(client client.Interface, limitFunc LimitFunc) admission.Interface { lw := &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return client.LimitRanges(api.NamespaceAll).List(labels.Everything()) }, WatchFunc: func(resourceVersion string) (watch.Interface, error) { return client.LimitRanges(api.NamespaceAll).Watch(labels.Everything(), fields.Everything(), resourceVersion) }, } indexer, reflector := cache.NewNamespaceKeyedIndexerAndReflector(lw, &api.LimitRange{}, 0) reflector.Run() return &limitRanger{ Handler: admission.NewHandler(admission.Create, admission.Update), client: client, limitFunc: limitFunc, indexer: indexer, } }
// NewLimitRanger returns an object that enforces limits based on the supplied limit function func NewLimitRanger(client client.Interface, limitFunc LimitFunc) admission.Interface { lw := &cache.ListWatch{ ListFunc: func(options unversioned.ListOptions) (runtime.Object, error) { return client.LimitRanges(api.NamespaceAll).List(options) }, WatchFunc: func(options unversioned.ListOptions) (watch.Interface, error) { return client.LimitRanges(api.NamespaceAll).Watch(options) }, } indexer, reflector := cache.NewNamespaceKeyedIndexerAndReflector(lw, &api.LimitRange{}, 0) reflector.Run() return &limitRanger{ Handler: admission.NewHandler(admission.Create, admission.Update), client: client, limitFunc: limitFunc, indexer: indexer, } }
// NewResourceQuota configures an admission controller that can enforce quota constraints // using the provided registry. The registry must have the capability to handle group/kinds that // are persisted by the server this admission controller is intercepting func NewResourceQuota(client clientset.Interface, registry quota.Registry) (admission.Interface, error) { liveLookupCache, err := lru.New(100) if err != nil { return nil, err } lw := &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return client.Core().ResourceQuotas(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return client.Core().ResourceQuotas(api.NamespaceAll).Watch(options) }, } indexer, reflector := cache.NewNamespaceKeyedIndexerAndReflector(lw, &api.ResourceQuota{}, 0) reflector.Run() return "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), client: client, indexer: indexer, registry: registry, liveLookupCache: liveLookupCache, liveTTL: time.Duration(30 * time.Second), }, nil }