forked from openshift/origin
/
admission.go
147 lines (131 loc) · 4.71 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
package admission
import (
"errors"
"fmt"
"io"
"k8s.io/kubernetes/pkg/admission"
kapi "k8s.io/kubernetes/pkg/api"
kclient "k8s.io/kubernetes/pkg/client"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util"
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
buildapi "github.com/openshift/origin/pkg/build/api"
"github.com/openshift/origin/pkg/client"
)
func init() {
admission.RegisterPlugin("BuildByStrategy", func(c kclient.Interface, config io.Reader) (admission.Interface, error) {
osClient, ok := c.(client.Interface)
if !ok {
return nil, errors.New("client is not an Origin client")
}
return NewBuildByStrategy(osClient), nil
})
}
type buildByStrategy struct {
*admission.Handler
client client.Interface
}
// 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,
}
}
const (
buildsResource = "builds"
buildConfigsResource = "buildconfigs"
)
func (a *buildByStrategy) Admit(attr admission.Attributes) error {
if resource := attr.GetResource(); resource != buildsResource && resource != buildConfigsResource {
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 resourceForStrategyType(strategyType buildapi.BuildStrategyType) string {
var resource string
switch strategyType {
case buildapi.DockerBuildStrategyType:
resource = authorizationapi.DockerBuildResource
case buildapi.CustomBuildStrategyType:
resource = authorizationapi.CustomBuildResource
case buildapi.SourceBuildStrategyType:
resource = authorizationapi.SourceBuildResource
}
return resource
}
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 {
strategyType := build.Spec.Strategy.Type
subjectAccessReview := &authorizationapi.LocalSubjectAccessReview{
Action: authorizationapi.AuthorizationAttributes{
Verb: "create",
Resource: resourceForStrategyType(strategyType),
Content: runtime.EmbeddedObject{Object: build},
ResourceName: resourceName(build.ObjectMeta),
},
User: attr.GetUserInfo().GetName(),
Groups: util.NewStringSet(attr.GetUserInfo().GetGroups()...),
}
return a.checkAccess(strategyType, subjectAccessReview, attr)
}
func (a *buildByStrategy) checkBuildConfigAuthorization(buildConfig *buildapi.BuildConfig, attr admission.Attributes) error {
strategyType := buildConfig.Spec.Strategy.Type
subjectAccessReview := &authorizationapi.LocalSubjectAccessReview{
Action: authorizationapi.AuthorizationAttributes{
Verb: "create",
Resource: resourceForStrategyType(strategyType),
Content: runtime.EmbeddedObject{Object: buildConfig},
ResourceName: resourceName(buildConfig.ObjectMeta),
},
User: attr.GetUserInfo().GetName(),
Groups: util.NewStringSet(attr.GetUserInfo().GetGroups()...),
}
return a.checkAccess(strategyType, 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(strategyType buildapi.BuildStrategyType, 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(strategyType, attr)
}
return nil
}
func notAllowed(strategyType buildapi.BuildStrategyType, attr admission.Attributes) error {
return admission.NewForbidden(attr, fmt.Errorf("build strategy type %s is not allowed", strategyType))
}