Skip to content

Commit c371133

Browse files
committed
Reorganize SubjectMapping design to separate architecture from implementation
Eliminate duplication between "Architecture and Components" and "Implementation Details" sections by clearly separating concerns: - Architecture section: lightweight overview of WHAT components exist and WHERE they are located (controller, authentication module, repository structure) - Implementation Details: comprehensive HOW covering ManagedServiceAccount creation, lifecycle management, cluster discovery, binding/unbinding, authentication flow, and token caching Removed duplicate Cluster Discovery section that appeared in both sections. This improves readability and follows standard OCM enhancement proposal patterns. Signed-off-by: zhujian <jiazhu@redhat.com>
1 parent 5ad09f7 commit c371133

1 file changed

Lines changed: 132 additions & 143 deletions

File tree

  • enhancements/sig-architecture/233-subject-mapping

enhancements/sig-architecture/233-subject-mapping/README.md

Lines changed: 132 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -253,30 +253,64 @@ See [API Specification](#api-specification) section below for complete type defi
253253

254254
### Architecture and Components
255255

256-
#### Component Overview
257-
258256
The SubjectMapping feature will be implemented in the **cluster-proxy** repository as it is fundamentally a transparent authentication feature built on top of cluster-proxy's existing proxy infrastructure.
259257

260258
**Implementation Location**: `open-cluster-management.io/cluster-proxy`
261259

262-
**1. SubjectMapping Controller (Hub-side)**
260+
#### 1. SubjectMapping Controller (Hub-side)
263261

264262
**Location**: `pkg/proxyserver/controllers/subjectmapping_controller.go`
265263

266264
**Deployment**: Runs in the cluster-proxy addon-manager on the hub cluster
267265

268-
Responsibilities:
266+
**Responsibilities**:
269267
- Watch SubjectMapping CRs and referenced Placements/PlacementDecisions
270-
- Discover target clusters based on subject type:
271-
- **ServiceAccount**: Via ManagedClusterSetBinding in the ServiceAccount's namespace
272-
- **User**: Via referenced Placement's PlacementDecisions
273-
- Create and maintain ManagedServiceAccount resources for each bound cluster with annotation to disable token sync
274-
- Update status conditions (Ready, PartiallyReady, Failed)
275-
- Handle cluster binding/unbinding events (ManagedClusterSetBinding changes or PlacementDecision updates)
268+
- Discover target clusters based on subject type (ServiceAccount or User)
269+
- Create and maintain ManagedServiceAccount resources for each bound cluster
270+
- Update SubjectMapping status conditions (Ready, PartiallyReady, Failed)
271+
- Handle cluster binding/unbinding lifecycle
276272

277-
**ManagedServiceAccount Creation**:
273+
#### 2. Authentication Module (Spoke-side)
274+
275+
**Location**: `pkg/proxyagent/authentication/`
276+
277+
**Deployment**: Runs in the proxy-agent on each managed cluster
278+
279+
**Responsibilities**:
280+
- Watch SubjectMapping CRs on the hub via informer
281+
- Intercept requests from mapped hub subjects
282+
- Validate hub tokens via TokenReview API
283+
- Resolve hub subjects to managed cluster ServiceAccount names
284+
- Generate tokens via local TokenRequest API
285+
- Cache tokens for performance optimization
286+
- Inject tokens into request Authorization headers
287+
288+
#### Repository Structure
289+
290+
```
291+
cluster-proxy/
292+
├── pkg/
293+
│ ├── apis/
294+
│ │ └── authentication/v1alpha1/ # NEW: SubjectMapping API
295+
│ │ ├── subjectmapping_types.go
296+
│ │ ├── groupversion_info.go
297+
│ │ └── zz_generated.deepcopy.go
298+
│ ├── proxyserver/controllers/
299+
│ │ └── subjectmapping_controller.go # NEW: SubjectMapping controller
300+
│ └── proxyagent/authentication/ # NEW: Authentication module
301+
│ ├── resolver.go # Subject → ServiceAccount mapping
302+
│ ├── cache.go # Token caching
303+
│ └── tokenrequest.go # TokenRequest API client
304+
└── cmd/
305+
├── addon-manager/main.go # Register SubjectMapping controller
306+
└── addon-agent/main.go # Integrate authentication module
307+
```
308+
309+
### Implementation Details
278310
279-
SubjectMapping controller creates ManagedServiceAccount resources with a special annotation to prevent token synchronization to the hub:
311+
#### ManagedServiceAccount Creation
312+
313+
The SubjectMapping controller creates ManagedServiceAccount resources with a special annotation to prevent token synchronization to the hub:
280314
281315
```go
282316
const (
@@ -319,82 +353,114 @@ The managed-serviceaccount addon agent honors this annotation:
319353
- **Missing annotation or `"secret"`**: Sync token to hub as Secret (default, backward compatible)
320354
- **`"none"`**: Create ServiceAccount on managed cluster only, don't sync token to hub
321355

322-
**Lifecycle Management**:
323-
324-
Since SubjectMapping is cluster-scoped and ManagedServiceAccount is namespaced (in cluster namespaces), owner references cannot be used. The controller uses:
325-
326-
- **Finalizers** on SubjectMapping to ensure cleanup of all associated ManagedServiceAccounts before deletion
327-
- **Labels** on ManagedServiceAccounts (see example above) to track which SubjectMapping created them
328-
- On SubjectMapping deletion, the controller deletes all ManagedServiceAccounts with matching labels across all cluster namespaces
329-
330356
This approach:
331357

332358
- Requires **no ManagedServiceAccount API changes**
333359
- Is **fully backward compatible** (existing ManagedServiceAccounts continue working)
334360
- Eliminates token storage on hub for SubjectMapping use case
335361
- Allows managed-serviceaccount addon to support both use cases simultaneously
336-
- Follows OCM patterns (consistent with ManifestWork, Placement, etc.)
337362

338-
**Cluster Binding/Unbinding**:
363+
#### Lifecycle Management
339364

340-
The controller continuously reconciles cluster membership via watches on ManagedClusterSetBinding, ManagedCluster labels, and PlacementDecision:
365+
Since SubjectMapping is cluster-scoped and ManagedServiceAccount is namespaced (in cluster namespaces), owner references cannot be used. The controller uses:
341366

342-
- **Cluster Added**: Creates ManagedServiceAccount in new cluster's namespace, updates status
343-
- **Cluster Removed**: Deletes corresponding ManagedServiceAccount, updates status
344-
- **Cleanup**: Orphaned resources removed during reconciliation
367+
- **Finalizers** on SubjectMapping to ensure cleanup of all associated ManagedServiceAccounts before deletion
368+
- **Labels** on ManagedServiceAccounts (see code example above) to track which SubjectMapping created them
369+
- On SubjectMapping deletion, the controller deletes all ManagedServiceAccounts with matching labels across all cluster namespaces
345370

346-
**2. Authentication Module (Spoke-side)**
371+
This approach follows OCM patterns (consistent with ManifestWork, Placement, etc.).
347372

348-
**Location**: `pkg/proxyagent/authentication/`
373+
#### Cluster Discovery
349374

350-
**Deployment**: Runs in the proxy-agent on each managed cluster
375+
The controller determines which clusters should receive the mapped service account based on subject type:
351376

352-
The proxy-agent component will be enhanced with an authentication module to:
377+
**For ServiceAccount Subjects:**
353378

354-
- Watch SubjectMapping CRs on the hub (via informer) for create/update/delete events
355-
- On update: Invalidate cached tokens if spec fields affecting token generation changed
356-
- On delete: Invalidate all cached tokens for the subject
357-
- Intercept requests from mapped hub subjects
358-
- Extract subject information from request authentication:
359-
- **ServiceAccount**: Extract from `system:serviceaccount:<namespace>:<name>` user
360-
- **User**: Extract from user identity (e.g., `admin@example.com`)
361-
- Resolve hub subject to managed cluster service account names via SubjectMapping lookup
362-
- Request tokens from the local TokenRequest API
363-
- Cache tokens for performance (keyed by hub subject + managed SA name)
364-
- Automatic invalidation on time expiration and SubjectMapping changes
365-
- Inject tokens transparently into Authorization headers
366-
- Forward authenticated requests to the managed cluster API server
367-
368-
**Repository Structure**:
379+
Uses ManagedClusterSetBinding in the ServiceAccount's namespace:
380+
381+
1. List all ManagedClusterSetBindings in the ServiceAccount's namespace
382+
2. Extract ManagedClusterSet names from bindings
383+
3. List all ManagedClusters with matching `cluster.open-cluster-management.io/clusterset` labels
384+
4. Create/update ManagedServiceAccount for each discovered cluster
385+
386+
Example:
387+
388+
```yaml
389+
# In argocd namespace
390+
apiVersion: cluster.open-cluster-management.io/v1beta2
391+
kind: ManagedClusterSetBinding
392+
metadata:
393+
name: production-clusters
394+
namespace: argocd
395+
spec:
396+
clusterSet: production
397+
---
398+
# SubjectMapping will create ManagedServiceAccounts
399+
# for all clusters in the "production" clusterset
369400
```
370-
cluster-proxy/
371-
├── pkg/
372-
│ ├── apis/
373-
│ │ └── authentication/v1alpha1/ # NEW: SubjectMapping API
374-
│ │ ├── subjectmapping_types.go
375-
│ │ ├── groupversion_info.go
376-
│ │ └── zz_generated.deepcopy.go
377-
│ ├── proxyserver/controllers/
378-
│ │ └── subjectmapping_controller.go # NEW: SubjectMapping controller
379-
│ └── proxyagent/authentication/ # NEW: Authentication module
380-
│ ├── resolver.go # Subject → ServiceAccount mapping
381-
│ ├── cache.go # Token caching
382-
│ └── tokenrequest.go # TokenRequest API client
383-
└── cmd/
384-
├── addon-manager/main.go # Register SubjectMapping controller
385-
└── addon-agent/main.go # Integrate authentication module
401+
402+
**For User Subjects:**
403+
404+
Uses Placement API for cluster selection:
405+
406+
```yaml
407+
apiVersion: authentication.open-cluster-management.io/v1alpha1
408+
kind: SubjectMapping
409+
metadata:
410+
name: admin-user-access
411+
spec:
412+
hubSubject:
413+
kind: User
414+
user:
415+
name: "admin@example.com"
416+
417+
managedServiceAccount:
418+
name: hub-admin-user
419+
420+
# Reference a Placement resource
421+
placementRef:
422+
name: admin-clusters
423+
---
424+
apiVersion: cluster.open-cluster-management.io/v1beta1
425+
kind: Placement
426+
metadata:
427+
name: admin-clusters
428+
spec:
429+
clusterSets:
430+
- production
431+
- staging
432+
predicates:
433+
- requiredClusterSelector:
434+
labelSelector:
435+
matchExpressions:
436+
- key: environment
437+
operator: In
438+
values: [production, staging]
386439
```
387440
388-
### Implementation Details
441+
The SubjectMapping controller:
442+
443+
1. Watches the referenced Placement resource
444+
2. Reads PlacementDecisions created by the Placement controller
445+
3. Extracts the list of selected clusters from PlacementDecisions
446+
4. Creates/updates ManagedServiceAccount for each selected cluster
447+
448+
This approach leverages OCM's existing Placement API capabilities (sophisticated cluster selection, dynamic updates, consistency with Policy and ManifestWork).
449+
450+
#### Cluster Binding/Unbinding
451+
452+
The controller continuously reconciles cluster membership via watches on ManagedClusterSetBinding, ManagedCluster labels, and PlacementDecision:
453+
454+
- **Cluster Added**: Creates ManagedServiceAccount in new cluster's namespace, updates status
455+
- **Cluster Removed**: Deletes corresponding ManagedServiceAccount, updates status
456+
- **Cleanup**: Orphaned resources removed during reconciliation
389457
390458
#### Authentication Flow
391459
392460
1. **Setup Phase:**
393461
- Admin creates SubjectMapping on the hub
394462
- For User subjects: Admin also creates a Placement resource (or references existing one)
395-
- Controller discovers bound clusters:
396-
- ServiceAccount: via ManagedClusterSetBinding in the ServiceAccount's namespace
397-
- User: via Placement's PlacementDecisions
463+
- Controller discovers bound clusters via cluster discovery mechanism
398464
- ManagedServiceAccount resources are automatically created for each cluster
399465
400466
2. **Request Phase:**
@@ -467,90 +533,13 @@ To optimize performance and reduce API server load:
467533
- **Detection mechanism**: proxy-agent runs informer watching SubjectMapping resources on the hub cluster
468534

469535
This distributed caching approach:
536+
470537
- Scales horizontally (each spoke caches independently)
471538
- Reduces managed cluster API server load
472539
- Maintains security through short-lived tokens
473540
- Provides fast request handling after initial token generation
474541
- Supports multiple subject types transparently
475542

476-
#### Cluster Discovery
477-
478-
The controller determines which clusters should receive the mapped service account based on subject type:
479-
480-
**For ServiceAccount Subjects:**
481-
482-
Uses ManagedClusterSetBinding in the ServiceAccount's namespace:
483-
484-
1. List all ManagedClusterSetBindings in the ServiceAccount's namespace
485-
2. Extract ManagedClusterSet names from bindings
486-
3. List all ManagedClusters with matching `cluster.open-cluster-management.io/clusterset` labels
487-
4. Create/update ManagedServiceAccount for each discovered cluster
488-
489-
Example:
490-
```yaml
491-
# In argocd namespace
492-
apiVersion: cluster.open-cluster-management.io/v1beta2
493-
kind: ManagedClusterSetBinding
494-
metadata:
495-
name: production-clusters
496-
namespace: argocd
497-
spec:
498-
clusterSet: production
499-
---
500-
# SubjectMapping will create ManagedServiceAccounts
501-
# for all clusters in the "production" clusterset
502-
```
503-
504-
**For User Subjects:**
505-
506-
Uses Placement API for cluster selection:
507-
508-
```yaml
509-
apiVersion: authentication.open-cluster-management.io/v1alpha1
510-
kind: SubjectMapping
511-
metadata:
512-
name: admin-user-access
513-
spec:
514-
hubSubject:
515-
kind: User
516-
user:
517-
name: "admin@example.com"
518-
519-
managedServiceAccount:
520-
name: hub-admin-user
521-
522-
# Reference a Placement resource
523-
placementRef:
524-
name: admin-clusters
525-
---
526-
apiVersion: cluster.open-cluster-management.io/v1beta1
527-
kind: Placement
528-
metadata:
529-
name: admin-clusters
530-
spec:
531-
clusterSets:
532-
- production
533-
- staging
534-
predicates:
535-
- requiredClusterSelector:
536-
labelSelector:
537-
matchExpressions:
538-
- key: environment
539-
operator: In
540-
values: [production, staging]
541-
```
542-
543-
The SubjectMapping controller:
544-
1. Watches the referenced Placement resource
545-
2. Reads PlacementDecisions created by the Placement controller
546-
3. Extracts the list of selected clusters from PlacementDecisions
547-
4. Creates/updates ManagedServiceAccount for each selected cluster
548-
549-
This approach leverages OCM's existing Placement API capabilities:
550-
- Sophisticated cluster selection with predicates and priorities
551-
- Dynamic cluster selection as PlacementDecisions update
552-
- Consistent with Policy, ManifestWork, and other OCM resources
553-
554543
### Risks and Mitigation
555544

556545
| Risk | Impact | Mitigation |

0 commit comments

Comments
 (0)