@@ -15,39 +15,43 @@ import (
15
15
"k8s.io/apiserver/pkg/authorization/authorizer"
16
16
kapi "k8s.io/kubernetes/pkg/apis/core"
17
17
"k8s.io/kubernetes/pkg/apis/extensions"
18
+ "k8s.io/kubernetes/pkg/auth/nodeidentifier"
18
19
19
20
"github.com/openshift/origin/pkg/api/meta"
20
21
configlatest "github.com/openshift/origin/pkg/cmd/server/apis/config/latest"
21
22
"github.com/openshift/origin/pkg/scheduler/admission/apis/podnodeconstraints"
22
23
)
23
24
25
+ const PluginName = "PodNodeConstraints"
26
+
24
27
// kindsToIgnore is a list of kinds that contain a PodSpec that
25
28
// we choose not to handle in this plugin
26
29
var kindsToIgnore = []schema.GroupKind {
27
30
extensions .Kind ("DaemonSet" ),
28
31
}
29
32
30
33
func Register (plugins * admission.Plugins ) {
31
- plugins .Register ("PodNodeConstraints" ,
34
+ plugins .Register (PluginName ,
32
35
func (config io.Reader ) (admission.Interface , error ) {
33
36
pluginConfig , err := readConfig (config )
34
37
if err != nil {
35
38
return nil , err
36
39
}
37
40
if pluginConfig == nil {
38
- glog .Infof ("Admission plugin %q is not configured so it will be disabled." , "PodNodeConstraints" )
41
+ glog .Infof ("Admission plugin %q is not configured so it will be disabled." , PluginName )
39
42
return nil , nil
40
43
}
41
- return NewPodNodeConstraints (pluginConfig ), nil
44
+ return NewPodNodeConstraints (pluginConfig , nodeidentifier . NewDefaultNodeIdentifier () ), nil
42
45
})
43
46
}
44
47
45
48
// NewPodNodeConstraints creates a new admission plugin to prevent objects that contain pod templates
46
49
// from containing node bindings by name or selector based on role permissions.
47
- func NewPodNodeConstraints (config * podnodeconstraints.PodNodeConstraintsConfig ) admission.Interface {
50
+ func NewPodNodeConstraints (config * podnodeconstraints.PodNodeConstraintsConfig , nodeIdentifier nodeidentifier. NodeIdentifier ) admission.Interface {
48
51
plugin := podNodeConstraints {
49
- config : config ,
50
- Handler : admission .NewHandler (admission .Create , admission .Update ),
52
+ config : config ,
53
+ Handler : admission .NewHandler (admission .Create , admission .Update ),
54
+ nodeIdentifier : nodeIdentifier ,
51
55
}
52
56
if config != nil {
53
57
plugin .selectorLabelBlacklist = sets .NewString (config .NodeSelectorLabelBlacklist ... )
@@ -61,6 +65,7 @@ type podNodeConstraints struct {
61
65
selectorLabelBlacklist sets.String
62
66
config * podnodeconstraints.PodNodeConstraintsConfig
63
67
authorizer authorizer.Authorizer
68
+ nodeIdentifier nodeidentifier.NodeIdentifier
64
69
}
65
70
66
71
func shouldCheckResource (resource schema.GroupResource , kind schema.GroupKind ) (bool , error ) {
@@ -135,6 +140,12 @@ func (o *podNodeConstraints) getPodSpec(attr admission.Attributes) (kapi.PodSpec
135
140
136
141
// validate PodSpec if NodeName or NodeSelector are specified
137
142
func (o * podNodeConstraints ) admitPodSpec (attr admission.Attributes , ps kapi.PodSpec ) error {
143
+ // a node creating a mirror pod that targets itself is allowed
144
+ // see the NodeRestriction plugin for further details
145
+ if o .isNodeSelfTargetWithMirrorPod (attr , ps .NodeName ) {
146
+ return nil
147
+ }
148
+
138
149
matchingLabels := []string {}
139
150
// nodeSelector blacklist filter
140
151
for nodeSelectorLabel := range ps .NodeSelector {
@@ -168,7 +179,10 @@ func (o *podNodeConstraints) SetAuthorizer(a authorizer.Authorizer) {
168
179
169
180
func (o * podNodeConstraints ) ValidateInitialization () error {
170
181
if o .authorizer == nil {
171
- return fmt .Errorf ("PodNodeConstraints needs an Openshift Authorizer" )
182
+ return fmt .Errorf ("%s requires an authorizer" , PluginName )
183
+ }
184
+ if o .nodeIdentifier == nil {
185
+ return fmt .Errorf ("%s requires a node identifier" , PluginName )
172
186
}
173
187
return nil
174
188
}
@@ -190,3 +204,25 @@ func (o *podNodeConstraints) checkPodsBindAccess(attr admission.Attributes) (boo
190
204
authorized , _ , err := o .authorizer .Authorize (authzAttr )
191
205
return authorized == authorizer .DecisionAllow , err
192
206
}
207
+
208
+ func (o * podNodeConstraints ) isNodeSelfTargetWithMirrorPod (attr admission.Attributes , nodeName string ) bool {
209
+ // make sure we are actually trying to target a node
210
+ if len (nodeName ) == 0 {
211
+ return false
212
+ }
213
+ // this check specifically requires the object to be pod (unlike the other checks where we want any pod spec)
214
+ pod , ok := attr .GetObject ().(* kapi.Pod )
215
+ if ! ok {
216
+ return false
217
+ }
218
+ // note that anyone can create a mirror pod, but they are not privileged in any way
219
+ // they are actually highly constrained since they cannot reference secrets
220
+ // nodes can only create and delete them, and they will delete any "orphaned" mirror pods
221
+ if _ , isMirrorPod := pod .Annotations [kapi .MirrorPodAnnotationKey ]; ! isMirrorPod {
222
+ return false
223
+ }
224
+ // we are targeting a node with a mirror pod
225
+ // confirm the user is a node that is targeting itself
226
+ actualNodeName , isNode := o .nodeIdentifier .NodeIdentity (attr .GetUserInfo ())
227
+ return isNode && actualNodeName == nodeName
228
+ }
0 commit comments