Skip to content

Commit e01c8d3

Browse files
committed
docs(secrets): add new Concepts/Secrets doc about passing sensitive data to services, including x-command extension
1 parent 925695a commit e01c8d3

4 files changed

Lines changed: 172 additions & 1 deletion

File tree

‎website/docs/3-concepts/7-configs.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,8 @@ If config changes don't take effect:
234234
1. Run `uc deploy` to redeploy with new config content
235235
2. Check that you're modifying the correct config file
236236
3. Verify the config is properly mounted in the container with `docker exec <service> cat <config-path>` on the remote machine
237+
238+
## See also
239+
240+
- [Secrets](8-secrets.md): Pass sensitive values such as passwords, tokens, and keys to your services
241+
- [Compose support matrix](../8-compose-file-reference/1-support-matrix.md): Which Compose features Uncloud supports
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# Secrets
2+
3+
Secrets allow you to keep **sensitive data** for your services out of your Compose file and version control. This
4+
includes database passwords, API tokens, TLS or SSH private keys.
5+
6+
Uncloud provides an extended support for
7+
[Compose secrets](https://github.com/compose-spec/compose-spec/blob/main/09-secrets.md), allowing you to fetch secret
8+
values at deploy time from your password manager, a cloud secrets store, or local files.
9+
10+
## How it works
11+
12+
Two things go into your Compose file:
13+
14+
1. Define a secret in the top-level `secrets` section. This tells Uncloud how to get the secret value.
15+
2. Reference that secret value in a service's `environment` using the `secret://<name>` format. This tells Uncloud to
16+
resolve the secret and set the environment variable to its value at deploy time.
17+
18+
```yaml title="compose.yaml"
19+
services:
20+
api:
21+
image: myapp:latest
22+
environment:
23+
DB_PASSWORD: secret://db_password
24+
TLS_KEY: secret://tls_key
25+
26+
secrets:
27+
db_password:
28+
# Read the secret value from 1Password by running this command locally.
29+
x-command: op read "op://prod/myapp/db_password"
30+
tls_key:
31+
# Read the secret value from a local file. Do NOT commit this file to the repository.
32+
file: ./secrets/tls_key.pem
33+
```
34+
35+
When you run `uc deploy`, it sees each `secret://<name>` reference, resolves the secret on your local machine, and sets
36+
the environment variable to its value. For example, it runs the command for `db_password` and reads the file for
37+
`tls_key`. The values never land in your Compose file or git. They go straight into the deployment.
38+
39+
Only secrets you reference in the services that you currently deploy get resolved. A secret referenced in multiple
40+
places or by several services resolves only once, and the value is reused.
41+
42+
Secrets are resolved after building images (if any) and before preparing the deployment plan.
43+
44+
:::info note
45+
46+
Secrets can only be used to set environment variables in your services. \
47+
Mounting a secret as a file inside the container is not supported yet. For mounting config files,
48+
see [Configs](7-configs.md).
49+
50+
:::
51+
52+
## Secret sources
53+
54+
Uncloud supports multiple sources for fetching secret values. Choose the one for each secret that fits your workflow.
55+
56+
### Arbitrary command
57+
58+
The `x-command` extension runs a command and uses its output as the secret value. It's the most versatile option that
59+
lets you pull a secret from a system Keychain, password managers, cloud services and secrets stores, or any CLI tool you
60+
already use.
61+
62+
```yaml title="compose.yaml"
63+
secrets:
64+
# 1Password
65+
db_password:
66+
x-command: op read "op://prod/myapp/db_password"
67+
# Bitwarden
68+
api_token:
69+
x-command: bw get password api-token
70+
# Infisical
71+
smtp_password:
72+
x-command: infisical secrets get --env=prod SMTP_PASSWORD --plain --silent
73+
# AWS Secrets Manager
74+
stripe_key:
75+
x-command: aws secretsmanager get-secret-value --secret-id stripe --query SecretString --output text
76+
```
77+
78+
The command runs on the machine where you run `uc deploy`, in the same directory as your Compose file and with the same
79+
environment. So it uses the CLIs and credentials you are already logged into.
80+
81+
If your password manager needs you to unlock it or touch a hardware key, the prompt shows up right in your terminal.
82+
Uncloud never stores your provider credentials.
83+
84+
A few details worth knowing:
85+
86+
- The command runs directly without a shell. To use pipes or variables, call a shell yourself: `sh -c 'cmd1 | cmd2'`.
87+
- A single trailing newline is trimmed from the output, because most CLI tools add one. Everything else is kept as is.
88+
- The command has 1 minute to finish before `uc` times out and aborts the deployment.
89+
90+
`x-command` is a short form for `driver: exec`. Use the long form if you prefer to be explicit:
91+
92+
```yaml title="compose.yaml"
93+
secrets:
94+
db_password:
95+
driver: exec
96+
driver_opts:
97+
command: op read "op://prod/myapp/db_password"
98+
```
99+
100+
:::tip
101+
102+
To pull secrets from many providers through a single CLI, or to keep **encrypted secrets in your git repository**,
103+
consider [fnox](https://fnox.jdx.dev/). It works with AWS, GCP, Azure, HashiCorp Vault, 1Password, Bitwarden, and more,
104+
and prints a plain value you can read with `x-command`:
105+
106+
```yaml title="compose.yaml"
107+
secrets:
108+
db_password:
109+
x-command: fnox get DB_PASSWORD
110+
```
111+
112+
:::
113+
114+
### File
115+
116+
Read the content of a local file as the secret value. The file path is relative to the Compose file location.
117+
118+
```yaml title="compose.yaml"
119+
secrets:
120+
db_password:
121+
file: ./secrets/db_password.txt
122+
```
123+
124+
The file content is used verbatim without trimming any whitespaces.
125+
126+
:::warning
127+
128+
Do NOT commit these files to your repository and ensure they are protected with proper file permissions. For example,
129+
make the file readable only by your user with `chmod 600 ./secrets/db_password.txt`.
130+
131+
:::
132+
133+
## Things to keep in mind
134+
135+
- Secrets resolve on the machine where you run `uc deploy`, not on the cluster. The cluster only receives the final
136+
value.
137+
- Secret values passed as environment variables are stored **unencrypted** as part of the service specification in the
138+
distributed cluster store.
139+
- Docker also stores the resolved environment variables **unencrypted** in each container's configuration at
140+
`/var/lib/docker/containers/<id>/config.v2.json` on the machine running the container. Anyone with `root` access to
141+
that machine or able to run `docker inspect` can read them.
142+
143+
## See also
144+
145+
- [Configs](7-configs.md): Mount non-sensitive configuration files into your containers
146+
- [Compose support matrix](../8-compose-file-reference/1-support-matrix.md): Which Compose features Uncloud supports

‎website/docs/8-compose-file-reference/1-support-matrix.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ If you rely on a specific Compose feature that is not supported by Uncloud, plea
4242
| `ports` | ⚠️ Limited | `mode: host` only, use [`x-ports`](2-extensions.md#x-ports) for HTTP/HTTPS |
4343
| `privileged` | ✅ Supported | Run containers in privileged mode |
4444
| `pull_policy` | ✅ Supported | `always`, `missing`, `never` |
45-
| `secrets` | ❌ Not supported | Use configs or environment variables |
45+
| `secrets` | ⚠️ Limited | Reference secrets in `environment`, see [Secrets](../3-concepts/8-secrets.md). File mounts not supported |
4646
| `security_opt` | ❌ Not supported | |
4747
| `shm_size` | ✅ Supported | Shared memory size |
4848
| `stop_grace_period` | ✅ Supported | Time to wait after SIGTERM before SIGKILL |

‎website/docs/8-compose-file-reference/2-extensions.md‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,23 @@ The hook container also gets `UNCLOUD_HOOK_PRE_DEPLOY=true` environment variable
117117

118118
See [Pre-deploy hooks](../4-guides/1-deployments/5-pre-deploy-hooks.md) for more details, usage examples, and failure
119119
handling.
120+
121+
## `secrets.*.x-command`
122+
123+
Resolve a secret by running a command locally and using its output as the value. Define a secret under the top-level
124+
`secrets` section, then reference it as `secret://<name>` in a service's `environment`:
125+
126+
```yaml
127+
services:
128+
api:
129+
image: myapp
130+
environment:
131+
DB_PASSWORD: secret://db_password
132+
133+
secrets:
134+
db_password:
135+
# Read the secret value from 1Password by running this command locally.
136+
x-command: op read "op://prod/myapp/db_password"
137+
```
138+
139+
See [Secrets](../3-concepts/8-secrets.md) for more details and supported secret sources.

0 commit comments

Comments
 (0)