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

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です