Skip to content

Mount a Secret as a File

Overview

From Kelvin 7.2 a secret can be delivered to a Workload as a file on disk, instead of an environment variable or a configuration value.

This uses the secret volume type in the system.volumes section. At startup Kelvin resolves the reference and writes the secret value into a file at the path you choose. When you use a secret reference, the value is never stored in the Application or in its configuration.

Secret volumes are available to every Application type.

Note

The secret must already exist on the Kelvin Platform. See Create a Secret.

How It Works

The volume declares where the file goes and which secret fills it.

  • target is the path inside the container where the file appears
  • type: secret tells Kelvin the content comes from a secret
  • secret.value holds the reference to the secret on the platform
  • secret.mode is optional and sets the file permissions, such as "0600"

The file contents are the secret value. One volume produces one file from one secret. To mount three credentials, declare three volumes.

When to Use a File

The secret is the same in every case. Only the delivery changes.

Method Where the value lands
Environment variable in app.yaml An environment variable your program reads
Configuration An App Configuration key your program reads
Secret volume A file on disk at the target path

Choose the file method when a library or tool will only accept a credential as a file, such as:

  • A TLS certificate or certificate authority bundle
  • A private key or SSH key
  • A service account JSON file
  • A kubeconfig or similar client config
  • A keyfile or password file for software that does not accept credentials from environment variables, such as a shared keyfile for a database cluster like MongoDB

Files also suit values that do not fit an environment variable cleanly, such as multi line text content.

Scope

The mount is defined on the Workload, so the file exists only inside that Workload's container.

The secret itself stays global on the Kelvin Platform. Each Workload decides which secret it mounts and where the file appears, so two Workloads of the same Application can read a different certificate from the same path.

app.yaml Setup

Declare the volume in the defaults.system.volumes section before you upload the Application.

Secret Volume Example
1
2
3
4
5
6
7
volumes:
    - name: mysecretfile
      target: /opt/share/mysecretfile
      type: secret
      secret:
        value: <% secrets.mysecret %>
        mode: "0600"  # optional, the file permissions
Field Description
name The name of the volume.
target The path inside the container where the file will be created.
type Set to secret to mount a secret as a file.
secret.value The reference to the secret on the Kelvin Platform.
secret.mode Optional. The file permissions in the Linux chmod octal format, for example "0600". It must be in quotes. The default is "0644".

Warning

Always set secret.value to a <% secrets.name %> reference. Kelvin then stores only the reference in the Application.

A literal value is stored as plain text in the Application, the same as a text volume.

File Permissions

Some software refuses to use a credential file if its permissions are too open. For example, SSH requires a private key to have the permissions 0600, and MongoDB rejects a keyFile with permissions looser than 0600.

Use secret.mode to set the permissions of the mounted file.

Secret Volume With File Permissions Example
1
2
3
4
5
6
7
volumes:
    - name: ssh-key
      target: /root/.ssh/id_rsa
      type: secret
      secret:
        value: <% secrets.ssh-key %>
        mode: "0600"
  • The mode uses the same octal format as the Linux chmod command. It is a leading 0 followed by three digits for the owner, the group and everyone else, for example "0600" gives the owner read and write access and nobody else any access
  • You must put the mode in quotes. Without quotes, YAML reads it as a number and it is rejected
  • If you do not set it, the file gets "0644"
  • The mount is always read-only

Size and Encoding

The value is carried in the app.yaml file, which Kelvin stores in a Kubernetes configMap on the Cluster. Kubernetes allows a maximum of 1 MB per configMap.

Kelvin compresses the content before storing it, so the 1 MB limit applies to the compressed size rather than to the original file. Content that compresses well, such as a PEM certificate or a JSON file, can therefore be considerably larger than 1 MB before it reaches the limit.

The final size is calculated during the deployment step, before the content reaches the Cluster. If it exceeds 1 MB the API returns an error.

The value is handled as a string, normally UTF-8. ASCII and UTF-8 content are both accepted, and what you store in the secret is exactly what the Workload receives.

Deploy Time Setup

The volume does not have to be fixed into the Application. It can also be added in the System ⟶ Volumes section when you deploy a workload or update an existing one.

This means a single Application can mount a different secret file per Workload, with no rebuild or re-upload.

Python Example

Read the file as you would any other file on disk.

Read Mounted Secret File Python Example
1
2
3
4
with open("/opt/share/mysecretfile") as f:
    mysecret = f.read().strip()

print(f'Your secret is {mysecret}')

Example: Mount a TLS Certificate

An Application needs to call an internal API that presents a certificate signed by a private certificate authority. The Python requests library needs that authority certificate as a file path.

1. Store the certificate as a secret

Create a secret whose value is the contents of the PEM file.

Create the Certificate Secret
kelvin secret create internal-ca-cert --value "$(cat internal-ca.pem)"

2. Mount it into the Workload

Certificate Volume in app.yaml
1
2
3
4
5
6
7
8
defaults:
  system:
    volumes:
      - name: internal-ca-cert
        target: /etc/ssl/certs/internal-ca.pem
        type: secret
        secret:
          value: <% secrets.internal-ca-cert %>

3. Use the file path in your code

Verify a Request With the Mounted Certificate
1
2
3
4
5
6
7
8
import requests

response = requests.get(
    "https://internal-api.example.com/status",
    verify="/etc/ssl/certs/internal-ca.pem",
)

print(response.status_code)

The certificate is never committed to the repository, never baked into the image, and never visible in the Workload configuration. Rotating it means updating the secret and restarting or redeploying the Workload.

Note

To inject a secret as an environment variable or a configuration value instead, see Use a Secret.