Secrets Management¶
The cluster uses aKeyless as the central secrets management platform. Secrets are accessed through three different authentication methods depending on the use case.
aKeyless Authentication Methods¶
1. Web GUI (Email Authentication)¶
Use case: Manual secret management, administrative tasks
Access: Log in to aKeyless Console with email and password
What you can do: - Create/update/delete secrets - Create database users for CNPG (see CNPG section) - View secret values - Manage access policies
Creating a Secret via Web GUI
- Log in to aKeyless Console
- Navigate to Items → Secrets
- Click + New → Static Secret
- Enter path (e.g.,
authentik) and secret value (JSON or plain text) - Save
2. Talos ESO (API Authentication)¶
Use case: Kubernetes apps syncing secrets automatically
Method: External Secrets Operator (ESO) authenticates to aKeyless API
How it works:
ESO runs in the cluster and automatically syncs secrets from aKeyless to Kubernetes Secrets. The ClusterSecretStore configures API authentication:
apiVersion: external-secrets.io/v1
kind: ClusterSecretStore
metadata:
name: akeyless-secret-store
spec:
provider:
akeyless:
akeylessGWApiURL: "https://api.akeyless.io"
authSecretRef:
secretRef:
accessID:
name: akeyless-secret
key: accessId
namespace: external-secrets
accessType:
name: akeyless-secret
key: accessType
namespace: external-secrets
accessTypeParam:
name: akeyless-secret
key: accessTypeParam
namespace: external-secrets
Apps create ExternalSecret CRDs that reference the ClusterSecretStore, and ESO handles fetching secrets from aKeyless API automatically.
This method is completely hands-off—once configured, ESO syncs secrets automatically without manual intervention.
3. Akeyless Agent (CLI Authentication)¶
Use case: Bootstrap process, Talos configuration, template rendering
Method: akeyless CLI configured with API key, used by akeyless-inject.sh
How it works:
Talos configuration templates and bootstrap resources use ak:// references:
machine:
ca:
crt: ak://talos/MACHINE_CA_CRT
key: ak://talos/MACHINE_CA_KEY
token: ak://talos/MACHINE_TOKEN
During rendering, akeyless-inject.sh uses the akeyless CLI to replace ak:// references with actual secret values fetched from aKeyless.
Setup:
# Configure CLI with API key
akeyless configure --access-type api_key \
--access-id <your-access-id> \
--access-key <your-access-key>
# Authenticate
akeyless auth
# Test retrieval
akeyless get-secret-value --name talos/MACHINE_TOKEN
ak:// Reference Format
The script supports two formats:
- Plain text secret:
ak://path/to/secret - Example:
ak://talos/token -
Returns: The raw secret value
-
JSON field extraction:
ak://secret/FIELD_NAME - Example:
ak://talos/MACHINE_TOKEN - Returns: The value of
MACHINE_TOKENkey from JSON
Nested paths work: ak://deeply/nested/path/to/secret/FIELD
Where CLI method is used: - Bootstrap resources: bootstrap/resources.yaml.j2 - Talos config rendering: just talos render-config - Template rendering: just template <file>
Kubernetes External Secrets Operator (ESO)¶
Once the cluster is running, Kubernetes apps use External Secrets Operator to sync secrets from aKeyless via the API.
ClusterSecretStore¶
The ClusterSecretStore is configured during bootstrap. It authenticates ESO to aKeyless using credentials stored in the akeyless-secret Secret.
ExternalSecret CRDs¶
Apps define ExternalSecret CRDs to sync secrets from aKeyless:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: authentik
spec:
secretStoreRef:
name: akeyless-secret-store
kind: ClusterSecretStore
target:
name: authentik-secret # Creates this Kubernetes Secret
dataFrom:
- extract:
key: authentik # Fetches from aKeyless path
ESO automatically:
- Fetches
authentiksecret from aKeyless API - Creates a Kubernetes Secret named
authentik-secret - Syncs changes every 1 hour (configurable)
Apps reference this secret:
Secret Workflows¶
Adding a New Secret for an App¶
-
Create secret in aKeyless (via Web GUI or CLI):
-
Create ExternalSecret CRD:
-
Reference in HelmRelease:
-
Deploy:
Updating an Existing Secret¶
-
Update in aKeyless (Web GUI or CLI):
-
Force ESO to resync:
-
Restart app to pick up new secret:
CNPG Database Secrets¶
IMPORTANT: The CNPG component does not automatically generate database user secrets. You must create them manually in aKeyless (via Web GUI or CLI).
Creating Database User Secrets¶
When using the cnpg component, you need to manually create secrets for database users in aKeyless.
Steps:
-
Create secret in aKeyless (Web GUI or CLI):
# Create JSON secret with database credentials akeyless create-secret \ --name <app-name>-pguser \ --value '{"username":"<app-name>","password":"<random-password>","dbname":"<app-name>"}'Example for Authentik:
-
Include CNPG component in app's
ks.yaml: -
CNPG component creates ExternalSecret:
The component automatically creates an
ExternalSecretthat syncs${APP}-pguserfrom aKeyless into a Kubernetes Secret named${APP}-pguser-secret. -
CNPG component CronJob creates database user:
The component includes a CronJob (
kubernetes/components/cnpg/cronjob.yaml) that runs daily to ensure the database user exists in PostgreSQL using the credentials from aKeyless. -
App references the secret:
Secret Must Exist Before Deployment
If the <app-name>-pguser secret doesn't exist in aKeyless, the ExternalSecret will fail to sync and the app won't start:
Always create the secret in aKeyless first (step 1 above) before deploying the app.
CNPG Component Breakdown¶
Located at kubernetes/components/cnpg/:
- ExternalSecret (
externalsecret.yaml): Syncs${APP}-pguserfrom aKeyless to Kubernetes Secret - CronJob (
cronjob.yaml): Runs daily to ensure database user exists in PostgreSQL
Apps using PostgreSQL:
- Authentik
- Gatus
- Immich
- And others in the
defaultnamespace
Bootstrap Secrets¶
During bootstrap, secrets are injected via the CLI method. See bootstrap/resources.yaml.j2 for examples of ak:// references used to create bootstrap-time Secrets.
These include:
akeyless-secret: ESO authentication credentialscloudflared-secret: Cloudflare tunnel credentialscluster-secrets: Cluster-wide variables (referenced by apps viapostBuild.substituteFrom)
Troubleshooting Secrets¶
ExternalSecret Not Syncing¶
Symptoms: SecretSyncedError status on ExternalSecret
Diagnosis:
Common causes:
-
Secret doesn't exist in aKeyless:
Fix: Create the secret in aKeyless Web GUI or CLI
-
ClusterSecretStore not ready:
Fix: Check ESO operator logs:
-
Authentication failed:
Fix: Verify
akeyless-secretcontains correct credentials:
Force Resync ExternalSecret¶
Viewing Decoded Secrets¶
# Decode and view secret
just kube view-secret <namespace> <secret-name>
# Or manually
kubectl get secret <name> -n <namespace> -o jsonpath='{.data}' | jq -r 'to_entries[] | "\(.key): \(.value | @base64d)"'
akeyless-inject.sh Not Resolving References¶
Symptoms: ak:// references not replaced during bootstrap or template rendering
Cause: aKeyless CLI not authenticated
Fix:
# Re-authenticate
akeyless auth
# Test secret retrieval
akeyless get-secret-value --name talos/MACHINE_TOKEN
# Re-run the failed stage
just bootstrap resources # or whichever stage failed
Best Practices¶
- Use JSON secrets: Store multiple related values in one secret (e.g., database credentials)
- Name consistently: Use
<app-name>for app secrets,<app-name>-pguserfor database credentials - Rotate regularly: Update secrets in aKeyless and force resync
- Limit access: Use aKeyless access policies to restrict who can view/modify secrets
- Never commit secrets: All secrets live in aKeyless, never in Git (even encrypted)
Secret Reference Summary¶
| Authentication Method | Use Case | How It Works |
|---|---|---|
| Web GUI (Email) | Manual management, creating secrets | Log in to aKeyless Console with email/password |
| Talos ESO (API) | Kubernetes apps syncing secrets | ClusterSecretStore authenticates ESO to aKeyless API; ExternalSecret CRDs fetch secrets automatically |
| Akeyless Agent (CLI) | Bootstrap, Talos configs, templates | akeyless-inject.sh uses CLI to resolve ak:// references in Jinja2 templates |
Next Steps¶
- Bootstrap Guide: How secrets are injected during cluster setup
- Operations Guide: Managing secrets in production
- Troubleshooting: Fixing ExternalSecret sync failures