AnsibleでIAM User/Group/Roleを管理する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

土日となると天気が悪い北海道の渡辺です。

今日は七夕の創立記念日ということで、AnsibleのAWSモジュールを使ってIAM User, Group, Role を管理する方法を紹介します。

iam / iam_policyモジュール

Ansibleのiamモジュールiam_policyモジュールはコアモジュールのひとつで、AWS上のIAMリソースとポシリードキュメントを管理します。

IAMリソースは、CloudFormationでも管理可能です。 Ansibleのモジュールを利用した場合、ポリシードキュメントの再利用テンプレートが利用できる点がポイントとなってきます。

iamモジュールでIAM Roleを作成する

iamモジュールは、iam_typeでIAMリソースの種類を指定し、User / Group / Roleを作成します。 profilestateを指定すること以外で特別なことはありません。

次のplaybookは、developという名前のIAM Roleを作成します。

- hosts: localhost
  connection: local
  gather_facts: False
  vars:
    profile: default
  tasks:
    - name: IAM Role, develop
      iam:
        iam_type: role
        name: develop
        state: present
        profile: "{{ profile }}"

iam_typeでは、user, group, roleのいずれかを指定します。 次のように、with_itemsなども併用して複数のユーザをまとめて作成することも容易です。

- hosts: localhost
  connection: local
  gather_facts: False
  vars:
    profile: default
  tasks:
    - name: IAM Users
      iam:
        iam_type: user
        name: {{ item }}
        state: present
        profile: "{{ profile }}"
      with_items:
        - greipel
        - sagan
        - kittel
        - cavendish

iam_policyモジュールでポリシードキュメントを管理する

iam_policyモジュールでは、IAMリソースのポリシードキュメントを管理します。 policy_documentでjsonファイルを指定し、対象のIAMリソースにアタッチします。

次のplaybookは、develop Roleにポリシードキュメントを2つ追加しています。

- hosts: localhost
  connection: local
  gather_facts: False
  vars:
    profile: default
  tasks:
    - name: IAM Policy, develop/cloudwatch-logs
      iam_policy:
        iam_type: role
        iam_name: develop
        policy_name: cloudwatch-logs
        policy_document: policy/cloudwatch-logs.json
        state: present
        profile: "{{ profile }}"
    - name: IAM Policy, develop/codedeploy
      iam_policy:
        iam_type: role
        iam_name: develop
        policy_name: codedeploy
        policy_document: policy/codedeploy.json
        state: present
        profile: "{{ profile }}"

ポリシードキュメントは、playbookを保存したディレクトリにpolicyディレクトリを作成し、それぞれjsonファイルとして保存します。

policy/cloudwatch-logs.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents",
        "logs:DescribeLogStreams"
      ],
      "Resource": [
        "arn:aws:logs:*:*:*"
      ]
    }
  ]
}

policy/codedeploy.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:GetObjectVersion",
        "s3:ListObjects",
        "codedeploy:RegisterApplicationRevision"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

ポリシードキュメントが独立したファイルとして参照され、共有資産として再利用可能です。

AWSの標準機能で管理ポリシーと呼ばれるテンプレート的なポリシーを提供しています。 現実的な運用では、管理ポリシーでは大雑把過ぎることが多いため、ポリシードキュメントのスニペットをコピペしながら利用することが多いでしょう(主にドキュメントからコピーします)。 Ansibleを利用することで、ポリシードキュメントはチームの資産としてストックできるようになります。

ポリシードキュメントをテンプレート化する

Jinja2によるテンプレート機能はAnsibleの魅力のひとつです。 実は、iam_policyモジュールのpolicy_jsonを利用すれば、このテンプレート機能が利用できます。 ポリシードキュメントをテンプレート化し、検証環境と本番環境での差異を吸収できれば、シアワセになれうでしょう。

例えばあるバケットにアクセスできるポリシードキュメントの「バケット名」のみを変数化したポリシードキュメントのテンプレートは次のようになります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:*"
      ],
      "Resource": [
        "arn:aws:s3:::{{ s3_bucket_name }}"
      ]
    }
  ]
}

しかしながら、Ansible 2.1ではこの機能が利用できません。 テンプレートからの変換時、JSONのエスケープ処理に不具合があるようで、ポリシードキュメント適用時にシンタックスエラーとなってしまいます。 Ansible 2.2では解決されるようなので、この機能は2.2リリース後に紹介したいと思います。

管理ポリシーに対応できない

Ansibleのiam_policyモジュールは管理ポリシーに対応できません。 実はこれ、Ansibleで利用しているbotoが対応していないからというのが理由のようです。

まとめ

AWSでの構成管理と言えば基本はCloudFormationです。 ですが、適用するシーンや再利用性などを検討すると使いにくい部分も幾つかあります。 先日紹介したキーペアの管理やポリシードキュメントあたりはそのひとつです。 AnsibleのAWSモジュールやCloudFormationを併用し、適材適所で構成管理をするのがベストプラクティスではないでしょうか?