k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/plugin/pkg/admission/certificates/subjectrestriction/admission_test.go (about) 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 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 // nil panic if any other methods called 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 }