Skip to content

enhance:Operator support referencing external ServiceAccount in WoodpeckerCluster CRD #137

@tinswzy

Description

@tinswzy

Background

The operator currently creates and manages its own ServiceAccount for each WoodpeckerCluster
(reconcile_serviceaccount.go). The SA is created with labels only — no annotations — and is
overwritten on every reconcile cycle.

This makes it impossible to use cloud-provider identity mechanisms such as:

  • AWS EKS IRSA (eks.amazonaws.com/role-arn)
  • GCP GKE Workload Identity (iam.gke.io/gcp-service-account)
  • Azure AKS Workload Identity (azure.workload.identity/client-id)

These mechanisms require specific annotations on the ServiceAccount. Since the operator
overwrites the SA every reconcile, any manually added annotation gets erased.

Use Case

Woodpecker pods need to access object storage (e.g. AWS S3) for data persistence. In EKS
environments, the recommended approach is IRSA — associating an IAM Role with a Kubernetes
ServiceAccount via annotation. The operator must allow users to either:

  1. Reference a pre-existing ServiceAccount (managed outside the operator), or
  2. Pass annotations through to the operator-managed ServiceAccount.

Proposal

Add a new optional field serviceAccountName to WoodpeckerClusterSpec:

spec:                                                                                                                                                                                                                                                                                                                      
  serviceAccountName: woodpecker-admin   # pre-existing SA with IRSA annotation
                                                                                                                                                                                                                                                                                                                           
Behavior:                               
- If serviceAccountName is set: skip SA creation, use the referenced SA in the
StatefulSet, and bind RBAC (node-reader ClusterRole) to it.                                                                                                                                                                                                                                                                
- If serviceAccountName is not set: current behavior (operator creates and manages SA).
                                                                                                                                                                                                                                                                                                                           
Files to Change                                                                                                                                                                                                                                                                                                            
                                        
┌────────────────────────────────────────────────────────┬─────────────────────────────────────────────┐                                                                                                                                                                                                                   
│                          File                          │                   Change                    │                                                                                                                                                                                                                   
├────────────────────────────────────────────────────────┼─────────────────────────────────────────────┤                                                                                                                                                                                                                   
│ api/v1alpha1/woodpeckercluster_types.go                │ Add ServiceAccountName field to spec        │                                                                                                                                                                                                                   
├────────────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ internal/controller/reconcile_serviceaccount.go        │ Skip creation when external SA is specified │
├────────────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ internal/controller/reconcile_statefulset.go           │ Resolve SA name from spec or default        │
├────────────────────────────────────────────────────────┼─────────────────────────────────────────────┤                                                                                                                                                                                                                   
│ internal/controller/reconcile_rbac.go                  │ Bind ClusterRole to the correct SA name     │                                                                                                                                                                                                                   
├────────────────────────────────────────────────────────┼─────────────────────────────────────────────┤                                                                                                                                                                                                                   
│ internal/webhook/v1alpha1/woodpeckercluster_webhook.go │ Validate referenced SA exists (optional)    │                                                                                                                                                                                                                   
└────────────────────────────────────────────────────────┴─────────────────────────────────────────────┘
                                                                                                                                                                                                                                                                                                                           
Run make manifests generate after type changes.
                                                                                                                                                                                                                                                                                                                           
Future Consideration
                                                                                                                                                                                                                                                                                                                           
A complementary serviceAccountAnnotations field could also be added, allowing users to
pass annotations (like IRSA ARN) through to the operator-managed SA without creating an                                                                                                                                                                                                                                    
external one. This can be done as a follow-up.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions