k8s.io/kubernetes@v1.29.3/test/integration/certificates/admission_approval_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 certificates 18 19 import ( 20 "context" 21 "testing" 22 23 certv1 "k8s.io/api/certificates/v1" 24 v1 "k8s.io/api/core/v1" 25 rbacv1 "k8s.io/api/rbac/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/runtime/schema" 28 clientset "k8s.io/client-go/kubernetes" 29 restclient "k8s.io/client-go/rest" 30 kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing" 31 "k8s.io/kubernetes/test/integration/authutil" 32 "k8s.io/kubernetes/test/integration/framework" 33 ) 34 35 // Verifies that the CSR approval admission plugin correctly enforces that a 36 // user has permission to approve CSRs for the named signer 37 func TestCSRSignerNameApprovalPlugin(t *testing.T) { 38 tests := map[string]struct { 39 allowedSignerName string 40 signerName string 41 error string 42 }{ 43 "should admit when a user has permission for the exact signerName": { 44 allowedSignerName: "example.com/something", 45 signerName: "example.com/something", 46 }, 47 "should admit when a user has permission for the wildcard-suffixed signerName": { 48 allowedSignerName: "example.com/*", 49 signerName: "example.com/something", 50 }, 51 "should deny if a user does not have permission for the given signerName": { 52 allowedSignerName: "example.com/not-something", 53 signerName: "example.com/something", 54 error: `certificatesigningrequests.certificates.k8s.io "csr" is forbidden: user not permitted to approve requests with signerName "example.com/something"`, 55 }, 56 } 57 for name, test := range tests { 58 t.Run(name, func(t *testing.T) { 59 // Run an apiserver with the default configuration options. 60 s := kubeapiservertesting.StartTestServerOrDie(t, kubeapiservertesting.NewDefaultTestServerOptions(), []string{"--authorization-mode=RBAC"}, framework.SharedEtcd()) 61 defer s.TearDownFn() 62 client := clientset.NewForConfigOrDie(s.ClientConfig) 63 64 // Grant 'test-user' permission to approve CertificateSigningRequests with the specified signerName. 65 const username = "test-user" 66 grantUserPermissionToApproveFor(t, client, username, test.allowedSignerName) 67 // Create a CSR to attempt to approve. 68 csr := createTestingCSR(t, client.CertificatesV1().CertificateSigningRequests(), "csr", test.signerName, "") 69 70 // Create a second client, impersonating the 'test-user' for us to test with. 71 testuserConfig := restclient.CopyConfig(s.ClientConfig) 72 testuserConfig.Impersonate = restclient.ImpersonationConfig{UserName: username} 73 testuserClient := clientset.NewForConfigOrDie(testuserConfig) 74 75 // Attempt to update the Approved condition. 76 csr.Status.Conditions = append(csr.Status.Conditions, certv1.CertificateSigningRequestCondition{ 77 Type: certv1.CertificateApproved, 78 Status: v1.ConditionTrue, 79 Reason: "AutoApproved", 80 Message: "Approved during integration test", 81 }) 82 _, err := testuserClient.CertificatesV1().CertificateSigningRequests().UpdateApproval(context.TODO(), csr.Name, csr, metav1.UpdateOptions{}) 83 if err != nil && test.error != err.Error() { 84 t.Errorf("expected error %q but got: %v", test.error, err) 85 } 86 if err == nil && test.error != "" { 87 t.Errorf("expected to get an error %q but got none", test.error) 88 } 89 }) 90 } 91 } 92 93 func grantUserPermissionToApproveFor(t *testing.T, client clientset.Interface, username string, signerNames ...string) { 94 resourceName := "signername-" + username 95 cr := buildApprovalClusterRoleForSigners(resourceName, signerNames...) 96 crb := buildClusterRoleBindingForUser(resourceName, username, cr.Name) 97 if _, err := client.RbacV1().ClusterRoles().Create(context.TODO(), cr, metav1.CreateOptions{}); err != nil { 98 t.Fatalf("unable to create test fixture RBAC rules: %v", err) 99 } 100 if _, err := client.RbacV1().ClusterRoleBindings().Create(context.TODO(), crb, metav1.CreateOptions{}); err != nil { 101 t.Fatalf("unable to create test fixture RBAC rules: %v", err) 102 } 103 approveRule := cr.Rules[0] 104 updateRule := cr.Rules[1] 105 authutil.WaitForNamedAuthorizationUpdate(t, context.TODO(), client.AuthorizationV1(), username, "", approveRule.Verbs[0], approveRule.ResourceNames[0], schema.GroupResource{Group: approveRule.APIGroups[0], Resource: approveRule.Resources[0]}, true) 106 authutil.WaitForNamedAuthorizationUpdate(t, context.TODO(), client.AuthorizationV1(), username, "", updateRule.Verbs[0], "", schema.GroupResource{Group: updateRule.APIGroups[0], Resource: updateRule.Resources[0]}, true) 107 } 108 109 func buildApprovalClusterRoleForSigners(name string, signerNames ...string) *rbacv1.ClusterRole { 110 return &rbacv1.ClusterRole{ 111 ObjectMeta: metav1.ObjectMeta{ 112 Name: name, 113 }, 114 Rules: []rbacv1.PolicyRule{ 115 // must have permission to 'approve' the 'certificatesigners' named 116 // 'signerName' to approve CSRs with the given signerName. 117 { 118 Verbs: []string{"approve"}, 119 APIGroups: []string{certv1.SchemeGroupVersion.Group}, 120 Resources: []string{"signers"}, 121 ResourceNames: signerNames, 122 }, 123 { 124 Verbs: []string{"update"}, 125 APIGroups: []string{certv1.SchemeGroupVersion.Group}, 126 Resources: []string{"certificatesigningrequests/approval"}, 127 }, 128 }, 129 } 130 } 131 132 func buildClusterRoleBindingForUser(name, username, clusterRoleName string) *rbacv1.ClusterRoleBinding { 133 return &rbacv1.ClusterRoleBinding{ 134 ObjectMeta: metav1.ObjectMeta{ 135 Name: name, 136 }, 137 Subjects: []rbacv1.Subject{ 138 { 139 Kind: rbacv1.UserKind, 140 Name: username, 141 }, 142 }, 143 RoleRef: rbacv1.RoleRef{ 144 APIGroup: rbacv1.SchemeGroupVersion.Group, 145 Kind: "ClusterRole", 146 Name: clusterRoleName, 147 }, 148 } 149 }