ENECHANGE Developer Blog

ENECHANGE開発者ブログ

TerraformでIAMグループ・ユーザを作成する

  • こんにちは。熱い太陽光を浴びるとモリモリ元気が出る気がするCTO室のigaharaです。 今日は以前から社内からAWSの機能検証を気軽に実施できる環境がほしいというリクエストがあったため、新たにAWSアカウントを作成し、異なる権限をもったIAMグループを作成し、エンジニアごとに所属させたことを記事にしたいと思います。

作成するグループとそれに付与する管理ポリシー

  • グループ名:administrator
    • 管理ポリシー名:AdministratorAccess
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        }
    ]
}
  • グループ名:development
    • 管理ポリシー名:PowerUserAccess
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "NotAction": [
                "iam:*",
                "organizations:*"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "iam:CreateServiceLinkedRole",
                "iam:DeleteServiceLinkedRole",
                "iam:ListRoles",
                "organizations:DescribeOrganization"
            ],
            "Resource": "*"
        }
    ]
}
  • グループ名:operators
    • 管理ポリシー名:未設定

作成するユーザ

  • 11ユーザ作成
    • administratorグループへ追加

設定ファイル構成

.
├── README.md
├── iam_group_membership.tf
├── iam_user.tf
├── main.tf
├── terraform_remote_state.tf
└── variables.tf
  • variables.tf
variable "aws_iam_user" {
  type = "list"

  default = [
    "exp.enechange.yell",
    "exp.enechange.ange",
    "exp.enechange.etoile",
    "exp.enechange.amor",
    "exp.enechange.macherie",
    "exp.enechange.whip",
    "exp.enechange.custerd",
    "exp.enechange.gelato",
    "exp.enechange.macaron",
    "exp.enechange.chocolat",
    "exp.enechange.parfait",

  ]
}

variable "aws_iam_group" {
  type = "list"

  default = [
    "administrator",
    "development",
    "operators",
  ]
}
  • iam_user.tf
    • シークレットキーはkeybaseを使用して暗号化し、ユーザIDと関連付けしてoutputさせています
resource "aws_iam_user" "enechange_exp" {
  count         = "${length(var.aws_iam_user)}"
  name          = "${element(var.aws_iam_user, count.index)}"
  path          = "/"
  force_destroy = true
}

resource "aws_iam_user_login_profile" "enechange_exp_login_profile" {
  count                   = "${length(var.aws_iam_user)}"
  user                    = "${element(var.aws_iam_user, count.index)}"
  pgp_key                 = "keybase:exp_enechange"
  password_reset_required = true
  password_length         = "20"
}

resource "aws_iam_access_key" "enechange_exp_access_key" {
  count   = "${length(var.aws_iam_user)}"
  user    = "${element(var.aws_iam_user, count.index)}"
  pgp_key = "keybase:exp_enechange"
}

output "encrypted_secret" {
  value = "${join("\n", aws_iam_access_key.enechange_exp_access_key.*.encrypted_secret)}"
}

output "id" {
  value = "${join("\n", aws_iam_access_key.enechange_exp_access_key.*.id)}"
}

output "user" {
  value = "${join("\n", aws_iam_access_key.enechange_exp_access_key.*.user)}"
}
  • iam_group_membership.tf
resource "aws_iam_group_membership" "enechange_exp_group_membership" {
  count = "${length(var.aws_iam_user)}"
  name  = "enechange_exp_group_membership"

  users = [
    "${element(var.aws_iam_user, count.index)}",
  ]

  group = "${element(var.aws_iam_group, 0)}"
}

resource "aws_iam_group" "enechange_exp_group" {
  count = "${length(var.aws_iam_group)}"
  name  = "${element(var.aws_iam_group, count.index)}"
}

resource "aws_iam_group_policy_attachment" "policy-attach" {
  group      = "${element(var.aws_iam_group, count.index)}"
  policy_arn = "arn:aws:iam::************:policy/administratoraccess"
}
  • output
$ terraform output
encrypted_secret = wcFMA615XJelCVO0ARAA(snip)
wcFMA615XJelCVO0ARAA(snip)
wcFMA615XJelCVO0ARAA(snip)
wcFMA615XJelCVO0ARAA(snip)
wcFMA615XJelCVO0ARAA(snip)
wcFMA615XJelCVO0ARAA(snip)
wcFMA615XJelCVO0ARAA(snip)
wcFMA615XJelCVO0ARAA(snip)
wcFMA615XJelCVO0ARAA(snip)
wcFMA615XJelCVO0ARAA(snip)
wcFMA615XJelCVO0ARAA(snip)
id = AKIA****************
AKIA****************
AKIA****************
AKIA****************
AKIA****************
AKIA****************
AKIA****************
AKIA****************
AKIA****************
AKIA****************
AKIA****************
AKIA****************
user =exp.enechange.yell
exp.enechange.ange
exp.enechange.etoile
exp.enechange.amor
exp.enechange.macherie
exp.enechange.whip
exp.enechange.custerd
exp.enechange.gelato
exp.enechange.macaron
exp.enechange.chocolat
exp.enechange.parfait
  • 作成したユーザ分のシークレットキーをoutputすることはできるんですが、outputにcount処理が使えなく、どのキーがどのユーザに紐付いてるのかわからず...、また、ユーザ分のシークレットキーを復号化する際は、terraform output encrypted_secret | base64 --decode | keybase pgp decryptで処理するんですが、複数のoutputをうまく処理できなく困ってました... どう処理をぶん回すのが効率がいいか悩んでいたところ弊社が誇るRuby関西のFounderでもあるRubyistのcuzic (a.k.a Tomoya Kawanishi )が助けてくれました。(私の社内でのコードレビューの90%はcuzic...!) 「ちょっとまっとき〜」と言って1時間後に下記ワンライナー付きでメンションがきました。
$ terraform output -json | ruby -rjson -ryaml -e 'json = JSON.load(ARGF); keys = %w(user id encrypted_secret); puts [keys, *keys.map{|key| v = json[key]["value"].split; key == "encrypted_secret" ? v.map{|s| `echo #{s} | base64 -d | keybase pgp decrypt -S exp_enechange`.chomp} : v}.transpose].map{|a| a.join(",")}'

素敵やん...!

  • 実行結果
user,id,encrypted_secret
exp.enechange.yell,AKIA****************,Ya3R************************************
enechange.ange,AKIA****************,GYW7************************************
enechange.etoile,AKIA****************,bUpd************************************
exp.enechange.amor,AKIA****************,5lHm************************************
exp.enechange.macherie,AKIA****************,RyoM************************************
exp.enechange.whip,AKIA****************,r7EW************************************
exp.enechange.custerd,AKIA****************,CoBk************************************
exp.enechange.gelato,AKIA****************,FWYd************************************
exp.enechange.macaron,AKIA****************,4taL************************************
exp.enechange.chocolat,AKIA****************,4taL************************************
exp.enechange.parfait,AKIA****************,4taL************************************

最高やん...!

  • これらをまとめてMFAを使うように手順も併せて配布すれば、きっと開発速度が向上し、技術的負債を熨斗付きで返済するようなイノベーションが発生するはず...!

お知らせ

弊社では下記職種で募集しています!

  • エンジニア
  • ディレクター
  • コーポレート・スタッフ
  • セールス
  • マーケティング
  • ライター
  • コンサルタント・アナリスト
  • プロジェクトマネージャー www.wantedly.com

  • オフィス見学 www.wantedly.com