Skip to content

ConfigBundleOperator can be deployed as a Kubernetes workload together with the RBAC resources and custom resource definition required for it to operate.

The deployment consists of several Kubernetes resources that work together:

flowchart LR
    CRD["CustomResourceDefinition<br/>ConfigBundle"]

    CR["ClusterRole<br/>cluster-wide permissions"]
    CRB["ClusterRoleBinding"]

    SA["ServiceAccount<br/>configbundleopeartor-service-account"]

    R["Role<br/>namespace-scoped permissions"]
    RB["RoleBinding"]

    D["Deployment<br/>configbundleoperator"]
    P["Pod"]
    C["Operator Container"]

    CRD -->|"defines"| CB["ConfigBundle"]

    CRB -->|"binds"| CR
    CRB -->|"to"| SA

    RB -->|"binds"| R
    RB -->|"to"| SA

    D -->|"creates"| P
    P -->|"uses"| SA
    P -->|"runs"| C

    C -->|"watches / reconciles"| CB

The resources can be grouped into four logical parts:

Component Purpose
CustomResourceDefinition Defines the ConfigBundle API
ServiceAccount Provides an identity for the operator
RBAC resources Define and grant the operator's permissions
Deployment Runs the operator

Custom Resource Definition

The ConfigBundle CRD introduces a Kubernetes-native API for the operator.

flowchart LR
    A["CustomResourceDefinition"]
    B["ConfigBundle API"]
    C["ConfigBundle Resources"]

    A -->|"defines"| B
    B -->|"creates"| C

Once the CRD is installed, Kubernetes recognizes resources using the ConfigBundle kind and the operator can watch them through the Kubernetes API.

The operator therefore does not need a separate configuration mechanism. Configuration is represented directly as a Kubernetes resource.

ServiceAccount

The operator runs under a dedicated ServiceAccount:

configbundleopeartor-service-account

The ServiceAccount provides the identity used by the operator when communicating with the Kubernetes API.

flowchart TB
    A["ConfigBundleOperator Pod"]
    B["ServiceAccount"]
    C["Kubernetes API Server"]

    A -->|"uses identity"| B
    B -->|"authenticated requests"| C

The ServiceAccount itself does not define what the operator is allowed to do.

Permissions are provided separately through Kubernetes RBAC.

RBAC

This gives the operator a combination of cluster-wide and namespace-scoped permissions.

flowchart TB
    SA["ServiceAccount<br/>configbundleopeartor-service-account"]

    CR["ClusterRole<br/>cluster-wide permissions"]
    CRB["ClusterRoleBinding"]

    R["Role<br/>namespace: default"]
    RB["RoleBinding"]

    CRB -->|"binds"| CR
    CRB -->|"grants to"| SA

    RB -->|"binds"| R
    RB -->|"grants to"| SA

The important distinction is that a Role is namespaced, while a ClusterRole can provide permissions for cluster-scoped resources and can also be bound for access across namespaces.

ClusterRole

The ClusterRole defines permissions that are required beyond a single namespace.

In this deployment, the cluster-level permissions include access required by the operator and its framework to interact with cluster-scoped Kubernetes resources.

Conceptually:

flowchart LR
    A["ClusterRole"]
    B["Cluster-wide Kubernetes Resources"]
    C["ServiceAccount"]

    A -->|"defines permissions"| B
    A -->|"granted through ClusterRoleBinding"| C

The ClusterRole does not grant permissions by itself.

It only defines them.

The actual authorization relationship is established by the ClusterRoleBinding.

ClusterRoleBinding

The ClusterRoleBinding connects the ClusterRole to the operator's ServiceAccount.

flowchart LR
    A["ClusterRole"]
    B["ClusterRoleBinding"]
    C["ServiceAccount"]

    A --> B
    B --> C

Therefore, when the operator makes an API request using this ServiceAccount, Kubernetes evaluates the permissions granted through the ClusterRoleBinding.

