forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
admission.go
158 lines (140 loc) · 5.03 KB
/
admission.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package strategyrestrictions
import (
"fmt"
"io"
"k8s.io/kubernetes/pkg/admission"
kapi "k8s.io/kubernetes/pkg/api"
kclient "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/util/sets"
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
buildapi "github.com/openshift/origin/pkg/build/api"
"github.com/openshift/origin/pkg/client"
oadmission "github.com/openshift/origin/pkg/cmd/server/admission"
)
func init() {
admission.RegisterPlugin("BuildByStrategy", func(c kclient.Interface, config io.Reader) (admission.Interface, error) {
return NewBuildByStrategy(), nil
})
}
type buildByStrategy struct {
*admission.Handler
client client.Interface
}
var _ = oadmission.WantsOpenshiftClient(&buildByStrategy{})
var _ = oadmission.Validator(&buildByStrategy{})
// NewBuildByStrategy returns an admission control for builds that checks
// on policy based on the build strategy type
func NewBuildByStrategy() admission.Interface {
return &buildByStrategy{
Handler: admission.NewHandler(admission.Create, admission.Update),
}
}
var (
buildsResource = buildapi.Resource("builds")
buildConfigsResource = buildapi.Resource("buildconfigs")
)
func (a *buildByStrategy) Admit(attr admission.Attributes) error {
if resource := attr.GetResource(); resource != buildsResource && resource != buildConfigsResource {
return nil
}
// Explicitly exclude the builds/details subresource because it's only
// updating commit info and cannot change build type.
if attr.GetResource() == buildsResource && attr.GetSubresource() == "details" {
return nil
}
switch obj := attr.GetObject().(type) {
case *buildapi.Build:
return a.checkBuildAuthorization(obj, attr)
case *buildapi.BuildConfig:
return a.checkBuildConfigAuthorization(obj, attr)
case *buildapi.BuildRequest:
return a.checkBuildRequestAuthorization(obj, attr)
default:
return admission.NewForbidden(attr, fmt.Errorf("unrecognized request object %#v", obj))
}
}
func (a *buildByStrategy) SetOpenshiftClient(c client.Interface) {
a.client = c
}
func (a *buildByStrategy) Validate() error {
if a.client == nil {
return fmt.Errorf("BuildByStrategy needs an Openshift client")
}
return nil
}
func resourceForStrategyType(strategy buildapi.BuildStrategy) string {
switch {
case strategy.DockerStrategy != nil:
return authorizationapi.DockerBuildResource
case strategy.CustomStrategy != nil:
return authorizationapi.CustomBuildResource
case strategy.SourceStrategy != nil:
return authorizationapi.SourceBuildResource
}
return ""
}
func resourceName(objectMeta kapi.ObjectMeta) string {
if len(objectMeta.GenerateName) > 0 {
return objectMeta.GenerateName
}
return objectMeta.Name
}
func (a *buildByStrategy) checkBuildAuthorization(build *buildapi.Build, attr admission.Attributes) error {
strategy := build.Spec.Strategy
subjectAccessReview := &authorizationapi.LocalSubjectAccessReview{
Action: authorizationapi.AuthorizationAttributes{
Verb: "create",
Resource: resourceForStrategyType(strategy),
Content: build,
ResourceName: resourceName(build.ObjectMeta),
},
User: attr.GetUserInfo().GetName(),
Groups: sets.NewString(attr.GetUserInfo().GetGroups()...),
}
return a.checkAccess(strategy, subjectAccessReview, attr)
}
func (a *buildByStrategy) checkBuildConfigAuthorization(buildConfig *buildapi.BuildConfig, attr admission.Attributes) error {
strategy := buildConfig.Spec.Strategy
subjectAccessReview := &authorizationapi.LocalSubjectAccessReview{
Action: authorizationapi.AuthorizationAttributes{
Verb: "create",
Resource: resourceForStrategyType(strategy),
Content: buildConfig,
ResourceName: resourceName(buildConfig.ObjectMeta),
},
User: attr.GetUserInfo().GetName(),
Groups: sets.NewString(attr.GetUserInfo().GetGroups()...),
}
return a.checkAccess(strategy, subjectAccessReview, attr)
}
func (a *buildByStrategy) checkBuildRequestAuthorization(req *buildapi.BuildRequest, attr admission.Attributes) error {
switch attr.GetResource() {
case buildsResource:
build, err := a.client.Builds(attr.GetNamespace()).Get(req.Name)
if err != nil {
return err
}
return a.checkBuildAuthorization(build, attr)
case buildConfigsResource:
build, err := a.client.BuildConfigs(attr.GetNamespace()).Get(req.Name)
if err != nil {
return err
}
return a.checkBuildConfigAuthorization(build, attr)
default:
return admission.NewForbidden(attr, fmt.Errorf("Unknown resource type %s for BuildRequest", attr.GetResource()))
}
}
func (a *buildByStrategy) checkAccess(strategy buildapi.BuildStrategy, subjectAccessReview *authorizationapi.LocalSubjectAccessReview, attr admission.Attributes) error {
resp, err := a.client.LocalSubjectAccessReviews(attr.GetNamespace()).Create(subjectAccessReview)
if err != nil {
return err
}
if !resp.Allowed {
return notAllowed(strategy, attr)
}
return nil
}
func notAllowed(strategy buildapi.BuildStrategy, attr admission.Attributes) error {
return admission.NewForbidden(attr, fmt.Errorf("build strategy %s is not allowed", buildapi.StrategyType(strategy)))
}