Skip to content

Commit df72578

Browse files
committed
wip008
Signed-off-by: Monis Khan <mkhan@redhat.com>
1 parent 4a9359f commit df72578

File tree

3 files changed

+185
-80
lines changed

3 files changed

+185
-80
lines changed

csr_check.go

+61-12
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1313
"k8s.io/apimachinery/pkg/util/sets"
1414
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
15+
"k8s.io/client-go/tools/cache"
1516

1617
"github.com/openshift/cluster-api/pkg/apis/machine/v1beta1"
1718
)
@@ -21,13 +22,16 @@ const (
2122
nodeGroup = "system:nodes"
2223
nodeUserPrefix = nodeUser + ":"
2324

25+
maxPendingDelta = time.Hour
26+
maxPendingCSRs = 100
27+
2428
nodeBootstrapperUsername = "system:serviceaccount:openshift-machine-config-operator:node-bootstrapper"
2529

26-
maxMachineDelta = 10 * time.Minute
30+
maxMachineClockSkew = 10 * time.Second
31+
maxMachineDelta = 10 * time.Minute
2732

28-
machineRoleKey = "machine.openshift.io/cluster-api-machine-role"
29-
machineTypeKey = "machine.openshift.io/cluster-api-machine-type"
30-
machineRoleTypeValue = "worker"
33+
machineCSRAutoApproveKey = "machine.openshift.io/csr-auto-approver"
34+
machineCSRAutoApproveValue = "cluster-machine-approver"
3135
)
3236

3337
var nodeBootstrapperGroups = sets.NewString(
@@ -103,9 +107,21 @@ func validateCSRContents(req *certificatesv1beta1.CertificateSigningRequest, csr
103107
return nodeAsking, nil
104108
}
105109

106-
// authorizeCSR authorizes the CertificateSigningRequest req for a node's server certificate.
107-
// csr should be the parsed CSR from req.Spec.Request. Names contained in the CSR are checked against addresses in the
108-
// corresponding node's machine status.
110+
// authorizeCSR authorizes the CertificateSigningRequest req for a node's client or server certificate.
111+
// csr should be the parsed CSR from req.Spec.Request.
112+
//
113+
// For client certificates:
114+
// The only information contained in the CSR is the future name of the node. Thus we perform a best effort check:
115+
//
116+
// 1. User is the node bootstrapper
117+
// 2. Node does not exist
118+
// 3. Use machine API internal DNS to locate matching machine based on node name
119+
// 4. Machine must not have a node ref
120+
// 5. Machine must opt-in to CSR auto approve via label
121+
// 6. CSR creation timestamp is very close to machine creation timestamp
122+
//
123+
// For server certificates:
124+
// Names contained in the CSR are checked against addresses in the corresponding node's machine status.
109125
func authorizeCSR(machines []v1beta1.Machine, nodes corev1client.NodeInterface, req *certificatesv1beta1.CertificateSigningRequest, csr *x509.CertificateRequest) error {
110126
if len(machines) == 0 || req == nil || csr == nil {
111127
return fmt.Errorf("Invalid request")
@@ -210,11 +226,11 @@ func authorizeNodeClientCSR(machines []v1beta1.Machine, nodes corev1client.NodeI
210226
return fmt.Errorf("machine for node %s already has node ref", nodeName)
211227
}
212228

213-
if !isWorkerMachine(nodeMachine) {
214-
return fmt.Errorf("machine for node %s is not a worker", nodeName)
229+
if !machineWantsCSRAutoApprove(nodeMachine) {
230+
return fmt.Errorf("machine for node %s is not configured for CSR auto approval", nodeName)
215231
}
216232

217-
start := nodeMachine.CreationTimestamp.Add(-maxMachineDelta) // TODO maybe this should be really small to account only for clock drift
233+
start := nodeMachine.CreationTimestamp.Add(-maxMachineClockSkew)
218234
end := nodeMachine.CreationTimestamp.Add(maxMachineDelta)
219235
if !inTimeSpan(start, end, req.CreationTimestamp.Time) {
220236
return fmt.Errorf("CSR %s creation time %s not in range (%s, %s)", req.Name, req.CreationTimestamp.Time, start, end)
@@ -247,10 +263,43 @@ func findMatchingMachineFromInternalDNS(nodeName string, machines []v1beta1.Mach
247263
return v1beta1.Machine{}, false
248264
}
249265

250-
func isWorkerMachine(machine v1beta1.Machine) bool {
251-
return machine.Labels[machineRoleKey] == machineRoleTypeValue && machine.Labels[machineTypeKey] == machineRoleTypeValue
266+
func machineWantsCSRAutoApprove(machine v1beta1.Machine) bool {
267+
return machine.Labels[machineCSRAutoApproveKey] == machineCSRAutoApproveValue
252268
}
253269

254270
func inTimeSpan(start, end, check time.Time) bool {
255271
return check.After(start) && check.Before(end)
256272
}
273+
274+
func isApproved(csr *certificatesv1beta1.CertificateSigningRequest) bool {
275+
for _, condition := range csr.Status.Conditions {
276+
if condition.Type == certificatesv1beta1.CertificateApproved {
277+
return true
278+
}
279+
}
280+
return false
281+
}
282+
283+
func recentlyPendingCSRs(indexer cache.Indexer) int {
284+
// assumes we are scheduled on the master meaning our clock is the same
285+
now := time.Now()
286+
start := now.Add(-maxPendingDelta)
287+
end := now.Add(maxMachineClockSkew)
288+
289+
var pending int
290+
291+
for _, item := range indexer.List() {
292+
csr := item.(*certificatesv1beta1.CertificateSigningRequest)
293+
294+
// ignore "old" CSRs
295+
if !inTimeSpan(start, end, csr.CreationTimestamp.Time) {
296+
continue
297+
}
298+
299+
if !isApproved(csr) {
300+
pending++
301+
}
302+
}
303+
304+
return pending
305+
}

0 commit comments

Comments
 (0)