Role

The deployment also contains a namespaced Role.

This Role is associated with the default namespace and provides permissions that are scoped to that namespace.

flowchart LR
    A["Role<br/>namespace: default"]
    B["Namespace-scoped resources"]
    C["RoleBinding"]
    D["ServiceAccount"]

    A -->|"defines permissions for"| B
    A --> C
    C --> D

Unlike the ClusterRole, the Role itself is limited to its namespace.

This is useful when the operator needs permissions for resources inside a specific namespace without making every permission cluster-wide.

RoleBinding

The RoleBinding connects the namespaced Role to the same ServiceAccount used by the operator.

flowchart LR
    A["Role"]
    B["RoleBinding<br/>namespace: default"]
    C["ServiceAccount"]

    A --> B
    B --> C

The effective permission set of the ServiceAccount is therefore composed of the permissions granted through both bindings.

flowchart TB
    CR["ClusterRole"]
    CRB["ClusterRoleBinding"]

    R["Role<br/>default"]
    RB["RoleBinding<br/>default"]

    SA["ServiceAccount"]

    CR --> CRB
    CRB --> SA

    R --> RB
    RB --> SA

    SA --> E["Effective Permissions"]

Deployment

The Deployment is responsible for running the operator itself.

flowchart TB
    D["Deployment<br/>configbundleoperator"]
    P["Pod"]
    C["Operator Container"]
    SA["ServiceAccount"]

    D -->|"manages"| P
    P -->|"runs"| C
    P -->|"uses"| SA

The Deployment provides the desired state for the operator workload. Kubernetes ensures that the requested Pod is running and recreates it when necessary. The Pod then runs the operator container.

Pod Identity

The Pod runs using the dedicated ServiceAccount rather than the default identity.

flowchart LR
    D["Deployment"]
    P["Operator Pod"]
    SA["Operator ServiceAccount"]
    API["Kubernetes API Server"]

    D --> P
    P -->|"serviceAccountName"| SA
    SA -->|"authenticated API requests"| API

This is important because all Kubernetes API operations performed by the operator are evaluated against the permissions granted to this ServiceAccount.

The container therefore does not need separate Kubernetes credentials.

Operator and Kubernetes API

Once the Pod is running, the operator communicates with the Kubernetes API using its ServiceAccount identity.

flowchart LR
    OP["ConfigBundleOperator"]
    SA["ServiceAccount"]
    RBAC["RBAC Authorization"]
    API["Kubernetes API Server"]

    OP -->|"uses"| SA
    SA -->|"request"| RBAC
    RBAC -->|"authorize"| API

The API Server is the central point through which the operator observes and modifies Kubernetes resources.

The operator does not communicate directly with etcd or other Kubernetes control-plane components.

ConfigBundle Reconciliation

After deployment, the operator watches the ConfigBundle resources and reconciles them with their managed ConfigMap resources.

flowchart LR
    CB["ConfigBundle<br/>Desired State"]
    OP["ConfigBundleOperator"]
    CM["ConfigMap<br/>Actual State"]

    CB -->|"observe"| OP
    CM -->|"observe"| OP

    OP -->|"create / update / replace"| CM

    CM -. "drift" .-> OP

The operator therefore behaves as a controller rather than as a one-time deployment script.

Complete Architecture

Putting the deployment resources, RBAC, workload, and managed resources together gives the following architecture:

