目的
運用対象サーバのアカウントやパスワードを運用者に教えなくてもサーバの設定変更ができるか確認する。
ストーリー
顧客からWebサーバの作成依頼がきたため要件通りにAapcheでWebサーバを構築した。
それの運用もやるのだが顧客側で運用ポリシーを確認してもらったところ支離滅裂なことを言い出した。
支離滅裂な運用要望
ここでの運用担当範囲はApacheの運用までとする
Machine認証を使うのはここでは無しとする
用語について
- Ansible Tower管理者
- Ansible Towerの管理者
- 組織管理アカウント
- Ansible Towerで作成された組織の管理アカウント
- Ansible Towerでのアカウント名は
admin01
とします
- 運用者アカウント
- Ansible TowerとPlaybookやサーバの設定ファイルを管理するアカウント
- Ansible Towerでのアカウント名は
ope01
とします
- OS運用アカウント
- Web設定を変更したり反映したりするアカウント
- ここでは、sudoersでNOPASSWDを設定します
- NOPASSWDにする理由は
copy
モジュールを使っているためです - 他の方法でやればNOPASSWDは不要だと思います
- NOPASSWDにする理由は
- アカウント名は
ope01
とします
要望を解決するために必要なもの
- Ansible Tower(or AWX)
- 実際にサーバへオペレーションを実行するために使う
- GitLab or GitHub
- サーバの設定管理をするために使う
- サーバの設定やPlaybookをAnsible Towerに同期させるために使う
どうやるか
Ansible Towerでやること
- Ansible Tower管理者が運用に必要な組織や組織管理者アカウント、運用者アカウントを作成する
- 必要に応じて各アカウントのロール設定をする
- GitLab or GitHubからリポジトリを同期
- インベントリを管理する(管理者のみアクセス可能にする)
- インベントリにはSSHのアカウントをパスワードを変数で定義する
- パスワードはセキュリティを考えてVaultで暗号化する(Ansible Tower管理者は見えてしまうので、それの対策)
- Vaultのパスワードを作成する
- Machine認証情報を作成すればいいだけかもしれないが、Vaultでやってみたかった
- 一応、複数ホストでパスワードがバラバラだったら変数直埋め込みなのかなぁと言うのも考えてみた
- テンプレートを作成する
- Playbookを実行して対象のサーバにオペレーション(テンプレート)を実行する
GitLab or GitHubでやること
ここは運用者が管理する想定
- Apache設定の管理
- Playbookの管理
解決方法
環境
今回は、Ansible TowerとGitLabを使います。
項目 | バージョン |
---|---|
Ansible Tower | 3.2.5 |
Ansible | 2.6.3 |
GitLab CE | 10.5.2 |
申請フローについて
今回の要件を満たすためには以下のようなフローが発生するのではないかと思います。
以下からは、Ansible Tower管理者の作業が完了していることを前提として説明します。
組織管理者アカウントがやること
プロジェクトのパーミッション変更
プロジェクトのパーミッションに ope01
を登録します。
やり方次第ですが、ここでは管理者権限を与えています。
管理者権限を与える理由ですがope01はSC認証情報の作成をします。
ope01が作ったSC認証情報はadmin01から見えないため設定することができません。
ope01が作ったSC認証情報のロールにadmin01を追加しようとしても権限が無いためかバグなのか追加できなかったためope01でもプロジェクトのSCM CREDENTIALが登録できるように管理者にしています。
Vaultパスワードを設定
運用パスワードやアカウントは運用者に教えたく無いのでインベントリーの変数に直接定義します。
ただし、パスワードを平文で登録するとAnsible Tower管理者から見えてしまうのでVaultで暗号化して登録します。
それを複合するために認証情報にVaultのパスワードを設定します。
インベントリーの設定
今回はWebサーバ1台と仮定しホストに1台登録します。
以下のようにユーザー名とパスワードを登録します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
--- ansible_user: ope01 ansible_password: __ansible_vault: >- $ANSIBLE_VAULT;1.1;AES256 32386132326465306239356165636162383930313434303630626132626239373461306235366565 3662343334336365366561646534306666343037363463360a646132393530353932366438353165 39643839306634653562386230626637643035326365366333316138653961393837666364333736 6136303735656137390a613536356434336366613632636339393464353962363835363163613236 6638 |
何故このような改行が必要が知りたい方は以下を参照してください。
テンプレートの作成
テンプレートを作成してope01に実行ロールを割り当てます。
そうすることでope01はテンプレートの修正ができないですが実行するこはできます。
sudoers設定
NOPASSWDがゆるされるかどうかは置いておいて一先ずここではNOPASSWDを設定します。
1 2 3 4 5 6 7 |
# sudoedit /etc/sudoers (snip) ## Allow root to run any commands anywhere root ALL=(ALL) ALL ope01 ALL=NOPASSWD: ALL (snip) |
運用者アカウントがやること
SC認証情報の作成
GitLabのリポジトリを同期させるため認証情報を設定します。
プロジェクトの更新
プロジェクトをGitベースにするため変更します。
SCM URL
SCM CREDENTIAL
を設定して保存し同期します。
テンプレートの実行
後は、テンプレートの実行すればWeb設定部分だけ更新することができます。
結果
- 運用者にパスワードを教えなくてもApacheの設定変更はできるようになりました
- また、お互いGitLabやOSアカウント名・パスワードを知られずに済む運用ができることが確認できました
- Vaultで暗号化しておくことでAnsible Tower管理者にもパスワードを知られないことが確認できました
- 運用者はGitLabリポジトリ更新、Ansible Towerで同期、テンプレートの実行という運用だけになりました
- サーバのOS運用アカウントパスワードを変更する時はインベントリの更新(Vaultで暗号化したもの)をしてもらえばいいです
- 複数ホストがアカウント・パスワードがバラバラで一つのテンプレートを使った運用もVault使えばできそうかな(めちゃんこ効率悪いけど)
これをやるには色々と調整事項がありますが、結果的に目的が達成できたと思います 🙂
付録
リポジトリ構造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
web-server/ ├── main.yml └── web-server ├── files │ ├── conf │ │ ├── httpd.conf │ │ └── magic │ ├── conf.d │ │ ├── README │ │ ├── autoindex.conf │ │ ├── userdir.conf │ │ └── welcome.conf │ └── conf.modules.d │ ├── 00-base.conf │ ├── 00-dav.conf │ ├── 00-lua.conf │ ├── 00-mpm.conf │ ├── 00-proxy.conf │ ├── 00-systemd.conf │ └── 01-cgi.conf └── tasks └── main.ym |
main.yml
1 2 3 4 5 6 7 8 |
--- - name: Web Server Operation hosts: all gather_facts: no become: yes roles: - web-server |
tasks/main.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
--- - name: Apache Config Update. copy: src: "{{ role_path }}/files" dest: /etc/httpd - name: Apache Graceful. shell: /usr/sbin/apachectl graceful register: r - name: Check Apache Status. fail: msg: Apache graceful failed. when: r.rc != 0 |