Help us understand the problem. What is going on with this article?

さらに一歩楽しむterraform. moduleでIAM UserとPolicy管理を簡素化しよう

More than 3 years have passed since last update.

俺です。

世界70億のterraform職人の皆様こんばんは。teraform職人の夜は遅いですね。

さてmodule使ってますか?
最近といってもつい数時間前から今まで自分が作ったterraform tfファイルのリファクタリングを始めました。

※同じ組織の方はGHEにpushしてるorenoシリーズリポジトリみてね(業務連絡)

今回はIAM Userとpolicyをmodule化して、
楽々使いまわせるようにする例を載せちゃいます。

参考というかこたえ

terraformのcommunity-moduleリポジトリがあるのでズバリこれで。
https://github.com/terraform-community-modules

さてやってみましょー

moduleの作成

moduleとなるterraform tfファイルを作ります

例として以下の様なディレクトリ/ファイル構成にしておきます。
1tfにまとめてもいいんじゃねって思うのですが
まあーresourceはながーくなることもあるし、community-modulesがこんな感じになってるので
この辺は準拠しておいたほうがよさそうな感じですかねー。
各プロジェクトでルール作ってしまえば良いと思いますね。

moduleのファイル用途

ファイル名 用途
variables.tf 変数定義
iam_***.tf resource定義
outputs.tf 戻り値定義

moduleのディレクトリ/ファイル構造

orenomac$ tree module/iam
module/iam
├── group
│   ├── iam_group.tf
│   ├── outputs.tf
│   └── variables.tf
├── policy
│   ├── aws_iam_policy.tf
│   ├── outputs.tf
│   └── variables.tf
├── role
└── user
    ├── aws_iam_user.tf
    ├── outputs.tf
    └── variables.tf

IAM Group用モジュールを作る

  • variables.tf

module resourceの引数に指定するvariableを定義します。

variable "aws_iam_groupname" {
  description = "iam group name"
}

variable "aws_iam_grouppath" {
  description = "iam group path(/users/)"
  default = "/"
}
  • iam_group.tf

moduleで動作するresourceを定義します

resource "aws_iam_group" "iam-group" {
  name = "${var.aws_iam_groupname}"
  path = "${var.aws_iam_grouppath}"
}
  • outputs.tf

module外から参照されるresourceでmodule内で定義された変数を参照するための戻り値を定義します。
outputを定義しておかないと、moduleで作られたresource内variableを、外部resourceで参照することができません。

output "name" {
  value = "${aws_iam_group.iam-group.name}"
}

IAM User用モジュールを作る

  • variables.tf
variable "aws_iam_username" {
  description = "iam user name"
}
variable "aws_iam_grouppath" {
  description = "iam group path(/users/)"
  default = "/"
}
  • aws_iam_user.tf
resource "aws_iam_user" "iam-user" {
  name = "${var.aws_iam_username}"
  path = "${var.aws_iam_grouppath}"
}
  • outputs.tf
output "name" {
  value = "${aws_iam_user.iam-user.name}"
}

IAM Policy用モジュールを作る

  • variables.tf
variable "aws_iam_policy_name" {
  description = "Policy Name"
  default = "iam-policy"
}

variable "aws_iam_policy_path" {
  description = "iam policy path"
  default = "/policy/"
}

variable "aws_iam_policy_description" {
  description = "iam policy description"
  default = "iam policy"
}
variable "aws_iampolicy_json" {
  description = "iampolicy json filename"
  default = "iam_policy.json"
}
  • aws_iam_policy.tf

policyにはjsonファイルをそのまま放り込めるように組み込み関数fileを使います。

resource "aws_iam_policy" "iam-policy" {
  name = "${var.aws_iam_policy_name}"
  path = "${var.aws_iam_policy_path}"
  description = "${var.aws_iam_policy_description}"
  policy = <<EOF
${file("${var.aws_iampolicy_json}")}
EOF
}
  • outputs.tf

arnを返すようにします。

output "name" {
  value = "${aws_iam_policy.iam-policy.name}"
}

output "arn" {
  value = "${aws_iam_policy.iam-policy.arn}"
}

moduleを利用するtfの作成

こんなかんじです

orenomac$ tree examples/
examples/
├── datawanwan_policy.json
└── test_terraform.tf
  • test_terraform.tf

メインとなるtfではmoduleに変数指定して呼び出すだけです。
sourceには使用するmoduleが格納されているディレクトリまでのパスを記述します。
本例ではディレクトリパスを指定してますが、github/bitbucketなどのパスを指定することもできます。

