Skip to main content

How to use secrets

What are Secrets?​

Secrets support in the Dagger CUE SDK allows you to utilize confidential information -- such as passwords, API keys, SSH keys, etc -- when running your Plans, without exposing those secrets in plaintext logs, writing them into the filesystem of containers you're building, or inserting them into cache.

Secrets are never merged into the CUE configuration. They are managed by the Dagger Engine, only referenced as opaque identifiers, and can only be used by a special filesystem mount or as an environment variable designed to minimize leak risk.

Getting or Generating Secrets​

Client operations​

Most operations in client support handling secrets (see Interacting with the client). More specifically, you can:

Read from Environment​

The simplest use case is reading from an environment variable:

dagger.#Plan & {
client: env: GITHUB_TOKEN: dagger.#Secret
}

Read from File​

You may need to trim the whitespace, especially when reading from a file:

dagger.#Plan & {
// Path may be absolute, or relative to current working directory
client: filesystem: ".registry": read: {
// CUE type defines expected content
contents: dagger.#Secret
}
actions: {
registry: core.#TrimSecret & {
input: client.filesystem.".registry".read.contents
}
pull: docker.#Pull & {
source: "registry.example.com/image"
auth: {
username: "_token_"
secret: registry.output
}
}
}
}

SOPS​

There’s many ways to store encrypted secrets in your git repository. If you use SOPS, here's a simple example where you can access keys from an encrypted yaml file:

secrets.yaml
myToken: ENC[AES256_GCM,data:AlUz7g==,iv:lq3mHi4GDLfAssqhPcuUIHMm5eVzJ/EpM+q7RHGCROU=,tag:dzbT5dEGhMnHbiRTu4bHdg==,type:str]
sops: ...
main.cue
dagger.#Plan & {
client: commands: sops: {
name: "sops"
args: ["-d", "./secrets.yaml"]
stdout: dagger.#Secret
}

actions: {
// Makes the yaml keys easily accessible
secrets: core.#DecodeSecret & {
input: client.commands.sops.stdout
format: "yaml"
}

run: docker.#Run & {
mounts: secret: {
dest: "/run/secrets/token"
contents: secrets.output.myToken.contents
}
// Do something with `/run/secrets/token`
}
}
}

When you pass a file (JSON/YAML) to be encrypted by SOPS, only the values will be encrypted. Follow the steps below to encrypt a .yaml file with SOPS and age:

1.Create an age key

$ age-keygen -o key.txt
Public key: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p

2.Use the public key to encrypt the keys in you yaml file using sops.

sops -e --age age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p unencryted_secrets_sops.yaml  > secrets_sops.yaml

3.Edit the secrets_sops.yaml using sops

sops secrets_sops.yaml

Exported from Filesystem​

In addition, you can export a secret from a filesystem with core.#NewSecret

This should be used carefully and sparingly, as the source of these secrets will stay in cache.

package main

import (
"encoding/yaml"
"dagger.io/dagger"
"dagger.io/dagger/core"
)

dagger.#Plan & {
actions: test: {
write: core.#WriteFile & {
input: dagger.#Scratch
path: "/secret"
contents: yaml.Marshal({
FOO: "bar"
ONE: TWO: "twelve"
})
}

secret: core.#NewSecret & {
input: write.output
path: "/secret"
}

decode: core.#DecodeSecret & {
input: secret.output
format: "yaml"
}
}
}

Using Secrets​

Secrets can be used in a number of contexts within a Plan (note: this list is not exhaustive):

In a Docker.#Run​

As a mounted file

dagger.#Plan & {
client: env: GITHUB_TOKEN: dagger.#Secret

actions: {
run: docker.#Run & {
mounts: secret: {
dest: "/run/secrets/token"
contents: client.env.GITHUB_TOKEN
}
// Do something with `/run/secrets/token`
}
}
}

Or as an environment variable

dagger.#Plan & {
client: env: GITHUB_TOKEN: dagger.#Secret

actions: {
run: docker.#Run & {
env: GITHUB_TOKEN
// Do something with `/run/secrets/token`
}
}
}

Passed into an Action that utilizes Secrets​

import (
"dagger.io/dagger"
"dagger.io/dagger/core"

"universe.dagger.io/netlify"
)

dagger.#Plan & {
client: env: NETLIFY_TOKEN: dagger.#Secret
actions: {
// Configuration common to all tests
data: core.#WriteFile & {
input: dagger.#Scratch
path: "index.html"
contents: "hello world"
}

// Test: deploy a simple site to Netlify
// Deploy to netlify
deploy: netlify.#Deploy & {
team: "dagger-test"
token: client.env.NETLIFY_TOKEN
site: "dagger-test"
contents: data.output
}
}
}
dagger.#Plan & {
client: env: GITHUB_TOKEN: dagger.#Secret

actions: {
run: docker.#Run & {
mounts: secret: {
dest: "/run/secrets/token"
contents: client.env.GITHUB_TOKEN
}
// Do something with `/run/secrets/token`
}
}
}

Sharp edges to be aware of​

It is possible use Secrets in ways that can risk leaks. Be aware of the risks of these uses, and avoid them if possible.

We provide safeguards against printing of Secret values to the logs, but you should generally not log Secrets to the console using echo, cat, etc.

Safe Transformations of Secrets​

Trim Whitespace​

You may need to trim the whitespace, especially when reading from a file:

dagger.#Plan & {
// Path may be absolute, or relative to current working directory
client: filesystem: ".registry": read: {
// CUE type defines expected content
contents: dagger.#Secret
}
actions: {
registry: core.#TrimSecret & {
input: client.filesystem.".registry".read.contents
}
pull: docker.#Pull & {
source: "registry.example.com/image"
auth: {
username: "_token_"
secret: registry.output
}
}
}
}