Skip to content

Commit 2a4a0e0

Browse files
authored
Prefix provider resource names with hashed consumer cluster name to prevent conflicts (#165)
- Prefix provider-side resource names with a 12-char hash of the consumer cluster name to prevent conflicts when multiple consumers create resources with the same name/namespace - Store original name in annotation for provider-to-consumer reverse lookup - Strip prefix from related resources when syncing back to consumer - Added unit tests for the generic functions - Modified the e2e examples test
1 parent 0ad6297 commit 2a4a0e0

File tree

15 files changed

+554
-117
lines changed

15 files changed

+554
-117
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ EXAMPLES_PREFIX ?= $(patsubst %,example-%,$(EXAMPLES))
9393
.PHONY: examples
9494
examples: $(EXAMPLES_PREFIX) ## Run the examples.
9595
example-%: manifests generate fmt vet
96-
go run github.com/ntnn/mdextract/cmd/mdextract@main -output run.bash -tags bash,ci ./examples/$*/README.md \
96+
go get github.com/ntnn/mdextract
97+
go run github.com/ntnn/mdextract@main -output run.bash -tags bash,ci ./examples/$*/README.md \
9798
&& trap 'rm -f run.bash' EXIT \
9899
&& bash -xe ./run.bash
99100

examples/certs/README.md

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,18 @@ kubectl --kubeconfig ./kubeconfigs/consumer.kubeconfig apply -f ./examples/certs
133133
<!--
134134
```bash ci
135135
source ./hack/lib.bash
136-
kubectl::wait ./kubeconfigs/internalca.kubeconfig certificates.example.platform-mesh.io/cert-from-consumer default create
137-
kubectl::wait ./kubeconfigs/internalca.kubeconfig certificates.cert-manager.io/cert-from-consumer default create
138-
kubectl::wait ./kubeconfigs/internalca.kubeconfig certificates.cert-manager.io/cert-from-consumer default condition=Ready
136+
consumer_cluster="consumer#/kubeconfigs/consumer/kubeconfig+default"
137+
provider_cert="$(echo -n "$consumer_cluster" | sha256sum | cut -c1-12)-cert-from-consumer"
138+
kubectl::wait ./kubeconfigs/internalca.kubeconfig certificates.example.platform-mesh.io/$provider_cert default create
139+
kubectl::wait ./kubeconfigs/internalca.kubeconfig certificates.cert-manager.io/$provider_cert default create
140+
kubectl::wait ./kubeconfigs/internalca.kubeconfig certificates.cert-manager.io/$provider_cert default condition=Ready
139141
```
140142
-->
141143

142144
This will be picked up by resource-broker and sent to the InternalCA provider:
143145

144146
```bash ci
145-
kubectl --kubeconfig ./kubeconfigs/internalca.kubeconfig get certificates.example.platform-mesh.io cert-from-consumer -o yaml
147+
kubectl --kubeconfig ./kubeconfigs/internalca.kubeconfig get certificates.example.platform-mesh.io "$provider_cert" -o yaml
146148
```
147149

148150
```yaml
@@ -154,7 +156,7 @@ metadata:
154156
- broker.platform-mesh.io/generic-finalizer
155157
- kro.run/finalizer
156158
# ...
157-
name: cert-from-consumer
159+
name: d480f64dc494-cert-from-consumer
158160
namespace: default
159161
# ...
160162
spec:
@@ -167,7 +169,7 @@ status:
167169
group: core
168170
kind: Secret
169171
version: v1
170-
name: cert-from-consumer
172+
name: d480f64dc494-cert-from-consumer
171173
namespace: default
172174
state: ACTIVE
173175
status: Available
@@ -186,7 +188,7 @@ items:
186188
kind: Certificate
187189
metadata:
188190
# ...
189-
name: cert-from-consumer
191+
name: d480f64dc494-cert-from-consumer
190192
namespace: default
191193
# ...
192194
spec:
@@ -216,7 +218,7 @@ items:
216218
blockOwnerDeletion: true
217219
controller: true
218220
kind: Certificate
219-
name: cert-from-consumer
221+
name: d480f64dc494-cert-from-consumer
220222
uid: f6010fea-e5b6-4be7-b6c3-b57165dc2588
221223
# ...
222224
type: kubernetes.io/tls
@@ -280,18 +282,18 @@ kubectl --kubeconfig ./kubeconfigs/consumer.kubeconfig patch certificate cert-fr
280282

281283
<!--
282284
```bash ci
283-
kubectl::wait ./kubeconfigs/externalca.kubeconfig certificates.example.platform-mesh.io/cert-from-consumer default create
284-
kubectl::wait ./kubeconfigs/externalca.kubeconfig certificates.cert-manager.io/cert-from-consumer default create
285-
kubectl::wait ./kubeconfigs/externalca.kubeconfig certificates.cert-manager.io/cert-from-consumer default condition=Ready
285+
kubectl::wait ./kubeconfigs/externalca.kubeconfig certificates.example.platform-mesh.io/$provider_cert default create
286+
kubectl::wait ./kubeconfigs/externalca.kubeconfig certificates.cert-manager.io/$provider_cert default create
287+
kubectl::wait ./kubeconfigs/externalca.kubeconfig certificates.cert-manager.io/$provider_cert default condition=Ready
286288
```
287289
-->
288290

289291
resource-broker will first create the Certificate in the ExternalCA provider:
290292

291293
<!--
292294
```bash ci
293-
kubectl::wait ./kubeconfigs/externalca.kubeconfig certificates.cert-manager.io/cert-from-consumer default create
294-
kubectl::wait ./kubeconfigs/externalca.kubeconfig certificates.cert-manager.io/cert-from-consumer default condition=Ready
295+
kubectl::wait ./kubeconfigs/externalca.kubeconfig certificates.cert-manager.io/$provider_cert default create
296+
kubectl::wait ./kubeconfigs/externalca.kubeconfig certificates.cert-manager.io/$provider_cert default condition=Ready
295297
```
296298
-->
297299

@@ -311,7 +313,7 @@ items:
311313
- broker.platform-mesh.io/generic-finalizer
312314
- kro.run/finalizer
313315
# ..
314-
name: cert-from-consumer
316+
name: d480f64dc494-cert-from-consumer
315317
namespace: default
316318
# ..
317319
spec:
@@ -324,7 +326,7 @@ items:
324326
group: core
325327
kind: Secret
326328
version: v1
327-
name: cert-from-consumer
329+
name: d480f64dc494-cert-from-consumer
328330
namespace: default
329331
state: ACTIVE
330332
status: Available
@@ -333,7 +335,7 @@ items:
333335
kind: Certificate
334336
metadata:
335337
# ...
336-
name: cert-from-consumer
338+
name: d480f64dc494-cert-from-consumer
337339
namespace: default
338340
# ..
339341
spec:
@@ -364,7 +366,7 @@ items:
364366
blockOwnerDeletion: true
365367
controller: true
366368
kind: Certificate
367-
name: cert-from-consumer
369+
name: d480f64dc494-cert-from-consumer
368370
# ...
369371
type: kubernetes.io/tls
370372
kind: List
@@ -376,7 +378,7 @@ And then delete it from the InternalCA provider:
376378
377379
<!--
378380
```bash ci
379-
kubectl::wait ./kubeconfigs/internalca.kubeconfig certificates.example.platform-mesh.io/cert-from-consumer default delete
381+
kubectl::wait ./kubeconfigs/internalca.kubeconfig certificates.example.platform-mesh.io/$provider_cert default delete
380382
```
381383
-->
382384

examples/certs/run.bash

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,19 +78,23 @@ _stop_broker() {
7878
}
7979

8080
_cleanup() {
81+
local consumer_cluster
82+
consumer_cluster="consumer#$(kubectl --kubeconfig "$kind_consumer" config current-context)"
83+
local hash
84+
hash=$(echo -n "$consumer_cluster" | sha256sum | cut -c1-12)
85+
local provider_cert="${hash}-cert-from-consumer"
86+
8187
kubectl::delete "$kind_consumer" \
8288
certificates.example.platform-mesh.io/cert-from-consumer \
8389
secret/cert-from-consumer
8490

8591
kubectl::delete "$kind_internalca" \
86-
certificates.example.platform-mesh.io/cert-from-consumer \
87-
certificates.cert-manager.io/cert-from-consumer \
88-
secret/cert-from-consumer
92+
"certificates.example.platform-mesh.io/$provider_cert" \
93+
"secret/$provider_cert"
8994

9095
kubectl::delete "$kind_externalca" \
91-
certificates.example.platform-mesh.io/cert-from-consumer \
92-
certificates.cert-manager.io/cert-from-consumer \
93-
secret/cert-from-consumer
96+
"certificates.example.platform-mesh.io/$provider_cert" \
97+
"secret/$provider_cert"
9498
return 0
9599
}
96100

examples/kcp-certs/README.md

Lines changed: 99 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,65 @@ spec:
315315
kubectl --kubeconfig="./kubeconfigs/workspaces/consumer.kubeconfig" apply -f ./examples/kcp-certs/cert.yaml
316316
```
317317

318-
The resource-broker will see the Certificate in the virtual workspace of the APIExport, pass it to a matching provider. Since the fqdn is `app.internal.corp` the InternalCA provider will issue the certificate:
318+
The resource-broker will see the Certificate in the virtual workspace of the APIExport, pass it to a matching provider. Since the fqdn is `app.internal.corp` the InternalCA provider will issue the certificate.
319+
320+
> [!NOTE]
321+
> Provider-side resource names are prefixed with a hash of the consumer cluster name to prevent
322+
> naming conflicts when multiple consumers create resources with the same name.
323+
> The original consumer-side name `cert-from-consumer` becomes `{hash}-cert-from-consumer` in
324+
> the provider's virtual workspace.
325+
326+
In the provider's virtual workspace the Certificate looks like this.
327+
328+
Grab the hash-prefixed name from the VW:
329+
330+
<!--
331+
Wait for the certificate to appear in the provider's virtual workspace:
332+
```bash ci
333+
kubectl::wait::list \
334+
kubeconfigs/workspaces/internalca.vw.kubeconfig \
335+
certificates.example.platform-mesh.io \
336+
--all-namespaces
337+
```
338+
-->
339+
340+
```bash ci
341+
provider_cert="$(kubectl --kubeconfig kubeconfigs/workspaces/internalca.vw.kubeconfig get certificates.example.platform-mesh.io -A -o jsonpath="{.items[0].metadata.name}")"
342+
```
343+
344+
```bash ci
345+
kubectl --kubeconfig kubeconfigs/workspaces/internalca.vw.kubeconfig get certificates.example.platform-mesh.io "$provider_cert" -o yaml
346+
```
347+
348+
```yaml
349+
apiVersion: v1
350+
items:
351+
- apiVersion: example.platform-mesh.io/v1alpha1
352+
kind: Certificate
353+
metadata:
354+
# ...
355+
name: {hash}-cert-from-consumer
356+
namespace: default
357+
# ...
358+
spec:
359+
fqdn: app.internal.corp
360+
status:
361+
# ...
362+
relatedResources:
363+
secret:
364+
gvk:
365+
group: core
366+
kind: Secret
367+
version: v1
368+
name: {hash}-cert-from-consumer
369+
namespace: default
370+
# ...
371+
kind: List
372+
metadata:
373+
resourceVersion: ""
374+
```
375+
376+
On the compute cluster, api-syncagent further transforms the name using its own cluster IDs and hashes:
319377
320378
<!--
321379
```bash ci
@@ -326,13 +384,10 @@ kubectl::wait::list \
326384
```
327385
-->
328386

329-
330387
```bash ci
331388
kubectl --kubeconfig kubeconfigs/internalca.kubeconfig get certificates.example.platform-mesh.io --all-namespaces
332389
```
333390

334-
For synchronisation api-syncagent is used, which uses the cluster IDs and hashes to uniquely name the resources:
335-
336391
```
337392
NAMESPACE NAME STATE SYNCED AGE
338393
9n832d7e4xebepg1 2747cabbb481a433679f-42b4d6246cf320c6cee5 ACTIVE True 10m
@@ -362,15 +417,15 @@ items:
362417
group: core
363418
kind: Secret
364419
version: v1
365-
name: 2747cabbb481a433679f-42b4d6246cf320c6cee5
420+
name: {hash}-cert-from-consumer
366421
namespace: default
367422
# ...
368423
kind: List
369424
metadata:
370425
resourceVersion: ""
371426
```
372427
373-
Grab the name and namespace:
428+
Grab the name and namespace from the compute cluster:
374429
375430
```bash ci
376431
secret_name="$(kubectl --kubeconfig kubeconfigs/internalca.kubeconfig get certificates.example.platform-mesh.io --all-namespaces -o jsonpath="{.items[0].metadata.name}")"
@@ -382,7 +437,7 @@ Wait for the certificate to be issued.
382437
```bash ci
383438
kubectl::wait::cert::subject \
384439
kubeconfigs/internalca.kubeconfig \
385-
"$secret_name" \
440+
"$provider_cert" \
386441
"$secret_namespace" \
387442
"app.internal.corp"
388443
```
@@ -399,7 +454,7 @@ kubectl --kubeconfig kubeconfigs/internalca.kubeconfig get secrets --namespace "
399454
Decoding the `tls.crt` field shows the certificate was correctly issued for `app.internal.corp`:
400455

401456
```bash ci
402-
kubectl --kubeconfig kubeconfigs/internalca.kubeconfig get secrets --namespace "$secret_namespace" "$secret_name" -o jsonpath="{.data.tls\.crt}" \
457+
kubectl --kubeconfig kubeconfigs/internalca.kubeconfig get secrets --namespace "$secret_namespace" "$provider_cert" -o jsonpath="{.data.tls\.crt}" \
403458
| base64 --decode \
404459
| openssl x509 -noout -subject
405460
# subject=CN=app.internal.corp
@@ -412,27 +467,27 @@ Wait for the certificate secret to be synced:
412467
```bash ci
413468
kubectl::wait::cert::subject \
414469
kubeconfigs/workspaces/consumer.kubeconfig \
415-
"$secret_name" \
470+
"cert-from-consumer" \
416471
"default" \
417472
"app.internal.corp"
418473
```
419474
-->
420475

421476
```bash ci
422-
kubectl --kubeconfig kubeconfigs/workspaces/consumer.kubeconfig get secrets "$secret_name"
477+
kubectl --kubeconfig kubeconfigs/workspaces/consumer.kubeconfig get secrets "cert-from-consumer"
423478
```
424479

425480
And comparing the serial number shows it's the same certificate:
426481

427482
```bash ci
428483
kubectl --kubeconfig kubeconfigs/internalca.kubeconfig \
429-
get secrets --namespace "$secret_namespace" "$secret_name" \
484+
get secrets --namespace "$secret_namespace" "$provider_cert" \
430485
-o jsonpath="{.data.tls\.crt}" \
431486
| base64 --decode \
432487
| openssl x509 -noout -serial
433488
# serial=0E7311D15E34081A8F1FD7447F1FF4C7BC055238
434489
kubectl --kubeconfig kubeconfigs/workspaces/consumer.kubeconfig \
435-
get secrets "$secret_name" \
490+
get secrets "cert-from-consumer" \
436491
-o jsonpath="{.data.tls\.crt}" \
437492
| base64 --decode \
438493
| openssl x509 -noout -serial
@@ -470,16 +525,43 @@ kubectl::wait::list \
470525
```
471526
-->
472527

528+
Grab the hash-prefixed name from the externalca VW:
529+
530+
<!--
531+
Wait for the certificate to appear in the externalca provider's virtual workspace:
532+
```bash ci
533+
kubectl::wait::list \
534+
kubeconfigs/workspaces/externalca.vw.kubeconfig \
535+
certificates.example.platform-mesh.io \
536+
--all-namespaces
537+
```
538+
-->
539+
540+
```bash ci
541+
provider_cert="$(kubectl --kubeconfig kubeconfigs/workspaces/externalca.vw.kubeconfig get certificates.example.platform-mesh.io -A -o jsonpath="{.items[0].metadata.name}")"
542+
```
543+
473544
```bash ci
474545
secret_name="$(kubectl --kubeconfig kubeconfigs/externalca.kubeconfig get certificates.example.platform-mesh.io --all-namespaces -o jsonpath="{.items[0].metadata.name}")"
475546
secret_namespace="$(kubectl --kubeconfig kubeconfigs/externalca.kubeconfig get certificates.example.platform-mesh.io --all-namespaces -o jsonpath="{.items[0].metadata.namespace}")"
476547
```
477548

549+
<!--
550+
Wait for the certificate to be issued.
551+
```bash ci
552+
kubectl::wait::cert::subject \
553+
kubeconfigs/externalca.kubeconfig \
554+
"$provider_cert" \
555+
"$secret_namespace" \
556+
"app.corp.com"
557+
```
558+
-->
559+
478560
And decoding the `tls.crt` field shows the certificate was correctly issued for `app.corp.com`:
479561

480562
```bash ci
481563
kubectl --kubeconfig kubeconfigs/externalca.kubeconfig \
482-
get secrets --namespace "$secret_namespace" "$secret_name" \
564+
get secrets --namespace "$secret_namespace" "$provider_cert" \
483565
-o jsonpath="{.data.tls\.crt}" \
484566
| base64 --decode \
485567
| openssl x509 -noout -subject
@@ -491,7 +573,7 @@ Wait for the certificate secret to be synced:
491573
```bash ci
492574
kubectl::wait::cert::subject \
493575
kubeconfigs/workspaces/consumer.kubeconfig \
494-
"$secret_name" \
576+
"cert-from-consumer" \
495577
"default" \
496578
"app.corp.com"
497579
```
@@ -501,7 +583,7 @@ And the secret in the consumer workspace has been updated accordingly:
501583

502584
```bash ci
503585
kubectl --kubeconfig kubeconfigs/workspaces/consumer.kubeconfig \
504-
get secrets "$secret_name" \
586+
get secrets "cert-from-consumer" \
505587
-o jsonpath="{.data.tls\.crt}" \
506588
| base64 --decode \
507589
| openssl x509 -noout -subject
@@ -512,13 +594,13 @@ And again comparing the serial numbers, now with the certificate in the external
512594

513595
```bash ci
514596
kubectl --kubeconfig kubeconfigs/externalca.kubeconfig \
515-
get secrets --namespace "$secret_namespace" "$secret_name" \
597+
get secrets --namespace "$secret_namespace" "$provider_cert" \
516598
-o jsonpath="{.data.tls\.crt}" \
517599
| base64 --decode \
518600
| openssl x509 -noout -serial
519601
# serial=204F68FCA700404CB7745D7A603BA5A28DC68E95
520602
kubectl --kubeconfig kubeconfigs/workspaces/consumer.kubeconfig \
521-
get secrets "$secret_name" \
603+
get secrets "cert-from-consumer" \
522604
-o jsonpath="{.data.tls\.crt}" \
523605
| base64 --decode \
524606
| openssl x509 -noout -serial

0 commit comments

Comments
 (0)