Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Ansible Vault for Secrets

By Kokil Thapa | Last reviewed: August 2026

Storing database passwords and API keys in plain-text YAML files is a security liability that eventually causes a breach or an embarrassing commit history cleanup. Ansible Vault for secrets provides native AES-256 encryption directly within your configuration management workflow, eliminating the need for external secret stores on smaller infrastructure. When configured correctly, it allows you to version-control sensitive data safely while keeping decryption keys out of your repository. This guide covers the practical implementation patterns I rely on for production deployments.

For teams managing CI/CD pipeline setups, integrating vault into your automation prevents credential leakage across staging and production environments. While tools like HashiCorp Vault or AWS Secrets Manager excel at dynamic secret generation, Ansible Vault remains the most pragmatic choice for static configuration where infrastructure complexity doesn't justify additional operational overhead. In my experience working on production Laravel applications and legal-tech portals, this balance of security and simplicity reduces deployment friction significantly.

How do you configure Ansible Vault for secrets in multi-environment projects?

The most common mistake engineers make with Ansible Vault for secrets is encrypting entire playbooks or creating a single monolithic secrets.yml file. This approach breaks down immediately when you need different credentials for staging, production, and local development. The sustainable pattern is directory-based separation combined with inventory-specific variable loading.

Directory structure for environment isolation

Organize encrypted variables by host group or environment rather than by secret type. This ensures that a developer working on staging cannot accidentally decrypt or modify production credentials, even if they possess the staging vault password.

inventory/
├── production/
│   ├── hosts
│   └── group_vars/
│       └── webservers/
│           ├── vars.yml          # Non-sensitive config (plaintext)
│           └── vault.yml         # Encrypted secrets only
├── staging/
│   ├── hosts
│   └── group_vars/
│       └── webservers/
│           ├── vars.yml
│           └── vault.yml
└── vault-pass-production.txt     # NEVER commit this file

In this structure, vault.yml contains only sensitive values. Your vars.yml remains readable plaintext for non-sensitive configuration like domain names or feature flags. Ansible automatically merges these files when targeting the webservers group, giving you clean separation without complex include statements.

Multi-Environment Vault StructureStaging Environmentgroup_vars/webservers/vars.ymlvault.yml (Encrypted)vault-pass-staging.txtProduction Environmentgroup_vars/webservers/vars.ymlvault.yml (Encrypted)vault-pass-prod.txtIsolated Keys
Environment isolation prevents staging credentials from accessing production secrets in Ansible Vault for secrets workflows

Naming conventions that prevent merge conflicts

When multiple developers work on the same inventory group, naming collisions in vault files cause painful merge conflicts. Prefix every vault variable with vault_ to distinguish encrypted values from plaintext references:

# inventory/production/group_vars/webservers/vault.yml
vault_db_password: "super-secret-production-password"
vault_stripe_api_key: "sk_live_..."
vault_mail_smtp_password: "..."

# inventory/production/group_vars/webservers/vars.yml
db_user: "app_production"
db_name: "laravel_prod"
db_password: "{{ vault_db_password }}"  # References encrypted value

This indirection means you can restructure plaintext configuration without touching encrypted content. It also makes grep searches trivial when auditing which secrets are actually used versus orphaned vault entries.

What are the essential Ansible Vault commands for daily operations?

Memorizing a core set of commands eliminates the friction that leads developers to bypass encryption entirely. These are the operations I perform weekly across client projects, from legal-tech portals to eCommerce platforms.

  • Create new encrypted file: ansible-vault create inventory/production/group_vars/webservers/vault.yml — opens your editor after prompting for a password. Never use echo piping as it exposes secrets in shell history.
  • Edit existing encrypted file: ansible-vault edit inventory/production/group_vars/webservers/vault.yml — decrypts to a temporary file, opens your editor, re-encrypts on save. The temp file is securely deleted even if your editor crashes.
  • View without editing: ansible-vault view inventory/production/group_vars/webservers/vault.yml — outputs decrypted content to stdout. Useful for quick verification without risking accidental modifications.
  • Encrypt existing plaintext file: ansible-vault encrypt inventory/staging/group_vars/webservers/vault.yml — converts an already-created file. Always verify with view afterward to confirm no corruption occurred.
  • Decrypt permanently: ansible-vault decrypt inventory/production/group_vars/webservers/vault.yml — removes encryption. Only use when migrating to a different secrets manager or decommissioning infrastructure.
  • Rekey (change password): ansible-vault rekey inventory/production/group_vars/webservers/vault.yml — prompts for old password then new password. Critical when team members leave or after suspected compromise.

