func init() { admission.RegisterPlugin(api.PluginName, func(client clientset.Interface, input io.Reader) (admission.Interface, error) { obj, err := configlatest.ReadYAML(input) if err != nil { return nil, err } if obj == nil { return nil, nil } config, ok := obj.(*api.ImagePolicyConfig) if !ok { return nil, fmt.Errorf("unexpected config object: %#v", obj) } if errs := validation.Validate(config); len(errs) > 0 { return nil, errs.ToAggregate() } glog.V(5).Infof("%s admission controller loaded with config: %#v", api.PluginName, config) return newImagePolicyPlugin(client, config) }) }
func TestDefaultPolicy(t *testing.T) { input, err := os.Open("api/v1/default-policy.yaml") if err != nil { t.Fatal(err) } obj, err := configlatest.ReadYAML(input) if err != nil { t.Fatal(err) } if obj == nil { t.Fatal(obj) } config, ok := obj.(*api.ImagePolicyConfig) if !ok { t.Fatal(config) } if errs := validation.Validate(config); len(errs) > 0 { t.Fatal(errs.ToAggregate()) } plugin, err := newImagePolicyPlugin(nil, config) if err != nil { t.Fatal(err) } goodImage := &imageapi.Image{ ObjectMeta: kapi.ObjectMeta{Name: "sha256:good"}, DockerImageReference: "integrated.registry/goodns/goodimage:good", } badImage := &imageapi.Image{ ObjectMeta: kapi.ObjectMeta{ Name: "sha256:bad", Annotations: map[string]string{ "images.openshift.io/deny-execution": "true", }, }, DockerImageReference: "integrated.registry/badns/badimage:bad", } client := testclient.NewSimpleFake( goodImage, badImage, // respond to image stream tag in this order: &unversioned.Status{ Reason: unversioned.StatusReasonNotFound, Code: 404, Details: &unversioned.StatusDetails{ Kind: "ImageStreamTag", }, }, &imageapi.ImageStreamTag{ ObjectMeta: kapi.ObjectMeta{Name: "mysql:goodtag", Namespace: "repo"}, Image: *goodImage, }, &imageapi.ImageStreamTag{ ObjectMeta: kapi.ObjectMeta{Name: "mysql:badtag", Namespace: "repo"}, Image: *badImage, }, ) store := setDefaultCache(plugin) plugin.SetOpenshiftClient(client) plugin.SetDefaultRegistryFunc(func() (string, bool) { return "integrated.registry", true }) if err := plugin.Validate(); err != nil { t.Fatal(err) } originalNowFn := now defer (func() { now = originalNowFn })() now = func() time.Time { return time.Unix(1, 0) } // should allow a non-integrated image attrs := admission.NewAttributesRecord( &kapi.Pod{Spec: kapi.PodSpec{Containers: []kapi.Container{{Image: "index.docker.io/mysql:latest"}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Pod"}, "default", "pod1", unversioned.GroupVersionResource{Version: "v1", Resource: "pods"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err != nil { t.Fatal(err) } // should resolve the non-integrated image and allow it attrs = admission.NewAttributesRecord( &kapi.Pod{Spec: kapi.PodSpec{Containers: []kapi.Container{{Image: "index.docker.io/mysql@sha256:good"}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Pod"}, "default", "pod1", unversioned.GroupVersionResource{Version: "v1", Resource: "pods"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err != nil { t.Fatal(err) } // should resolve the integrated image by digest and allow it attrs = admission.NewAttributesRecord( &kapi.Pod{Spec: kapi.PodSpec{Containers: []kapi.Container{{Image: "integrated.registry/repo/mysql@sha256:good"}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Pod"}, "default", "pod1", unversioned.GroupVersionResource{Version: "v1", Resource: "pods"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err != nil { t.Fatal(err) } // should attempt resolve the integrated image by tag and fail because tag not found attrs = admission.NewAttributesRecord( &kapi.Pod{Spec: kapi.PodSpec{Containers: []kapi.Container{{Image: "integrated.registry/repo/mysql:missingtag"}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Pod"}, "default", "pod1", unversioned.GroupVersionResource{Version: "v1", Resource: "pods"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err != nil { t.Fatal(err) } // should attempt resolve the integrated image by tag and allow it attrs = admission.NewAttributesRecord( &kapi.Pod{Spec: kapi.PodSpec{Containers: []kapi.Container{{Image: "integrated.registry/repo/mysql:goodtag"}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Pod"}, "default", "pod1", unversioned.GroupVersionResource{Version: "v1", Resource: "pods"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err != nil { t.Fatal(err) } // should attempt resolve the integrated image by tag and forbid it attrs = admission.NewAttributesRecord( &kapi.Pod{Spec: kapi.PodSpec{Containers: []kapi.Container{{Image: "integrated.registry/repo/mysql:badtag"}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Pod"}, "default", "pod1", unversioned.GroupVersionResource{Version: "v1", Resource: "pods"}, "", admission.Create, nil, ) t.Logf("%#v", plugin.accepter) if err := plugin.Admit(attrs); err == nil || !apierrs.IsInvalid(err) { t.Fatal(err) } // should reject the non-integrated image due to the annotation attrs = admission.NewAttributesRecord( &kapi.Pod{Spec: kapi.PodSpec{Containers: []kapi.Container{{Image: "index.docker.io/mysql@sha256:bad"}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Pod"}, "default", "pod1", unversioned.GroupVersionResource{Version: "v1", Resource: "pods"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err == nil || !apierrs.IsInvalid(err) { t.Fatal(err) } // should reject the non-integrated image due to the annotation on an init container attrs = admission.NewAttributesRecord( &kapi.Pod{Spec: kapi.PodSpec{InitContainers: []kapi.Container{{Image: "index.docker.io/mysql@sha256:bad"}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Pod"}, "default", "pod1", unversioned.GroupVersionResource{Version: "v1", Resource: "pods"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err == nil || !apierrs.IsInvalid(err) { t.Fatal(err) } // should reject the non-integrated image due to the annotation for a build attrs = admission.NewAttributesRecord( &buildapi.Build{Spec: buildapi.BuildSpec{CommonSpec: buildapi.CommonSpec{Source: buildapi.BuildSource{Images: []buildapi.ImageSource{ {From: kapi.ObjectReference{Kind: "DockerImage", Name: "index.docker.io/mysql@sha256:bad"}}, }}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Build"}, "default", "build1", unversioned.GroupVersionResource{Version: "v1", Resource: "builds"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err == nil || !apierrs.IsInvalid(err) { t.Fatal(err) } attrs = admission.NewAttributesRecord( &buildapi.Build{Spec: buildapi.BuildSpec{CommonSpec: buildapi.CommonSpec{Strategy: buildapi.BuildStrategy{DockerStrategy: &buildapi.DockerBuildStrategy{ From: &kapi.ObjectReference{Kind: "DockerImage", Name: "index.docker.io/mysql@sha256:bad"}, }}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Build"}, "default", "build1", unversioned.GroupVersionResource{Version: "v1", Resource: "builds"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err == nil || !apierrs.IsInvalid(err) { t.Fatal(err) } attrs = admission.NewAttributesRecord( &buildapi.Build{Spec: buildapi.BuildSpec{CommonSpec: buildapi.CommonSpec{Strategy: buildapi.BuildStrategy{SourceStrategy: &buildapi.SourceBuildStrategy{ From: kapi.ObjectReference{Kind: "DockerImage", Name: "index.docker.io/mysql@sha256:bad"}, }}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Build"}, "default", "build1", unversioned.GroupVersionResource{Version: "v1", Resource: "builds"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err == nil || !apierrs.IsInvalid(err) { t.Fatal(err) } attrs = admission.NewAttributesRecord( &buildapi.Build{Spec: buildapi.BuildSpec{CommonSpec: buildapi.CommonSpec{Strategy: buildapi.BuildStrategy{CustomStrategy: &buildapi.CustomBuildStrategy{ From: kapi.ObjectReference{Kind: "DockerImage", Name: "index.docker.io/mysql@sha256:bad"}, }}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Build"}, "default", "build1", unversioned.GroupVersionResource{Version: "v1", Resource: "builds"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err == nil || !apierrs.IsInvalid(err) { t.Fatal(err) } // should allow the non-integrated image due to the annotation for a build config because it's not in the list, even though it has // a valid spec attrs = admission.NewAttributesRecord( &buildapi.BuildConfig{Spec: buildapi.BuildConfigSpec{CommonSpec: buildapi.CommonSpec{Source: buildapi.BuildSource{Images: []buildapi.ImageSource{ {From: kapi.ObjectReference{Kind: "DockerImage", Name: "index.docker.io/mysql@sha256:bad"}}, }}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "BuildConfig"}, "default", "build1", unversioned.GroupVersionResource{Version: "v1", Resource: "buildconfigs"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err != nil { t.Fatal(err) } // should hit the cache on the previously good image and continue to allow it (the copy in cache was previously safe) goodImage.Annotations = map[string]string{"images.openshift.io/deny-execution": "true"} attrs = admission.NewAttributesRecord( &kapi.Pod{Spec: kapi.PodSpec{Containers: []kapi.Container{{Image: "index.docker.io/mysql@sha256:good"}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Pod"}, "default", "pod1", unversioned.GroupVersionResource{Version: "v1", Resource: "pods"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err != nil { t.Fatal(err) } // moving 2 minutes in the future should bypass the cache and deny the image now = func() time.Time { return time.Unix(1, 0).Add(2 * time.Minute) } attrs = admission.NewAttributesRecord( &kapi.Pod{Spec: kapi.PodSpec{Containers: []kapi.Container{{Image: "index.docker.io/mysql@sha256:good"}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Pod"}, "default", "pod1", unversioned.GroupVersionResource{Version: "v1", Resource: "pods"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err == nil || !apierrs.IsInvalid(err) { t.Fatal(err) } // setting a namespace annotation should allow the rule to be skipped immediately store.Add(&kapi.Namespace{ ObjectMeta: kapi.ObjectMeta{ Namespace: "", Name: "default", Annotations: map[string]string{ api.IgnorePolicyRulesAnnotation: "execution-denied", }, }, }) attrs = admission.NewAttributesRecord( &kapi.Pod{Spec: kapi.PodSpec{Containers: []kapi.Container{{Image: "index.docker.io/mysql@sha256:good"}}}}, nil, unversioned.GroupVersionKind{Version: "v1", Kind: "Pod"}, "default", "pod1", unversioned.GroupVersionResource{Version: "v1", Resource: "pods"}, "", admission.Create, nil, ) if err := plugin.Admit(attrs); err != nil { t.Fatal(err) } }