Skip to content

Secret Management

Aleem Isiaka edited this page Apr 2, 2026 · 4 revisions

Secret Management

Store sensitive credentials securely with Heimdal's secret management system.

Table of Contents

Overview

Heimdal stores secrets in your operating system's native keychain, keeping them encrypted and out of your Git repository.

# BAD — secret in plaintext YAML (never do this)
vars:
  api_key: "sk-1234567890abcdef"

# GOOD — store in keychain, reference in templates
# heimdal secret add api_key --value "sk-1234567890abcdef"
# In template: {{ secret:api_key }}

How It Works

Heimdal uses the keyring library to store secret values in the OS-native keychain. A names-only manifest tracks which secrets are required on a given machine — it lists secret names so you can tell what to set up on a new machine, but it contains no values.

Manifest storage:

Bifrost key configured? Manifest location
Yes <dotfiles_path>/.heimdal/secrets_manifest.json.enc (encrypted)
No <dotfiles_path>/.heimdal/secrets_manifest.json (plaintext names only)

The encrypted manifest is re-encrypted with a new manifest subkey whenever the bifrost key changes. See Encryption Key Management.

Secret value storage by platform:

Platform Backend
macOS macOS Keychain
Linux Secret Service (GNOME Keyring, KWallet, etc.)

Secret values are:

  • Encrypted at rest by the OS
  • Never stored in heimdal.yaml or committed to Git
  • Per-machine — each machine must have its secrets set independently
  • Accessible in templates via {{ secret:NAME }}

Commands

heimdal secret add

Add a new secret or update an existing one.

# Provide the value directly
heimdal secret add github_token --value "ghp_xxxxxxxxxxxx"

# Omit --value to enter the secret interactively (hidden input)
heimdal secret add github_token
Enter value: [hidden]

heimdal secret get

Retrieve a secret value.

heimdal secret get github_token
# Prints the value to stdout

# Use in scripts
export GITHUB_TOKEN=$(heimdal secret get github_token)

heimdal secret remove

Delete a secret from the keychain.

heimdal secret remove github_token

heimdal secret list

List secret names only — values are never shown.

heimdal secret list

Output example:

Stored secrets:
  github_token
  openai_api_key
  db_password

Total: 3 secrets

Using Secrets in Templates

Once a secret is stored, reference it in any template with the {{ secret:NAME }} syntax:

Store secrets:

heimdal secret add github_token --value "ghp_xxxxxxxxxxxx"
heimdal secret add db_password --value "supersecret"

Template .env.tmpl:

# Machine: {{ hostname }}
GITHUB_TOKEN={{ secret:github_token }}
DB_HOST={{ db_host }}
DB_PASSWORD={{ secret:db_password }}

heimdal.yaml:

profiles:
  work:
    templates:
      - src: .env.tmpl
        dest: ~/.env
        vars:
          db_host: prod-db.company.com

Apply:

heimdal apply

The rendered .env contains the actual secret values. This file should not be committed:

# .gitignore
.env
.aws/credentials
.ssh/config

Example: Git Config with Signing Key

heimdal secret add git_signing_key --value "ABC123"

.gitconfig.tmpl:

[user]
    name = {{ name }}
    email = {{ email }}
    signingkey = {{ secret:git_signing_key }}

[commit]
    gpgsign = true

Example: AWS Credentials

heimdal secret add aws_access_key_id --value "AKIAIOSFODNN7EXAMPLE"
heimdal secret add aws_secret_access_key --value "wJalrXUtnFEMI/..."

.aws/credentials.tmpl:

[default]
aws_access_key_id = {{ secret:aws_access_key_id }}
aws_secret_access_key = {{ secret:aws_secret_access_key }}
region = {{ aws_region }}

Security Model

What Heimdal does:

  • Stores secret values in the OS keychain (encrypted at rest, OS-managed access control)
  • Keeps only a names manifest in Git — no values ever
  • Retrieves secrets at render time; they are never cached on disk by Heimdal

What Heimdal does NOT do:

  • Sync secret values across machines — you must set secrets on each machine independently
  • Encrypt dotfiles themselves — only secret values are in the keychain
  • Protect rendered output files — once .env is rendered, it contains plaintext values; protect it with file permissions
  • Provide secret rotation — update secrets manually with heimdal secret add

Platform-Specific Notes

macOS

Backend: macOS Keychain

No setup required. On first access, macOS may prompt for your login password. Click "Always Allow" to avoid repeated prompts.

You can view Heimdal entries in Keychain Access (search for heimdal).

Linux

Backend: Secret Service (libsecret)

Supported keychains: GNOME Keyring, KWallet

Install if needed:

# Ubuntu/Debian
sudo apt-get install gnome-keyring libsecret-tools

# Fedora
sudo dnf install gnome-keyring

# Arch
sudo pacman -S gnome-keyring

Start the daemon:

gnome-keyring-daemon --start
# Or set up automatic start via your desktop session

On headless servers without a desktop environment, consider a fallback like pass or a different secrets strategy.

Best Practices

Use Descriptive Names

# Clear and descriptive
heimdal secret add github_personal_token --value "..."
heimdal secret add openai_api_key --value "..."
heimdal secret add work_vpn_password --value "..."

# Avoid
heimdal secret add key1 --value "..."
heimdal secret add token --value "..."

Use Interactive Input to Avoid Shell History Exposure

# Secret appears in shell history
heimdal secret add api_key --value "sk-1234567890"

# Better: interactive prompt (hidden input, not in history)
heimdal secret add api_key
Enter value: [hidden]

Or disable history temporarily:

set +o history
heimdal secret add api_key --value "sk-1234567890"
set -o history

Document Required Secrets

Add a comment in your dotfiles README listing which secrets need to be set on a new machine:

## Required Secrets (set on each machine)

heimdal secret add github_token
heimdal secret add openai_api_key
heimdal secret add db_password

Protect Rendered Output Files

After heimdal apply, rendered files that contain secrets should have restricted permissions:

chmod 600 ~/.env
chmod 600 ~/.ssh/config
chmod 600 ~/.aws/credentials

Add Rendered Files to .gitignore

.env
.aws/credentials
.ssh/config

Troubleshooting

Cannot Store Secret on Linux

Problem: Failed to store secret. Note: On Linux, you may need a running keyring.

Fix:

sudo apt-get install gnome-keyring
gnome-keyring-daemon --start
export $(gnome-keyring-daemon --start)

Add the export line to ~/.bashrc or ~/.profile to start the daemon on login.

Secret Not Found

Problem: Failed to retrieve secret 'api_key'

Fix:

# Check if the secret is listed
heimdal secret list

# If missing, add it
heimdal secret add api_key --value "your_value"

macOS Password Prompt on Every Access

This is normal security behavior. Click "Always Allow" in the Keychain Access prompt to grant permanent access.

Template Renders {{ secret:NAME }} as Literal Text

The secret is not set on this machine. Fix:

heimdal secret add NAME --value "..."
heimdal apply

Next Steps

Related Commands

heimdal secret add <name> [--value <val>]   # Add/update a secret
heimdal secret get <name>                    # Retrieve a secret value
heimdal secret list                          # List secret names
heimdal secret remove <name>                 # Delete a secret

heimdal template preview <src>              # Preview template output
heimdal template variables                  # Show available variables
heimdal apply                               # Render templates and apply

Clone this wiki locally