A frequent gotcha: if you run ansible-vault encrypt on a file that's already encrypted, Ansible silently double-encrypts it. Subsequent operations fail with confusing YAML parse errors. Always check file headers first — encrypted files begin with $ANSIBLE_VAULT;1.1;AES256.

Using password files for automation

Interactive password prompts break CI/CD pipelines and scripted deployments. Store the vault password in a file with restrictive permissions, then reference it explicitly:

# Create password file (one-time setup)
echo "your-strong-vault-password" > ~/.vault-pass-production
chmod 600 ~/.vault-pass-production

# Use in commands
ansible-playbook deploy.yml --vault-password-file ~/.vault-pass-production

# Or set in ansible.cfg for convenience
[defaults]
vault_password_file = ~/.vault-pass-production

Never commit password files to Git. Add *vault-pass* and .vault-pass to your global .gitignore. For shared team environments, distribute password files through a separate secure channel like Bitwarden or 1Password, not Slack or email.

How does Ansible Vault for secrets integrate with CI/CD pipelines?

Automation is where vault practices either succeed or collapse under operational friction. On projects using Deployer 7 with GitLab CI, I've found that environment-variable-based password injection provides the cleanest integration without exposing secrets in pipeline logs or artifact metadata.

Vault Integration in CI/CD PipelineGit PushTriggers PipelineLint & TestNo Decryption NeededDeploy Stage$VAULT_PASS env varinjected at runtimeProductionSecrets AppliedSecurity BoundariesVault password never in repoDecryption happens only on runnerLogs mask decrypted values
Secure CI/CD integration keeps Ansible Vault for secrets passwords out of repositories and pipeline artifacts

GitLab CI configuration example

Store your vault password as a masked, protected CI/CD variable named ANSIBLE_VAULT_PASS. Masking prevents accidental exposure in job logs; protection restricts access to protected branches only.

# .gitlab-ci.yml
deploy_production:
  stage: deploy
  only:
    - main
  variables:
    ANSIBLE_VAULT_PASS_FILE: "/tmp/.vault-pass"
  before_script:
    - echo "$ANSIBLE_VAULT_PASS" > /tmp/.vault-pass
    - chmod 600 /tmp/.vault-pass
  script:
    - ansible-playbook deploy.yml 
        --vault-password-file $ANSIBLE_VAULT_PASS_FILE 
        -i inventory/production/
  after_script:
    - rm -f /tmp/.vault-pass  # Clean up even on failure

The after_script block executes regardless of job success or failure, ensuring the password file doesn't persist on shared runners. For self-hosted runners with persistent filesystems, this cleanup is non-negotiable.

Handling multiple vault passwords in CI

When staging and production use different vault passwords (as they should), leverage Ansible's vault ID feature introduced in 2.4 and stabilized through 2026:

# Encrypt with labeled vault IDs
ansible-vault encrypt --vault-id staging@prompt inventory/staging/group_vars/webservers/vault.yml
ansible-vault encrypt --vault-id production@prompt inventory/production/group_vars/webservers/vault.yml

# Decrypt with specific ID in CI
ansible-playbook deploy.yml \
  --vault-id staging@~/.vault-pass-staging \
  --vault-id production@~/.vault-pass-production \
  -i inventory/production/

Vault IDs eliminate ambiguity when playbooks span multiple environments. Without them, Ansible tries every known password against every encrypted file, causing performance degradation and confusing error messages when passwords don't match.

How does Ansible Vault compare to external secrets managers in 2026?

Choosing between Ansible Vault for secrets and dedicated tools like HashiCorp Vault, AWS Secrets Manager, or Doppler depends on team size, compliance requirements, and operational maturity. Neither is universally superior — each solves different problems.

