1
16
17 package subjectrestriction
18
19 import (
20 "context"
21 "crypto/ed25519"
22 "crypto/rand"
23 "crypto/x509"
24 "crypto/x509/pkix"
25 "encoding/pem"
26 "testing"
27
28 certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
29 "k8s.io/apimachinery/pkg/runtime"
30 "k8s.io/apimachinery/pkg/runtime/schema"
31 "k8s.io/apiserver/pkg/admission"
32 certificatesapi "k8s.io/kubernetes/pkg/apis/certificates"
33 )
34
35 func TestPlugin_Validate(t *testing.T) {
36 tests := []struct {
37 name string
38 a admission.Attributes
39 wantErr string
40 }{
41 {
42 name: "ignored resource",
43 a: &testAttributes{
44 resource: schema.GroupResource{
45 Group: "foo",
46 Resource: "bar",
47 },
48 },
49 wantErr: "",
50 },
51 {
52 name: "ignored subresource",
53 a: &testAttributes{
54 resource: certificatesapi.Resource("certificatesigningrequests"),
55 subresource: "approve",
56 },
57 wantErr: "",
58 },
59 {
60 name: "wrong type",
61 a: &testAttributes{
62 resource: certificatesapi.Resource("certificatesigningrequests"),
63 obj: &certificatesapi.CertificateSigningRequestList{},
64 name: "panda",
65 },
66 wantErr: `certificatesigningrequests.certificates.k8s.io "panda" is forbidden: expected type CertificateSigningRequest, got: *certificates.CertificateSigningRequestList`,
67 },
68 {
69 name: "some other signer",
70 a: &testAttributes{
71 resource: certificatesapi.Resource("certificatesigningrequests"),
72 obj: &certificatesapi.CertificateSigningRequest{Spec: certificatesapi.CertificateSigningRequestSpec{
73 Request: pemWithGroup("system:masters"),
74 SignerName: certificatesv1beta1.KubeAPIServerClientKubeletSignerName,
75 }},
76 },
77 wantErr: "",
78 },
79 {
80 name: "invalid request",
81 a: &testAttributes{
82 resource: certificatesapi.Resource("certificatesigningrequests"),
83 obj: &certificatesapi.CertificateSigningRequest{Spec: certificatesapi.CertificateSigningRequestSpec{
84 Request: []byte("this is not a CSR"),
85 SignerName: certificatesv1beta1.KubeAPIServerClientSignerName,
86 }},
87 name: "bear",
88 },
89 wantErr: `certificatesigningrequests.certificates.k8s.io "bear" is forbidden: failed to parse CSR: PEM block type must be CERTIFICATE REQUEST`,
90 },
91 {
92 name: "some other group",
93 a: &testAttributes{
94 resource: certificatesapi.Resource("certificatesigningrequests"),
95 obj: &certificatesapi.CertificateSigningRequest{Spec: certificatesapi.CertificateSigningRequestSpec{
96 Request: pemWithGroup("system:admin"),
97 SignerName: certificatesv1beta1.KubeAPIServerClientSignerName,
98 }},
99 },
100 wantErr: "",
101 },
102 {
103 name: "request for system:masters",
104 a: &testAttributes{
105 resource: certificatesapi.Resource("certificatesigningrequests"),
106 obj: &certificatesapi.CertificateSigningRequest{Spec: certificatesapi.CertificateSigningRequestSpec{
107 Request: pemWithGroup("system:masters"),
108 SignerName: certificatesv1beta1.KubeAPIServerClientSignerName,
109 }},
110 name: "pooh",
111 },
112 wantErr: `certificatesigningrequests.certificates.k8s.io "pooh" is forbidden: use of kubernetes.io/kube-apiserver-client signer with system:masters group is not allowed`,
113 },
114 }
115 for _, tt := range tests {
116 t.Run(tt.name, func(t *testing.T) {
117 p := &Plugin{}
118 if err := p.Validate(context.TODO(), tt.a, nil); errStr(err) != tt.wantErr {
119 t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
120 }
121 })
122 }
123 }
124
125 type testAttributes struct {
126 resource schema.GroupResource
127 subresource string
128 obj runtime.Object
129 name string
130
131 admission.Attributes
132 }
133
134 func (t *testAttributes) GetResource() schema.GroupVersionResource {
135 return t.resource.WithVersion("ignored")
136 }
137
138 func (t *testAttributes) GetSubresource() string {
139 return t.subresource
140 }
141
142 func (t *testAttributes) GetObject() runtime.Object {
143 return t.obj
144 }
145
146 func (t *testAttributes) GetName() string {
147 return t.name
148 }
149
150 func errStr(err error) string {
151 if err == nil {
152 return ""
153 }
154 es := err.Error()
155 if len(es) == 0 {
156 panic("invalid empty error")
157 }
158 return es
159 }
160
161 func pemWithGroup(group string) []byte {
162 template := &x509.CertificateRequest{
163 Subject: pkix.Name{
164 Organization: []string{group},
165 },
166 }
167
168 _, key, err := ed25519.GenerateKey(rand.Reader)
169 if err != nil {
170 panic(err)
171 }
172
173 csrDER, err := x509.CreateCertificateRequest(rand.Reader, template, key)
174 if err != nil {
175 panic(err)
176 }
177
178 csrPemBlock := &pem.Block{
179 Type: "CERTIFICATE REQUEST",
180 Bytes: csrDER,
181 }
182
183 p := pem.EncodeToMemory(csrPemBlock)
184 if p == nil {
185 panic("invalid pem block")
186 }
187
188 return p
189 }
190
View as plain text