Skip to content

Commit 3a9556f

Browse files
committed
move comments to docs
1 parent f54cdfa commit 3a9556f

3 files changed

Lines changed: 330 additions & 101 deletions

File tree

docs/content/developers/.pages

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
nav:
22
- index.md
3+
- Architecture: architecture.md
34
- Development Environment: dev-environments.md
45
- Backend: backend
56
- Konnector: konnector
Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
# Architecture Overview
2+
3+
This document provides detailed architecture diagrams and explanations for how kube-bind handles resource synchronization between consumer and provider clusters, with a focus on isolation strategies and namespace mapping.
4+
5+
## Cluster-Scoped Resources
6+
7+
Cluster-scoped resources (like Sheriffs in our examples) can use different isolation strategies to control how they are placed on the provider cluster and how their associated secrets are isolated.
8+
9+
### Architecture Flow
10+
11+
```
12+
CONSUMER CLUSTER PROVIDER CLUSTER (Backend)
13+
================ ==========================
14+
15+
┌─────────────────────────────┐ ┌────────────────────────────────────────────┐
16+
│ Namespace: wild-west │ │ Contract Namespace (per consumer): │
17+
│ - Secret: sheriff-badge- │──────────▶│ kube-bind-<consumer-id-hash> │
18+
│ credentials (ref) │ Sync │ │
19+
│ - Secret: sheriff-juris- │ │ APIServiceNamespace CR: │
20+
│ diction-config (label) │ │ metadata.name: wild-west │
21+
└─────────────────────────────┘ │ status.namespace: (varies by isolation)│
22+
└────────────────────────────────────────────┘
23+
┌─────────────────────────────┐
24+
│ Sheriff: wyatt-earp │──────────▶ PROVIDER CLUSTER (varies by isolation)
25+
│ (cluster-scoped) │ Sync See isolation strategies below ↓
26+
│ spec.intent │
27+
│ spec.secretRefs: [...] │
28+
└─────────────────────────────┘
29+
30+
│ Status updates
31+
└────────────────────────────────
32+
```
33+
34+
### Isolation Strategies for Cluster-Scoped Resources
35+
36+
#### 1. IsolationPrefixed
37+
38+
```
39+
┌────────────────────────────────────────────┐
40+
│ [cc-prefixed] IsolationPrefixed: │
41+
│ Sheriff: <consumer-id>-wyatt-earp │
42+
│ (cluster-scoped, prefixed name) │
43+
│ Secrets in namespace: │
44+
│ kube-bind-<consumer-id>-wild-west │
45+
│ (APIServiceNamespace mapping) │
46+
└────────────────────────────────────────────┘
47+
```
48+
49+
**How it works:**
50+
- Sheriff resource name is prefixed with consumer ID: `<consumer-id>-wyatt-earp`
51+
- Sheriff remains cluster-scoped on provider
52+
- Secrets are isolated via namespace mapping: `wild-west``kube-bind-<consumer-id>-wild-west`
53+
- Multiple consumers can safely coexist with different prefixed resources
54+
55+
**Use case:** When you want cluster-scoped resources on the provider but need to support multiple consumers safely.
56+
57+
#### 2. IsolationNone
58+
59+
```
60+
┌────────────────────────────────────────────┐
61+
│ [cc-none] IsolationNone: │
62+
│ Sheriff: wyatt-earp │
63+
│ (cluster-scoped, same name on both!) │
64+
│ ⚠ Last write wins between consumers │
65+
│ Secrets in namespace: wild-west │
66+
│ (Same namespace name on both sides!) │
67+
└────────────────────────────────────────────┘
68+
```
69+
70+
**How it works:**
71+
- Sheriff resource keeps the same name on both sides: `wyatt-earp`
72+
- Sheriff remains cluster-scoped on provider
73+
- **Namespace mapping is 1:1**: `wild-west``wild-west` (same name!)
74+
- **⚠️ WARNING:** No isolation! Multiple consumers share the same namespace. This is possible but discouraged.
75+
- Last write wins if multiple consumers create the same resource
76+
77+
**Use case:** Single consumer scenarios or when you explicitly want shared resources. **Not recommended for multi-consumer environments.**
78+
79+
#### 3. IsolationNamespaced
80+
81+
```
82+
┌────────────────────────────────────────────┐
83+
│ [cc-namespaced] IsolationNamespaced: │
84+
│ Sheriff: wyatt-earp │
85+
│ (CRD toggled to NamespaceScoped) │
86+
│ in namespace: │
87+
│ kube-bind-<consumer-id>-wild-west │
88+
│ Secrets in same namespace (isolated) │
89+
└────────────────────────────────────────────┘
90+
```
91+
92+
**How it works:**
93+
- Sheriff CRD is toggled from ClusterScoped to NamespaceScoped on the provider
94+
- Sheriff is placed in consumer-specific namespace: `kube-bind-<consumer-id>-wild-west`
95+
- Secrets are in the same namespace (isolated)
96+
- Namespace mapping: `wild-west``kube-bind-<consumer-id>-wild-west`
97+
98+
**Use case:** When you want the strongest isolation and are willing to modify the CRD scope on the provider.
99+
100+
### Key Insights for Cluster-Scoped Resources
101+
102+
The isolation strategy determines **BOTH** how Sheriff resources are placed **AND** how namespaces are mapped:
103+
104+
- **IsolationNone**: Same namespace name on both sides (`wild-west``wild-west`)
105+
- ⚠️ **NO isolation for secrets!** Multiple consumers can exist but share the same namespace (discouraged)
106+
107+
- **IsolationPrefixed**: Sheriff name prefixed, secrets isolated via namespace mapping
108+
- (`wild-west``kube-bind-<consumer-id>-wild-west`)
109+
110+
- **IsolationNamespaced**: Sheriff becomes namespaced, secrets isolated in same namespace
111+
- (`wild-west``kube-bind-<consumer-id>-wild-west`)
112+
113+
## Namespaced Resources
114+
115+
Namespaced resources (like Cowboys in our examples) always use the ServiceNamespaced isolation strategy, regardless of the isolation parameter.
116+
117+
### Architecture Flow
118+
119+
```
120+
CONSUMER CLUSTER PROVIDER CLUSTER (Backend)
121+
================ ==========================
122+
123+
┌─────────────────────────────┐ ┌────────────────────────────────────────────┐
124+
│ Namespace: wild-west │ │ Contract Namespace (per consumer): │
125+
│ │──────────▶│ kube-bind-<consumer-id-hash> │
126+
│ Cowboy: billy-the-kid │ Sync │ │
127+
│ (namespaced) │ │ APIServiceNamespace CR: │
128+
│ spec.intent │ │ metadata.name: wild-west │
129+
│ spec.secretRefs: [...] │ │ status.namespace: ─────────────────┐ │
130+
│ │ │ kube-bind-<consumer-id>-wild-west│ │
131+
│ - Secret: colt-45-permit │ └────────────────────────────────────────┼───┘
132+
│ (ref) │ │
133+
│ - Secret: cowboy-gang- │ ACTUAL PROVIDER NAMESPACE: ◀─────────────┘
134+
│ affiliation (label) │ ┌────────────────────────────────────────────┐
135+
└─────────────────────────────┘ │ Namespace: kube-bind-<consumer-id>-wild- │
136+
▲ │ west │
137+
│ Status updates │ │
138+
└────────────────────────────────│ Cowboy: billy-the-kid (namespaced) │
139+
│ - Secret: colt-45-permit │
140+
│ - Secret: cowboy-gang-affiliation │
141+
│ │
142+
│ RBAC (for secret access): │
143+
│ - Role: kube-binder-export-wild-west- │
144+
│ cowboys (in this namespace) │
145+
│ - RoleBinding: ... (in this namespace) │
146+
└────────────────────────────────────────────┘
147+
```
148+
149+
### InformerScope Variations
150+
151+
Namespaced resources support two informer scope configurations:
152+
153+
#### 1. NamespacedScope (nn)
154+
155+
```
156+
┌────────────────────────────────────────────────────────────────────┐
157+
│ [nn] Namespaced → Namespaced (informerScope=NamespacedScope): │
158+
│ - Consumer: Cowboy in namespace wild-west │
159+
│ - Provider: Cowboy in namespace kube-bind-<id>-wild-west │
160+
│ - Konnector watches only its own namespace on provider side │
161+
│ - Natural isolation via namespaces │
162+
└────────────────────────────────────────────────────────────────────┘
163+
```
164+
165+
**How it works:**
166+
- Consumer resource is namespaced: `wild-west/billy-the-kid`
167+
- Provider resource is namespaced: `kube-bind-<consumer-id>-wild-west/billy-the-kid`
168+
- Konnector watches **only its own namespace** on the provider side
169+
- RBAC uses namespace-scoped Roles and RoleBindings
170+
171+
**Use case:** Most efficient for namespaced resources, minimizes RBAC and watch scope.
172+
173+
#### 2. ClusterScope (nc)
174+
175+
```
176+
┌────────────────────────────────────────────────────────────────────┐
177+
│ [nc] Namespaced → Cluster (informerScope=ClusterScope): │
178+
│ - Consumer: Cowboy in namespace wild-west │
179+
│ - Provider: Cowboy in namespace kube-bind-<id>-wild-west │
180+
│ - Konnector watches cluster-wide on provider side │
181+
│ - Still isolated via namespaces, but different RBAC model │
182+
└────────────────────────────────────────────────────────────────────┘
183+
```
184+
185+
**How it works:**
186+
- Consumer resource is namespaced: `wild-west/billy-the-kid`
187+
- Provider resource is namespaced: `kube-bind-<consumer-id>-wild-west/billy-the-kid`
188+
- Konnector watches **cluster-wide** on the provider side
189+
- RBAC uses ClusterRoles and ClusterRoleBindings
190+
191+
**Use case:** When you need cluster-wide visibility or have specific RBAC requirements.
192+
193+
### Key Insights for Namespaced Resources
194+
195+
Namespaced resources **ALWAYS** use the ServiceNamespaced isolation strategy:
196+
197+
- The `isolation` parameter **only applies to cluster-scoped resources**
198+
- Each consumer gets its own provider namespace via APIServiceNamespace mapping
199+
- Namespace mapping is always: `wild-west``kube-bind-<consumer-id>-wild-west`
200+
- The `informerScope` parameter only affects whether the konnector watches at namespace or cluster level
201+
- Secrets are always isolated per consumer
202+
203+
## Complete Test Lifecycle
204+
205+
The end-to-end test validates the complete binding and synchronization flow:
206+
207+
### Setup Phase
208+
209+
1. **Create provider workspace (KCP)**
210+
- Install kube-bind CRDs
211+
- Start backend server (HTTP API for binding)
212+
- Bootstrap example CRDs (Cowboys/Sheriffs)
213+
- Apply templates (template-cowboys.yaml / template-sheriffs.yaml)
214+
215+
2. **Create consumer workspaces**
216+
- Start konnector on each consumer (watches APIServiceBinding)
217+
218+
### Binding Phase
219+
220+
3. **Login to provider**
221+
- Simulate browser auth flow
222+
- Save credentials to kube-bind-config.yaml
223+
224+
4. **List templates & collections**
225+
- Verify backend returns templates
226+
- Verify collections exist
227+
228+
5. **Bind API**
229+
- Send BindableResourcesRequest with templateRef and clusterIdentity
230+
- Backend creates on provider:
231+
- Contract namespace: `kube-bind-<consumer-id-hash>`
232+
- APIServiceExportRequest
233+
- APIServiceNamespace: `wild-west``kube-bind-<id>-wild-west`
234+
- RBAC resources for secret access
235+
- Backend returns BindingResourceResponse with CRDs, RBAC manifests
236+
237+
6. **Apply binding on consumer**
238+
- Create APIServiceBinding (watched by konnector)
239+
- Apply CRDs
240+
- Wait for CRD to be established
241+
242+
### Synchronization & Verification Phase
243+
244+
7. **Create instance on consumer**
245+
- Create resource (Cowboy or Sheriff) in namespace `wild-west`
246+
- Create associated secrets
247+
248+
8. **Verify sync to provider**
249+
- Instance created on provider with ClusterNamespaceAnnotation
250+
- Extract providerContractNamespace and providerObjectNamespace
251+
252+
9. **Verify namespace pre-seeding & RBAC**
253+
- APIServiceNamespace created with status.namespace populated
254+
- Actual provider namespace exists
255+
- RBAC resources created (ClusterRole/Role + Bindings)
256+
257+
10. **Test bi-directional sync**
258+
- Update spec on consumer → synced to provider
259+
- Update status on provider → synced to consumer
260+
261+
11. **Verify secret sync**
262+
- Referenced secret (spec.secretRefs) synced to provider namespace
263+
- Label-selected secret synced
264+
265+
12. **Test deletion**
266+
- Delete on consumer → deleted on provider
267+
268+
### Multi-Consumer Isolation Verification
269+
270+
Running with 2 consumers validates:
271+
- Each consumer gets isolated contract namespace
272+
- Each consumer gets isolated provider namespace (except with IsolationNone)
273+
- Secrets are properly isolated (except with IsolationNone)
274+
- For cluster-scoped resources with IsolationNone, last-write-wins
275+
- For cluster-scoped resources with IsolationPrefixed, resources are name-prefixed
276+
- For cluster-scoped resources with IsolationNamespaced, provider CRD is toggled to NamespaceScoped
277+
278+
## Implementation Details
279+
280+
### Code Structure
281+
282+
- **Isolation strategies**: `pkg/konnector/controllers/cluster/serviceexport/isolation/`
283+
- `none.go`: No isolation, same names/namespaces on both sides
284+
- `prefixed.go`: Prefix resource names with consumer ID
285+
- `namespaced.go`: Convert cluster-scoped to namespaced
286+
- `servicenamespaced.go`: APIServiceNamespace-based mapping for namespaced resources
287+
288+
- **Controller logic**: `pkg/konnector/controllers/cluster/serviceexport/serviceexport_reconcile.go`
289+
- Determines which isolation strategy to use based on resource scope and configuration
290+
- Lines 247-284: Strategy selection logic
291+
292+
### Strategy Selection Logic
293+
294+
```go
295+
switch {
296+
case schema.Spec.Scope == apiextensionsv1.NamespaceScoped:
297+
// ALWAYS use ServiceNamespaced for namespaced resources
298+
isolationStrategy = isolation.NewServiceNamespaced(...)
299+
300+
case export.Spec.Isolation == kubebindv1alpha2.IsolationNone:
301+
isolationStrategy = isolation.NewNone(...)
302+
303+
case export.Spec.Isolation == kubebindv1alpha2.IsolationPrefixed:
304+
isolationStrategy = isolation.NewPrefixed(...)
305+
306+
case export.Spec.Isolation == kubebindv1alpha2.IsolationNamespaced:
307+
isolationStrategy = isolation.NewNamespaced(...)
308+
}
309+
```
310+
311+
## References
312+
313+
- Test implementation: `test/e2e/bind/happy-case_test.go`
314+
- API types: `sdk/apis/kubebind/v1alpha2/apiserviceexport_types.go`
315+
- Isolation strategies: `pkg/konnector/controllers/cluster/serviceexport/isolation/`

0 commit comments

Comments
 (0)