flowchart TB

    subgraph Definition["API Definition"]
        CRD["CustomResourceDefinition"]
        CB["ConfigBundle"]
        CRD -->|"defines"| CB
    end

    subgraph Identity["Identity"]
        SA["ServiceAccount"]
    end

    subgraph RBAC["RBAC"]
        CR["ClusterRole"]
        CRB["ClusterRoleBinding"]

        R["Role<br/>default"]
        RB["RoleBinding<br/>default"]

        CR --> CRB
        CRB --> SA

        R --> RB
        RB --> SA
    end

    subgraph Workload["Operator Workload"]
        D["Deployment"]
        P["Pod"]
        C["Operator Container"]

        D --> P
        P --> C
        P -->|"uses"| SA
    end

    subgraph Managed["Managed Resources"]
        CM["ConfigMap"]
    end

    C -->|"watch / reconcile"| CB
    C -->|"create / update / replace"| CM

    CB -->|"desired state"| C
    CM -->|"actual state"| C

Complete Request Flow

The complete interaction can be summarized as:

sequenceDiagram
    participant User
    participant API as Kubernetes API Server
    participant Operator as ConfigBundleOperator
    participant RBAC as RBAC
    participant CM as ConfigMap

    User->>API: Create ConfigBundle

    Operator->>API: Watch / read ConfigBundle
    API-->>Operator: ConfigBundle

    Operator->>RBAC: API request using ServiceAccount
    RBAC-->>Operator: Authorized

    Operator->>API: Read ConfigMap
    API-->>Operator: Current state

    Operator->>Operator: Compare desired and actual state

    alt ConfigMap does not exist
        Operator->>API: Create ConfigMap
        API-->>CM: ConfigMap created
    else Configuration differs
        Operator->>API: Update / replace ConfigMap
        API-->>CM: ConfigMap updated
    else Configuration matches
        Operator->>Operator: No action
    end

    API-->>Operator: Resource changes / events
    Operator->>Operator: Reconcile again

Resource Relationships

The deployment can ultimately be understood through three separate relationships.

1. Workload relationship

flowchart LR
    D["Deployment"]
    P["Pod"]
    C["Container"]

    D --> P
    P --> C

The Deployment keeps the operator workload running.

2. Authorization relationship

flowchart LR
    CR["ClusterRole"]
    CRB["ClusterRoleBinding"]
    R["Role"]
    RB["RoleBinding"]
    SA["ServiceAccount"]

    CR --> CRB
    CRB --> SA

    R --> RB
    RB --> SA

The RBAC resources determine what the operator is allowed to do.

3. Reconciliation relationship

flowchart LR
    CB["ConfigBundle<br/>Desired State"]
    OP["Operator"]
    CM["ConfigMap<br/>Actual State"]

    CB --> OP
    CM --> OP
    OP --> CM

    CM -. "Drift" .-> OP

The operator uses its identity and permissions to maintain the managed resources.

Deployment Lifecycle

The resources themselves are established in a logical order:

flowchart TD
    A["Install CRD"]
    B["Create ServiceAccount"]
    C["Create RBAC Resources"]
    D["Create Deployment"]
    E["Pod Starts"]
    F["Operator Connects to Kubernetes API"]
    G["Operator Watches ConfigBundles"]
    H["Reconciliation Begins"]

    A --> B
    B --> C
    C --> D
    D --> E
    E --> F
    F --> G
    G --> H

Once the operator reaches the reconciliation stage, the Deployment's role is mainly to keep the operator process running.

The ongoing management of ConfigBundle and ConfigMap resources is performed by the operator itself.

Summary

The deployment is built around a simple separation of concerns:

flowchart TB
    A["CRD"]
    B["Identity"]
    C["Authorization"]
    D["Workload"]
    E["Reconciliation"]

    A -->|"defines API"| E
    B -->|"identifies"| D
    C -->|"authorizes"| B
    D -->|"runs"| E
  • The CRD defines the ConfigBundle API.
  • The ServiceAccount provides the operator's Kubernetes identity.
  • The Role and ClusterRole define permissions.
  • The RoleBinding and ClusterRoleBinding grant those permissions to the ServiceAccount.
  • The Deployment runs the operator.
  • The operator watches ConfigBundle resources and reconciles their corresponding ConfigMap resources.

Together, these resources form the complete Kubernetes deployment required to run ConfigBundleOperator.