AWS IAMについての忘備録

# 目的
- AWSソリューションアーキテクトの勉強を踏まえてUdemyで勉強中
- ただコンソールを触っていてもつまらないので`Terraform`の勉強を含めてハンズオンを実施
  
# 投稿で説明すること
- IAMについての基本的な説明
    - IAMとは
    - IAMユーザ
    - IAMグループ
    - IAMロール
    - IAMポリシー
- Terraformを使ったハンズオン
    - ポリシーの作成
    - グループの作成
        - ポリシーをアタッチ
    - ユーザの作成
        - グループに参加させる

# IAMの概要
- AWS Identity and Access Managementの略をとってIAM
- AWS利用者認証の設定やアクセスポリシーの設定、ユーザまたはグループに対してアクセス制限を与えたりする

## 全体のイメージ
- IAMユーザにポリシーを適用する場合には１ユーザに紐づいている
- IAMグループは複数のIAMユーザが所属している
- IAMロールはあるAWSサービスが別のAWSサービスに操作を行う場合
    - EC2がS3に対してファイルをアップロードするなど
    
![無題のプレゼンテーション (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179132/6d636c2c-90a5-5332-4fe5-de1d1964855e.jpeg)

## IAMユーザ
- `ルートユーザ`とルートユーザから作成される`ユーザ`が存在する
    - `ルートユーザ`はAWSアカウントを作成した際に一番最初に作られる
    - Admin権限以外にAWSサービスの停止やルートユーザのアカウントなど`ルートユーザ`にしかできない操作がある
    - アクセスキーが漏洩した場合には影響が非常に大きいため、通常の開発や運用では利用しない
    - MFA(多要素認証)を設定しておき、乗っ取られない対策をしておく
- １つのAWSアカウントに対して5000ユーザまで作成が可能
- 個人利用であればIAMユーザを作成してそれぞれにIAMポリシーを割り当てればいいかもしれない、各人毎にポリシーをアタッチするのは面倒が多すぎる

## IAMグループ
- 複数のIAMユーザを特定のグループに束ねる
    - AさんとBさんはシステム管理者なので`Administratorグループ`に所属
    - Cさんはシステム運用者なので`Operationグループ`に所属
- １つのAWSアカウントで300グループまで作成が可能

![無題のプレゼンテーション (3).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179132/9127d9cf-4880-8111-1aac-8c36b486d152.jpeg)



## IAMポリシー
- どのリソースにアクセスできるのかJSON形式で定義したもの
    - ACLに近いかもしれない
- Effect
    - `Allow`:リソースへの操作を許可する
    - `Deny`:リソースへの操作を拒否する
- Action
    - ポリシーをかける対象の操作
        - S3に保存されているオブジェクトの取得など
- Resource
    - ある特定のAWSリソースに限定する場合に`ARN`で記述する
- Condition
    - ポリシーが適用される条件
        - 特定のIPアドレスからの接続のみ許可など
     
```json:S3へのフルアクセスを許可する場合
{
    "Effect": "Allow",
    "Action": [
        "S3:*",
    ],
    "Resources": [
        "arn:aws:s3::mybucket"
    ],
    "Condition": {
        "IpAddress":{
            "aws:SourceIP":
            ["192.168.10.1/32"]
        }
    }
}
```
- ポリシーには`管理ポリシー`と`インラインポリシー`が存在する

### 管理ポリシー
- １つのポリシーを複数のユーザやグループに同種の権限を付与できる
- AWS管理ポリシーとカスタマー管理ポリシーが存在する
    - AWS管理ポリシーはAWS側が用意しているポリシー
    - カスタマー管理ポリシーはユーザ自身が管理するポリシー
        - 最大５世代までバージョン管理が可能
### インラインポリシー
- ポリシーと対象が`1対1`で紐づくポリシー
    - 複数のユーザ・グループで同種のポリシーを共有できない


# Terraformでのハンズオン
## 前提
- Terraformを扱える`AdministratorAccess`ポリシーをアタッチしたIAMユーザを作成している
- Terraformの環境構築が完了している
## 想定
- `AdministratorPolicy`の操作権限もつIAMグループを作成する(グループ名Administrator)
- `AmazonEC2FullAccess `・`AmazonS3FullAccess`の操作権限をもつIAMグループを作成する(グループ名Application)
- `AmazonEC2FullAccess `・`AmazonS3FullAccess`・`AWSConfigRole`も操作権限をもつIAMグループを作成する
## ディレクトリ構造

```
.
├── iam_policy
│   ├── main.tf
│   └── policy
│       ├── administrator_policy.json
│       ├── application_policy.json
│       └── operation_policy.json
├── main.tf
└── note.md
```
## IAMグループを作成(/iam_policy)
- AWS管理ポリシーをそのまま利用しているため、ポリシーのJSONについては今回は割愛
- `resource aws_iam_policy`でIAMポリシーを作成する
- `policy = "${file("ファイルパス")}`で適用するポリシーを定義する
    - もちろんtfファイルにインラインで書くこともできる
- 後でIAM Groupにアタッチするので`output`でARNを出力させています

```tf:iam_policy/main.tf
resource "aws_iam_policy" "AdministrationPolicy" {
    name   = "AdministerPolicy"
    policy = "${file("iam_policy/policy/administrator_policy.json")}"
}

resource "aws_iam_policy" "ApplicationPolicy" {
    name   = "AppcalitionPolicy"
    policy = "${file("iam_policy/policy/application_policy.json")}"
}

resource "aws_iam_policy" "OperationPolicy" {
    name   = "OpperationPolicy"
    policy = "${file("iam_policy/policy/operation_policy.json")}"
}

#
# Ouput
#
output "Administrator_policy_arn" {
    value = "${aws_iam_policy.AdministrationPolicy.arn}"
}
output "Application_policy_arn" {
    value = "${aws_iam_policy.ApplicationPolicy.arn}"
}
output "Operation_policy_arn" {
    value = "${aws_iam_policy.OperationPolicy.arn}"
}
```

## IAMユーザを作成
- `aws_iam_user`でIAMユーザを作成する
    - `force_destory`を設定するとIAMユーザを削除時にログインプロファイルやアクセスキーも一緒に削除してくれる
- `aws_iam_user_login_profile`はWebコンソールログイン時のログイン情報となる
    - `pgp_key`の設定にはbase64でエンコードされた公開鍵かkeybaseで作成したユーザと紐付ける
    - 今回はgpgコマンドで作成し、base64文字列を変数に入れて実装
    - テストだから１個しか作らなかったが、本番利用時にはユーザ毎に証明書を作成する

- `aws_iam_access_key`はAWS-CLIやAPIを利用する際に使う認証情報となる

```terraform:iam_user/main.tf
variable "pgp_key" {
    default = "(base64でエンコードされた公開鍵)"
}
#
# Adminユーザ
#
resource "aws_iam_user" "admin_exp" {
    name          = "admin.example.one"
    path          = "/"
    force_destroy = true
}

resource "aws_iam_user_login_profile" "admin_exp_login_profile" {
    user    = "${aws_iam_user.admin_exp.name}"
    pgp_key = "${var.pgp_key}"
}

resource "aws_iam_access_key" "admin_exp_access_key" {
    user    = "${aws_iam_user.admin_exp.name}"
    pgp_key = "${var.pgp_key}"
}

output "administrator_IAM_name" {
    value = "${aws_iam_access_key.admin_exp_access_key.*.user}"
}

output "administrator_IAM_id" {
    value = "${aws_iam_access_key.admin_exp_access_key.*.id}"
}

output "administrator_IAM_encrypted_secret" {
    value = "${aws_iam_access_key.admin_exp_access_key.*.encrypted_secret}"
}


#
# Operationユーザ
#
resource "aws_iam_user" "operation_exp" {
    name          = "operaion.example.one"
    path          = "/user/operation"
    force_destroy = true
}

resource "aws_iam_user_login_profile" "operation_exp_login_profile" {
    user    = "${aws_iam_user.operation_exp.name}"
    pgp_key = "${var.pgp_key}"
}

resource "aws_iam_access_key" "operation_exp_acccess_key" {
    user    = "${aws_iam_user.operation_exp.name}"
    pgp_key = "${var.pgp_key}"
}

output "operations_IAM_name" {
    value = "${aws_iam_access_key.operation_exp_acccess_key.*.user}"
}

output "operations_IAM_id" {
    value = "${aws_iam_access_key.operation_exp_acccess_key.*.id}"
}

output "operations_IAM_encrypted_secret" {
    value = "${aws_iam_access_key.operation_exp_acccess_key.*.encrypted_secret}"
}

#
# Application ユーザ
#
resource "aws_iam_user" "application_exp" {
    name          = "operaion.example.one"
    path          = "/user/application"
    force_destroy = true
}

resource "aws_iam_user_login_profile" "application_exp_login_profile" {
    user    = "${aws_iam_user.application_exp.name}"
    pgp_key = "${var.pgp_key}"
}

resource "aws_iam_access_key" "application_exp_access_key" {
    user    = "${aws_iam_user.application_exp.name}"
    pgp_key = "${var.pgp_key}"
}

output "applications_IAM_name" {
    value = "${aws_iam_access_key.application_exp_access_key.*.user}"
}
output "application_IAM_id" {
    value = "${aws_iam_access_key.operation_exp_acccess_key.*.id}"
}
output "application_IAM_encrypted_password" {
    value = "${aws_iam_access_key.operation_exp_acccess_key.*.encrypted_secret}"
}
```

## IAMグループを作成
- `variable`は他のモジュールで作成したOutputを受け取る想定
- `aws_iam_group`でIAMグループを作成する
- `aws_iam_group_policy_attachment`でポリシーをアタッチする
- `aws_iam_group_policy_attachment`が肝
    - usersは配列を想定している
    - `element`を利用する
    
```terraform:/iam_group/main.tf
variable "AdministrationsRoleARN" {}
variable "OperationsRoleARN" {}
variable "ApplicationsRoleARN" {}
variable "AdministrationsUsers" {
    type = "list"
}
variable "OperationsUsers" {
    type = "list"
}
variable "ApplicationsUsers" {
    type = "list"
}


#
# グループ作成
resource "aws_iam_group" "Administrators" {
    name = "Administrators"
    path = "/"
}

resource "aws_iam_group" "Applications" {
    name = "Applications"
    path = "/users/applications/"
}

resource "aws_iam_group" "Operations" {
    name = "Operations"
    path = "/users/operations/"
}

#
# グループへのポリシーアタッチ
#
resource "aws_iam_group_policy_attachment" "AdministratorsPolicyAttachment" {
    group      = "${aws_iam_group.Administrators.name}"
    policy_arn = "${var.AdministrationsRoleARN}"
}
resource "aws_iam_group_policy_attachment" "ApplicationsPolicyAttachment" {
    group      = "${aws_iam_group.Applications.name}"
    policy_arn = "${var.OperationsRoleARN}"
}
resource "aws_iam_group_policy_attachment" "OperationsPolicyAttachment"{
    group      = "${aws_iam_group.Operations.name}"
    policy_arn = "${var.OperationsRoleARN}"
}


#
# ユーザをグループに参加させる
#
resource "aws_iam_group_membership" "Administrations" {
    count = "${length(var.AdministrationsUsers)}"
    name  = "Administrators-group-membership"
    users = [
        "${element(var.AdministrationsUsers, count.index)}"
    ]

    group = "${aws_iam_group.Administrators.name}"
}

resource "aws_iam_group_membership" "Operations" {
    count = "${length(var.OperationsUsers)}"
    name  = "Operations-group-membership"
    users = [
        "${element(var.OperationsUsers, count.index)}"
    ]

    group = "${aws_iam_group.Operations.name}"
}

resource "aws_iam_group_membership" "Applications" {
    count = "${length(var.ApplicationsUsers)}"
    name  = "Applications-group-membership"
    users = [
        "${element(var.ApplicationsUsers, count.index)}"
    ]

    group = "${aws_iam_group.Applications.name}"
}
```

## main.tf
```
provider "aws" {
  region = "ap-northeast-1"
}


module "iam_policy" {
    source = "./iam_policy"
}

module "iam_user" {
    source = "./iam_user"
}

module "iam_group" {
    # Policy Arn
    AdministrationsRoleARN = "${module.iam_policy.Administrator_policy_arn}"
    OperationsRoleARN      = "${module.iam_policy.Operation_policy_arn}"
    ApplicationsRoleARN    = "${module.iam_policy.Application_policy_arn}"
    # Users
    AdministrationsUsers   = "${module.iam_user.administrator_IAM_name}"
    OperationsUsers        = "${module.iam_user.operations_IAM_name}"
    ApplicationsUsers      = "${module.iam_user.applications_IAM_name}"
    source = "./iam_group"
}
```

# 参考
- https://qiita.com/reflet/items/dc109d1856b1ea525284
- https://qiita.com/digitalpeak/items/427f6cf7ed14f4187cd2