Skip to content

Commit d7e10f9

Browse files
author
James Munnelly
committed
Add Certificate signerName admission plugins
1 parent a983356 commit d7e10f9

File tree

27 files changed

+1793
-31
lines changed

27 files changed

+1793
-31
lines changed

pkg/kubeapiserver/options/BUILD

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ go_library(
2626
"//plugin/pkg/admission/admit:go_default_library",
2727
"//plugin/pkg/admission/alwayspullimages:go_default_library",
2828
"//plugin/pkg/admission/antiaffinity:go_default_library",
29+
"//plugin/pkg/admission/certificates/approval:go_default_library",
30+
"//plugin/pkg/admission/certificates/signing:go_default_library",
31+
"//plugin/pkg/admission/certificates/subjectrestriction:go_default_library",
2932
"//plugin/pkg/admission/defaulttolerationseconds:go_default_library",
3033
"//plugin/pkg/admission/deny:go_default_library",
3134
"//plugin/pkg/admission/eventratelimit:go_default_library",

pkg/kubeapiserver/options/plugins.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import (
2424
"k8s.io/kubernetes/plugin/pkg/admission/admit"
2525
"k8s.io/kubernetes/plugin/pkg/admission/alwayspullimages"
2626
"k8s.io/kubernetes/plugin/pkg/admission/antiaffinity"
27+
certapproval "k8s.io/kubernetes/plugin/pkg/admission/certificates/approval"
28+
certsigning "k8s.io/kubernetes/plugin/pkg/admission/certificates/signing"
29+
certsubjectrestriction "k8s.io/kubernetes/plugin/pkg/admission/certificates/subjectrestriction"
2730
"k8s.io/kubernetes/plugin/pkg/admission/defaulttolerationseconds"
2831
"k8s.io/kubernetes/plugin/pkg/admission/deny"
2932
"k8s.io/kubernetes/plugin/pkg/admission/eventratelimit"
@@ -87,6 +90,9 @@ var AllOrderedPlugins = []string{
8790
gc.PluginName, // OwnerReferencesPermissionEnforcement
8891
resize.PluginName, // PersistentVolumeClaimResize
8992
runtimeclass.PluginName, // RuntimeClass
93+
certapproval.PluginName, // CertificateApproval
94+
certsigning.PluginName, // CertificateSigning
95+
certsubjectrestriction.PluginName, // CertificateSubjectRestriction
9096

9197
// new admission plugins should generally be inserted above here
9298
// webhook, resourcequota, and deny plugins must go at the end
@@ -128,6 +134,9 @@ func RegisterAllAdmissionPlugins(plugins *admission.Plugins) {
128134
setdefault.Register(plugins)
129135
resize.Register(plugins)
130136
storageobjectinuseprotection.Register(plugins)
137+
certapproval.Register(plugins)
138+
certsigning.Register(plugins)
139+
certsubjectrestriction.Register(plugins)
131140
}
132141

133142
// DefaultOffAdmissionPlugins get admission plugins off by default for kube-apiserver.
@@ -146,6 +155,9 @@ func DefaultOffAdmissionPlugins() sets.String {
146155
podpriority.PluginName, //PodPriority
147156
nodetaint.PluginName, //TaintNodesByCondition
148157
runtimeclass.PluginName, //RuntimeClass, gates internally on the feature
158+
certapproval.PluginName, // CertificateApproval
159+
certsigning.PluginName, // CertificateSigning
160+
certsubjectrestriction.PluginName, // CertificateSubjectRestriction
149161
)
150162

151163
return sets.NewString(AllOrderedPlugins...).Difference(defaultOnPlugins)

plugin/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ filegroup(
1414
"//plugin/pkg/admission/admit:all-srcs",
1515
"//plugin/pkg/admission/alwayspullimages:all-srcs",
1616
"//plugin/pkg/admission/antiaffinity:all-srcs",
17+
"//plugin/pkg/admission/certificates:all-srcs",
1718
"//plugin/pkg/admission/defaulttolerationseconds:all-srcs",
1819
"//plugin/pkg/admission/deny:all-srcs",
1920
"//plugin/pkg/admission/eventratelimit:all-srcs",
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_library")
2+
3+
package(default_visibility = ["//visibility:public"])
4+
5+
filegroup(
6+
name = "package-srcs",
7+
srcs = glob(["**"]),
8+
tags = ["automanaged"],
9+
visibility = ["//visibility:private"],
10+
)
11+
12+
filegroup(
13+
name = "all-srcs",
14+
srcs = [
15+
":package-srcs",
16+
"//plugin/pkg/admission/certificates/approval:all-srcs",
17+
"//plugin/pkg/admission/certificates/signing:all-srcs",
18+
"//plugin/pkg/admission/certificates/subjectrestriction:all-srcs",
19+
],
20+
tags = ["automanaged"],
21+
)
22+
23+
go_library(
24+
name = "go_default_library",
25+
srcs = ["util.go"],
26+
importpath = "k8s.io/kubernetes/plugin/pkg/admission/certificates",
27+
deps = [
28+
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
29+
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
30+
"//vendor/k8s.io/klog:go_default_library",
31+
],
32+
)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# See the OWNERS docs at https://go.k8s.io/owners
2+
3+
approvers:
4+
- sig-auth-certificates-approvers
5+
reviewers:
6+
- sig-auth-certificates-approvers
7+
labels:
8+
- sig/auth
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
2+
3+
go_library(
4+
name = "go_default_library",
5+
srcs = ["admission.go"],
6+
importpath = "k8s.io/kubernetes/plugin/pkg/admission/certificates/approval",
7+
visibility = ["//visibility:public"],
8+
deps = [
9+
"//pkg/apis/certificates:go_default_library",
10+
"//plugin/pkg/admission/certificates:go_default_library",
11+
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
12+
"//staging/src/k8s.io/apiserver/pkg/admission/initializer:go_default_library",
13+
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
14+
"//vendor/k8s.io/klog:go_default_library",
15+
],
16+
)
17+
18+
go_test(
19+
name = "go_default_test",
20+
srcs = ["admission_test.go"],
21+
embed = [":go_default_library"],
22+
deps = [
23+
"//pkg/apis/certificates:go_default_library",
24+
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
25+
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
26+
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
27+
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
28+
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
29+
],
30+
)
31+
32+
filegroup(
33+
name = "package-srcs",
34+
srcs = glob(["**"]),
35+
tags = ["automanaged"],
36+
visibility = ["//visibility:private"],
37+
)
38+
39+
filegroup(
40+
name = "all-srcs",
41+
srcs = [":package-srcs"],
42+
tags = ["automanaged"],
43+
visibility = ["//visibility:public"],
44+
)
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package approval
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"io"
23+
24+
"k8s.io/klog"
25+
26+
"k8s.io/apiserver/pkg/admission"
27+
genericadmissioninit "k8s.io/apiserver/pkg/admission/initializer"
28+
"k8s.io/apiserver/pkg/authorization/authorizer"
29+
30+
api "k8s.io/kubernetes/pkg/apis/certificates"
31+
"k8s.io/kubernetes/plugin/pkg/admission/certificates"
32+
)
33+
34+
// PluginName is a string with the name of the plugin
35+
const PluginName = "CertificateApproval"
36+
37+
// Register registers a plugin
38+
func Register(plugins *admission.Plugins) {
39+
plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) {
40+
return NewPlugin(), nil
41+
})
42+
}
43+
44+
// Plugin holds state for and implements the admission plugin.
45+
type Plugin struct {
46+
*admission.Handler
47+
authz authorizer.Authorizer
48+
}
49+
50+
// SetAuthorizer sets the authorizer.
51+
func (p *Plugin) SetAuthorizer(authz authorizer.Authorizer) {
52+
p.authz = authz
53+
}
54+
55+
// ValidateInitialization ensures an authorizer is set.
56+
func (p *Plugin) ValidateInitialization() error {
57+
if p.authz == nil {
58+
return fmt.Errorf("%s requires an authorizer", PluginName)
59+
}
60+
return nil
61+
}
62+
63+
var _ admission.ValidationInterface = &Plugin{}
64+
var _ genericadmissioninit.WantsAuthorizer = &Plugin{}
65+
66+
// NewPlugin creates a new CSR approval admission plugin
67+
func NewPlugin() *Plugin {
68+
return &Plugin{
69+
Handler: admission.NewHandler(admission.Update),
70+
}
71+
}
72+
73+
var csrGroupResource = api.Resource("certificatesigningrequests")
74+
75+
// Validate verifies that the requesting user has permission to approve
76+
// CertificateSigningRequests for the specified signerName.
77+
func (p *Plugin) Validate(ctx context.Context, a admission.Attributes, _ admission.ObjectInterfaces) error {
78+
// Ignore all calls to anything other than 'certificatesigningrequests/approval'.
79+
// Ignore all operations other than UPDATE.
80+
if a.GetSubresource() != "approval" ||
81+
a.GetResource().GroupResource() != csrGroupResource {
82+
return nil
83+
}
84+
85+
// We check permissions against the *old* version of the resource, in case
86+
// a user is attempting to update the SignerName when calling the approval
87+
// endpoint (which is an invalid/not allowed operation)
88+
csr, ok := a.GetOldObject().(*api.CertificateSigningRequest)
89+
if !ok {
90+
return admission.NewForbidden(a, fmt.Errorf("expected type CertificateSigningRequest, got: %T", a.GetOldObject()))
91+
}
92+
93+
if !certificates.IsAuthorizedForSignerName(ctx, p.authz, a.GetUserInfo(), "approve", csr.Spec.SignerName) {
94+
klog.V(4).Infof("user not permitted to approve CertificateSigningRequest %q with signerName %q", csr.Name, csr.Spec.SignerName)
95+
return admission.NewForbidden(a, fmt.Errorf("user not permitted to approve requests with signerName %q", csr.Spec.SignerName))
96+
}
97+
98+
return nil
99+
}

0 commit comments

Comments
 (0)