mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 19:13:34 +00:00
docs(secrets): add new Concepts/Secrets doc about passing sensitive data to services, including x-command extension
This commit is contained in:
@@ -234,3 +234,8 @@ If config changes don't take effect:
|
|||||||
1. Run `uc deploy` to redeploy with new config content
|
1. Run `uc deploy` to redeploy with new config content
|
||||||
2. Check that you're modifying the correct config file
|
2. Check that you're modifying the correct config file
|
||||||
3. Verify the config is properly mounted in the container with `docker exec <service> cat <config-path>` on the remote machine
|
3. Verify the config is properly mounted in the container with `docker exec <service> cat <config-path>` on the remote machine
|
||||||
|
|
||||||
|
## See also
|
||||||
|
|
||||||
|
- [Secrets](8-secrets.md): Pass sensitive values such as passwords, tokens, and keys to your services
|
||||||
|
- [Compose support matrix](../8-compose-file-reference/1-support-matrix.md): Which Compose features Uncloud supports
|
||||||
|
|||||||
@@ -0,0 +1,146 @@
|
|||||||
|
# Secrets
|
||||||
|
|
||||||
|
Secrets allow you to keep **sensitive data** for your services out of your Compose file and version control. This
|
||||||
|
includes database passwords, API tokens, TLS or SSH private keys.
|
||||||
|
|
||||||
|
Uncloud provides an extended support for
|
||||||
|
[Compose secrets](https://github.com/compose-spec/compose-spec/blob/main/09-secrets.md), allowing you to fetch secret
|
||||||
|
values at deploy time from your password manager, a cloud secrets store, or local files.
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
Two things go into your Compose file:
|
||||||
|
|
||||||
|
1. Define a secret in the top-level `secrets` section. This tells Uncloud how to get the secret value.
|
||||||
|
2. Reference that secret value in a service's `environment` using the `secret://<name>` format. This tells Uncloud to
|
||||||
|
resolve the secret and set the environment variable to its value at deploy time.
|
||||||
|
|
||||||
|
```yaml title="compose.yaml"
|
||||||
|
services:
|
||||||
|
api:
|
||||||
|
image: myapp:latest
|
||||||
|
environment:
|
||||||
|
DB_PASSWORD: secret://db_password
|
||||||
|
TLS_KEY: secret://tls_key
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
db_password:
|
||||||
|
# Read the secret value from 1Password by running this command locally.
|
||||||
|
x-command: op read "op://prod/myapp/db_password"
|
||||||
|
tls_key:
|
||||||
|
# Read the secret value from a local file. Do NOT commit this file to the repository.
|
||||||
|
file: ./secrets/tls_key.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
When you run `uc deploy`, it sees each `secret://<name>` reference, resolves the secret on your local machine, and sets
|
||||||
|
the environment variable to its value. For example, it runs the command for `db_password` and reads the file for
|
||||||
|
`tls_key`. The values never land in your Compose file or git. They go straight into the deployment.
|
||||||
|
|
||||||
|
Only secrets you reference in the services that you currently deploy get resolved. A secret referenced in multiple
|
||||||
|
places or by several services resolves only once, and the value is reused.
|
||||||
|
|
||||||
|
Secrets are resolved after building images (if any) and before preparing the deployment plan.
|
||||||
|
|
||||||
|
:::info note
|
||||||
|
|
||||||
|
Secrets can only be used to set environment variables in your services. \
|
||||||
|
Mounting a secret as a file inside the container is not supported yet. For mounting config files,
|
||||||
|
see [Configs](7-configs.md).
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Secret sources
|
||||||
|
|
||||||
|
Uncloud supports multiple sources for fetching secret values. Choose the one for each secret that fits your workflow.
|
||||||
|
|
||||||
|
### Arbitrary command
|
||||||
|
|
||||||
|
The `x-command` extension runs a command and uses its output as the secret value. It's the most versatile option that
|
||||||
|
lets you pull a secret from a system Keychain, password managers, cloud services and secrets stores, or any CLI tool you
|
||||||
|
already use.
|
||||||
|
|
||||||
|
```yaml title="compose.yaml"
|
||||||
|
secrets:
|
||||||
|
# 1Password
|
||||||
|
db_password:
|
||||||
|
x-command: op read "op://prod/myapp/db_password"
|
||||||
|
# Bitwarden
|
||||||
|
api_token:
|
||||||
|
x-command: bw get password api-token
|
||||||
|
# Infisical
|
||||||
|
smtp_password:
|
||||||
|
x-command: infisical secrets get --env=prod SMTP_PASSWORD --plain --silent
|
||||||
|
# AWS Secrets Manager
|
||||||
|
stripe_key:
|
||||||
|
x-command: aws secretsmanager get-secret-value --secret-id stripe --query SecretString --output text
|
||||||
|
```
|
||||||
|
|
||||||
|
The command runs on the machine where you run `uc deploy`, in the same directory as your Compose file and with the same
|
||||||
|
environment. So it uses the CLIs and credentials you are already logged into.
|
||||||
|
|
||||||
|
If your password manager needs you to unlock it or touch a hardware key, the prompt shows up right in your terminal.
|
||||||
|
Uncloud never stores your provider credentials.
|
||||||
|
|
||||||
|
A few details worth knowing:
|
||||||
|
|
||||||
|
- The command runs directly without a shell. To use pipes or variables, call a shell yourself: `sh -c 'cmd1 | cmd2'`.
|
||||||
|
- A single trailing newline is trimmed from the output, because most CLI tools add one. Everything else is kept as is.
|
||||||
|
- The command has 1 minute to finish before `uc` times out and aborts the deployment.
|
||||||
|
|
||||||
|
`x-command` is a short form for `driver: exec`. Use the long form if you prefer to be explicit:
|
||||||
|
|
||||||
|
```yaml title="compose.yaml"
|
||||||
|
secrets:
|
||||||
|
db_password:
|
||||||
|
driver: exec
|
||||||
|
driver_opts:
|
||||||
|
command: op read "op://prod/myapp/db_password"
|
||||||
|
```
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
|
||||||
|
To pull secrets from many providers through a single CLI, or to keep **encrypted secrets in your git repository**,
|
||||||
|
consider [fnox](https://fnox.jdx.dev/). It works with AWS, GCP, Azure, HashiCorp Vault, 1Password, Bitwarden, and more,
|
||||||
|
and prints a plain value you can read with `x-command`:
|
||||||
|
|
||||||
|
```yaml title="compose.yaml"
|
||||||
|
secrets:
|
||||||
|
db_password:
|
||||||
|
x-command: fnox get DB_PASSWORD
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
### File
|
||||||
|
|
||||||
|
Read the content of a local file as the secret value. The file path is relative to the Compose file location.
|
||||||
|
|
||||||
|
```yaml title="compose.yaml"
|
||||||
|
secrets:
|
||||||
|
db_password:
|
||||||
|
file: ./secrets/db_password.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
The file content is used verbatim without trimming any whitespaces.
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
|
||||||
|
Do NOT commit these files to your repository and ensure they are protected with proper file permissions. For example,
|
||||||
|
make the file readable only by your user with `chmod 600 ./secrets/db_password.txt`.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Things to keep in mind
|
||||||
|
|
||||||
|
- Secrets resolve on the machine where you run `uc deploy`, not on the cluster. The cluster only receives the final
|
||||||
|
value.
|
||||||
|
- Secret values passed as environment variables are stored **unencrypted** as part of the service specification in the
|
||||||
|
distributed cluster store.
|
||||||
|
- Docker also stores the resolved environment variables **unencrypted** in each container's configuration at
|
||||||
|
`/var/lib/docker/containers/<id>/config.v2.json` on the machine running the container. Anyone with `root` access to
|
||||||
|
that machine or able to run `docker inspect` can read them.
|
||||||
|
|
||||||
|
## See also
|
||||||
|
|
||||||
|
- [Configs](7-configs.md): Mount non-sensitive configuration files into your containers
|
||||||
|
- [Compose support matrix](../8-compose-file-reference/1-support-matrix.md): Which Compose features Uncloud supports
|
||||||
@@ -42,7 +42,7 @@ If you rely on a specific Compose feature that is not supported by Uncloud, plea
|
|||||||
| `ports` | ⚠️ Limited | `mode: host` only, use [`x-ports`](2-extensions.md#x-ports) for HTTP/HTTPS |
|
| `ports` | ⚠️ Limited | `mode: host` only, use [`x-ports`](2-extensions.md#x-ports) for HTTP/HTTPS |
|
||||||
| `privileged` | ✅ Supported | Run containers in privileged mode |
|
| `privileged` | ✅ Supported | Run containers in privileged mode |
|
||||||
| `pull_policy` | ✅ Supported | `always`, `missing`, `never` |
|
| `pull_policy` | ✅ Supported | `always`, `missing`, `never` |
|
||||||
| `secrets` | ❌ Not supported | Use configs or environment variables |
|
| `secrets` | ⚠️ Limited | Reference secrets in `environment`, see [Secrets](../3-concepts/8-secrets.md). File mounts not supported |
|
||||||
| `security_opt` | ❌ Not supported | |
|
| `security_opt` | ❌ Not supported | |
|
||||||
| `shm_size` | ✅ Supported | Shared memory size |
|
| `shm_size` | ✅ Supported | Shared memory size |
|
||||||
| `stop_grace_period` | ✅ Supported | Time to wait after SIGTERM before SIGKILL |
|
| `stop_grace_period` | ✅ Supported | Time to wait after SIGTERM before SIGKILL |
|
||||||
|
|||||||
@@ -117,3 +117,23 @@ The hook container also gets `UNCLOUD_HOOK_PRE_DEPLOY=true` environment variable
|
|||||||
|
|
||||||
See [Pre-deploy hooks](../4-guides/1-deployments/5-pre-deploy-hooks.md) for more details, usage examples, and failure
|
See [Pre-deploy hooks](../4-guides/1-deployments/5-pre-deploy-hooks.md) for more details, usage examples, and failure
|
||||||
handling.
|
handling.
|
||||||
|
|
||||||
|
## `secrets.*.x-command`
|
||||||
|
|
||||||
|
Resolve a secret by running a command locally and using its output as the value. Define a secret under the top-level
|
||||||
|
`secrets` section, then reference it as `secret://<name>` in a service's `environment`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
api:
|
||||||
|
image: myapp
|
||||||
|
environment:
|
||||||
|
DB_PASSWORD: secret://db_password
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
db_password:
|
||||||
|
# Read the secret value from 1Password by running this command locally.
|
||||||
|
x-command: op read "op://prod/myapp/db_password"
|
||||||
|
```
|
||||||
|
|
||||||
|
See [Secrets](../3-concepts/8-secrets.md) for more details and supported secret sources.
|
||||||
|
|||||||
Reference in New Issue
Block a user