@@ -19,8 +19,10 @@ package signer
19
19
20
20
import (
21
21
"context"
22
+ "crypto/x509"
22
23
"encoding/pem"
23
24
"fmt"
25
+ "strings"
24
26
"time"
25
27
26
28
capi "k8s.io/api/certificates/v1beta1"
@@ -89,37 +91,82 @@ func newSigner(caFile, caKeyFile string, client clientset.Interface, certificate
89
91
}
90
92
91
93
func (s * signer ) handle (csr * capi.CertificateSigningRequest ) error {
94
+ // Ignore unapproved requests
92
95
if ! certificates .IsCertificateRequestApproved (csr ) {
93
96
return nil
94
97
}
95
- csr , err := s .sign (csr )
98
+
99
+ // Fast-path to avoid any additional processing if the CSRs signerName does
100
+ // not have a 'kubernetes.io/' prefix.
101
+ if ! strings .HasPrefix (* csr .Spec .SignerName , "kubernetes.io/" ) {
102
+ return nil
103
+ }
104
+
105
+ x509cr , err := capihelper .ParseCSR (csr .Spec .Request )
106
+ if err != nil {
107
+ return fmt .Errorf ("unable to parse csr %q: %v" , csr .Name , err )
108
+ }
109
+ if ! requestValidForSignerName (x509cr , csr .Spec .Usages , * csr .Spec .SignerName ) {
110
+ // TODO: mark the CertificateRequest as being in a terminal state and
111
+ // communicate to the user why the request has been refused.
112
+ return nil
113
+ }
114
+ cert , err := s .sign (x509cr , csr .Spec .Usages )
96
115
if err != nil {
97
116
return fmt .Errorf ("error auto signing csr: %v" , err )
98
117
}
118
+ csr .Status .Certificate = cert
99
119
_ , err = s .client .CertificatesV1beta1 ().CertificateSigningRequests ().UpdateStatus (context .TODO (), csr , metav1.UpdateOptions {})
100
120
if err != nil {
101
121
return fmt .Errorf ("error updating signature for csr: %v" , err )
102
122
}
103
123
return nil
104
124
}
105
125
106
- func (s * signer ) sign (csr * capi.CertificateSigningRequest ) (* capi.CertificateSigningRequest , error ) {
107
- x509cr , err := capihelper .ParseCSR (csr .Spec .Request )
108
- if err != nil {
109
- return nil , fmt .Errorf ("unable to parse csr %q: %v" , csr .Name , err )
110
- }
111
-
126
+ func (s * signer ) sign (x509cr * x509.CertificateRequest , usages []capi.KeyUsage ) ([]byte , error ) {
112
127
currCA , err := s .caProvider .currentCA ()
113
128
if err != nil {
114
129
return nil , err
115
130
}
116
131
der , err := currCA .Sign (x509cr .Raw , authority.PermissiveSigningPolicy {
117
132
TTL : s .certTTL ,
118
- Usages : csr . Spec . Usages ,
133
+ Usages : usages ,
119
134
})
120
135
if err != nil {
121
136
return nil , err
122
137
}
123
- csr .Status .Certificate = pem .EncodeToMemory (& pem.Block {Type : "CERTIFICATE" , Bytes : der })
124
- return csr , nil
138
+ return pem .EncodeToMemory (& pem.Block {Type : "CERTIFICATE" , Bytes : der }), nil
139
+ }
140
+
141
+ func requestValidForSignerName (req * x509.CertificateRequest , usages []capi.KeyUsage , signerName string ) bool {
142
+ // Only handle CSRs with the specific known signerNames.
143
+ switch signerName {
144
+ case capi .KubeletServingSignerName :
145
+ return capihelper .IsKubeletServingCSR (req , usages )
146
+ case capi .KubeAPIServerClientKubeletSignerName :
147
+ return capihelper .IsKubeletClientCSR (req , usages )
148
+ case capi .KubeAPIServerClientSignerName :
149
+ return validAPIServerClientUsages (usages )
150
+ case capi .LegacyUnknownSignerName :
151
+ // No restrictions are applied to the legacy-unknown signerName to
152
+ // maintain backward compatibility in v1beta1.
153
+ return true
154
+ default :
155
+ return false
156
+ }
157
+ }
158
+
159
+ func validAPIServerClientUsages (usages []capi.KeyUsage ) bool {
160
+ hasClientAuth := false
161
+ for _ , u := range usages {
162
+ switch u {
163
+ // these usages are optional
164
+ case capi .UsageDigitalSignature , capi .UsageKeyEncipherment :
165
+ case capi .UsageClientAuth :
166
+ hasClientAuth = true
167
+ default :
168
+ return false
169
+ }
170
+ }
171
+ return hasClientAuth
125
172
}
0 commit comments