-
Notifications
You must be signed in to change notification settings - Fork 165
/
adminapi_csr.go
130 lines (107 loc) · 5.6 KB
/
adminapi_csr.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package e2e
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
import (
"context"
"encoding/base64"
"net/http"
"net/url"
"strconv"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
certificatesv1 "k8s.io/api/certificates/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var _ = Describe("[Admin API] CertificateSigningRequest action", func() {
BeforeEach(skipIfNotInDevelopmentEnv)
const prefix = "e2e-test-csr"
const namespace = "openshift"
const csrCount = 4
BeforeEach(func(ctx context.Context) {
const csrdataStr = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ3BEQ0NBWXdDQVFBd1h6RUxNQWtHQTFVRUJoTUNWVk14Q3pBSkJnTlZCQWdNQWtOUE1ROHdEUVlEVlFRSApEQVpFWlc1MlpYSXhFakFRQmdOVkJBb01DVTFwWTNKdmMyOW1kREVNTUFvR0ExVUVDd3dEUVZKUE1SQXdEZ1lEClZRUUREQWRsTW1VdVlYSnZNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQWxqWUUKcnFkU0hvV1p2MVdHSnN1RFZsaGExVU1BVnJiUk0xWjJHaWZJMzNETlBUWGFmQnN1QVI2ZGVCQVgyWmpybUozNQpuekNBZ0k5d1ltdlYwN3JtTEFYQlloRnJiTWtNN1pSU1ZFT01hL2ZXdlN5ZjJVQWxSdm5Jd0JmRkgwS1pRSGg5Cm5aV3RIZHQxSzRuZ3ZnM1NuQ3JEU0NBRUhsS2hoN3Jua1pyRkdrMldabFFoVklWUXFReFFzdmx3VStvWlhnNjQKdmpleDRuc3BZaXFXMERzakl6RzFsSEszWHczN3RGeWhNNzJ4SjByblBYVTRGWkJsWXUzWkVqOFVhSFBoTlcrdgpqZmg2c0hCbWFkcHpEMWRuNDJ4eXgrUGhOaCtKWTVVT3ZWWnR2MWx5UU44eEswL0VjK0Mvcm1mOWZPYmdFSkNVCm00Z3pFSXhhVGhCVURsN1JHd0lEQVFBQm9BQXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBQnYvVHdUR0JvL20KcVJVK0djZ3Bsa3I1aDlKQVdSZjNNazV3Z1o0ZmlSZm85UEVaYUxJWkZYQ0V0elNHV3JZenFjbFpZQ3JuRmUySQpzdHdNUU8yb1pQUzNvcUVIcWs5Uk0rbzRUVmtkSldjY3hKV3RMY3JoTWRwVjVMc3VMam1qRS9jeDcrbEtUZkh1Cno0eDllYzJTajhnZmV3SFowZTkzZjFTT3ZhVGFMaTQrT3JkM3FTT0NyNE5ZSGhvVDJiM0pBUFpMSmkvVEFpb1gKOUxJNFJpVXNSSWlMUm45VDZidzczM0FLMkpNMXREWU9Tc0hXdmJrZ3FDOFlHMmpYUW9LNUpZOWdTN0V5TkF6NwpjT1plbkkwK2dVeE1leUlNN2I0S05YWFQ3NmxVdHZ5M2N3LzhwVmxQU01pTDFVZ2RpMXFZMDl0MW9FMmU4YnljCm5GdWhZOW5ERU53PQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K"
csrDataEncoded := []byte(csrdataStr)
csrDataDecoded := make([]byte, base64.StdEncoding.DecodedLen(len(csrDataEncoded)))
csrDataLength, err := base64.StdEncoding.Decode(csrDataDecoded, csrDataEncoded)
Expect(err).NotTo(HaveOccurred())
csrData := csrDataDecoded[:csrDataLength]
By("creating mock CSRs via Kubernetes API")
for i := 0; i < csrCount; i++ {
csr := mockCSR(prefix+strconv.Itoa(i), namespace, csrData)
createFunc := clients.Kubernetes.CertificatesV1().CertificateSigningRequests().Create
CreateK8sObjectWithRetry(ctx, createFunc, csr, metav1.CreateOptions{})
}
})
AfterEach(func(ctx context.Context) {
By("deleting the mock CSRs via Kubernetes API")
for i := 0; i < csrCount; i++ {
deleteFunc := clients.Kubernetes.CertificatesV1().CertificateSigningRequests().Delete
DeleteK8sObjectWithRetry(ctx, deleteFunc, prefix+strconv.Itoa(i), metav1.DeleteOptions{})
}
})
It("must be able to approve one CSRs", func(ctx context.Context) {
testCSRApproveOK(ctx, prefix+"0", namespace)
})
It("must be able to approve multiple CSRs", func(ctx context.Context) {
testCSRMassApproveOK(ctx, prefix, namespace, csrCount)
})
})
func testCSRApproveOK(ctx context.Context, objName, namespace string) {
By("approving the CSR via RP admin API")
params := url.Values{
"csrName": []string{objName},
}
resp, err := adminRequest(ctx, http.MethodPost, "/admin"+clusterResourceID+"/approvecsr", params, true, nil, nil)
Expect(err).NotTo(HaveOccurred())
Expect(resp.StatusCode).To(Equal(http.StatusOK))
By("checking that the CSR was approved via Kubernetes API")
getFunc := clients.Kubernetes.CertificatesV1().CertificateSigningRequests().Get
testcsr := GetK8sObjectWithRetry(ctx, getFunc, objName, metav1.GetOptions{})
approved := false
for _, condition := range testcsr.Status.Conditions {
if condition.Type == certificatesv1.CertificateApproved {
Expect(condition.Status).To(Equal(corev1.ConditionTrue))
Expect(condition.Reason).To(Equal("AROSupportApprove"))
Expect(condition.Message).To(Equal("This CSR was approved by ARO support personnel."))
approved = true
}
}
Expect(approved).Should(BeTrue())
}
func testCSRMassApproveOK(ctx context.Context, namePrefix, namespace string, csrCount int) {
By("approving all CSRs via RP admin API")
resp, err := adminRequest(ctx, http.MethodPost, "/admin"+clusterResourceID+"/approvecsr", nil, true, nil, nil)
Expect(err).NotTo(HaveOccurred())
Expect(resp.StatusCode).To(Equal(http.StatusOK))
By("checking that all CSRs were approved via Kubernetes API")
for i := 1; i < csrCount; i++ {
getFunc := clients.Kubernetes.CertificatesV1().CertificateSigningRequests().Get
testcsr := GetK8sObjectWithRetry(ctx, getFunc, namePrefix+strconv.Itoa(i), metav1.GetOptions{})
approved := false
for _, condition := range testcsr.Status.Conditions {
if condition.Type == certificatesv1.CertificateApproved {
Expect(condition.Status).To(Equal(corev1.ConditionTrue))
Expect(condition.Reason).To(Equal("AROSupportApprove"))
Expect(condition.Message).To(Equal("This CSR was approved by ARO support personnel."))
approved = true
}
}
Expect(approved).Should(BeTrue())
}
}
func mockCSR(objName, namespace string, csrData []byte) *certificatesv1.CertificateSigningRequest {
csr := &certificatesv1.CertificateSigningRequest{
// Username, UID, Groups will be injected by API server.
TypeMeta: metav1.TypeMeta{Kind: "CertificateSigningRequest"},
ObjectMeta: metav1.ObjectMeta{
Name: objName,
Namespace: namespace,
},
Spec: certificatesv1.CertificateSigningRequestSpec{
Request: csrData,
Usages: []certificatesv1.KeyUsage{certificatesv1.UsageClientAuth},
SignerName: "kubernetes.io/kube-apiserver-client",
},
}
return csr
}