Ansible Vaultは、Playbookやインベントリに含まれるパスワード・APIキーを暗号化し、Gitに置ける状態にするAnsible標準の機能です。この記事では、2026年10月時点のansible-core 2.21系を前提に、ansible-vaultコマンドでのファイル暗号化、encrypt_stringによる変数単位の暗号化、vault-idで開発と本番のパスワードを分ける運用、CIからパスワードを渡して実行する設定までを、コピーして試せるコードで解説します。Ansible Vaultで足りる環境と、外部のシークレット管理に移すべき環境の線引きも示します。
まとめ|機密値はvault.ymlに分けて暗号化しvault-idで環境ごとに鍵を分ける
機密値だけをvault.ymlに集め、ファイルごとansible-vault encryptで暗号化します。参照名は平文のvars.ymlに残し、Gitで差分を読める状態にしておきます。値を1つだけ足したい場面ではansible-vault encrypt_stringを使いますが、変数単位の暗号化はパスワードを変更できないため、長く使う値はファイル暗号化に寄せてください。
パスワードは--vault-id dev@...と--vault-id prod@...のように環境ごとに分け、開発者が本番の値を復号できない構成にします。CIでは、パスワードをコマンドラインに書かず、秘密変数を読んで標準出力に返すスクリプトを--vault-idの取得元に指定します。
Ansible Vaultが守る範囲と暗号化の仕組みを2026年10月時点で整理
Ansibleが対象サーバーへ手順を流す仕組みはAnsibleとは?エージェントレスの仕組みとメリット・デメリットで解説しています。Vaultは、その手順に渡す秘密の値を、保存しているあいだだけ読めなくする仕組みです。
保存時の暗号化に限られる保護範囲とPlaybookの復号後に値が漏れる経路
Ansible Vaultの公式ガイドは、Vaultが守るのは保存されたデータ(data at rest)だけだと警告しています。Playbookの実行中に復号された値を漏らさない責任は、Playbookやプラグインを書く側にあります。
漏れる経路は主に3つです。1つ目は-v付きで実行したときのタスク結果の表示、2つ目はdebugモジュールでの変数の出力、3つ目はcopyやtemplateで配った先のファイルです。公式ガイドには、暗号化したファイルをcopy・template・unarchive・script・assembleのsrcに渡すと、対象ホスト上では復号された状態で置かれると書かれています。配布先で読めるようにするための仕様なので、配布先のファイル権限はmodeで絞ります。
暗号化ファイルのヘッダー形式とAES256・PBKDF2による鍵導出の中身
暗号化済みデータの利用ガイドによると、暗号化したファイルはUTF-8のテキストで、先頭行にセミコロン区切りのヘッダーが付きます。
$ANSIBLE_VAULT;1.1;AES256 … vault-idを付けずに暗号化した場合
$ANSIBLE_VAULT;1.2;AES256;prod … vault-id「prod」で暗号化した場合
3061626364... … 以降は80文字ごとに折り返した16進の暗号文
ヘッダーは「形式ID・版・暗号方式・vault-idのラベル」の最大4要素で、暗号方式はAES256だけが使えます。鍵はパスワードとソルトからPBKDF2(SHA256・10,000回)で導出され、AES256をCTRモードで使い、改ざん検知にHMAC-SHA256を付けます。ラベルは平文で残るため、ラベルに秘密の情報を含めてはいけません。
ansible-vaultコマンドでファイル全体を暗号化・編集・確認する手順
PyPIのansible-coreは2.21.5(2026年10月5日公開)が最新で、Python 3.12以上を要求します。ansible-vaultはansible-coreに含まれるので、追加のインストールは要りません。
create・encrypt・view・edit・decryptの基本コマンドと動き
# 新しい暗号化ファイルを作る($EDITORが開く。既定はvi)
ansible-vault create group_vars/prod/vault.yml
# 既存の平文ファイルを暗号化する(複数指定可)
ansible-vault encrypt group_vars/dev/vault.yml group_vars/stg/vault.yml
# 中身を表示するだけ・一時的に復号して編集する
ansible-vault view group_vars/prod/vault.yml
ansible-vault edit group_vars/prod/vault.yml
# 恒久的に平文へ戻す(戻したファイルをそのままコミットしないこと)
ansible-vault decrypt group_vars/dev/vault.yml
ansible-vaultのコマンドリファレンスにあるとおり、どのサブコマンドもパスワードの指定に--vault-id・--vault-password-file・-J(--ask-vault-pass)を受け付けます。何も指定しなければ、パスワードを対話で入力する方式です。editは一時ファイルに復号して開くため、vimのスワップファイルやバックアップに平文が残らないよう、公式ガイドが示すエディタ設定を入れておきます。
vars.ymlとvault.ymlに分けて平文の参照名を残す構成
ファイルを丸ごと暗号化すると、どの変数が定義されているかをGitの差分で読めなくなります。そこで、機密値にはvault_の接頭辞を付けてvault.ymlに置き、平文のvars.ymlからその名前を参照させます。
# group_vars/prod/vars.yml(平文・Gitで差分を読める)
db_user: app
db_password: "{{ vault_db_password }}"
api_token: "{{ vault_api_token }}"
# group_vars/prod/vault.yml(ansible-vault encrypt で暗号化する)
vault_db_password: "S3cure-Example"
vault_api_token: "tok_example"
この形にすると、grep db_passwordで使用箇所を追え、値だけが暗号化されたままになります。暗号化の公式ガイドによると、Ansibleが暗号化ファイルを読み込む際の復号対象は、毎回ファイル全体です。タスクファイルまで暗号化すると読みにくくなるので、暗号化は変数ファイルに限ります。Playbook側の書き方はAnsible Playbookの書き方と実行手順を参照してください。
encrypt_stringで変数1つだけを暗号化してYAMLに埋め込む手順
平文のvars.ymlに、暗号化した値を1つだけ直接書きたい場面があります。このときはansible-vault encrypt_stringで、YAMLにそのまま貼れる形の出力を作ります。
–stdin-nameで値をシェル履歴に残さず暗号化するコマンド
# 値を引数に書く方法はシェル履歴に残るため、検証以外では使わない
ansible-vault encrypt_string --vault-id prod@prompt --stdin-name 'vault_smtp_password'
# 値を入力したら Enter を押さずに Ctrl+D で入力を終える
# 出力(そのまま vars.yml に貼る)
vault_smtp_password: !vault |
$ANSIBLE_VAULT;1.2;AES256;prod
6131346436633566...
公式ガイドは、入力の最後にEnterを押すと改行まで暗号化されると注意しています。改行が混ざることも、認証で「パスワードが違う」と弾かれる原因の1つです。暗号化した値の中身は、次のコマンドで確認できます。
ansible localhost -m ansible.builtin.debug -a var=vault_smtp_password \
-e "@group_vars/prod/vars.yml" --vault-id prod@prompt
変数単位の暗号化とファイル暗号化の違いをパスワード変更と差分の比較表で確認
| 項目 | encrypt_string | ファイル暗号化 |
|---|---|---|
| 差分の読みやすさ | 変数名が見える | 全体が読めない |
| パスワード変更 | rekey不可 | rekeyで一括変更 |
| 暗号化できる物 | 変数の値だけ | タスクや任意のファイル |
| 向いている場面 | 値を1つ足すとき | 長く使う機密値 |
差が大きいのはパスワード変更です。公式ガイドには、暗号化した変数はrekeyできないと明記されています。担当者の退職などでパスワードを替えるとき、変数単位の暗号化はすべて手で作り直す必要があります。値が10を超えるようなら、最初からvault.ymlにまとめてください。
vault-idで開発と本番のVaultパスワードを分けて運用する手順
パスワードが1つだと、開発環境を触る人全員が本番の値も復号できます。vault-idは、暗号化した内容に「どのパスワードで暗号化したか」のラベルを付ける仕組みで、環境ごとにパスワードを分けられます。
label@sourceの書き方と複数のvault-idを渡す実行例
パスワード管理の公式ガイドのとおり、指定は--vault-id ラベル@取得元の形です。取得元はprompt、パスワードファイル、スクリプトのいずれかです。
# 環境ごとにラベルを付けて暗号化する
ansible-vault encrypt --vault-id dev@~/.vault/dev.txt group_vars/dev/vault.yml
ansible-vault encrypt --vault-id prod@prompt group_vars/prod/vault.yml
# 両方を使うPlaybookは --vault-id を並べて渡す
ansible-playbook -i inventories/prod site.yml \
--vault-id dev@~/.vault/dev.txt --vault-id prod@prompt
既定では、ラベルはヒントにすぎません。同じラベルのパスワードが先に試され、合わなければ指定した順にほかのパスワードも試されます。ラベルが一致したパスワードしか使わせたくない場合は、ansible.cfgでvault_id_matchを有効にする設定が必要です。毎回の指定を省くなら、設定リファレンスにある次のキーを使います。
# ansible.cfg
[defaults]
vault_identity_list = dev@~/.vault/dev.txt, prod@prompt
vault_id_match = True
vault_encrypt_identity = dev
パスワードファイルはchmod 600にして、Gitには含めません。同じラベルで別のパスワードを使ってもAnsibleはエラーにしないと公式ガイドにあるため、ラベルとパスワードの対応表は運用手順として文書に残します。
rekeyでファイル暗号化のパスワードを変更するときの手順と注意点
# dev のパスワードを新しいファイルの値へ替える
ansible-vault rekey --vault-id dev@~/.vault/dev.txt \
--new-vault-id dev@~/.vault/dev-2026q4.txt \
group_vars/dev/vault.yml roles/*/vars/vault.yml
rekeyの対象はファイル単位の暗号化だけです。encrypt_stringで作った値は、新しいパスワードで作り直して貼り替えます。パスワードを替えても、古いパスワードで暗号化された過去のコミットはGitの履歴に残ります。退職者がリポジトリを複製していた場合に備え、Vaultのパスワードと合わせて中身の秘密の値(DBパスワードやAPIキー)そのものも替えてください。
パスワードクライアントスクリプトでOSのキーリングから取得する
パスワードをファイルに平文で置きたくない場合は、取得元にスクリプトを指定します。公式ガイドによると、ファイル名が-clientで終わる実行可能ファイルは、Ansibleから--vault-id ラベルを引数にして呼ばれ、標準出力に返した値がパスワードになります。Ansibleコミュニティが公開しているvault-keyring-client.pyは、Pythonのkeyringモジュール経由でOSのキーチェーンからパスワードを取り出す実装例です。
pip install keyring
chmod +x vault-keyring-client.py
# キーリングへ登録(--set で入力を求められる)
./vault-keyring-client.py --vault-id prod --set
# 実行時はスクリプトを取得元に指定する
ansible-playbook site.yml --vault-id prod@./vault-keyring-client.py
CIからVaultパスワードを渡してPlaybookを実行する手順と漏えい対策
CIでは対話の入力ができないため、promptは使えません。GitHub Actionsのシークレットの公式ガイドは、秘密の値をコマンドラインで渡すことを避け、環境変数か標準入力を使うよう求めています。
GitHub Actionsのsecretsを環境変数で渡してスクリプトから読ませる
設定リファレンスには、パスワードファイルが実行可能なら実行し、その標準出力をパスワードとして使うと書かれています。この仕様を使い、環境変数を出力するだけのスクリプトを取得元にすれば、パスワードはディスクにもコマンドラインにも出ません。
# scripts/vault-pass-env.sh(chmod +x してリポジトリに入れてよい。値は含まない)
#!/bin/sh
printf '%s' "${ANSIBLE_VAULT_PASSWORD:?未設定}"
# .github/workflows/deploy.yml(抜粋)
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- run: pip install "ansible-core>=2.21,<2.22"
- name: Playbookを本番へ適用
env:
ANSIBLE_VAULT_PASSWORD: ${{ secrets.ANSIBLE_VAULT_PASSWORD_PROD }}
run: ansible-playbook -i inventories/prod site.yml --vault-id prod@scripts/vault-pass-env.sh
本番用のパスワードは、承認者を設定したenvironmentのシークレットに置きます。こうすると、プルリクエストの検証ジョブからは本番の値を読めません。AWXやautomation controllerから実行する場合は、Vaultの認証情報をジョブテンプレートに登録する方式になります。設定画面はAnsible Towerの機能と設定手順で扱っています。
no_logで復号した秘密の値をCIのログに出さないタスクの書き方
CIのログは多くの人が読めるため、復号後の値の扱いが本題になります。公式FAQは、秘密の値を扱うタスクにno_log: trueを付けると、-v付きの実行でも結果とコマンドを表示しないと説明しています。
- name: アプリ用のDBユーザーを作成する
community.postgresql.postgresql_user:
name: "{{ db_user }}"
password: "{{ db_password }}"
no_log: true
- name: 設定ファイルを配置する(配布先は所有者だけが読める)
ansible.builtin.template:
src: app.env.j2
dest: /etc/app/app.env
owner: app
mode: "0600"
FAQは、no_logをプレイ全体ではなく個別のタスクに付けるよう推奨しています。プレイ全体に付けると、失敗の原因も表示されなくなるためです。ANSIBLE_DEBUGを有効にした実行ではno_logでも値が表示される点にも注意してください。
Ansible Vaultで足りる条件とHashiCorp Vaultなどへ移る判断基準
判断の軸は、秘密の値を誰がどの頻度で替えるか、取得の記録を残す必要があるかの2つです。
Ansible Vaultで足りる条件:少人数で値の更新が年数回程度
Playbookを書く人と秘密の値を管理する人が同じチームで、値の更新が年に数回程度なら、Ansible Vaultで足ります。追加のサーバーが要らず、Gitのブランチやレビューの流れにそのまま乗るのが利点です。環境ごとのvault-idと、CIの秘密変数からの受け渡しまで整えれば、平文のパスワードがリポジトリに残る状態は解消できます。
外部のシークレット管理へ移す判断基準:自動ローテーションと取得履歴の監査
DBのパスワードを定期的に自動で替えたい、誰がいつ値を読んだかを監査で示す必要がある、Ansible以外のアプリからも同じ値を使う、のいずれかに当たるなら、Ansible Vaultだけの構成は見送ります。Ansible Vaultには取得の記録も、値の自動更新もありません。その場合は外部のシークレット管理に値を置き、Ansibleからは実行時に取りに行きます。HashiCorp Vaultなら、Galaxyのcommunity.hashi_vault(2026年10月時点の最新は7.1.0)のlookupで読めます。
製品ごとの仕組みはHashiCorp Vaultとは?シークレット管理の仕組みとAzure Key Vaultとはで整理しています。外部のシークレット管理に移しても、そこへ接続するための認証情報は残ります。その1つだけをAnsible VaultかCIの秘密変数で守る、という組み合わせが現実的です。
環境ごとのパスワード分離やCIでの受け渡しを含めて、構成管理の実行基盤を整えたい場合は、DevOps・CI/CD導入支援でご相談を承っています。
よくある質問
Ansible Vaultとansible-vaultコマンドについて、検索されることの多い質問に答えます。
Vaultのパスワードを忘れた場合、暗号化したファイルは復元できますか?
復元できません。鍵はパスワードから導出されるため、パスワードが無ければ暗号文から値を取り出す手段はありません。元の秘密の値を発行元で再発行し、新しいパスワードで暗号化し直します。パスワードは個人の手元だけでなく、チームのパスワード管理ツールにも保管しておいてください。
「Decryption failed」と表示されてPlaybookが止まる原因は?
多いのは、渡したパスワードとヘッダーのラベルの組み合わせ違いです。head -1で暗号化ファイルの先頭行を見て、ラベルと--vault-idの指定が一致しているかを確認します。rekeyでパスワードを替えたあと、古いパスワードのままの暗号化ファイルやencrypt_stringの値が残っている場合も、表示されるエラーは同じです。-vvvを付けて実行すると、どのファイルの復号で失敗したかを確かめられます。
暗号化したファイルの差分をgit diffで読めるようにできますか?
差分表示のときだけ復号するために使えるのが、Gitのtextconv機能です。.gitattributesにvault.yml diff=ansible-vaultと書き、git config diff.ansible-vault.textconv "ansible-vault view"を設定します。復号には手元のパスワードが要るため、パスワードを持たない人には従来どおり暗号文の差分が表示されます。
Ansible Vaultの暗号はどの程度の強度ですか?
AES256をCTRモードで使い、鍵はPBKDF2(SHA256・10,000回)で導出します。暗号方式そのものより、パスワードの強さで決まる面が大きい仕組みです。短いパスワードは総当たりで破られやすくなるため、パスワード生成ツールで20文字以上のランダムな文字列を作って使ってください。
ansible-vaultでSSH秘密鍵や証明書のファイルも暗号化できますか?
SSH秘密鍵や証明書のファイルも暗号化の対象です。公式ガイドは、変数ファイルに限らずバイナリを含む任意のファイルを暗号化できるとしています。暗号化した鍵ファイルをcopyのsrcに渡すと、対象ホストには復号された状態で置かれます。mode: "0600"と所有者を必ず指定し、秘密鍵が他のユーザーから読めない状態で配置してください。
関連記事
- Ansibleとは?エージェントレスの仕組みとメリット・デメリット、Red Hat AAPの制約:Ansible本体の仕組み。
- Ansible Playbookの書き方と実行手順:–checkでのdry-runとhandlers【2.21系】:暗号化した変数を参照するPlaybookの文法。
- Ansible Galaxyの使い方:ansible-galaxyコマンドとrequirements.ymlでロール・コレクションを管理する手順【2.21系】:community.hashi_vaultなどのコレクションの入れ方。
- Ansible AWXとは:AWX OperatorでKubernetesへ導入する手順とAAPとの違い【2.19.1】:Vaultの認証情報を登録して実行する基盤。
- HashiCorp Vaultとは?シークレット管理の仕組み・動的シークレット・Kubernetes連携と採用判断を実装者目線で解説:外部のシークレット管理へ移す場合の候補。