CriteriaAnsible VaultHashiCorp Vault / AWS SM
Setup complexityZero infrastructure; CLI-onlyRequires HA cluster or managed service
Dynamic secretsNot supported; static encryption onlyNative support for DB creds, PKI, tokens
Audit loggingNone; relies on Git historyComprehensive access logs and policies
Team scale sweet spot1–10 engineers, <50 secrets10+ engineers, compliance-mandated
Rotation automationManual rekey + redeployAutomatic rotation with zero downtime
Cost (NPR/month)Free (included with Ansible)Rs 5,000–50,000+ depending on tier
Offline capabilityFull functionality without networkRequires API connectivity

For Nepal-based SMEs and legal-tech projects where budget sensitivity is real and compliance frameworks are still maturing, Ansible Vault for secrets delivers 80% of the security benefit at zero marginal cost. I typically recommend graduating to HashiCorp Vault only when dynamic database credentials become necessary or when audit requirements exceed what Git commit messages can provide.

Secrets Manager Decision TreeNeed Dynamic Secrets?NoYesTeam < 10 Engineers?HashiCorp Vault /AWS Secrets ManagerYesNoAnsible VaultBest fit for static secretsConsider SOPS orDoppler as middle ground
Decision framework for selecting Ansible Vault for secrets based on team size and secret dynamism requirements

What security pitfalls must you avoid when using Ansible Vault?

Encryption alone doesn't guarantee security. Misconfigurations undermine the protection Ansible Vault for secrets provides. These are the failure modes I audit for during server security hardening engagements.

Plaintext leaks in command history and process lists

Running ansible-vault encrypt_string "my-password" interactively records the secret in your shell history. Similarly, passing passwords via --extra-vars exposes them in ps aux output on shared systems. Always use stdin redirection or prompt mode:

# SAFE: Password prompted, not in history or process list
ansible-vault encrypt_string --name 'db_password' --stdin-name 'db_password'

# UNSAFE: Visible in history and /proc
ansible-vault encrypt_string "my-password" --name 'db_password'

Configure your shell to ignore lines starting with spaces (HISTCONTROL=ignorespace in bash) as an additional defense layer for ad-hoc operations.

Committing decrypted files accidentally

After running ansible-vault view or decrypt, it's easy to forget re-encryption before committing. Add a pre-commit hook that fails if unencrypted vault files are staged:

#!/bin/bash
# .git/hooks/pre-commit
for file in $(git diff --cached --name-only | grep -E 'vault\.yml$'); do
  if ! head -1 "$file" | grep -q '^\$ANSIBLE_VAULT'; then
    echo "ERROR: $file appears to be decrypted. Re-encrypt before committing."
    exit 1
  fi
done

This catches mistakes before they enter version history. Remember that removing secrets from Git history requires git filter-repo or BFG Repo-Cleaner — simple deletion leaves traces in packfiles indefinitely.

Weak vault passwords and shared credentials

Your vault password protects everything inside. A weak password or one shared across environments defeats the purpose. Generate strong passwords with openssl rand -base64 32 and rotate them quarterly or on personnel changes. For teams larger than five people, consider individual vault IDs with per-developer passwords, though this adds coordination overhead that may justify migrating to an external secrets manager instead.

Implementing Ansible Vault for secrets securely in production

Ansible Vault for secrets remains the most pragmatic encryption solution for small-to-medium infrastructure where operational simplicity matters as much as cryptographic strength. Start with environment-separated vault files, enforce naming conventions that prevent merge conflicts, integrate cleanly with your CI/CD pipeline using masked environment variables, and audit regularly for plaintext leakage vectors. When your team outgrows static encryption or faces compliance mandates requiring audit trails, graduate to HashiCorp Vault or AWS Secrets Manager — but don't adopt complexity before you've exhausted what disciplined vault usage provides. If you're evaluating secrets management for a production system and want practical guidance grounded in real deployment experience, reach out to discuss your specific infrastructure needs.

Frequently Asked Questions

Ansible Vault encrypts sensitive data like database passwords, API keys, and SSH private keys within your automation codebase. It allows you to commit secrets safely to Git without exposing plaintext credentials, ensuring encrypted values are only decrypted at runtime using a secure password or key file during playbook execution.

Run ansible-vault create secrets.yml to open an editor for a new encrypted file. You will be prompted to set a vault password immediately. Save and close the editor to write the AES-256 encrypted content to disk, which can then be safely committed to version control alongside your playbooks.

