Secrets Management
Muvee provides a built-in Secrets store for safely managing passwords, API tokens, and SSH private keys. Secrets are encrypted at rest using AES-256-GCM and are injected into deployments at runtime.
How It Works
User creates Secret → encrypted in DB (AES-256-GCM)
↓
User binds Secret to Project (env_var_name, use_for_git, use_for_build, build_secret_id)
↓
On deploy, scheduler decrypts secrets and:
• SSH key (use_for_git=true) → builder uses for git clone
• Any secret with use_for_build=true + build_secret_id → builder passes docker buildx --secret id=build_secret_id
• Any secret with env_var_name → injected as docker run -e KEY=VALUE
Secrets are write-only — their values cannot be retrieved after creation. To rotate a secret, delete the old one and create a new one with the same name, then re-bind it to your projects.
Prerequisites
Set the SECRET_ENCRYPTION_KEY environment variable on the control plane before creating any secrets. This must be a 64-character hex string (32 bytes):
# Generate a secure key
openssl rand -hex 32
# e.g. a3f4e1b2c8d7...
# Set it in your environment / .env file
SECRET_ENCRYPTION_KEY=a3f4e1b2c8d7...
If SECRET_ENCRYPTION_KEY is not set, secret creation will be disabled. Back up this key — losing it makes all encrypted secrets unrecoverable.
Secret Types
| Type | Use case | Display |
|---|---|---|
password | API tokens, database passwords, generic credentials | Write-only (value never shown) |
ssh_key | PEM-format SSH private keys for cloning private git repositories | Write-only (value never shown) |
api_key | API keys / provider tokens where a masked fingerprint helps identify which key is which | Shows first 4 + last 4 characters (e.g. sk-1****wxyz) |
env_var | Non-sensitive configuration (public endpoints, feature flags) that benefits from central management | Shows full plaintext in the secrets list |
registry | Pull credentials for a private container registry (e.g. ghcr.io) so compose projects can pull private images | Write-only (token never shown); registry address + username are shown |
Only use env_var for values that are safe to view in the UI. Anything sensitive should use password or api_key.
Private registry credentials
A registry secret holds a login for a private container registry. Unlike other
secret types it is not bound per-project: every compose project you own
automatically uses all of your registry secrets when pulling images at
deploy time. This is how a docker-compose project pulls a private image such as
ghcr.io/your-org/your-app:latest.
The secret's value is the registry password / token; registry address
(e.g. ghcr.io) and login username are stored alongside it. At deploy time
the agent writes a temporary, per-deploy docker config with these credentials —
they never land in the shared agent docker config and never leak across tenants.
Only the compose deploy path uses registry credentials. Single-container (Dockerfile/image) projects are built by Muvee and pulled from Muvee's own registry, which is already authenticated.
Managing Secrets in the UI
Navigate to Secrets in the sidebar to:
- View all your secrets (names, types, and — for
api_key/env_var— their preview) - Create a new secret (one of the four types above)
- Delete a secret
Binding Secrets to a Project
Open a project and click the Secrets tab to:
- Attach / detach secrets from the project
- Set the environment variable name each secret is injected as (e.g.
GITHUB_TOKEN,DATABASE_PASSWORD) - For SSH key secrets, enable "Use for git clone" — this makes the builder use the key when cloning the git repository
- Enable "Use for docker build secret" and set Build Secret ID (e.g.
github_token) so Dockerfile can read/run/secrets/github_tokenduring build
Environment variable injection takes effect on the next deployment. Redeploy the project after updating secret bindings.
Managing Secrets via CLI
Secrets
# List secrets (values never returned)
muveectl secrets list
# Create a password secret
muveectl secrets create --name GITHUB_TOKEN --type password --value ghp_xxxxx
# Create an SSH key from a file
muveectl secrets create --name DEPLOY_KEY --type ssh_key --value-file ~/.ssh/id_ed25519
# Create a private registry pull credential (applies to all your compose projects)
muveectl secrets create --name GHCR_PULL --type registry \
--registry-addr ghcr.io --registry-username my-gh-user --value ghp_xxxxx
# Delete a secret
muveectl secrets delete SECRET_ID
Project Bindings
# List secrets bound to a project
muveectl projects secrets PROJECT_ID
# Bind a secret as an environment variable
muveectl projects bind-secret PROJECT_ID \
--secret-id SECRET_ID \
--env-var GITHUB_TOKEN
# Bind an SSH key secret for git clone
muveectl projects bind-secret PROJECT_ID \
--secret-id SSH_KEY_SECRET_ID \
--use-for-git
# Bind a secret for docker buildx secret mount
muveectl projects bind-secret PROJECT_ID \
--secret-id SECRET_ID \
--use-for-build \
--build-secret-id github_token
# Remove a secret binding
muveectl projects unbind-secret PROJECT_ID SECRET_ID
Private Git Repository Workflows
Muvee supports two methods for cloning private repositories. Choose the one that fits your git provider.
Method A: GitHub / GitLab Fine-Grained Access Token (HTTPS) — Recommended
GitHub now recommends fine-grained personal access tokens (PAT) over SSH deploy keys for repository access.
-
Generate a fine-grained PAT in GitHub → Settings → Developer settings → Fine-grained tokens. Grant it Contents: Read-only permission on the target repository.
-
Create a
passwordsecret in Muvee with the token value:muveectl secrets create --name GITHUB_TOKEN --type password --value github_pat_xxxx -
Bind the secret to your project, enabling HTTPS git auth:
muveectl projects bind-secret PROJECT_ID \
--secret-id SECRET_ID \
--use-for-git \
--git-username x-access-tokenThe builder rewrites the git URL to
https://x-access-token:TOKEN@github.com/...before cloning.Provider --git-usernamevalueGitHub x-access-token(default)GitLab oauth2Bitbucket your Bitbucket username Azure DevOps AzureDevOps -
Trigger a deployment — no further configuration needed.
You can also inject the same token as an environment variable for use at runtime (e.g. to push images or interact with the GitHub API):
muveectl projects bind-secret PROJECT_ID \
--secret-id SECRET_ID \
--env-var GITHUB_TOKEN \
--use-for-git \
--git-username x-access-token
Method B: SSH Deploy Key
Use this method when your provider requires SSH, or when you prefer key-based authentication.
- Generate an SSH key pair:
ssh-keygen -t ed25519 -f deploy_key -N "" - Add
deploy_key.pubas a Deploy Key in your repository settings (GitHub: Settings → Deploy keys). - Create an SSH key secret in Muvee:
muveectl secrets create --name DEPLOY_KEY --type ssh_key --value-file deploy_key - Bind it to the project with git clone enabled:
muveectl projects bind-secret PROJECT_ID \
--secret-id SECRET_ID \
--use-for-git - Trigger a deployment — the builder uses the key via
GIT_SSH_COMMAND.
Security Notes
- Secret values are encrypted with AES-256-GCM before being stored in the database.
- Decrypted values are included in task payloads sent from the control plane to agent nodes over the internal network. Ensure this network is trusted.
- Secrets are scoped to the user who created them. Other users cannot see or use your secrets unless you share access.
Build-Time Secret Example (Private Go Modules)
When your repository needs private Go modules, you can bind a PAT secret for build-time use:
# 1) Create PAT secret
muveectl secrets create --name GITHUB_TOKEN --type password --value github_pat_xxxx
# 2) Bind for docker build secret
muveectl projects bind-secret PROJECT_ID \
--secret-id SECRET_ID \
--use-for-build \
--build-secret-id github_token
# 3) Deploy
muveectl projects deploy PROJECT_ID
In your Dockerfile:
# syntax=docker/dockerfile:1.7
RUN \
TOKEN="$(cat /run/secrets/github_token)" && \
git config --global url."https://x-access-token:${TOKEN}@github.com/".insteadOf "https://github.com/" && \
GOPRIVATE=github.com/your-org/* GONOSUMDB=github.com/your-org/* \
go mod download