Skip to content

Kubernetes Secrets with OCI Vault - External Secrets Operator

This cluster uses OCI Vault (Always Free tier) to securely store all sensitive configuration. This approach ensures that secrets are never committed to the repository and can be retrieved for cluster recreation.

ResourceFree LimitOur Usage
Vault Secrets150~10
Master Key Versions201
HSM-protected Keys

All secrets are stored in the oke-secrets-vault OCI Vault:

Secret NamePurposeUsed By
cloudflare-api-tokenDNS automationExternal DNS, Cert Manager
cloudflare-zone-idCloudflare zoneExternal DNS
domain-nameBase domainManifests
github-patRepository accessArgoCD, GHCR
github-usernameGitHub authenticationArgoCD, GHCR
git-repo-urlRepository URLArgoCD
acme-emailLet’s Encrypt contactCert Manager
argocd-admin-passwordArgoCD UI loginArgoCD
argocd-admin-password-hashBcrypt hash for argocd-secretArgoCD
gemma-api-keyGemma LLM AuthenticationGemma (scaled to 0)
huggingface-tokenHuggingFace model downloadsGemma (scaled to 0)
gemini-api-keyGoogle Gemini API keyOpenClaw
openclaw-gateway-tokenWeb UI auth tokenOpenClaw
telegram-bot-tokenTelegram Bot API tokenOpenClaw
google-places-api-keyGoogle Places API keyOpenClaw
discord-bot-tokenDiscord bot token (optional)OpenClaw
gog-keyring-passwordGoogle Workspace CLI keyring (legacy)OpenClaw
alphavantage-api-keyAlpha Vantage financial data API keyOpenClaw
bw-client-idBitwarden CLI client IDOpenClaw
bw-client-secretBitwarden CLI client secretOpenClaw
oidc-client-idOIDC authenticationOpen WebUI
oidc-client-secretOIDC authenticationOpen WebUI
oidc-provider-urlOIDC provider endpointOpen WebUI
ssh-public-keyInstance access (Vault only, not synced to K8s)OCI Compute

Install and configure the OCI CLI:

Terminal window
brew install oci-cli
oci setup config
Terminal window
oci vault secret list \
--compartment-id <your-compartment-ocid> \
--query 'data[].{"name":"secret-name","id":id}' \
--output table
Terminal window
oci secrets secret-bundle get \
--secret-id <secret-ocid> \
--query 'data."secret-bundle-content".content' \
--raw-output | base64 -d

The ArgoCD admin password is automatically synced from Vault to the cluster via External Secrets Operator.

Terminal window
# From cluster (password is synced from Vault)
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath='{.data.password}' | base64 -d
# Or directly from Vault
ARGOCD_SECRET_ID=$(terraform -chdir=tf-oke output -json secret_ocids | jq -r '.argocd_admin_password')
oci secrets secret-bundle get \
--secret-id "$ARGOCD_SECRET_ID" \
--query 'data."secret-bundle-content".content' \
--raw-output | base64 -d

To recreate terraform.tfvars from OCI Vault:

  1. Get all secret OCIDs

    Terminal window
    terraform -chdir=tf-oke output -json secret_ocids
  2. Create the tfvars file

    Terminal window
    cat > tf-oke/terraform.tfvars << 'EOF'
    tenancy_ocid = "<from OCI Console>"
    user_ocid = "<from OCI Console>"
    fingerprint = "<from OCI Console>"
    private_key_path = "/path/to/oci_api_key.pem"
    region = "<your-region>"
    compartment_ocid = "<from OCI Console>"
    EOF
  3. Add secrets from Vault

    Terminal window
    # Example for one secret
    echo "cloudflare_api_token = \"$(oci secrets secret-bundle get \
    --secret-id <cloudflare-api-token-ocid> \
    --query 'data."secret-bundle-content".content' \
    --raw-output | base64 -d)\"" >> tf-oke/terraform.tfvars

The cluster runs External Secrets Operator (ESO) to sync OCI Vault secrets to Kubernetes Secrets. This enables GitOps-friendly secret management where:

  1. Secrets are stored in OCI Vault
  2. ESO reads secrets from Vault
  3. ESO creates/updates Kubernetes Secrets
  4. Applications reference standard Kubernetes Secrets

The cluster uses Instance Principals to authenticate with OCI Vault. This eliminates the need for managing long-lived API keys for the cluster itself.

  1. Dynamic Group: oke-nodes-dg groups all instances in the compartment (instance.compartment.id = '<compartment_ocid>').
  2. Policy: oke-secrets-read-policy allows the dynamic group to read secret-family and use vaults in the compartment.
  3. ClusterSecretStore: Configured with principalType: InstancePrincipal.
flowchart LR
    subgraph OCI["OCI Cloud"]
        Vault[(Vault)]
        IAM[IAM Policy]
    end
    
    subgraph K8s["OKE Cluster"]
        Node[Worker Node]
        ESO[External Secrets<br/>Operator]
        css[ClusterSecretStore]
        es[ExternalSecret]
        Secret[K8s Secret]
    end
    
    Node --"Identity"--> IAM
    IAM --"Allow Read"--> Vault
    Vault --"Secret Bundle"--> ESO
    css --"Config"--> ESO
    es --"Ref"--> ESO
    ESO --"Sync"--> Secret
  1. Never commit secrets - All .tfvars files are gitignored
  2. Use HSM protection - OCI Vault uses HSM-backed master keys
  3. Enable versioning - Secret versions are retained for rollback
  4. Least privilege - Use scoped API tokens (Cloudflare Zone.DNS only)
  5. Rotate regularly - Update secrets and create new versions

Terraform state is stored in OCI Object Storage:

SettingValue
Bucketoke-tfstate
VersioningEnabled
AccessPrivate (NoPublicAccess)
EncryptionServer-side (default)