Trust files and TLS
Trust files
These files decide who gets in and what they can do: anyone who can write them can grant themselves access. The server judges them at startup, and at reload for those that reload.
| File | Judged |
|---|---|
the file passed to --config | startup, reload |
sftp.host_keys | startup |
auth.users_file, auth.methods.local.users_file, or an adopted users.toml | startup, reload |
auth.roles_file, or an adopted roles.toml | startup, reload |
auth.jwt.public_key_file | startup |
admin.tls.cert_file, admin.tls.key_file | startup, reload |
admin.session.key_file | startup |
CRAFT_FILE_GATE_JWT_SECRET_FILE, CRAFT_FILE_GATE_ADMIN_BEARER_TOKEN_FILE | startup |
auth.password_file and ca_bundle of a webhdfs backend | backend construction |
SSL_CERT_FILE, SSL_CERT_DIR, if set | startup |
The file, and every directory crossed from / to reach it (symbolic links
included), is judged on its mode bits, its owner and its group. The server
then reads the file through the descriptor it judged.
Setting them up
| Setup | Verdict |
|---|---|
| owned by root, writable by its owner only, directories the same | accepted silently |
| owned by the server’s uid, writable by it only | accepted, reported at startup |
on a read-only mount (Kubernetes Secret or ConfigMap, :ro volume) | accepted; the directories are not judged |
/, /tmp (root, sticky bit) on the path | accepted |
The recommended setup:
chown root:root /etc/craft-file-gate /etc/craft-file-gate/*
chmod 755 /etc/craft-file-gate
chmod 644 /etc/craft-file-gate/config.toml /etc/craft-file-gate/roles.toml
chmod 640 /etc/craft-file-gate/users.toml /etc/craft-file-gate/host_ed25519
chgrp craft-file-gate /etc/craft-file-gate/users.toml /etc/craft-file-gate/host_ed25519
In a container, mount the configuration read-only (readOnly: true, :ro):
a Kubernetes Secret in 0440 with the pod’s fsGroup works as is.
[security]
All keys: Reference [security].
Read at startup. Keep it for a deployment where the server’s group contains only the server.
What the server creates itself
The process sets umask(077) at startup.
| Created by the server | Mode |
|---|---|
| generated host key, generated admin TLS key | 0600 (generated certificate: 0644) |
| directory of a generated key, bans file, temporary files | 0700 / 0600 |
| files uploaded by clients, home directories (local backend) | 0666 / 0777 masked by the umask inherited at launch |
| log and audit files | 0640 masked by the inherited umask |
Instances that share a bans volume run under the same uid.
Client paths
A client path is judged on its virtual form, then the backend resolves it under its root. On a local backend, a symbolic link never leaves the root: see Local.
TLS trust roots
This is outgoing TLS: S3 backend over HTTPS, jwks_url, authorization
service, OTLP collector over https://, WebHDFS backend. Incoming TLS for
the console is set in [admin.tls] (see
Admin API and console).
The server embeds no root: it reads the system store.
| Variable | Content |
|---|---|
SSL_CERT_FILE | a PEM file, any number of certificates |
SSL_CERT_DIR | directories, separated by : |
When set, either variable replaces the system store, it does not add to it. To trust an internal authority and the public roots, concatenate:
cat /etc/ssl/certs/ca-certificates.crt ca-interne.pem > bundle.pem
Without a variable, the first file found among the usual paths wins
(/etc/ssl/certs/ca-certificates.crt, /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem,
/etc/pki/tls/certs/ca-bundle.crt, /etc/ssl/ca-bundle.pem, /etc/ssl/cert.pem),
then the directories /etc/ssl/certs and /etc/pki/tls/certs. The
:latest and :alpine images carry a store; the :scratch image has none.
Mounting a set of roots
The Mozilla bundle maintained by the curl project works:
curl -fsSLo bundle.pem https://curl.se/ca/cacert.pem
Mount it at the default path (/etc/ssl/certs/ca-certificates.crt,
read-only), or anywhere with SSL_CERT_FILE; in Kubernetes, a ConfigMap is
enough, it is not a secret.
A deployment without outgoing TLS connections (local backend or SFTP proxy, local accounts or static JWT key, no OTLP) needs no root.
Deployment recommendations
| Topic | Recommendation |
|---|---|
| trust files | read-only, owned by root; a Secret or a ConfigMap mounted readOnly: true |
| secrets | the _FILE forms rather than variables, readable in /proc/<pid>/environ |
| uid | a dedicated uid per instance, NoNewPrivileges=yes, a seccomp filter (SystemCallFilter=@system-service, seccompProfile: RuntimeDefault) |
| pod | the Helm chart applies the restricted profile: see Kubernetes |
| admin port | control_listen on an internal interface; in a container, behind a NetworkPolicy (the Helm chart sets one, and a separate ClusterIP Service) |
| OpenAPI description | [api] openapi, off by default: without authentication, it describes the whole API |
| console TLS | [admin.tls], certificate provided or generated |
| brute force | the three ban lists and the two limiters (see Bans) |
| audit trail | exported in full off the host; authentication refusals are at INFO, a WARN filter loses them |
| JWT | regular rotation of the signing keys; issuer and audience set |