AnsibleVaultを使用して機密性の高いPlaybookデータを保護する方法
序章
Ansible Vaultは、ユーザーがAnsibleプロジェクト内の値とデータ構造を暗号化できるようにする機能です。 これにより、Ansibleプレイを正常に実行するために必要であるが、パスワードや秘密鍵などの公開されるべきではない機密データを保護する機能が提供されます。 Ansibleは、キーが提供されると、実行時にボールトで暗号化されたコンテンツを自動的に復号化します。
このガイドでは、Ansible Vaultの使用方法を示し、その使用を簡素化するためのいくつかの推奨プラクティスを探ります。 AnsibleコントロールマシンにはUbuntu20.04サーバーを使用します。 リモートホストは必要ありません。
前提条件
従うには、sudo権限を持つ非rootユーザーのUbuntu20.04サーバーが必要です。 Ubuntu 20.04初期サーバーセットアップガイドに従って、適切な権限を持つユーザーを作成できます。
サーバー上で、Ansibleをインストールして構成する必要があります。 Ubuntu 20.04 へのAnsibleのインストールに関するチュートリアルに従って、適切なパッケージをインストールできます。
サーバーが上記の要件で構成されている場合は、このガイドを続けてください。
Ansible Vaultとは何ですか?
Ansible Vaultは、暗号化されたコンテンツをAnsibleワークフローに透過的に組み込むことができるメカニズムです。 ansible-vaultと呼ばれるユーティリティは、ディスク上で暗号化することにより、secretsと呼ばれる機密データを保護します。 これらのシークレットを通常のAnsibleデータと統合するために、アドホックタスクと構造化プレイブックをそれぞれ実行するためのansibleコマンドとansible-playbookコマンドの両方で、実行時にボールト暗号化コンテンツを復号化することがサポートされています。
Vaultはファイルレベルの粒度で実装されます。つまり、個々のファイルは暗号化されているか、暗号化されていないかのどちらかです。 AES256アルゴリズムを使用して、ユーザーが指定したパスワードに合わせた対称暗号化を提供します。 これは、コンテンツの暗号化と復号化に同じパスワードが使用されることを意味します。これは、使いやすさの観点から役立ちます。 Ansibleは、プレイブックまたはタスクの実行中に見つかったボールト暗号化ファイルを識別して復号化できます。
Vaultとは何かについて少し理解できたので、Ansibleが提供するツールと既存のワークフローでVaultを使用する方法について説明します。
AnsibleVaultエディターの設定
ansible-vaultコマンドを使用する前に、お好みのテキストエディタを指定することをお勧めします。 Vaultのコマンドのいくつかは、暗号化されたファイルの内容を操作するためにエディターを開くことを含みます。 Ansibleは、EDITOR環境変数を調べて、好みのエディターを見つけます。 これが設定されていない場合、デフォルトでviになります。
viエディターで編集したくない場合は、ご使用の環境でEDITOR変数を設定する必要があります。
注:誤ってviセッションに参加した場合は、 Esc キーを押し、:q!と入力して、[ X159X]Enter。 viエディターに慣れていない場合は、意図しない変更を加える可能性があるため、このコマンドは保存せずに終了します。
個々のコマンドのエディターを設定するには、次のように、コマンドの前に環境変数の割り当てを追加します。
EDITOR=nano ansible-vault . . .
これを永続的にするには、~/.bashrcファイルを開きます。
nano ~/.bashrc
ファイルの最後にEDITOR割り当てを追加して、希望するエディターを指定します。
〜/ .bashrc
export EDITOR=nano
終了したら、ファイルを保存して閉じます。
ファイルを再度ソースして、変更を現在のセッションに読み込みます。
. ~/.bashrc
EDITOR変数を表示して、設定が適用されたことを確認します。
echo $EDITOR
Outputnano
好みのエディタを確立したので、ansible-vaultコマンドで使用できる操作について説明します。
ansible-vaultで機密ファイルを管理する方法
ansible-vaultコマンドは、Ansible内で暗号化されたコンテンツを管理するためのメインインターフェイスです。 このコマンドは、最初にファイルを暗号化するために使用され、その後、データを表示、編集、または復号化するために使用されます。
新しい暗号化ファイルの作成
Vaultで暗号化された新しいファイルを作成するには、ansible-vault createコマンドを使用します。 作成するファイルの名前を渡します。 たとえば、vault.ymlという暗号化されたYAMLファイルを作成して機密変数を保存するには、次のように入力します。
ansible-vault create vault.yml
パスワードを入力して確認するように求められます。
OutputNew Vault password: Confirm New Vault password:
パスワードを確認すると、Ansibleはすぐに編集ウィンドウを開き、目的のコンテンツを入力できます。
暗号化機能をテストするには、次のテストテキストを入力します。
vault.yml
Secret information
Ansibleは、ファイルを閉じるときにコンテンツを暗号化します。 ファイルをチェックすると、入力した単語が表示される代わりに、暗号化されたブロックが表示されます。
cat vault.yml
Output$ANSIBLE_VAULT;1.1;AES256 65316332393532313030636134643235316439336133363531303838376235376635373430336333 3963353630373161356638376361646338353763363434360a363138376163666265336433633664 30336233323664306434626363643731626536643833336638356661396364313666366231616261 3764656365313263620a383666383233626665376364323062393462373266663066366536306163 31643731343666353761633563633634326139396230313734333034653238303166
Ansibleがファイルの処理方法を知るために使用するいくつかのヘッダー情報と、それに続く数字として表示される暗号化されたコンテンツを見ることができます。
既存のファイルの暗号化
Vaultで暗号化するファイルがすでにある場合は、代わりにansible-vault encryptコマンドを使用してください。
テストのために、次のように入力してサンプルファイルを作成できます。
echo 'unencrypted stuff' > encrypt_me.txt
これで、次のように入力して既存のファイルを暗号化できます。
ansible-vault encrypt encrypt_me.txt
ここでも、パスワードを入力して確認するように求められます。 その後、暗号化を確認するメッセージが表示されます。
OutputNew Vault password: Confirm New Vault password: Encryption successful
ansible-vaultは、編集ウィンドウを開く代わりに、ファイルの内容を暗号化してディスクに書き戻し、暗号化されていないバージョンを置き換えます。
ファイルを確認すると、同様の暗号化されたパターンが表示されます。
cat encrypt_me.txt
Output$ANSIBLE_VAULT;1.1;AES256 66633936653834616130346436353865303665396430383430353366616263323161393639393136 3737316539353434666438373035653132383434303338640a396635313062386464306132313834 34313336313338623537333332356231386438666565616537616538653465333431306638643961 3636663633363562320a613661313966376361396336383864656632376134353039663662666437 39393639343966363565636161316339643033393132626639303332373339376664
ご覧のとおり、Ansibleは、新しいファイルを暗号化するのとほぼ同じ方法で既存のコンテンツを暗号化します。
暗号化されたファイルの表示
場合によっては、ボールトで暗号化されたファイルを編集したり、暗号化されていないファイルシステムに書き込んだりせずに、ファイルの内容を参照する必要があります。 ansible-vault viewコマンドは、ファイルの内容を標準出力に送ります。 デフォルトでは、これはコンテンツが端末に表示されることを意味します。
ボールト暗号化ファイルを次のコマンドに渡します。
ansible-vault view vault.yml
ファイルのパスワードの入力を求められます。 入力に成功すると、内容が表示されます。
OutputVault password: Secret information
ご覧のとおり、ファイルの内容の出力にはパスワードプロンプトが混在しています。 自動化されたプロセスでansible-vault viewを使用する場合は、このことに注意してください。
暗号化されたファイルの編集
暗号化されたファイルを編集する必要がある場合は、ansible-vault editコマンドを使用します。
ansible-vault edit vault.yml
ファイルのパスワードの入力を求められます。 入力後、Ansibleはファイルを編集ウィンドウで開き、必要な変更を加えることができます。
保存すると、新しいコンテンツはファイルの暗号化パスワードを使用して再度暗号化され、ディスクに書き込まれます。
暗号化されたファイルを手動で復号化する
ボールト暗号化ファイルを復号化するには、ansible-vault decryptコマンドを使用します。
注:機密データをプロジェクトリポジトリに誤ってコミットする可能性が高くなるため、ansible-vault decryptコマンドは、ファイルから暗号化を完全に削除する場合にのみ推奨されます。 ボールト暗号化ファイルを表示または編集する必要がある場合は、通常、それぞれansible-vault viewまたはansible-vault editコマンドを使用することをお勧めします。
暗号化されたファイルの名前を渡します。
ansible-vault decrypt vault.yml
ファイルの暗号化パスワードの入力を求められます。 正しいパスワードを入力すると、ファイルは復号化されます。
OutputVault password: Decryption successful
ボールト暗号化の代わりにファイルを再度表示すると、ファイルの実際の内容が表示されます。
cat vault.yml
OutputSecret information
これで、ファイルはディスク上で暗号化されなくなりました。 終了したら、機密情報を削除するか、ファイルを再暗号化してください。
暗号化されたファイルのパスワードの変更
暗号化されたファイルのパスワードを変更する必要がある場合は、ansible-vault rekeyコマンドを使用してください。
ansible-vault rekey encrypt_me.txt
コマンドを入力すると、最初にファイルの現在のパスワードの入力を求められます。
OutputVault password:
入力後、新しいボールトパスワードを選択して確認するように求められます。
OutputVault password: New Vault password: Confirm New Vault password:
新しいパスワードを正常に確認すると、再暗号化プロセスが成功したことを示すメッセージが表示されます。
OutputRekey successful
これで、新しいパスワードを使用してファイルにアクセスできるようになります。 古いパスワードは機能しなくなります。
Vaultで暗号化されたファイルでAnsibleを実行する
Vaultで機密情報を暗号化した後、Ansibleの従来のツールでファイルの使用を開始できます。 ansibleコマンドとansible-playbookコマンドはどちらも、正しいパスワードを指定してボールトで保護されたファイルを復号化する方法を知っています。 必要に応じて、これらのコマンドにパスワードを提供する方法はいくつかあります。
従うには、ボールトで暗号化されたファイルが必要になります。 次のように入力して作成できます。
ansible-vault create secret_key
パスワードを選択して確認します。 必要なダミーコンテンツを入力します。
secret_key
confidential data
ファイルを保存して閉じます。
一時的なhostsファイルをインベントリとして作成することもできます。
nano hosts
Ansibleローカルホストだけを追加します。 後のステップの準備として、[database]グループに配置します。
ホスト
[database] localhost ansible_connection=local
終了したら、ファイルを保存して閉じます。
次に、ansible.cfgファイルがまだ存在しない場合は、現在のディレクトリに作成します。
nano ansible.cfg
今のところ、[defaults]セクションを追加し、作成したインベントリにAnsibleをポイントします。
ansible.cfg
[defaults] inventory = ./hosts
準備ができたら、続行します。
インタラクティブプロンプトの使用
実行時にコンテンツを復号化する最も簡単な方法は、Ansibleに適切なクレデンシャルの入力を求めるプロンプトを表示させることです。 これを行うには、--ask-vault-passを任意のansibleまたはansible-playbookコマンドに追加します。 Ansibleは、ボールトで保護されたコンテンツを見つけた場合に復号化するために使用するパスワードの入力を求めます。
たとえば、ボールトで暗号化されたファイルの内容をホストにコピーする必要がある場合は、copyモジュールと--ask-vault-passフラグを使用してコピーできます。 ファイルに実際に機密データが含まれている場合は、アクセス許可と所有権の制限を使用して、リモートホストへのアクセスをロックダウンすることをお勧めします。
注:必要なサーバーの数を最小限に抑えるために、この例ではターゲットホストとしてlocalhostを使用していますが、結果はホストが本当にリモートである場合と同じになります。
ansible --ask-vault-pass -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost
このタスクでは、ファイルの所有権をrootに変更する必要があることを指定しているため、管理者権限が必要です。 -bKフラグは、ターゲットホストのsudoパスワードの入力を求めるプロンプトをAnsibleに指示するため、sudoパスワードの入力を求められます。 次に、Vaultのパスワードの入力を求められます。
OutputBECOME password: Vault password:
パスワードが提供されると、Ansibleは、検出した暗号化ファイルにVaultパスワードを使用して、タスクの実行を試みます。 実行中に参照されるすべてのファイルは同じパスワードを使用する必要があることに注意してください。
Outputlocalhost | SUCCESS => {
"changed": true,
"checksum": "7a2eb5528c44877da9b0250710cba321bc6dac2d",
"dest": "/tmp/secret_key",
"gid": 0,
"group": "root",
"md5sum": "270ac7da333dd1db7d5f7d8307bd6b41",
"mode": "0600",
"owner": "root",
"size": 18,
"src": "/home/sammy/.ansible/tmp/ansible-tmp-1480978964.81-196645606972905/source",
"state": "file",
"uid": 0
}
パスワードの入力を求めることは安全ですが、特に繰り返し実行する場合は面倒であり、自動化の妨げにもなります。 ありがたいことに、これらの状況にはいくつかの選択肢があります。
パスワードファイルでのAnsibleVaultの使用
タスクを実行するたびにVaultパスワードを入力したくない場合は、Vaultパスワードをファイルに追加して、実行中にファイルを参照できます。
たとえば、次のように.vault_passファイルにパスワードを入力できます。
echo 'my_vault_password' > .vault_pass
バージョン管理を使用している場合は、誤ってコミットしないように、バージョン管理ソフトウェアの無視ファイルにパスワードファイルを追加してください。
echo '.vault_pass' >> .gitignore
これで、代わりにファイルを参照できます。 --vault-password-fileフラグはコマンドラインで使用できます。 次のように入力することで、前のセクションと同じタスクを完了することができます。
ansible --vault-password-file=.vault_pass -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost
今回は、Vaultパスワードの入力を求められることはありません。
Outputlocalhost | SUCCESS => {
"changed": false,
"checksum": "52d7a243aea83e6b0e478db55a2554a8530358b0",
"dest": "/tmp/secret_key",
"gid": 80,
"group": "root",
"mode": "0600",
"owner": "root",
"path": "/tmp/secret_key",
"size": 8,
"state": "file",
"uid": 0
}
パスワードファイルの自動読み取り
フラグをまったく提供する必要がないように、ANSIBLE_VAULT_PASSWORD_FILE環境変数にパスワードファイルへのパスを設定できます。
export ANSIBLE_VAULT_PASSWORD_FILE=./.vault_pass
これで、現在のセッションの--vault-password-fileフラグなしでコマンドを実行できるようになります。
ansible -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost
Ansibleにセッション間でのパスワードファイルの場所を認識させるために、ansible.cfgファイルを編集できます。
以前に作成したローカルansible.cfgファイルを開きます。
nano ansible.cfg
[defaults]セクションで、vault_password_file設定を行います。 パスワードファイルの場所をポイントします。 これは、どちらが最も役立つかに応じて、相対パスまたは絶対パスにすることができます。
ansible.cfg
[defaults] . . . vault_password_file = ./.vault_pass
これで、復号化が必要なコマンドを実行するときに、ボールトパスワードの入力を求められなくなりました。 ボーナスとして、ansible-vaultはファイル内のパスワードを使用してファイルを復号化するだけでなく、ansible-vault createおよびansible-vault encryptで新しいファイルを作成するときにパスワードを適用します。
環境変数からのパスワードの読み取り
パスワードファイルを誤ってリポジトリにコミットすることを心配するかもしれません。 Ansibleにはパスワードファイルの場所を指す環境変数がありますが、パスワード自体を設定するための環境変数はありません。
ただし、パスワードファイルが実行可能である場合、Ansibleはそれをスクリプトとして実行し、結果の出力をパスワードとして使用します。 GitHubの問題で、 Brian Schwind は、次のスクリプトを使用して環境変数からパスワードを取得できることを示唆しています。
.vault_passファイルをエディターで開きます。
nano .vault_pass
内容を次のスクリプトに置き換えます。
.vault_pass
#!/usr/bin/env python3 import os print os.environ['VAULT_PASSWORD']
次のように入力して、ファイルを実行可能にします。
chmod +x .vault_pass
次に、VAULT_PASSWORD環境変数を設定してエクスポートできます。これは、現在のセッションで使用できます。
export VAULT_PASSWORD=my_vault_password
これは、各Ansibleセッションの開始時に行う必要があり、不便に聞こえるかもしれません。 ただし、これにより、Vault暗号化パスワードを誤ってコミットすることを効果的に防ぐことができます。これは重大な欠点をもたらす可能性があります。
Vaultで暗号化された変数を通常の変数で使用する
Ansible Vaultは任意のファイルで使用できますが、機密性の高い変数を保護するために最も頻繁に使用されます。 例を使用して、通常の変数ファイルをセキュリティと使いやすさのバランスが取れた構成に変換する方法を示します。
例の設定
この例では、前提条件としてデータベースを実際にインストールする必要なしに、データベースサーバーを構成しているように見せかけます。
以前にhostsファイルを作成したときに、localhostエントリをdatabaseというグループに配置して、この手順の準備をしました。 データベースには通常、機密性の高い変数と機密性の低い変数が混在している必要があります。 これらは、グループにちなんで名付けられたファイルのgroup_varsディレクトリに割り当てることができます。
mkdir -p group_vars nano group_vars/database
group_vars/databaseファイル内に、いくつかの一般的な変数を追加します。 MySQLポート番号などの一部の変数は秘密ではなく、自由に共有できます。 データベースパスワードなどの他の変数は機密扱いになります。
group_vars / database
--- # nonsensitive data mysql_port: 3306 mysql_host: 10.0.0.3 mysql_user: fred # sensitive data mysql_password: supersecretpassword
Ansibleのdebugモジュールとhostvars変数を使用して、すべての変数がホストで使用可能であることをテストできます。
ansible -m debug -a 'var=hostvars[inventory_hostname]' database
Outputlocalhost | SUCCESS => {
"hostvars[inventory_hostname]": {
"ansible_check_mode": false,
"ansible_version": {
"full": "2.2.0.0",
"major": 2,
"minor": 2,
"revision": 0,
"string": "2.2.0.0"
},
"group_names": [
"database"
],
"groups": {
"all": [
"localhost"
],
"database": [
"localhost"
],
"ungrouped": []
},
"inventory_dir": "/home/sammy",
"inventory_file": "hosts",
"inventory_hostname": "localhost",
"inventory_hostname_short": "localhost",
"mysql_host": "10.0.0.3",
"mysql_password": "supersecretpassword",
"mysql_port": 3306,
"mysql_user": "fred",
"omit": "__omit_place_holder__1c934a5a224ca1d235ff05eb9bda22044a6fb400",
"playbook_dir": "."
}
}
出力は、設定したすべての変数がホストに適用されていることを確認します。 ただし、現在、group_vars/databaseファイルにはすべての変数が含まれています。 これは、データベースのパスワード変数のためにセキュリティ上の懸念がある暗号化されないままにするか、すべての変数を暗号化することで、使いやすさとコラボレーションの問題を引き起こす可能性があることを意味します。
機密変数をAnsibleVaultに移動する
この問題を解決するには、機密変数と非機密変数を区別する必要があります。 機密値を暗号化すると同時に、機密性の低い変数を簡単に共有できる必要があります。 そのために、変数を2つのファイルに分割します。
複数のファイルから変数を適用するために、Ansible変数fileの代わりに変数directoryを使用することができます。 その機能を利用するために、構成をリファクタリングできます。 まず、既存のファイルの名前をdatabaseからvarsに変更します。 これは、暗号化されていない変数ファイルになります。
mv group_vars/database group_vars/vars
次に、古い変数ファイルと同じ名前のディレクトリを作成します。 varsファイルを次の場所に移動します。
mkdir group_vars/database mv group_vars/vars group_vars/database/
これで、単一のファイルではなく、databaseグループの可変ディレクトリが作成され、暗号化されていない単一の可変ファイルが作成されました。 機密変数を暗号化するので、暗号化されていないファイルからそれらを削除する必要があります。 group_vars/database/varsファイルを編集して、機密データを削除します。
nano group_vars/database/vars
この場合、mysql_password変数を削除します。 ファイルは次のようになります。
group_vars / database / vars
--- # nonsensitive data mysql_port: 3306 mysql_host: 10.0.0.3 mysql_user: fred
次に、暗号化されていないvarsファイルと一緒に存在するディレクトリ内にボールト暗号化ファイルを作成します。
ansible-vault create group_vars/database/vault
このファイルで、varsファイルにあった機密変数を定義します。 同じ変数名を使用しますが、文字列vault_を前に付けて、これらの変数がボールトで保護されたファイルで定義されていることを示します。
group_vars / database / vault
--- vault_mysql_password: supersecretpassword
終了したら、ファイルを保存して閉じます。
結果のディレクトリ構造は次のようになります。
. ├── . . . ├── group_vars/ │ └── database/ │ ├── vars │ └── vault └── . . .
この時点で、変数は分離され、機密データのみが暗号化されます。 これは安全ですが、私たちの実装は私たちの使いやすさに影響を与えました。 私たちの目標は機密性の高い値を保護することでしたが、実際の変数名の可視性も意図せずに低下させました。 複数のファイルを参照せずにどの変数が割り当てられるかは明確ではありません。共同作業中に機密データへのアクセスを制限したい場合でも、変数名を共有したい場合があります。
これに対処するために、Ansibleプロジェクトは通常、わずかに異なるアプローチを推奨しています。
暗号化されていない変数からのVault変数の参照
機密データをボールトで保護されたファイルに移動したとき、変数名の前にvault_を付けました(mysql_passwordはvault_mysql_passwordになりました)。 元の変数名(mysql_password)を暗号化されていないファイルに戻すことができます。 これらを機密値に直接設定する代わりに、Jinja2テンプレートステートメントを使用して、暗号化されていない変数ファイル内から暗号化された変数名を参照できます。 このように、単一のファイルを参照することで定義されたすべての変数を確認できますが、機密値は暗号化されたファイルに残ります。
実例を示すために、暗号化されていない変数ファイルをもう一度開きます。
nano group_vars/database/vars
mysql_password変数を再度追加します。 今回は、Jinja2テンプレートを使用して、ボールトで保護されたファイルで定義された変数を参照します。
group_vars / database / vars
---
# nonsensitive data
mysql_port: 3306
mysql_host: 10.0.0.3
mysql_user: fred
# sensitive data
mysql_password: "{{ vault_mysql_password }}"
mysql_password変数は、ボールトファイルで定義されているvault_mysql_password変数の値に設定されます。
この方法では、group_vars/database/varsファイルを表示することで、databaseグループのホストに適用されるすべての変数を理解できます。 敏感な部分は、Jinja2のテンプレートによって隠されます。 group_vars/database/vaultを開く必要があるのは、値自体を表示または変更する必要がある場合のみです。
前回と同じ方法で、すべてのmysql_*変数が正しく適用されていることを確認できます。
注: Vaultのパスワードがパスワードファイルで自動的に適用されない場合は、以下のコマンドに--ask-vault-passフラグを追加してください。
ansible -m debug -a 'var=hostvars[inventory_hostname]' database
Outputlocalhost | SUCCESS => {
"hostvars[inventory_hostname]": {
"ansible_check_mode": false,
"ansible_version": {
"full": "2.2.0.0",
"major": 2,
"minor": 2,
"revision": 0,
"string": "2.2.0.0"
},
"group_names": [
"database"
],
"groups": {
"all": [
"localhost"
],
"database": [
"localhost"
],
"ungrouped": []
},
"inventory_dir": "/home/sammy/vault",
"inventory_file": "./hosts",
"inventory_hostname": "localhost",
"inventory_hostname_short": "localhost",
"mysql_host": "10.0.0.3",
"mysql_password": "supersecretpassword",
"mysql_port": 3306,
"mysql_user": "fred",
"omit": "__omit_place_holder__6dd15dda7eddafe98b6226226c7298934f666fc8",
"playbook_dir": ".",
"vault_mysql_password": "supersecretpassword"
}
}
vault_mysql_passwordとmysql_passwordの両方にアクセスできます。 この複製は無害であり、このシステムの使用に影響を与えることはありません。
結論
プロジェクトには、複雑なシステムを正常にインストールおよび構成するために必要なすべての情報が含まれている必要があります。 ただし、一部の構成データは定義上機密性が高く、公開すべきではありません。 このガイドでは、セキュリティを損なうことなくすべての構成データを1つの場所に保持できるように、AnsibleVaultが機密情報を暗号化する方法を示しました。