同僚の皆様GHEにpushしとくので使って下さいww(業務連絡

provider "aws" {
  region = "ap-northeast-1"
}

module "iam-group" {
  source = "../module/iam/group"
  aws_iam_groupname = "oreore"
  aws_iam_grouppath = "/oreore/"
}

module "iam-user" {
  source = "../module/iam/user"
  aws_iam_username = "iam-user"
  aws_iam_grouppath = "/oreore/users/"
}

module "iam-datawanwan" {
  source = "../module/iam/user"
  aws_iam_username = "iam-datawanwan"
  aws_iam_grouppath = "/oreore/users/"
}

module "iam-datawanwan_policy" {
  source = "../module/iam/policy/"
  aws_iam_policy_name = "datawanwan"
  aws_iam_policy_path = "/policy/"
  aws_iam_policy_description =  "datawanwan policy"
  aws_iampolicy_json = "datawanwan_policy.json"
}

/* moduleで定義されたresourceのvariablesを外部resourceから参照する例 */

resource "aws_iam_policy_attachment" "datawanwan" {
  name = "datawanwan"
  users = ["${module.iam-datawanwan.name}"]
  policy_arn = "${module.iam-datawanwan_policy.arn}"
}
  • datawanwan_policy.json

datadogのドキュメントに書いてる通りのポリシーを準備しておきます。
module

{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Action": [
        "autoscaling:Describe*",
        "cloudformation:DescribeStacks",
        "cloudformation:DescribeStackEvents",
        "cloudformation:DescribeStackResources",
        "cloudformation:GetTemplate",
        "cloudfront:Get*",
        "cloudfront:List*",
        "cloudtrail:DescribeTrails",
        "cloudtrail:GetTrailStatus",
        "cloudwatch:Describe*",
        "cloudwatch:Get*",
        "cloudwatch:List*",
        "dynamodb:GetItem",
        "dynamodb:BatchGetItem",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:DescribeTable",
        "dynamodb:ListTables",
        "ec2:Describe*",
        "elasticache:Describe*",
        "elasticbeanstalk:Check*",
        "elasticbeanstalk:Describe*",
        "elasticbeanstalk:List*",
        "elasticbeanstalk:RequestEnvironmentInfo",
        "elasticbeanstalk:RetrieveEnvironmentInfo",
        "elasticloadbalancing:Describe*",
        "iam:List*",
        "iam:Get*",
        "route53:Get*",
        "route53:List*",
        "rds:Describe*",
        "rds:ListTagsForResource",
        "s3:List*",
        "sdb:GetAttributes",
        "sdb:List*",
        "sdb:Select*",
        "ses:Get*",
        "ses:List*",
        "sns:Get*",
        "sns:List*",
        "sqs:GetQueueAttributes",
        "sqs:ListQueues",
        "sqs:ReceiveMessage"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

いざterraform plan/apply..のまえに

terraform getでmoduleを取得します

orenomac$ cd <path>/<to>/examples
orenomac$ terraform get
Get: file:///orenoterraform/module/iam/group
Get: file:///orenoterraform/module/iam/user
Get: file:///orenoterraform/module/iam/user
Get: file:///orenoterraform/module/iam/policy

plan

planを実行します

orenomac$ terraform plan
Refreshing Terraform state prior to plan...


The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

+ aws_iam_policy_attachment.datawanwan
    name:             "" => "datawanwan"
    policy_arn:       "" => "${module.iam-datawanwan_policy.arn}"
    users.#:          "" => "1"
    users.XXXXXXXXXXX: "" => "iam-datawanwan"

+ module.iam-datawanwan_policy.aws_iam_policy.iam-policy
    arn:         "" => "<computed>"
    description: "" => "datawanwan policy"
    name:        "" => "datawanwan"
..省略..

apply

apply叩く前にACCESS_KEYとSECRET_KEYは設定しておきましょうー。
direnvとか環境変数のexportで。

orenomac$ terraform apply
module.iam-user.aws_iam_user.iam-user: Creating...
  arn:       "" => "<computed>"
  name:      "" => "iam-user"
  path:      "" => "/oreore/users/"
  unique_id: "" => "<computed>"
module.iam-datawanwan_policy.aws_iam_policy.iam-policy: Creating...
  arn:         "" => "<computed>"
..省略..
orenomac$ terraform show
aws_iam_policy_attachment.datawanwan:
  id = datawanwan
  groups.# = 0
  name = datawanwan
  policy_arn = arn:aws:iam::XXXXXXXXXXX:policy/policy/datawanwan
  roles.# = 0
  users.# = 1
  users.XXXXXXXXXXXX = iam-datawanwan

ちなみに
moduleのoutputは、terraform outputで参照することはできません。

orenomac$ terraform output
The state file has no outputs defined. Define an output
in your configuration with the `output` directive and re-run
`terraform apply` for it to become available.

みんなterraform module使って楽しましょう的~

gamisan9999
俺です。 株式会社アンドゲートに全力コミットしてます
http://www.andgate.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした