ArgoCD Configuration

After installing the ArgoPlane Helm chart, you need to configure ArgoCD to route extension requests, mount custom styles, and load UI bundles. The chart deploys backends and generates ConfigMaps with all the config you need. This page walks through wiring it up.

How ArgoCD extensions work

ArgoCD extensions have three layers:

  1. UI bundle (JavaScript): registers tabs, panels, or pages via window.extensionsAPI. ArgoCD loads any file matching extension*.js from /tmp/extensions/ inside the argocd-server pod.
  2. Proxy routing (argocd-cm): maps /extensions/<name>/* requests to a backend service URL.
  3. RBAC (argocd-rbac-cm): grants roles permission to invoke specific extensions.

The Helm chart handles layer 2 and 3 via ConfigMaps. Layer 1 (UI bundles) needs an init container or sidecar on argocd-server.

Step 1: Enable proxy extensions

Tell ArgoCD to enable the proxy extension mechanism:

kubectl -n argocd patch cm argocd-cmd-params-cm --type merge 
  -p '{"data":{"server.enable.proxy.extension":"true"}}'

Step 2: Add proxy routing

The chart generates argoplane-proxy-config with the correct routing entries. Merge them into argocd-cm:

kubectl -n argocd patch cm argocd-cm --type merge -p '{
  "data": {
    "extension.config.metrics": "services:\n- url: http://argoplane-metrics-backend.argocd.svc:8080\n",
    "extension.config.backups": "services:\n- url: http://argoplane-backups-backend.argocd.svc:8081\n",
    "extension.config.networking": "services:\n- url: http://argoplane-networking-backend.argocd.svc:8082\n",
    "extension.config.logs": "services:\n- url: http://argoplane-logs-backend.argocd.svc:8083\n",
    "extension.config.vulnerabilities": "services:\n- url: http://argoplane-vulnerabilities-backend.argocd.svc:8084\n",
    "extension.config.events": "services:\n- url: http://argoplane-events-backend.argocd.svc:8085\n"
  }
}'

Each entry routes /extensions/<name>/* to the corresponding backend service. ArgoCD validates the user’s auth token before proxying.

Step 3: Configure RBAC

ArgoCD v3 requires explicit RBAC for extensions. The chart generates argoplane-rbac-config with policies. View them:

kubectl -n argocd get cm argoplane-rbac-config 
  -o jsonpath='{.data.argoplane-policy.csv}'

Add the output to your argocd-rbac-cm ConfigMap’s policy.csv field:

p, role:admin, extensions, invoke, metrics, allow
p, role:admin, extensions, invoke, backups, allow
p, role:admin, extensions, invoke, networking, allow
p, role:admin, extensions, invoke, logs, allow
p, role:admin, extensions, invoke, vulnerabilities, allow
p, role:admin, extensions, invoke, events, allow

p, role:developer, extensions, invoke, metrics, allow
p, role:developer, extensions, invoke, backups, allow
p, role:developer, extensions, invoke, logs, allow
p, role:developer, extensions, invoke, vulnerabilities, allow
p, role:developer, extensions, invoke, events, allow
Warning
Without explicit RBAC, users will see extension tabs but get 403 errors when loading data. Every role that should use extensions needs an `extensions, invoke` policy.

Step 4: Load UI extension bundles

ArgoCD discovers UI extensions by scanning /tmp/extensions/ for files matching extension*.js. The recommended approach for production is an init container that copies bundles from a ConfigMap or OCI image.

Package your built extension bundles into a ConfigMap, then use an init container to copy them into the shared /tmp/extensions/ volume.

1. Create a ConfigMap from the built bundles:

kubectl -n argocd create configmap argoplane-ui-extensions 
  --from-file=extension-metrics.js=extensions/metrics/ui/dist/extension-metrics.js 
  --from-file=extension-backups.js=extensions/backups/ui/dist/extension-backups.js 
  --from-file=extension-networking.js=extensions/networking/ui/dist/extension-networking.js 
  --dry-run=client -o yaml | kubectl apply --server-side -f -

2. Patch argocd-server with an init container and shared volume:

kubectl -n argocd patch deployment argocd-server --type json -p '[
  {
    "op": "add",
    "path": "/spec/template/spec/volumes/-",
    "value": {
      "name": "argoplane-extensions",
      "configMap": {
        "name": "argoplane-ui-extensions"
      }
    }
  },
  {
    "op": "add",
    "path": "/spec/template/spec/initContainers",
    "value": [{
      "name": "copy-argoplane-extensions",
      "image": "busybox:1.36",
      "command": ["sh", "-c",
        "cp /extensions-src/*.js /tmp/extensions/"
      ],
      "volumeMounts": [
        {
          "name": "argoplane-extensions",
          "mountPath": "/extensions-src",
          "readOnly": true
        },
        {
          "name": "extensions",
          "mountPath": "/tmp/extensions"
        }
      ]
    }]
  }
]'
Note
The init container copies from the ConfigMap mount (read-only) to the `/tmp/extensions` emptyDir volume. ArgoCD's main container reads from the same emptyDir. This survives pod restarts because the ConfigMap is persistent.

Why an init container instead of a direct volume mount? ArgoCD expects files directly in /tmp/extensions/, but ConfigMap volume mounts create a directory structure with symlinks. The init container flattens the files into the expected location. It also allows combining extensions from multiple sources.

Option B: Init container with OCI image

For production, use the pre-built ArgoPlane UI extensions image as an init container. The image contains all UI bundles and a script that selectively copies only the ones you enable.

spec:
  template:
    spec:
      initContainers:
        - name: argoplane-extensions
          image: ghcr.io/natrontech/argoplane-ui-extensions:v0.1.0
          env:
            - name: ENABLED_EXTENSIONS
              value: "metrics,backups,argoplane"
          volumeMounts:
            - name: extensions
              mountPath: /tmp/extensions
      containers:
        - name: argocd-server
          volumeMounts:
            - name: extensions
              mountPath: /tmp/extensions
      volumes:
        - name: extensions
          emptyDir: {}

The ENABLED_EXTENSIONS env var is a comma-separated list of extension names. Only matching UI bundles (extension-<name>.js) are copied to /tmp/extensions/. If you omit the env var entirely, all bundles are copied (backwards compatible).

This approach is cleaner for CI/CD pipelines: build once, tag with version, deploy via image reference.

Loading only enabled UI bundles

When you disable an extension backend via extensions.<name>.enabled: false in the Helm chart, the proxy routing, RBAC, and backend Deployment are all skipped. However, the UI bundle is separate: it lives in the init container image and gets loaded into ArgoCD independently.

Without the ENABLED_EXTENSIONS filter, disabled extensions still show tabs and panels in ArgoCD. They appear broken (empty or error state) because there’s no backend to serve data. To prevent this, set ENABLED_EXTENSIONS on the init container to match your enabled backends.

For example, if you only enable metrics and backups:

extensions:
  metrics:
    enabled: true
  backups:
    enabled: true
  networking:
    enabled: false
  logs:
    enabled: false
  vulnerabilities:
    enabled: false
  events:
    enabled: false

Set the init container env to:

env:
  - name: ENABLED_EXTENSIONS
    value: "metrics,backups,argoplane"

Always include argoplane in the list. It’s the consolidation extension that combines all enabled extension tabs into a single unified “ArgoPlane” tab. If you use branding, also add argoplane-links.

Note
The Helm chart's `helm install` output shows the exact `ENABLED_EXTENSIONS` value to use based on your `values.yaml` configuration.

Option C: kubectl cp (development only)

For local development, copy bundles directly into the running pod:

ARGOCD_POD=$(kubectl -n argocd get pods 
  -l app.kubernetes.io/name=argocd-server 
  -o jsonpath='{.items[0].metadata.name}')

kubectl exec -n argocd $ARGOCD_POD -- mkdir -p /tmp/extensions

for ext in metrics backups networking logs vulnerabilities events; do
  kubectl cp extensions/$ext/ui/dist/extension-$ext.js 
    argocd/$ARGOCD_POD:/tmp/extensions/extension-$ext.js
done
Warning
Files in `/tmp/extensions/` are ephemeral. They are lost when the pod restarts. Use init containers (Option A or B) for anything beyond local development.

Step 5: Custom styles (optional)

The Helm chart can deploy a ConfigMap with the ArgoPlane CSS theme and login wallpaper. Enable it with argocd.styles.enabled=true.

1. Tell ArgoCD where to find the CSS:

kubectl -n argocd patch cm argocd-cm --type merge 
  -p '{"data":{"ui.cssurl":"./custom/argoplane.css"}}'

2. Mount the styles ConfigMap into argocd-server:

kubectl -n argocd patch deployment argocd-server --type json -p '[
  {
    "op": "add",
    "path": "/spec/template/spec/volumes/-",
    "value": {
      "name": "argoplane-styles",
      "configMap": { "name": "argoplane-styles" }
    }
  },
  {
    "op": "add",
    "path": "/spec/template/spec/containers/0/volumeMounts/-",
    "value": {
      "name": "argoplane-styles",
      "mountPath": "/shared/app/custom"
    }
  }
]'

ArgoCD serves files from /shared/app/custom/ at the relative URL ./custom/. The CSS transforms ArgoCD’s UI with ArgoPlane’s pixel-art aesthetic: flat design, warm grays, pastel orange accent.

Step 6: Branding (optional)

Enable argocd.branding.enabled=true to deploy the branding JS extension. Mount it:

kubectl -n argocd patch deployment argocd-server --type json -p '[
  {
    "op": "add",
    "path": "/spec/template/spec/volumes/-",
    "value": {
      "name": "argoplane-branding",
      "configMap": { "name": "argoplane-links" }
    }
  },
  {
    "op": "add",
    "path": "/spec/template/spec/containers/0/volumeMounts/-",
    "value": {
      "name": "argoplane-branding",
      "mountPath": "/tmp/extensions/branding",
      "readOnly": true
    }
  }
]'

Step 7: Restart argocd-server

After all patches:

kubectl -n argocd rollout restart deployment argocd-server
kubectl -n argocd rollout status deployment argocd-server

Complete example: Kustomize overlay

For production, manage all ArgoCD patches as a Kustomize overlay instead of imperative kubectl commands.

Create argocd-patches/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: argocd

patches:
  # Enable proxy extensions
  - target:
      kind: ConfigMap
      name: argocd-cmd-params-cm
    patch: |
      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: argocd-cmd-params-cm
      data:
        server.enable.proxy.extension: "true"

  # Add proxy routing + CSS URL
  - target:
      kind: ConfigMap
      name: argocd-cm
    patch: |
      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: argocd-cm
      data:
        ui.cssurl: "./custom/argoplane.css"
        extension.config.metrics: |
          services:
          - url: http://argoplane-metrics-backend.argocd.svc:8080
        extension.config.backups: |
          services:
          - url: http://argoplane-backups-backend.argocd.svc:8081
        extension.config.networking: |
          services:
          - url: http://argoplane-networking-backend.argocd.svc:8082
        extension.config.logs: |
          services:
          - url: http://argoplane-logs-backend.argocd.svc:8083
        extension.config.vulnerabilities: |
          services:
          - url: http://argoplane-vulnerabilities-backend.argocd.svc:8084
        extension.config.events: |
          services:
          - url: http://argoplane-events-backend.argocd.svc:8085

  # RBAC for extensions
  - target:
      kind: ConfigMap
      name: argocd-rbac-cm
    patch: |
      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: argocd-rbac-cm
      data:
        policy.csv: |
          p, role:admin, extensions, invoke, metrics, allow
          p, role:admin, extensions, invoke, backups, allow
          p, role:admin, extensions, invoke, networking, allow
          p, role:admin, extensions, invoke, logs, allow
          p, role:admin, extensions, invoke, vulnerabilities, allow
          p, role:admin, extensions, invoke, events, allow
          p, role:developer, extensions, invoke, metrics, allow
          p, role:developer, extensions, invoke, backups, allow
          p, role:developer, extensions, invoke, logs, allow
          p, role:developer, extensions, invoke, vulnerabilities, allow
          p, role:developer, extensions, invoke, events, allow
        policy.default: role:admin

  # Patch argocd-server with init container + volume mounts
  - target:
      kind: Deployment
      name: argocd-server
    patch: |
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: argocd-server
      spec:
        template:
          spec:
            initContainers:
              - name: argoplane-extensions
                image: ghcr.io/natrontech/argoplane-ui-extensions:v0.1.0
                env:
                  - name: ENABLED_EXTENSIONS
                    value: "metrics,backups,networking,logs,vulnerabilities,events,argoplane"
                volumeMounts:
                  - name: extensions
                    mountPath: /tmp/extensions
            containers:
              - name: argocd-server
                volumeMounts:
                  - name: argoplane-styles
                    mountPath: /shared/app/custom
                  - name: argoplane-branding
                    mountPath: /tmp/extensions/branding
                    readOnly: true
            volumes:
              - name: argoplane-styles
                configMap:
                  name: argoplane-styles
              - name: argoplane-branding
                configMap:
                  name: argoplane-links
              - name: extensions
                emptyDir: {}

Apply with:

kubectl apply -k argocd-patches/

Complete example: ArgoCD Application (GitOps)

Deploy ArgoPlane and its ArgoCD configuration together as a single ArgoCD Application:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: argoplane
  namespace: argocd
spec:
  project: default
  sources:
    # ArgoPlane Helm chart (backends, ConfigMaps)
    - repoURL: https://github.com/natrontech/argoplane
      path: deploy/helm/argoplane
      targetRevision: main
      helm:
        valueFiles:
          - values-prod.yaml

    # ArgoCD patches (proxy config, RBAC, init containers)
    - repoURL: https://github.com/your-org/platform-config
      path: argocd-patches
      targetRevision: main

  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
Note
Using multiple sources lets you keep the ArgoPlane chart separate from your organization's ArgoCD patches. The chart handles backends. Your config repo handles the ArgoCD integration.

ArgoCD v3 changes

Key changes in ArgoCD v3 that affect extension configuration:

ChangeImpact
Fine-grained RBACupdate/delete on applications no longer cascades to sub-resources. Grant update/* and delete/* explicitly if needed.
Logs RBAC enforcedUsers need explicit logs, get permission.
Extensions require RBACEvery extension needs p, role:<role>, extensions, invoke, <name>, allow.
Annotation-based trackingResource tracking uses annotations by default, not labels.
Health in RedisResource health is stored in Redis, not in Application status.

Troubleshooting