Secret

In Juju, (starting with Juju 3.0) a secret is a sensitive bit of information (e.g., account credential, password, certificate, SSH key, API key, encryption key, etc.) that a charm needs to know.

Secret taxonomy

Charm

A charm secret is a secret created by a charm. A charm secret is shared with another charm (the secret ‘observer’) over relation data. The secret is tied to the lifecycle of the relation.

Unit

A unit secret is a charm secret created by a unit and owned by the unit.

Application

An application secret is a charm secret created by the leader unit and (because the leader unit does not have a fixed identity) owned by the application (i.e., when the leader unit changes, the secret is owned by the new leader).

User

A user secret is a secret created by a user with a model admin access level and (because this does not have a fixed identity) owned by the model . A user secret is shared with a charm (the secret ‘observer’) via a configuration option. The charm must support the configuration option.

Secret identification

Secrets are identified by an automatically-assigned ID (a URI generated by Juju at creation time) or (for user secrets, also) a user-defined name.

Secret backend

A secret backend is a service that is used to store sensitive content which Juju manages as secrets.

Secret backends are per model.

A secret backend is identified by a name and a type, and admits various configuration options, some of them generic and some backend-type-specific.

Name

The name of a secret backend can be:

  • auto (i.e., internal for machine models and local for Kubernetes models)

  • internal

  • <some custom name>

The name is set via the secret-backend model configuration key.

Type

The type of a secret backend can be controller, kubernetes, and vault.

Tip

For production use, we recommend vault.

controller

The controller backend is the Juju model database.

It is the default secret backend for machine (VM) models.

kubernetes

The kubernetes backend is the model’s Kubernetes namespace.

It is the default secret backend for container (Kubernetes) models.

Available starting with Juju 3.1.

vault

The vault backend refers to the Hashicorp Vault.

It is available as an opt-in to both machine and Kubernetes models.

Available starting with Juju 3.1.

Configuration options

Generic

The generic configuration keys currently include just the following:

token-rotate

The maximum period for which an access token is valid for. Some time prior to the token expiring Juju will generate a new one. Possible values: standard Go duration (e.g., 2h, 7d). The minimum is 1h.

The vault backend is the only one that supports it for now.

Backend-specific

The vault backend is the only one that supports specific configuration keys. These are:

ca-cert

The path to a PEM-encoded CA certificate file on the local disk. This file is used to verify the Vault server’s SSL certificate.

client-cert

The path to a PEM-encoded client certificate on the local disk. This file is used for TLS communication with the Vault server.

client-key

The path to an unencrypted, PEM-encoded private key on disk which corresponds to the matching client certificate.

endpoint

namespace

The namespace to use for the command. Setting this is not necessary but allows using relative paths.

tls-server-name

The name to use as the SNI host when connecting via TLS.

token

The vault authentication token.

See more: Vault | vault server, Hashicorp | Vault commands.
(You will see more options there as we currently support only support a subset.)

A minimum configuration must include the endpoint and token. However, just that would not be insecure, as it wouldn’t establish an encrypted TLS connection to Vault. For production you should configure your Vault securely, following recommendations in the upstream Vault documentation.

Permissions around secrets

An entity – unit/app or user – that has created / owns the secret can manage it (call secret-set, secret-grant, secret-revoke, secret-info-get, etc.).

An entity that does not own the secret can only view it (call secret-get), and only if it has been granted access to it – except for peer units or a model admin user, who get view access automatically.

Secret lifecycle

Important

This section currently covers only the lifecycle of a charm secret.

Charms can use relations to share secrets, such as API keys, a database’s address, credentials and so on. Like a relation has a “provider” and a “requirer”, so a secret has an “owner” and an “observer” – though these need not coincide with the applications’ roles in the relation.

Every secret has a scope, and that is the relation its lifecycle is tied to. If the relation is removed, the secret access will be revoked.

When a unit adds a secret, it becomes that secret’s owner, and it will obtain from Juju a secret ID, which it can then pass to some remote application via relation data. Any remote unit with access to that ID can get the secret (that is, access its contents). Before that is possible, however, the owner needs to grant the secret to the whole application or a specific unit.

Once the remote unit (the secret observer) gets its contents for the first time, it starts to track that secret in Juju – more specifically, its latest revision, as we will see later. When the owner adds the secret, and when the observer gets it, they both have a chance to assign to the secret a label, a locally-unique string that will be associated with that secret and can be used by the charm to refer to the secret “by name”.

The owner can choose at any time to publish a new revision of the secret, that is, change its payload (for example, replace an old key with a new one). When that happens, the observer will be notified by means of a secret-changed event. The observer can then refresh the secret, which means inform Juju that it wishes to start tracking the latest revision. From that moment on, every time the unit gets the secret, it will receive the newly-tracked revision’s contents.

However, a unit does not have to immediately update whenever a new revision becomes available. It can peek the secret’s contents, which means to inspect the latest revision of the secret without updating to it, or choose to do nothing.

When a charm secret is added, the owner can configure it to have a rotation policy (hourly, daily, monthly, and so on). In that case, the owner will be periodically notified, by means of a secret-rotate event, that it is time to rotate the secret – that is, create a new revision for it.

Alternatively, a charm secret can be configured to have an expiration date, that is, a specific point in time at which the charm will be notified by Juju that it is time to retire the secret by means of a secret-expired event.

Juju maintains a list of which observers are tracking each revision of each secret. The idea is that if an observer receives a secret-changed event, it will update the secret and start tracking the latest revision. Once Juju notices that there are no observers left for a given revision, it will notify the secret owner that that secret revision can be safely removed – which corresponds to the secret-remove event.

Important

When a unit gets a secret for the first time it will automatically be set to track the latest revision. A unit cannot choose to track an outdated revision, but it can in principle refuse to update to a newer one.