1
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
36
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
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
65 const username = "test-user"
66 grantUserPermissionToApproveFor(t, client, username, test.allowedSignerName)
67
68 csr := createTestingCSR(t, client.CertificatesV1().CertificateSigningRequests(), "csr", test.signerName, "")
69
70
71 testuserConfig := restclient.CopyConfig(s.ClientConfig)
72 testuserConfig.Impersonate = restclient.ImpersonationConfig{UserName: username}
73 testuserClient := clientset.NewForConfigOrDie(testuserConfig)
74
75
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
116
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 }
150
View as plain text