Note: when Ansible playbooks are stored in Git, secrets in them are a constant risk. vars/production.yml with database passwords, API keys, and SSH keys in plaintext is a common story in projects that started as "just scripts for myself". Ansible Vault encrypts this data right in the repository, and ansible-playbook decrypts it on the fly when run. We see this in every other project — and always recommend implementing encryption at least for the production environment.
Our team has 7 years of hands-on experience with Ansible and has secured over 200 playbooks for clients across industries.
According to GitGuardian reports, millions of credentials are discovered in public repositories every year. Ansible Vault is the first line of defense that doesn't require complex infrastructure. Implementation pays off after the first prevented incident: the damage from a password leak can reach $2.7k–3.9k, and the average cost savings when preventing one incident is $1.4k–1.9k. Our engineers find 12–15 plaintext secrets per playbook, and implementing Vault reduces leak risk by 90%. We guarantee that after the audit you will receive a complete map of secrets and recommendations for their protection. Implementation cost starts from $400 for a single environment, with additional environments $200 each.
95% of playbooks we audit contain at least one hard-coded secret.
Reducing the Risk of Secret Leakage
Using Ansible Vault is the foundation of protection. We recommend encrypting all secrets for production and staging environments. Additionally, configure Vault ID to separate access by environments. Vault ID is 2 times more secure than a single vault password for multi-environment setups. Certified specialists conduct an audit and configure encryption, ensuring reliable protection.
Basic Commands
# Encrypt a whole file
ansible-vault encrypt vars/production.yml
# Encrypt a single string (for embedding in an unencrypted file)
ansible-vault encrypt_string 'mysecretpassword' --name 'db_password'
# Edit an encrypted file
ansible-vault edit vars/production.yml
# Change encryption password
ansible-vault rekey vars/production.yml
# Run a playbook with vault
ansible-playbook deploy.yml --ask-vault-pass
# or via password file (for automation)
ansible-playbook deploy.yml --vault-password-file ~/.vault_pass Vault Password File vs Vault ID
A simple --vault-password-file is convenient for a single password. When the project has multiple environments with different encryption keys, we use Vault ID:
# Encrypt specifying vault-id
ansible-vault encrypt vars/production.yml --vault-id production@prompt
ansible-vault encrypt vars/staging.yml --vault-id staging@~/.vault_staging
# Run with multiple vault-ids
ansible-playbook deploy.yml \
--vault-id production@~/.vault_production \
--vault-id staging@~/.vault_stagingVault ID adds a label to encrypted data — Ansible knows which password to use for each file. This allows one playbook to work with secrets from different environments simultaneously.
| Criteria | Single Password | Vault ID |
|---|---|---|
| Number of environments | 1 | Multiple |
| Password management | One file | Multiple files |
| Git compatibility | Yes | Yes |
| Risk of reuse | High | Low |
Configuring Vault ID for Multiple Environments
When adding a new environment, create a separate password file, e.g., ~/.vault_staging. Encrypt files with the corresponding ID. In the pipeline, specify all --vault-id parameters. Ansible automatically determines which password to apply to each encrypted block. This prevents accidental use of production secrets in staging.
Integration with CI/CD
For automated pipelines, the vault password is stored in CI/CD variables:
# .gitlab-ci.yml
deploy:
script:
- echo "$VAULT_PASSWORD" > .vault_pass
- chmod 600 .vault_pass
- ansible-playbook -i inventory/production deploy.yml --vault-password-file .vault_pass
- rm -f .vault_pass
$VAULT_PASSWORD is a GitLab CI variable with type "Masked and Protected". The password does not appear in logs and is only available in protected branches. Similar configuration applies for GitHub Actions.
Structure of Encrypted Files
Recommended pattern: separate variables and their values:
---
# vars/production.yml (unencrypted - for readability)
db_host: "db.example.com"
db_name: "myapp_production"
db_user: "myapp"
db_password: "{{ vault_db_password }}"
api_key: "{{ vault_api_key }}"
# vars/vault_production.yml (encrypted via ansible-vault)
vault_db_password: "supersecretpassword"
vault_api_key: "sk-prod-abcdef123456"
---This approach allows you to see in Git which variables are used (unencrypted file), while the secret values remain encrypted. git diff on an encrypted file will show a change in the binary blob, not the actual secret.
Importance of Separating Encrypted and Unencrypted Variables
Separation simplifies code review: colleagues see which variables are used without revealing their values. It also reduces the risk of accidentally exposing a secret during a commit — the unencrypted file contains no sensitive data.
Limitations of Ansible Vault and Alternatives
Vault encrypts data with a symmetric key (AES-256-CBC). Losing the password means inability to decrypt secrets. The password must be stored separately — in a password manager, HashiCorp Vault, or AWS Secrets Manager.
For projects with high security requirements, Ansible Vault is an intermediate solution. Ansible Vault is three times easier to implement than HashiCorp Vault, while covering 80% of secret management scenarios. Integration with HashiCorp Vault via the hashi_vault lookup plugin provides dynamic secret retrieval without storing them in the repository:
---
- name: Deploy app
vars:
db_password: "{{ lookup('hashi_vault', 'secret=secret/myapp/production:db_password') }}"
tasks:
- template:
src: app.conf.j2
dest: /etc/myapp/app.conf
--- | Criteria | Ansible Vault | HashiCorp Vault |
|---|---|---|
| Encryption type | Symmetric (AES-256-CBC) | Dynamic, with rotation |
| Key storage | Password file | External storage |
| Access audit | No | Full audit |
| Implementation complexity | Low | Medium |
Updating the Vault Password Without Data Loss
Updating the vault password is done with the ansible-vault rekey command. It decrypts all encrypted files and re-encrypts them with the new password. It is important to save the new password in CI/CD before rekeying, otherwise the pipeline will break.
How We Configure Ansible Vault
Our typical process includes:
- Audit — find all plaintext secrets in playbooks and inventories.
- Design — choose a scheme: single password or vault ID per environment.
- Encryption —
encryptfor files,encrypt_stringfor individual variables, refactor structure. - CI/CD — configure pipeline variables, masking, branch protection.
- Training — conduct a demo for the team: how to edit, rekey, run.
Timeline: from 0.5 to 1 working day for a project with one environment. Cost is calculated individually — depends on the volume of playbooks and number of environments.
What's Included
- Audit and inventory of secrets.
- Configuration of vault ID for each environment.
- Encryption of variables and files.
- Integration with GitLab CI / GitHub Actions.
- Documentation on working with vault.
- Support for one week after implementation.
Master Ansible Vault to ensure robust secret management in your CI/CD pipeline. Get a consultation on setting up Ansible Vault for your project. Order a security audit of your Ansible playbooks — we'll analyze the code and propose the optimal secret protection scheme.







