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
- External Secrets Operator installed in your cluster (install guide)
- Arcan server running and reachable from the cluster (e.g.,
https://arcan.internal:9797) - 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
| Endpoint | Method | Response | Use Case |
|---|---|---|---|
/api/v1/eso/{realm}/{key}?env=prod | GET | {"value": "secret-value"} | Single secret |
/api/v1/eso/{realm}?env=prod | GET | {"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:
| Interval | Propagation delay | API load |
|---|---|---|
15m | Up to 15 minutes | Low |
1h (default) | Up to 1 hour | Very low |
5m | Up to 5 minutes | Moderate |
1m | Up to 1 minute | High |
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-caConfigMap exists and contains the correct certificate. - 401 Unauthorized: Invalid or expired token. Verify the token in the
arcan-credentialsSecret. - 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.