Skip to content

Commit d9dfa2a

Browse files
Enable a simple image policy admission controller
Start adding policy and rules
1 parent df90cb2 commit d9dfa2a

File tree

16 files changed

+1310
-0
lines changed

16 files changed

+1310
-0
lines changed

pkg/cmd/server/api/install/install.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
_ "github.com/openshift/origin/pkg/build/admission/defaults/api/install"
1515
_ "github.com/openshift/origin/pkg/build/admission/overrides/api/install"
16+
_ "github.com/openshift/origin/pkg/image/admission/imagepolicy/api/install"
1617
_ "github.com/openshift/origin/pkg/project/admission/requestlimit/api/install"
1718
_ "github.com/openshift/origin/pkg/quota/admission/clusterresourceoverride/api/install"
1819
_ "github.com/openshift/origin/pkg/quota/admission/runonceduration/api/install"

pkg/cmd/server/origin/master_config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ var (
324324
overrideapi.PluginName,
325325
serviceadmit.ExternalIPPluginName,
326326
serviceadmit.RestrictedEndpointsPluginName,
327+
imagepolicy.PluginName,
327328
"LimitRanger",
328329
"ServiceAccount",
329330
"SecurityContextConstraint",
@@ -356,6 +357,7 @@ var (
356357
overrideapi.PluginName,
357358
serviceadmit.ExternalIPPluginName,
358359
serviceadmit.RestrictedEndpointsPluginName,
360+
imagepolicy.PluginName,
359361
"LimitRanger",
360362
"ServiceAccount",
361363
"SecurityContextConstraint",

pkg/cmd/server/start/admission.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
_ "github.com/openshift/origin/pkg/build/admission/overrides"
1313
_ "github.com/openshift/origin/pkg/build/admission/strategyrestrictions"
1414
_ "github.com/openshift/origin/pkg/image/admission"
15+
_ "github.com/openshift/origin/pkg/image/admission/imagepolicy"
1516
_ "github.com/openshift/origin/pkg/project/admission/lifecycle"
1617
_ "github.com/openshift/origin/pkg/project/admission/nodeenv"
1718
_ "github.com/openshift/origin/pkg/project/admission/requestlimit"
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package install
2+
3+
import (
4+
"github.com/golang/glog"
5+
6+
"k8s.io/kubernetes/pkg/api/unversioned"
7+
8+
configapi "github.com/openshift/origin/pkg/cmd/server/api"
9+
"github.com/openshift/origin/pkg/image/admission/imagepolicy/api"
10+
"github.com/openshift/origin/pkg/image/admission/imagepolicy/api/v1"
11+
)
12+
13+
// availableVersions lists all known external versions for this group from most preferred to least preferred
14+
var availableVersions = []unversioned.GroupVersion{v1.SchemeGroupVersion}
15+
16+
func init() {
17+
if err := enableVersions(availableVersions); err != nil {
18+
panic(err)
19+
}
20+
}
21+
22+
// TODO: enableVersions should be centralized rather than spread in each API group.
23+
func enableVersions(externalVersions []unversioned.GroupVersion) error {
24+
addVersionsToScheme(externalVersions...)
25+
return nil
26+
}
27+
28+
func addVersionsToScheme(externalVersions ...unversioned.GroupVersion) {
29+
// add the internal version to Scheme
30+
api.AddToScheme(configapi.Scheme)
31+
// add the enabled external versions to Scheme
32+
for _, v := range externalVersions {
33+
switch v {
34+
case v1.SchemeGroupVersion:
35+
v1.AddToScheme(configapi.Scheme)
36+
default:
37+
glog.Errorf("Version %s is not known, so it will not be added to the Scheme.", v)
38+
continue
39+
}
40+
}
41+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package api
2+
3+
const PluginName = "ImagePolicy"
4+
const ConfigKind = "ImagePolicyConfig"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package api
2+
3+
import (
4+
"k8s.io/kubernetes/pkg/api/unversioned"
5+
"k8s.io/kubernetes/pkg/runtime"
6+
)
7+
8+
var SchemeGroupVersion = unversioned.GroupVersion{Group: "", Version: runtime.APIVersionInternal}
9+
10+
// Adds the list of known types to api.Scheme.
11+
func AddToScheme(scheme *runtime.Scheme) {
12+
scheme.AddKnownTypes(SchemeGroupVersion,
13+
&ImagePolicyConfig{},
14+
)
15+
}
16+
17+
func (obj *ImagePolicyConfig) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package api
2+
3+
import (
4+
"k8s.io/kubernetes/pkg/api"
5+
"k8s.io/kubernetes/pkg/api/unversioned"
6+
)
7+
8+
// ImagePolicyConfig is the configuration for controlling how images are used in the cluster.
9+
type ImagePolicyConfig struct {
10+
unversioned.TypeMeta
11+
12+
// ExecutionRules determine whether the use of an image is allowed in an object with a pod spec.
13+
// By default, these rules only apply to pods, but may be extended to other resource types.
14+
ExecutionRules []ImageExecutionPolicyRule
15+
// ConsumptionRules are applied when creating resources with pod specs.
16+
ConsumptionRules []ImageConsumptionPolicyRule
17+
// PlacementRules are applied when creating resources with pod specs.
18+
PlacementRules []ImagePlacementPolicyRule
19+
20+
// Everyone except cluster admins or platform infra must use an image from the registry
21+
// Content in this namespace must use an image from the registry
22+
// Images with a certain annotation/label must be run on these nodes
23+
// Using this image consumes a certain amount of resource
24+
// Images cannot be run or imported unless they come from these registries (unless the user is an admin)
25+
// Images with/without these annotations/labels cannot be run (except in certain namespaces)
26+
// Image cannot be tagged with/without these labels
27+
// Images that are not signed by the listed authorities cannot be run (cert not expired)
28+
// Unsigned images may not be run on the following nodes
29+
30+
// Enforce/Relax by namespace, labels, user permission
31+
// Actions: Create pod, Tag image, Import image (ISM), Mutate pod (node selector, resources)
32+
// Add a resource to pod / container (for the image, this is not resource auto-sizing)
33+
// Add a node selector constraint
34+
// Require a permission check on the service account / current user to tag / create an image
35+
36+
// Pods with this annotation / label should consume one resource increment (per container / per pod)
37+
//
38+
}
39+
40+
// ImagePlacementPolicyRule, when matching an image, applies the provided tolerations or taints.
41+
type ImagePlacementPolicyRule struct {
42+
ImageSourceRule
43+
44+
Constrain []ConstrainPodNodeSelectorEffect
45+
Tolerate []TolerateNodeSelectorEffect
46+
}
47+
48+
type ConstrainPodNodeSelectorEffect struct {
49+
Add map[string]string
50+
}
51+
52+
type TolerateNodeSelectorEffect struct {
53+
Add api.Toleration
54+
}
55+
56+
// ImageConsumptionPolicyRule, when matching an image, adds a counted resource to the object.
57+
type ImageConsumptionPolicyRule struct {
58+
ImageSourceRule
59+
60+
Add []ConsumeResourceEffect
61+
}
62+
63+
type ConsumeResourceEffect struct {
64+
Name string
65+
Quantity string
66+
67+
// OnlyOnce means this resource consumption rule applies once per object, rather than once per
68+
// image encountered.
69+
OnlyOnce bool
70+
}
71+
72+
type ImageExecutionPolicyRule struct {
73+
ImageSourceRule
74+
75+
// Deny indicates this rule is inverted and a match results in a rejection
76+
Deny bool
77+
78+
// Resolve indicates that images referenced by this resource must be resolved
79+
Resolve bool
80+
}
81+
82+
// ImageSourceRule defines the conditions for matching a particular image source. The conditions below
83+
// are all required (logical AND)
84+
type ImageSourceRule struct {
85+
// Name is the name of this policy rule for reference. It must be unique across all rules.
86+
Name string
87+
// OnResources determines which resources this applies to. Defaults to 'pods' for RuntimeSourceRules.
88+
OnResources []string
89+
// IgnoreNamespaceOverride prevents this rule from being overriden when the
90+
// `alpha.image.policy.openshift.io/ignore-rules` is set on a namespace and contains this rule name.
91+
IgnoreNamespaceOverride bool
92+
93+
MatchIntegratedRegistry bool
94+
MatchRegistries []string
95+
96+
// AllowResolutionFailure allows the subsequent rules to be bypassed if the integrated registry does
97+
// not have access to image metadata (no image exists matching the image digest).
98+
AllowResolutionFailure bool
99+
100+
MatchDockerImageLabels []ValueMatch
101+
MatchImageLabels []ValueMatch
102+
MatchImageAnnotations []ValueMatch
103+
MatchSignatures []SignatureMatch
104+
}
105+
106+
type ValueMatch struct {
107+
Key string
108+
109+
// One of the following conditions must apply
110+
Set bool
111+
Value string
112+
}
113+
114+
type SignatureMatch struct {
115+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package v1
2+
3+
import (
4+
"k8s.io/kubernetes/pkg/api/unversioned"
5+
"k8s.io/kubernetes/pkg/runtime"
6+
)
7+
8+
// SchemeGroupVersion is group version used to register these objects
9+
var SchemeGroupVersion = unversioned.GroupVersion{Group: "", Version: "v1"}
10+
11+
// Adds the list of known types to api.Scheme.
12+
func AddToScheme(scheme *runtime.Scheme) {
13+
scheme.AddKnownTypes(SchemeGroupVersion,
14+
&ImagePolicyConfig{},
15+
)
16+
scheme.AddDefaultingFuncs(
17+
func(c *ImagePolicyConfig) {
18+
for i := range c.ExecutionRules {
19+
if len(c.ExecutionRules[i].OnResources) == 0 {
20+
c.ExecutionRules[i].OnResources = []string{"pods"}
21+
}
22+
}
23+
},
24+
)
25+
}
26+
27+
func (obj *ImagePolicyConfig) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package v1
2+
3+
import (
4+
"k8s.io/kubernetes/pkg/api/unversioned"
5+
"k8s.io/kubernetes/pkg/api/v1"
6+
)
7+
8+
// ImagePolicyConfig is the configuration for control of images running on the platform.
9+
type ImagePolicyConfig struct {
10+
unversioned.TypeMeta `json:",inline"`
11+
12+
// ExecutionRules determine whether the use of an image is allowed in an object with a pod spec.
13+
// By default, these rules only apply to pods, but may be extended to other resource types.
14+
ExecutionRules []ImageExecutionPolicyRule `json:"executionRules"`
15+
// ConsumptionRules are applied when creating resources with pod specs.
16+
ConsumptionRules []ImageConsumptionPolicyRule `json:"consumptionRules"`
17+
// PlacementRules are applied when creating resources with pod specs.
18+
PlacementRules []ImagePlacementPolicyRule `json:"placementRules"`
19+
20+
// Everyone except cluster admins or platform infra must use an image from the registry
21+
// Content in this namespace must use an image from the registry
22+
// Images with a certain annotation/label must be run on these nodes
23+
// Using this image consumes a certain amount of resource
24+
// Images cannot be run or imported unless they come from these registries (unless the user is an admin)
25+
// Images with/without these annotations/labels cannot be run (except in certain namespaces)
26+
// Image cannot be tagged with/without these labels
27+
// Images that are not signed by the listed authorities cannot be run (cert not expired)
28+
// Unsigned images may not be run on the following nodes
29+
30+
// Enforce/Relax by namespace, labels, user permission
31+
// Actions: Create pod, Tag image, Import image (ISM), Mutate pod (node selector, resources)
32+
// Add a resource to pod / container (for the image, this is not resource auto-sizing)
33+
// Add a node selector constraint
34+
// Require a permission check on the service account / current user to tag / create an image
35+
36+
// Pods with this annotation / label should consume one resource increment (per container / per pod)
37+
//
38+
}
39+
40+
// ImagePlacementPolicyRule, when matching an image, applies the provided tolerations or taints.
41+
type ImagePlacementPolicyRule struct {
42+
ImageSourceRule `json:",inline"`
43+
44+
Constrain []ConstrainPodNodeSelectorEffect `json:"constrain"`
45+
Tolerate []TolerateNodeSelectorEffect `json:"tolerate"`
46+
}
47+
48+
type ConstrainPodNodeSelectorEffect struct {
49+
Add map[string]string `json:"add"`
50+
}
51+
52+
type TolerateNodeSelectorEffect struct {
53+
Add v1.Toleration `json:"add"`
54+
}
55+
56+
// ImageConsumptionPolicyRule, when matching an image, adds a counted resource to the object.
57+
type ImageConsumptionPolicyRule struct {
58+
ImageSourceRule `json:",inline"`
59+
60+
Add []ConsumeResourceEffect `json:"add"`
61+
}
62+
63+
type ConsumeResourceEffect struct {
64+
Name string `json:"name"`
65+
Quantity string `json:"quantity"`
66+
67+
// OnlyOnce means this resource consumption rule applies once per object, rather than once per
68+
// image encountered.
69+
OnlyOnce bool `json:"onlyOnce"`
70+
}
71+
72+
type ImageExecutionPolicyRule struct {
73+
ImageSourceRule `json:",inline"`
74+
75+
// Deny indicates this rule is inverted and a match results in a rejection
76+
Deny bool `json:"deny"`
77+
78+
// Resolve indicates that images referenced by this resource must be resolved
79+
Resolve bool `json:"resolve"`
80+
}
81+
82+
// ImageSourceRule defines the conditions for matching a particular image source. The conditions below
83+
// are all required (logical AND)
84+
type ImageSourceRule struct {
85+
// Name is the name of this policy rule for reference. It must be unique across all rules.
86+
Name string `json:"name"`
87+
// OnResources determines which resources this applies to. Defaults to 'pods' for RuntimeSourceRules.
88+
OnResources []string `json:"onResources"`
89+
// IgnoreNamespaceOverride prevents this rule from being overriden when the
90+
// `alpha.image.policy.openshift.io/ignore-rules` is set on a namespace and contains this rule name.
91+
IgnoreNamespaceOverride bool `json:"ignoreNamespaceOverride"`
92+
93+
MatchIntegratedRegistry bool `json:"matchIntegratedRegistry"`
94+
MatchRegistries []string `json:"matchRegistries"`
95+
96+
// AllowResolutionFailure allows the subsequent rules to be bypassed if the integrated registry does
97+
// not have access to image metadata (no image exists matching the image digest).
98+
AllowResolutionFailure bool `json:"allowResolutionFailure"`
99+
100+
MatchDockerImageLabels []ValueMatch `json:"matchDockerImageLabels"`
101+
MatchImageLabels []ValueMatch `json:"matchImageLabels"`
102+
MatchImageAnnotations []ValueMatch `json:"matchImageAnnotations"`
103+
MatchSignatures []SignatureMatch `json:"matchSignatures"`
104+
}
105+
106+
type ValueMatch struct {
107+
Key string `json:"key"`
108+
109+
// One of the following conditions must apply
110+
Set bool `json:"set"`
111+
Value string `json:"value"`
112+
}
113+
114+
type SignatureMatch struct {
115+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package validation
2+
3+
import (
4+
"k8s.io/kubernetes/pkg/util/validation/field"
5+
6+
"github.com/openshift/origin/pkg/image/admission/imagepolicy/api"
7+
)
8+
9+
func Validate(config *api.ImagePolicyConfig) field.ErrorList {
10+
allErrs := field.ErrorList{}
11+
if config == nil {
12+
return allErrs
13+
}
14+
// if config.MemoryRequestToLimitPercent < 0 || config.MemoryRequestToLimitPercent > 100 {
15+
// allErrs = append(allErrs, field.Invalid(field.NewPath(api.PluginName, "MemoryRequestToLimitPercent"), config.MemoryRequestToLimitPercent, "must be between 0 and 100"))
16+
// }
17+
return allErrs
18+
}

0 commit comments

Comments
 (0)