Secrets¶
12-factor app charms use Juju secrets for application secret material. The
secret key used to sign sessions is generated and stored automatically, while
user-provided secrets can be passed as environment variables through configuration
options of type secret.
Application secret key¶
Each 12-factor app charm maintains an application secret key used for session
signing, CSRF protection, or any other purpose that requires a random secret
shared by all units. The charm stores this key in a Juju application-owned
secret with the app-secret-key label instead of the peer relation databag.
The key is exposed to the workload through FLASK_SECRET_KEY for Flask,
DJANGO_SECRET_KEY for Django, and APP_SECRET_KEY for FastAPI,
ExpressJS, Go, and Spring Boot. If no user-provided key is configured, a random
key is generated.
Because the key is stored in a Juju secret, it can be rotated without repacking
the charm. Identify the current leader with juju status and run the
rotate-secret-key action on that unit to generate and store a new fallback
key:
juju run <current leader unit> rotate-secret-key
This action rotates only the charm-managed key used when app-secret-key is
not configured. If app-secret-key refers to a Juju user secret, update or
rotate that user secret instead.
Warning
Rotating the key, or upgrading from paas-charm 1.x to 2.0, invalidates
any existing sessions signed with the previous key. On upgrade a fresh key
is always generated because previous values are not migrated from the peer
relation databag. Applications that use the key for session signing
(including Flask, Django, FastAPI, ExpressJS, and Spring Boot) may sign out
existing users.
User-provided secret key¶
To use your own secret key instead of the generated one, set the app-secret-key
option, which has type secret, to a Juju user secret ID. The Charmcraft framework
extension for Ubuntu 26.04 LTS declares this option for you, so don’t declare it in
charmcraft.yaml: Charmcraft fails with an “overlapping keys” error if you do.
Then create the Juju secret, grant it to the application, and set the configuration option to the secret ID:
juju add-secret my-app-secret-key value=<secret-string>
juju grant-secret my-app-secret-key <app name>
juju config <app name> app-secret-key=secret:<secret id>
The secret must contain a single key, value, which holds the actual secret
key.
User secrets as environment variables¶
You can expose arbitrary Juju secret keys and values as environment variables by
adding a configuration option of type secret. Each key inside the secret becomes an
environment variable named after the option and the secret key:
config:
options:
api-token:
type: secret
description: Secret needed to access an API.
Then create the Juju secret, grant it to the application, and set the configuration option to the secret ID:
juju add-secret my-api-token value=1234 othervalue=5678
juju grant-secret my-api-token <app name>
juju config <app name> api-token=secret:<secret id>
For a configuration option api-token and a secret key value, Flask receives
FLASK_API_TOKEN_VALUE, Django receives DJANGO_API_TOKEN_VALUE, and
FastAPI, ExpressJS, Go, and Spring Boot receive APP_API_TOKEN_VALUE. In
general, the environment variable uses the framework prefix followed by the
option and key names, with hyphens replaced by underscores and all letters
in uppercase.
See also