How do I manage secrets securely?¶
Keyword: How do I manage secrets securely on SmartTouch?
SmartTouch uses HashiCorp Vault to manage all secrets. Services never receive secrets as environment variables or Kubernetes Secrets in plain text. Instead, the platform injects short-lived credentials directly into the pod at runtime via the Vault Agent Injector.
Goal¶
Store the Remote Access Service TLS certificate and broker authentication credentials in Vault and configure the SSD to inject them at runtime.
Prerequisites¶
stctlinstalled and authenticated- The Remote Access Service SSD created—See Create the Remote Access Service SSD
- Administrator or Platform Engineer role (required to create Vault policies)
How Vault secret injection works¶
Pod starts
↓
Vault Agent Injector intercepts the pod spec
↓
Agent authenticates to Vault using the pod's Kubernetes Service Account
↓
Agent fetches the secrets specified in the SSD
↓
Agent writes secrets to a tmpfs volume at /vault/secrets/
↓
Service reads secrets from the file path
Secrets are written to memory-only storage ('tmpfs'). They're never written to disk and are removed when the pod stops.
Steps¶
Step 1—Store a secret in Vault¶
Use stctl to write a secret to your service's Vault path:
stctl secrets set \
--service remote-access-service \
--env dev \
--key broker-tls-cert \
--file sensor-001.crt
stctl secrets set \
--service remote-access-service \
--env dev \
--key broker-tls-key \
--file sensor-001.key
Expected output:
✔ Secret stored
Path: secret/remote-access-service/dev/broker-tls-cert
Version: 1
Step 2—List secrets for your service¶
stctl secrets list --service remote-access-service --env dev
Expected:
KEY VERSION LAST UPDATED
broker-tls-cert 1 2026-06-06T14:00:00Z
broker-tls-key 1 2026-06-06T14:00:01Z
Step 3—Reference secrets in the SSD¶
Add a secrets block to smarttouch.yaml:
secrets:
vault-path: "secret/remote-access-service/{{env}}"
inject:
- key: broker-tls-cert
mount-path: /vault/secrets/broker.crt
- key: broker-tls-key
mount-path: /vault/secrets/broker.key
The {{env}} placeholder is replaced at deploy time with the target environment (dev, staging, prod). This means the same SSD works across all environments—Each environment reads from its own Vault path.
Step 4—Read the secret in your service code¶
The secret is available at the file path specified in mount-path:
// Node.js — read the injected TLS certificate
const fs = require('fs');
const cert = fs.readFileSync('/vault/secrets/broker.crt');
const key = fs.readFileSync('/vault/secrets/broker.key');
# Python — read the injected TLS certificate
with open('/vault/secrets/broker.crt') as f:
cert = f.read()
with open('/vault/secrets/broker.key') as f:
key = f.read()
Step 5—Rotate a secret¶
When a certificate expires or a key is compromised, update the secret in Vault and trigger a pod restart to pick up the new version:
stctl secrets set \
--service remote-access-service \
--env dev \
--key broker-tls-cert \
--file sensor-001-renewed.crt
stctl restart --env dev --service remote-access-service
The pods restart one at a time (rolling restart). Each new pod fetches the updated secret from Vault on startup.
Validation¶
Secret injection is working when:
stctl exec --env dev --service remote-access-service \
-- ls /vault/secrets/
Expected:
broker.crt
broker.key
Troubleshooting¶
/vault/secrets/ directory is empty after pod start
The Vault Agent Injector didn't run. Check whether the injector is enabled for your 'namespace':
kubectl get namespace team-myteam -o yaml | grep vault-injection
If the annotation vault.hashicorp.com/agent-inject: "true" is missing, contact your Platform Engineer to enable Vault injection for your namespace.
permission denied when reading the secret file
The secret file is owned by the vault-agent user. If your service runs as a different user, add your service's UID to the Vault injection annotation. Contact your Platform Engineer.