Ansibleでサーバーの公開鍵や設定ファイルを管理する
前回はItamaeでしたが、今回はAnsibleを使ってサーバーの公開鍵や設定ファイルを触ってみようというお話。
どんだけ公開鍵が好きやねん!という感じですが、試してみます。
環境
ローカル
OS X EI Capitan 10.11.4
サーバー
Ubuntu 14.04.3 LTS
やりたいこと
- いろんなサーバーの複数ユーザーの複数の公開鍵(authorized_keys)を管理したい
- ユーザーと鍵を保持しておいて、実行時に自動生成したい
- (おまけ)ミドルウェアの設定ファイルなんかもちょっと管理してみたい
Ansibleインストール
公式に各環境でのインストールのやり方が載っていました。
Installation — Ansible Documentation
ディレクトリ構成
最終的にこんな感じのディレクトリ構成を考えています。
. ├── common-roles │ ├── base │ │ ├── defaults │ │ ├── files │ │ ├── handlers │ │ ├── meta │ │ ├── tasks │ │ └── templates │ ├── publickeys │ └── vars └── project ├── group_vars │ ├── production │ ├── staging │ └── test ├── host_vars ├── hosts └── roles ├── apache2 │ ├── defaults │ ├── files │ ├── handlers │ ├── meta │ ├── tasks │ └── templates ├── adminmusers │ ├── defaults │ ├── files │ ├── handlers │ ├── meta │ ├── tasks │ └── templates └── users ├── defaults ├── files ├── handlers ├── meta ├── tasks └── templates
やってみる
参考URL
Best Practices — Ansible Documentation
Ansible ( 俺の中で ) 最強の Best Practices – Qiita
Ansible オレオレベストプラクティス – Qiita
Ansibleを使い出す前に押さえておきたかったディレクトリ構成のベストプラクティス – 双六工場日誌
仮定
- とあるプロジェクトのフロントサーバーを立てることになった
- 例えばfront1.project.domainというホスト名で接続できるものとする
- サーバーで一般ユーザーと管理ユーザーを分けて作成する
- 管理ユーザーはパスワードなしでsudo可能にする
- apacheをインストールして設定ファイルも配置する
公開鍵登録
まずサーバーユーザーのauthorized_keysに登録する鍵ファイルを準備します。
./common-roles/publickeys/userA
ssh-rsa hogehoge userA@localhost
社員が4人いるということにしてuserB、userC、userDの鍵ファイルも作成しておきます。
site.ymlの作成
いわばトップレベルのプレイブックです。
ここでは一つのグループ用のプレイブックをincludeしてみます。
./project/site.yml
--- - include: project-front.yml
グループ用プレイブック作成
例えばあるプロジェクトのフロントWebサーバー群、ということでプレイブックを作成します。
どこにおいてもいいですが、単純にsite.ymlと同じ階層に配置します。
./project/project−front.yml
--- - hosts: project-front become: yes vars_files: - ../common-roles/vars/common.yml roles: - ../common-roles/base - users - adminusers - apache2
インベントリファイルの作成
実行対象をつらつらと定義しておきます。
グループに複数サーバーがある時は該当グループのところに列挙すればいけるようです。
./project/hosts/production
[project-front] front1.prooject.domain [production:children] project-front
変数ファイルの作成
各種参考URLに従いつつ、下記のように作成しました。
共通変数
playbookから呼び出す共通変数ファイルを作成します。
最低限の必要ディレクトリパスだけを記載しました。
./common-roles/vars/common.yml
common_template_dir: "../common-roles/base/templates" public_keys_dir: "../common-roles/publickeys"
ステージ、グループごとの変数
inventoryに記載したようなグループ単位で使用する変数を定義します。
./project/group_vars/
. ├── all.yml ├── production │ └── project-front.yml ├── staging │ └── project-front.yml └── test └── project-front.yml
group_vars/all.ymlは空ファイルでも動きます。
このへんの読み込み順序については参考URLに詳しく説明がありました。
各ステージのディレクトリ配下に同じキーを持つ複数のファイルがあると後勝ちするような気がしますが検証していません。。
./project/group_vars/production/project-front.yml
users: - name: user group: user groups: "" list: - "userA" - "userB" adminusers: - name: adminuser group: adminuser groups: "" list: - "userC" - "userD"
ホストごとの変数
さらに細かくホストごとに変えたい変数があればhost_varsの中にファイルを準備すればいいようです。
./project/host_vars/front1.project.domain
メインタスクの作成
一般ユーザー用
公開鍵登録用のタスクでは、templateを用いて鍵ファイルを読み込んで動的に生成するようにします。
./project/roles/users/tasks/main.yml
- name: groups exist group: name={{item.group}} state=present with_items: users tags: users - name: users exist user: name={{item.name}} state=present group={{item.group}} groups={{item.groups}} with_items: users tags: users - name: ~/ for users exist file: path="/home/{{item.name}}" state=directory owner={{item.name}} group={{item.group}} mode=0755 with_items: users tags: users - name: ~/.ssh for users exist file: path="/home/{{item.name}}/.ssh" state=directory owner={{item.name}} group={{item.group}} mode=0700 with_items: users tags: users - name: authorized keys is deployed template: src="{{common_template_dir}}/authorized_keys.j2" dest="/home/{{item.name}}/.ssh/authorized_keys" owner={{item.name}} group={{item.group}} mode=0600 with_items: users tags: users
管理ユーザー用
特権ユーザー用にsudoerファイルをプラスしたタスクを作ります。
./project/roles/adminusers/tasks/main.yml
- name: groups exist group: name={{item.group}} state=present with_items: adminusers tags: users - name: users exist user: name={{item.name}} state=present group={{item.group}} groups={{item.groups}} with_items: adminusers tags: users - name: ~/ for users exist file: path="/home/{{item.name}}" state=directory owner={{item.name}} group={{item.group}} mode=0700 with_items: adminusers tags: users - name: ~/.ssh for users exist file: path="/home/{{item.name}}/.ssh" state=directory owner={{item.name}} group={{item.group}} mode=0700 with_items: adminusers tags: users - name: authorized keys is deployed template: src="{{common_template_dir}}/authorized_keys.j2" dest="/home/{{item.name}}/.ssh/authorized_keys" owner={{item.name}} group={{item.group}} mode=0600 with_items: adminusers tags: users - name: sudo configured template: src="{{common_template_dir}}/sudoers_user.j2" dest="/etc/sudoers.d/{{item.name}}" owner=root group=root mode=0440 with_items: adminusers tags: users
authorized_keysのテンプレート作成
itemで指定ディレクトリの公開鍵ファイルを読み込んでいます。
public_keys_dirは共通varsファイルに記載しました。
./common-roles/base/templates/authorized_keys.j2
# Created by Ansible {% for i in item.list %} {% for j in lookup('file', public_keys_dir + '/' + i, wantlist=True) %} {{ j }} {% endfor %} {% endfor %}
sudoerファイルのテンプレート作成
本来は設定も動的に入れられるようにしておいたほうがいいかとは思いますが、ユーザー名だけitemで渡すようにしました。
./common-roles/base/templates/sudoers_user.j2
{{item.name}} ALL=(ALL) NOPASSWD:ALL
apache用
ついでにapacheのタスクファイルも作っておきます。
サービスを有効化して共通設定ファイル置いてリロード、個別設定ファイル置いてリロードという大雑把なタスクです。
./project/roles/apache2/tasks/main.yml
- name: apache2 is enabled and started service: name=apache2 state=running enabled=yes tags: apache2 - name: apache2 is configured template: src="apache2.conf" dest="/etc/apache2/apache2.conf" owner=root group=root mode=0644 notify: - reload apache2 tags: apache2 - name: apache2 specific is configured template: src="apache2_000-default.conf" dest="/etc/apache2/sites-available/000-default.conf" owner=root group=root mode=0644 notify: - reload apache2 tags: apache2
ここでは何気なくnotifyに「reload apache2」というように書いていますが、handlerなるものが必要みたいです。
apacheハンドラの作成
ということでhandlerなるものを定義しておきます。
ここではreloadとrestartのhandlerを作っています。
./project/roles/apache2/handlers/main.yml
- name: reload apache2 service: name=apache2 state=reloaded - name: restart apache2 service: name=apache2 state=restarted
apache設定ファイルテンプレートの作成
グループや環境ごとにtemplateを用意しておくのであればServerNameなど一部だけ変えられるようにしておくか、ファイルそのままでもいいかもしれません。
内容は割愛しますが、例として以下のパスに作成しました。
./project/roles/apache2/templates/apache2.conf
./project/roles/apache2/templates/apache2_000-default.conf
実行
「-D」オプションを使うとファイル変更があった場合などdiffを表示してくれるので便利でした。
ドライラン(-Cオプション)
$ ansible-playbook -i hosts/production site.yml -u ubuntu -D -C
本実行
$ ansible-playbook -i hosts/production site.yml -u ubuntu -D
ツリー構造
最終的にこんな構成になりました。
忘れてましたが、ansible.cfg(サンプル)を作業ルートディレクトリと各projectディレクトリ直下に置いておくと便利です。サーバーに接続する際のデフォルトユーザーなどの設定ができます。
. ├── ansible.cfg ├── common-roles │ ├── base │ │ ├── defaults │ │ ├── files │ │ ├── handlers │ │ ├── meta │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ ├── authorized_keys.j2 │ │ └── sudoers_user.j2 │ ├── publickeys │ │ ├── userA │ │ ├── userB │ │ ├── userC │ │ └── userD │ └── vars │ └── common.yml └── project ├── ansible.cfg ├── group_vars │ ├── all.yml │ ├── production │ │ └── project-front.yml │ ├── staging │ │ └── project-front.yml │ └── test │ └── project-front.yml ├── host_vars │ └── front1.project.domain ├── hosts │ ├── production │ ├── staging │ └── test ├── roles │ ├── adminusers │ │ ├── defaults │ │ ├── files │ │ ├── handlers │ │ ├── meta │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ ├── apache2 │ │ ├── defaults │ │ ├── files │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ ├── apache2.conf │ │ └── apache2_000-default.conf │ └── users │ ├── defaults │ ├── files │ ├── handlers │ ├── meta │ ├── tasks │ │ └── main.yml │ └── templates ├── project-front.yml └── site.yml