Yes. Use vault IDs to assign unique passwords per environment. Create files with ansible-vault create --vault-id staging@prompt secrets-staging.yml and reference them in playbooks using --vault-id staging@secrets-staging-pass.txt. This isolates compromise risk so leaking one environment's password does not expose production credentials.

Ansible Vault uses AES-256 encryption which is cryptographically strong, but security depends entirely on how you manage the vault password. In my experience managing deployments for Nepal-based clients, Vault works well for small teams, but larger organizations should integrate with HashiCorp Vault or AWS Secrets Manager for dynamic secret rotation and audit logging that static files cannot provide.

Use ansible-vault edit secrets.yml to decrypt the file temporarily into a secure memory buffer, open it in your default editor, and re-encrypt upon saving. Never decrypt to disk permanently with ansible-vault decrypt unless absolutely necessary, as this leaves plaintext secrets vulnerable to accidental commits or unauthorized access on shared development machines.

There is no recovery mechanism. The encrypted data is permanently inaccessible without the original password. I always store vault passwords in a separate password manager like Bitwarden or 1Password, never in the same repository as the encrypted files. For team projects, share the password securely through encrypted channels, not email or chat.

Store the vault password as a masked CI/CD variable named ANSIBLE_VAULT_PASS. In your pipeline, write it to a temporary file before running ansible-playbook --vault-password-file /tmp/vault-pass.yml. Delete the file immediately after execution. On projects I have deployed via GitLab CI, this pattern prevents secrets from appearing in job logs while keeping deployments fully automated.

Yes. Use ansible-vault encrypt_string to encrypt single values inline within unencrypted YAML files. This is useful when most of your configuration is non-sensitive but contains a few passwords. The encrypted string includes a header marking it as vault-encrypted, allowing Ansible to selectively decrypt only those values during playbook execution while leaving the rest readable.

Ansible Vault integrates natively with Ansible playbooks but lacks cloud KMS integration. SOPS supports AWS KMS, GCP KMS, and Azure Key Vault for envelope encryption, enabling automatic key rotation and IAM-based access control. For Nepal-based projects on modest budgets, Ansible Vault suffices. For multi-cloud infrastructure requiring compliance auditing, SOPS provides stronger key management despite added complexity.

Set permissions to 0600 so only the owner can read the file. Run chmod 600 /path/to/vault-pass.txt and verify ownership matches the deployment user. In production environments I manage on Ubuntu servers, I also ensure the file resides outside the web root and application directory to prevent accidental exposure through misconfigured web servers or backup scripts that might include application files.

Run ansible-vault rekey secrets.yml to change the password without decrypting to disk. You will be prompted for the old password once and the new password twice. Update all references in CI/CD variables and team password managers simultaneously. Test decryption immediately after rotation. Schedule rotations quarterly or whenever team members with vault access leave the project to limit exposure window.

Yes, but it is inefficient. Ansible Vault encodes binary content as base64 text, increasing file size by roughly 33 percent. For SSL certificates and private keys on production servers I manage, I prefer copying them via Ansible copy module with encrypted source files or fetching from a dedicated secrets backend at runtime rather than storing large binaries in vault-encrypted repositories.

Common causes include wrong vault password, mismatched vault ID, or corrupted encrypted file. Verify the password works with ansible-vault view secrets.yml first. Check that --vault-id labels match those used during encryption. Ensure no manual edits corrupted the file structure. In my experience, most failures stem from copy-paste errors when transferring passwords between environments or outdated CI/CD variables after rotation.

Never. Committing vault passwords defeats the purpose of encryption. Add vault password files to .gitignore immediately upon creation. Distribute passwords through secure channels like password managers or encrypted messaging. On client projects, I maintain a separate encrypted document listing which vault IDs exist and where authorized team members can obtain passwords, without storing actual passwords in any tracked file.

Ansible Vault itself is free and included in core Ansible. Implementation costs involve developer time for setup, typically four to eight hours for initial configuration and team training. For Nepal-based small businesses, this translates to roughly NPR 20,000 to 40,000 (USD 150 to 300) as a one-time investment. Ongoing costs are negligible unless integrating external secret backends requiring paid subscriptions.

Share this article

Quick Contact Options
Choose how you want to connect me: