Skip to content

Secrets

Secrets are a flavor of Configs focusing on sensitive data, with specific constraint for this usage.

Services can only access secrets when explicitly granted by a secrets attribute within the services top-level element.

Secrets are project-scoped, which means that they can be accessed by the different services deployed within the same project. It also means that you could overwrite secrets if you reuse the secret names within a specific project.

Use secrets

Secrets are mounted as a file in /run/secrets/<secret_name> inside the container.

Getting a secret into a container is a two-step process. First, define the secret using the top-level secrets element in your Compose file. Next, update your service definitions to reference the secrets they require with the secrets attribute. Levv grants access to secrets on a per-service basis.

Deprecation notice

Injecting secrets as environment variables is still supported but will be deprecated in the future, as you risk unintentional information exposure.

secrets top-level element

The top-level secrets declaration defines or references sensitive data that is granted to the services in your Compose application. The source of the secret is either file, environment or external.

  • file: The secret is created with the contents of the file at the specified path.
  • environment: The secret is created with the value of an environment variable.
  • external: If set to true, external specifies that this secret has already been created. Levv does not attempt to create it, and if it does not exist, an error occurs.
  • name: The name of the secret object in Levv. This field can be used to reference secrets. The name is used as is and will be scoped with the project name.

secrets attribute within the services top-level element

secrets grants access to sensitive data defined by secrets on a per-service basis. Two different syntax variants are supported; the short syntax and the long syntax.

Levv reports an error if the secret doesn't exist on the platform or isn't defined in the secrets section of the Compose file.

Services can be granted access to multiple secrets. Long and short syntax for secrets may be used in the same Compose file. Defining a secret in the top-level secrets must not imply granting any service access to it. Such grant must be explicit within service specification as secrets service element.

Short syntax

The short syntax variant only specifies the secret name. This grants the container access to the secret and mounts it as read-only to /run/secrets/<secret_name> within the container. The source name and destination mountpoint are both set to the secret name.

The following example uses the short syntax to grant the frontend service access to the server-certificate secret. The value of server-certificate is set to the contents of the file ./server.cert.

services:
  frontend:
    image: example/webapp
    secrets:
      - server-certificate
secrets:
  server-certificate:
    file: ./server.cert

Long syntax

The long syntax provides more granularity in how the secret is created within the service's containers.

  • source: The name of the secret as it exists on the platform.
  • target: The name of the file to be mounted in /run/secrets/ in the service's task container, or absolute path of the file if an alternate location is required. Defaults to source if not specified.
  • mode: The permissions for the file to be mounted in /run/secrets/ in the service's task containers, in octal notation. The default value is world-readable permissions (mode 0444). The writable is ignored if set. The executable bit may be set.

The following example sets the name of the server-certificate secret file to server.crt within the container, and sets the mode to 0440 (group-readable). The value of server-certificate secret is provided by the platform through a lookup and the secret's lifecycle is not directly managed by Levv.

services:
  frontend:
    image: example/webapp
    secrets:
      - source: server-certificate
        target: server.cert
        uid: "103"
        gid: "103"
        mode: 0o440
secrets:
  server-certificate:
    external: true

Examples

Example 1

server-certificate secret is created by registering content of the server.cert as a platform secret.

secrets:
  server-certificate:
    file: ./server.cert

Example 2

token secret is created by registering the content of the OAUTH_TOKEN environment variable as a platform secret.

secrets:
  token:
    environment: "OAUTH_TOKEN"

Alternatively, server-certificate can be declared as external. Levv looks up the server-certificate secret to expose to relevant services.

secrets:
  server-certificate:
    external: true

Example 3

External secrets lookup can also use a distinct key by specifying a name.

The following example modifies the previous example to look up a secret using the name CERTIFICATE_KEY. The actual lookup key is set at deployment time by the interpolation of variables, but exposed to containers as hard-coded ID server-certificate.

secrets:
  server-certificate:
    external: true
    name: "${CERTIFICATE_KEY}"

If external is set to true, all other attributes apart from name are irrelevant. If Levv detects any other attribute, it rejects the Compose file as invalid.

Single-service secret injection

In the following example, the frontend service is given access to the my_secret secret. In the container, /run/secrets/my_secret is set to the contents of the file ./my_secret.txt.

services:
  myapp:
    image: myapp:latest
    secrets:
      - my_secret
secrets:
  my_secret:
    file: ./my_secret.txt

Multi-service secret sharing and password management

services:
  db:
    image: mysql:latest
    labels:
      io.levv.size: "mini"
    volumes:
      - db-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_root_password
      - db_password

  wordpress:
    image: wordpress:latest
    ports:
      - "8000:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

secrets:
  db_password:
    file: db_password.txt
  db_root_password:
    file: db_root_password.txt

volumes:
  db-data:

In the advanced example above:

  • The secrets attribute under each service defines the secrets you want to inject into the specific container.
  • The top-level secrets section defines the variables db_password and db_root_password and provides the file that populates their values.
  • The deployment of each container means Levv creates a bind mount under /run/secrets/<secret_name> with their specific values.