Skip to main content

External Secrets Operator Integration

Arcan provides an ESO-compatible webhook endpoint that lets the External Secrets Operator sync secrets from Arcan into Kubernetes Secrets automatically.

Why Webhook Provider?

ESO supports many providers natively (AWS SM, Vault, GCP SM), but Arcan uses the webhook provider -- a generic HTTP-based backend. This means:

  • No custom ESO controller or CRD required
  • Works with any ESO installation out of the box
  • Arcan controls the API contract (/api/v1/eso/...)

Prerequisites

  1. External Secrets Operator installed in your cluster (install guide)
  2. Arcan server running and reachable from the cluster (e.g., https://arcan.internal:9797)
  3. Arcan API token created:
    arcan token create --realm=production --name="eso-operator" --policy=read-only

Quick Start

Step 1: Create the token Secret

kubectl create secret generic arcan-credentials \
--namespace=default \
--from-literal=token=arc_YOUR_API_TOKEN

Step 2: Trust Arcan's TLS certificate

If Arcan uses a self-signed or private CA certificate:

kubectl create configmap arcan-ca \
--namespace=default \
--from-file=ca.crt=/path/to/arcan-ca.crt

Skip this if Arcan uses a publicly trusted certificate (and remove the caProvider block from the manifests).

Step 3: Generate and apply manifests

arcan generate eso --realm=production --env=prod --namespace=default | kubectl apply -f -

Or use the static manifests in deploy/kubernetes/eso/ after replacing the REPLACE_ME placeholders:

kubectl apply -f deploy/kubernetes/eso/arcan-token-secret.yaml
kubectl apply -f deploy/kubernetes/eso/secret-store.yaml
kubectl apply -f deploy/kubernetes/eso/external-secret.yaml

API Endpoints

EndpointMethodResponseUse Case
/api/v1/eso/{realm}/{key}?env=prodGET{"value": "secret-value"}Single secret
/api/v1/eso/{realm}?env=prodGET{"data": {"KEY1": "val1", ...}}All secrets in realm

Both endpoints require Authorization: Bearer arc_... header.

Bulk Secrets

To sync all secrets from a realm at once, use the bulk endpoint with a separate SecretStore:

kubectl apply -f deploy/kubernetes/eso/external-secret-bulk.yaml

The bulk SecretStore points to /api/v1/eso/{realm}?env={env} (no key in the path) and uses $.data as the jsonPath to extract all key-value pairs.

ClusterSecretStore

For cross-namespace access, use a ClusterSecretStore:

arcan generate eso --realm=production --env=prod --cluster-wide | kubectl apply -f -

Or apply the static manifest:

kubectl apply -f deploy/kubernetes/eso/cluster-secret-store.yaml

With a ClusterSecretStore, ExternalSecrets in any namespace can reference kind: ClusterSecretStore in their secretStoreRef. The token Secret and CA ConfigMap must exist in the ESO controller namespace (typically external-secrets).

TLS Trust

Arcan requires TLS in all deployment modes. If using a self-signed certificate (the default for standalone mode), ESO needs to trust Arcan's CA.

The caProvider block in the SecretStore tells ESO where to find the CA:

caProvider:
type: ConfigMap
name: arcan-ca
key: ca.crt

To extract Arcan's CA certificate:

# From the Arcan data directory
cp /var/lib/arcan/tls/ca.crt ./arcan-ca.crt

# Or fetch it from a running server
openssl s_client -connect arcan.internal:9797 -showcerts </dev/null 2>/dev/null \
| openssl x509 -outform PEM > arcan-ca.crt

Refresh Intervals

The refreshInterval on an ExternalSecret controls how often ESO polls Arcan:

IntervalPropagation delayAPI load
15mUp to 15 minutesLow
1h (default)Up to 1 hourVery low
5mUp to 5 minutesModerate
1mUp to 1 minuteHigh

Choose based on how quickly secret changes need to propagate. For most workloads, 1h is sufficient.

Troubleshooting

ExternalSecret stuck in "SecretSyncedError"

Check the ESO controller logs:

kubectl logs -n external-secrets deploy/external-secrets -f

Common causes:

  • Connection refused: Arcan not reachable. Verify the URL and that the Arcan service exists in the cluster.
  • TLS handshake failure: CA certificate not trusted. Ensure the arcan-ca ConfigMap exists and contains the correct certificate.
  • 401 Unauthorized: Invalid or expired token. Verify the token in the arcan-credentials Secret.
  • 404 Not Found: Wrong realm slug or key name. Check the realm exists with arcan realm list.

Verify connectivity from the cluster

kubectl run arcan-test --rm -it --image=curlimages/curl -- \
curl -sk -H "Authorization: Bearer arc_YOUR_TOKEN" \
https://arcan.internal:9797/api/v1/eso/production/DATABASE_URL?env=prod

Check SecretStore status

kubectl get secretstore arcan -o yaml
kubectl describe secretstore arcan

A healthy SecretStore shows status.conditions with type: Ready and status: "True".

Check ExternalSecret sync status

kubectl get externalsecret my-app-secrets -o yaml
kubectl describe externalsecret my-app-secrets

Look at status.conditions and status.syncedResourceVersion to confirm secrets are syncing.