func createResourceQuota(client client.Interface, indexer cache.Indexer) admission.Interface { return "a{ Handler: admission.NewHandler(admission.Create, admission.Update), client: client, indexer: indexer, } }
func TestLimitRangerIgnoresSubresource(t *testing.T) { client := testclient.NewSimpleFake() indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}) handler := &limitRanger{ Handler: admission.NewHandler(admission.Create, admission.Update), client: client, limitFunc: Limit, indexer: indexer, } limitRange := validLimitRangeNoDefaults() testPod := validPod("testPod", 1, api.ResourceRequirements{}) indexer.Add(&limitRange) err := handler.Admit(admission.NewAttributesRecord(&testPod, "Pod", limitRange.Namespace, "pods", "", admission.Update, nil)) if err == nil { t.Errorf("Expected an error since the pod did not specify resource limits in its update call") } err = handler.Admit(admission.NewAttributesRecord(&testPod, "Pod", limitRange.Namespace, "pods", "status", admission.Update, nil)) if err != nil { t.Errorf("Should have ignored calls to any subresource of pod %v", err) } }
func createProvision(c client.Interface, store cache.Store) admission.Interface { return &provision{ Handler: admission.NewHandler(admission.Create), client: c, store: store, } }
func NewTestAdmission(store cache.Store, kclient client.Interface) kadmission.Interface { return &constraint{ Handler: kadmission.NewHandler(kadmission.Create), client: kclient, store: store, } }
// 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, } }
// 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) { return cl.ServiceAccounts(api.NamespaceAll).Watch(labels.Everything(), fields.Everything(), resourceVersion) }, }, &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) { return cl.Secrets(api.NamespaceAll).Watch(labels.Everything(), tokenSelector, resourceVersion) }, }, &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, } }
// NewExists creates a new namespace exists admission control handler func NewExists(c client.Interface) admission.Interface { store := cache.NewStore(cache.MetaNamespaceKeyFunc) reflector := cache.NewReflector( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return c.Namespaces().List(labels.Everything(), fields.Everything()) }, WatchFunc: func(resourceVersion string) (watch.Interface, error) { return c.Namespaces().Watch(labels.Everything(), fields.Everything(), resourceVersion) }, }, &api.Namespace{}, store, 5*time.Minute, ) reflector.Run() return &exists{ client: c, store: store, Handler: admission.NewHandler(admission.Create, admission.Update, admission.Delete), } }
// NewConstraint creates a new SCC constraint admission plugin. func NewConstraint(kclient client.Interface) kadmission.Interface { store := cache.NewStore(cache.MetaNamespaceKeyFunc) reflector := cache.NewReflector( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return kclient.SecurityContextConstraints().List(labels.Everything(), fields.Everything()) }, WatchFunc: func(resourceVersion string) (watch.Interface, error) { return kclient.SecurityContextConstraints().Watch(labels.Everything(), fields.Everything(), resourceVersion) }, }, &kapi.SecurityContextConstraints{}, store, 0, ) reflector.Run() return &constraint{ Handler: kadmission.NewHandler(kadmission.Create), client: kclient, store: store, } }
// NewLifecycle creates a new namespace lifecycle admission control handler func NewLifecycle(c client.Interface) admission.Interface { store := cache.NewStore(cache.MetaNamespaceKeyFunc) reflector := cache.NewReflector( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return c.Namespaces().List(labels.Everything(), fields.Everything()) }, WatchFunc: func(resourceVersion string) (watch.Interface, error) { return c.Namespaces().Watch(labels.Everything(), fields.Everything(), resourceVersion) }, }, &api.Namespace{}, store, 0, ) reflector.Run() return &lifecycle{ Handler: admission.NewHandler(admission.Create, admission.Delete), client: c, store: store, immortalNamespaces: util.NewStringSet(api.NamespaceDefault), } }
// NewSecurityContextDeny creates a new instance of the SecurityContextDeny admission controller func NewSecurityContextDeny(client client.Interface) admission.Interface { return &plugin{ Handler: admission.NewHandler(admission.Create, admission.Update), client: client, } }
// NewBuildByStrategy returns an admission control for builds that checks // on policy based on the build strategy type func NewBuildByStrategy(client client.Interface) admission.Interface { return &buildByStrategy{ Handler: admission.NewHandler(admission.Create), client: client, } }
func TestCreateProvidersFromConstraints(t *testing.T) { namespaceValid := &kapi.Namespace{ ObjectMeta: kapi.ObjectMeta{ Name: "default", Annotations: map[string]string{ allocator.UIDRangeAnnotation: "1/3", allocator.MCSAnnotation: "s0:c1,c0", }, }, } namespaceNoUID := &kapi.Namespace{ ObjectMeta: kapi.ObjectMeta{ Name: "default", Annotations: map[string]string{ allocator.MCSAnnotation: "s0:c1,c0", }, }, } namespaceNoMCS := &kapi.Namespace{ ObjectMeta: kapi.ObjectMeta{ Name: "default", Annotations: map[string]string{ allocator.UIDRangeAnnotation: "1/3", }, }, } testCases := map[string]struct { // use a generating function so we can test for non-mutation scc func() *kapi.SecurityContextConstraints namespace *kapi.Namespace expectedErr string }{ "valid non-preallocated scc": { scc: func() *kapi.SecurityContextConstraints { return &kapi.SecurityContextConstraints{ ObjectMeta: kapi.ObjectMeta{ Name: "valid non-preallocated scc", }, SELinuxContext: kapi.SELinuxContextStrategyOptions{ Type: kapi.SELinuxStrategyRunAsAny, }, RunAsUser: kapi.RunAsUserStrategyOptions{ Type: kapi.RunAsUserStrategyRunAsAny, }, } }, namespace: namespaceValid, }, "valid pre-allocated scc": { scc: func() *kapi.SecurityContextConstraints { return &kapi.SecurityContextConstraints{ ObjectMeta: kapi.ObjectMeta{ Name: "valid pre-allocated scc", }, SELinuxContext: kapi.SELinuxContextStrategyOptions{ Type: kapi.SELinuxStrategyMustRunAs, SELinuxOptions: &kapi.SELinuxOptions{User: "******"}, }, RunAsUser: kapi.RunAsUserStrategyOptions{ Type: kapi.RunAsUserStrategyMustRunAsRange, }, } }, namespace: namespaceValid, }, "pre-allocated no uid annotation": { scc: func() *kapi.SecurityContextConstraints { return &kapi.SecurityContextConstraints{ ObjectMeta: kapi.ObjectMeta{ Name: "pre-allocated no uid annotation", }, SELinuxContext: kapi.SELinuxContextStrategyOptions{ Type: kapi.SELinuxStrategyMustRunAs, }, RunAsUser: kapi.RunAsUserStrategyOptions{ Type: kapi.RunAsUserStrategyMustRunAsRange, }, } }, namespace: namespaceNoUID, expectedErr: "unable to find pre-allocated uid annotation", }, "pre-allocated no mcs annotation": { scc: func() *kapi.SecurityContextConstraints { return &kapi.SecurityContextConstraints{ ObjectMeta: kapi.ObjectMeta{ Name: "pre-allocated no mcs annotation", }, SELinuxContext: kapi.SELinuxContextStrategyOptions{ Type: kapi.SELinuxStrategyMustRunAs, }, RunAsUser: kapi.RunAsUserStrategyOptions{ Type: kapi.RunAsUserStrategyMustRunAsRange, }, } }, namespace: namespaceNoMCS, expectedErr: "unable to find pre-allocated mcs annotation", }, "bad scc strategy options": { scc: func() *kapi.SecurityContextConstraints { return &kapi.SecurityContextConstraints{ ObjectMeta: kapi.ObjectMeta{ Name: "bad scc user options", }, SELinuxContext: kapi.SELinuxContextStrategyOptions{ Type: kapi.SELinuxStrategyRunAsAny, }, RunAsUser: kapi.RunAsUserStrategyOptions{ Type: kapi.RunAsUserStrategyMustRunAs, }, } }, namespace: namespaceValid, expectedErr: "MustRunAs requires a UID", }, } for k, v := range testCases { store := cache.NewStore(cache.MetaNamespaceKeyFunc) // create the admission handler tc := testclient.NewSimpleFake(v.namespace) admit := &constraint{ Handler: kadmission.NewHandler(kadmission.Create), client: tc, store: store, } scc := v.scc() // create the providers, this method only needs the namespace attributes := kadmission.NewAttributesRecord(nil, "", v.namespace.Name, "", kadmission.Create, nil) _, errs := admit.createProvidersFromConstraints(attributes.GetNamespace(), []*kapi.SecurityContextConstraints{scc}) if !reflect.DeepEqual(scc, v.scc()) { diff := util.ObjectDiff(scc, v.scc()) t.Errorf("%s createProvidersFromConstraints mutated constraints. diff:\n%s", k, diff) } if len(v.expectedErr) > 0 && len(errs) != 1 { t.Errorf("%s expected a single error '%s' but received %v", k, errs) continue } if len(v.expectedErr) == 0 && len(errs) != 0 { t.Errorf("%s did not expect an error but received %v", k, errs) continue } // check that we got the error we expected if len(v.expectedErr) > 0 { if !strings.Contains(errs[0].Error(), v.expectedErr) { t.Errorf("%s expected error '%s' but received %v", k, v.expectedErr, errs[0]) } } } }
// NewDenyExecOnPrivileged creates a new admission controller that denies an exec operation on a privileged pod func NewDenyExecOnPrivileged(client client.Interface) admission.Interface { return &denyExecOnPrivileged{ Handler: admission.NewHandler(admission.Connect), client: client, } }