Kubernetes secrets
| Secret | As a file | As an environment variable |
|---|---|---|
| whole configuration | config.toml mounted in /config | - |
| users, roles | users_file, roles_file | - |
| SSH host keys | host_keys | - |
| admin TLS pair | [admin.tls] cert_file, key_file | CRAFT_FILE_GATE_ADMIN_TLS_CERT, CRAFT_FILE_GATE_ADMIN_TLS_KEY |
| JWT secret | CRAFT_FILE_GATE_JWT_SECRET_FILE | CRAFT_FILE_GATE_JWT_SECRET |
admin token (fallback; forbidden by allow_static_token = false, which the chart sets) | CRAFT_FILE_GATE_ADMIN_BEARER_TOKEN_FILE | CRAFT_FILE_GATE_ADMIN_BEARER_TOKEN |
| S3 keys | credentials = { type = "static", ... } | AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY with type = "iam_role" |
| admin console session key | [admin.session] key_file | CRAFT_FILE_GATE_ADMIN_SESSION_SECRET_NAME: the shared Secret, filled by the pods (below) |
- A Secret mounted as a volume is updated by Kubernetes, which repoints the
..datalink: configuration, users, roles and TLS pair are reloaded at runtime. See Hot reload. - A Secret mounted with
subPathis never updated: avoidsubPath. - Mount Secrets and ConfigMaps
readOnly: true, as the chart does, never on a writableemptyDirorhostPath(Trust files and TLS). - A Secret passed through
envFrom(extraEnvFrom) is read only at startup: runkubectl rollout restartfor a new value. - The server does not read Secrets through the Kubernetes API: mount them. The only exception is the pods’ shared Secret (below).
A file rather than a variable
Mount the Secret as a file through the chart values, and name it with the
_FILE variable (the same for the admin token, with
config.allowStaticToken: true):
extraVolumes:
- name: jwt
secret: { secretName: sftp-jwt, defaultMode: 0440 }
extraVolumeMounts:
- { name: jwt, mountPath: /secrets/jwt, readOnly: true }
extraEnv:
- { name: CRAFT_FILE_GATE_JWT_SECRET_FILE, value: /secrets/jwt/jwt-secret }
The file is read once, at startup; /proc/<pid>/environ shows only a path.
See Environment variables.
users.toml is mounted the same way, named by users_file: see
Kubernetes.
The pods’ shared Secret
The pods of a release share the key that signs admin console sessions, so
that a pod accepts the token another pod issued. The chart creates an empty
Secret and gives the pods get and update on that name only. The first pod
that does not find the admin-session.key entry generates it and writes it;
the others read it. Each entry has its own life: the certificate of the
channel between pods lives there too (tls.crt, tls.key).
| Chart value | Effect |
|---|---|
clusterSecret.enabled | true by default, with [admin] or the channel between pods: the Secret, the Role (get, update on that name), the service account token; with [admin], CRAFT_FILE_GATE_ADMIN_SESSION_SECRET_NAME |
clusterSecret.name | <release>-cluster by default |
adminRevocations.backend | empty by default: configmap with the shared Secret, memory otherwise; configmap creates the access ConfigMap, where the revocations live, its Role (get, update, patch on that name), and sets CRAFT_FILE_GATE_ADMIN_SESSION_BACKEND, CRAFT_FILE_GATE_ADMIN_SESSION_REVOCATION_CONFIGMAP_NAME |
adminGrants.backend | empty by default: configmap with [admin] and the shared Secret or several replicas, memory otherwise; temporary accesses in the same ConfigMap, CRAFT_FILE_GATE_ADMIN_GRANTS_BACKEND, CRAFT_FILE_GATE_ADMIN_GRANTS_GRANT_CONFIGMAP_NAME; memory, or file without persist_file under [admin.grants], with several replicas makes rendering fail |
access.configmapName | the access ConfigMap, <release>-access by default |
With replicaCount above 1, clusterSecret.enabled: false requires a
key_file under [admin.session] in config.inline, and a shared key
requires shared revocations (adminRevocations.backend: configmap, or
persist_file under [admin.session]).
To change the key: remove the entry (kubectl patch secret ... --type=json -p '[{"op":"remove","path":"/data/admin-session.key"}]') then restart the
pods; open sessions are lost.
SSH host key
Create the key once, keep it in a Secret, mount it. Do not let the server
generate it (generate_host_key) in a pod: each pod, or each restart without
a volume, would have its own key, and clients would see “host key changed”.
ssh-keygen -t ed25519 -f host_ed25519 -N ""
ssh-keygen -l -f host_ed25519.pub # the fingerprint to give to clients
kubectl create secret generic sftp-host-keys --from-file=host_ed25519
hostKeys.existingSecret: sftp-host-keys mounts it in /keys (The chart),
and the configuration points to it: host_keys = ["/keys/host_ed25519"].
The fingerprint at startup (loaded host key, field fingerprint) and in
GET /admin/config is the one from ssh-keygen -l.