TerraformでOIDCを作成

## はじめに
今回はTerraformでOIDCを実装します。
AWSの認証にOIDCを実装するとセキュアな認証が可能です。
下の記事がわかりやすかったので、共有いたします。
[一番分かりやすい OpenID Connect の説明](https://qiita.com/TakahikoKawasaki/items/498ca08bbfcc341691fe)

本記事は前回の続きです。[tfstateをS3で管理](https://qiita.com/bkend_2/items/5fd085f87a1984c841ff)
Terraform planを実装するときにAWSの認証でOIDCを使用したいので、今回作成します。


#### 記事の概要
TerraformでOIDCを作成します。
ID プロバイダはregistryのmoduleを使用します。[IAM GitHub OIDC Provider](https://registry.terraform.io/modules/terraform-aws-modules/iam/aws/latest/submodules/iam-github-oidc-provider)

#### 想定読者
- TerraformでOIDCを実装したい方

## 今回作成するAWSリソース
- OIDC


## ディレクトリ構成
`prepare`ディレクトリでは環境で共通のリソースを管理したいと思います。
OIDCは環境ごとに作成する必要がないので、prepareで呼び出します。

`prepare_tfstate`ディレクトリでは、prepareのtfstateをS3に保管するためのS3を作成しています。
下を参考にしてください。
[tfstateをS3で管理](https://qiita.com/bkend_2/items/5fd085f87a1984c841ff)

```bash
.
├── envs 
│   ├── dev # develop環境
│   │   ├── backend.tf # tfstateを管理
│   │   ├── main.tf # module呼び出し
│   │   ├── provider.tf # providerブロック
│   │   ├── terraform.tfvars # 変数を入力
│   │   └── variables.tf # 変数
│   ├── prd # production環境
│   └── stg # staging環境
├── modules
│   ├── network # ネットワーク
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   └── variables.tf
│   ├── oidc # OIDC
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   └── variables.tf
│   ├── prepare_tfstate # prepareのtfstateを管理するS3
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   └── variables.tf
│   └── tfstate # devのtfstateを管理するS3
│       ├── main.tf
│       ├── outputs.tf
│       └── variables.tf
└── prepare # 共通リソース作成
    ├── backend.tf
    ├── main.tf
    ├── provider.tf
    ├── terraform.tfvars
    └── variables.tf
```

※ outputs.tfとvariables.tfは空でも作成します。
ディレクトリ構成の参考文献
- [20 Terraform Best Practices to Improve your TF](https://spacelift.io/blog/terraform-best-practices)
- [Standard Module Structure](https://developer.hashicorp.com/terraform/language/modules/develop/structure)

## Terraformのコードと解説

OIDCを実装するために`ID プロバイダ`を作成する必要があります。
moduleを参考に`ID プロバイダ`を作成しました。[IAM GitHub OIDC Provider](https://registry.terraform.io/modules/terraform-aws-modules/iam/aws/latest/submodules/iam-github-oidc-provider)

IAMポリシーとIAMロールを作成して、`ID プロバイダ`と連携させています。
#### modules/oidc/main.tf
```terraform:modules/oidc/main.tf
# IDプロバイダを作成
module "iam_github_oidc_provider" {
  source = "terraform-aws-modules/iam/aws//modules/iam-github-oidc-provider"
}

# IAMポリシーを作成
resource "aws_iam_policy" "this" {
  name        = "Terraform-OIDC-policy"
  description = "Terraform-OIDC-policy"

  policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Effect" : "Allow",
        "NotAction" : [
          "iam:ListRoles",                      # IAMロールの一覧を取得
          "organizations:DescribeOrganization", # 組織の詳細を取得
          "account:ListRegions"                 # リージョンの一覧を取得
        ],
        "Resource" : "*"
      },
      {
        "Effect" : "Allow",
        "Action" : [
          "iam:DeleteServiceLinkedRole", # サービス連携ロールを削除
          "iam:CreateServiceLinkedRole", # サービス連携ロールを作成
          "iam:DeleteServiceLinkedRole", # サービス連携ロールを削除
          "iam:GetPolicy",               # IAMポリシーの詳細を取得
          "iam:GetOpenIDConnectProvider" # OIDCプロバイダの詳細を取得
        ],
        "Resource" : "arn:aws:iam::${var.account_id}:role/Terraform-OIDC-role"
      }
    ]
  })
}

# IAMロールを作成
resource "aws_iam_role" "this" {
  name = "Terraform-OIDC-role"
  assume_role_policy = jsonencode({
    "Version" : "2008-10-17",
    "Statement" : [
      {
        "Effect" : "Allow",
        "Principal" : {
          "Federated" : "arn:aws:iam::${var.account_id}:oidc-provider/token.actions.githubusercontent.com"
        },
        "Action" : "sts:AssumeRoleWithWebIdentity",
        "Condition" : {
          "StringLike" : {
            "token.actions.githubusercontent.com:sub" : "repo:${var.user_name}/${var.repository_name}:*"
          }
        }
      }
    ]
  })
  managed_policy_arns = [aws_iam_policy.this.arn]
}
```
※ 機密情報は環境変数で管理しています。
<details><summary>コード解説</summary>

var.account_id : アカウントIDを環境変数で入力
var.user_name : GitHubのUserアカウント
var.repository_name : GitHubのリポジトリ名

</details>

#### prepare/main.tf

prepare/main.tfでは、作成したmodules/oidcを呼び出します。
`account_id`・`user_name`・`repository_name`はterraform.tfvarsに設定しました。
```terraform:prepare/main.tf
module "oidc" {
  source          = "../modules/oidc"
  account_id      = var.account_id
  user_name       = var.user_name
  repository_name = var.repository_name
}
```

## 終わりに
今回はTerraform でOIDCを実装しました。
AWSクレデンシャルを直接設定するのは、セキュリティや運用で課題になる可能性があります。
認証はOIDCで作成しましょう。
OIDCもTerraformで作成できるので、本記事を参考にコードを書いてみてください。

今回作成したOIDCを使って、次回こそはTerraform PlanをするCIを作成します。

今回作成したGitHubのリポジトリ : https://github.com/hikobend/terraform-qiita

## 参考文献
- [一番分かりやすい OpenID Connect の説明](https://qiita.com/TakahikoKawasaki/items/498ca08bbfcc341691fe)
- [IAM GitHub OIDC Provider](https://registry.terraform.io/modules/terraform-aws-modules/iam/aws/latest/submodules/iam-github-oidc-provider)
- [20 Terraform Best Practices to Improve your TF](https://spacelift.io/blog/terraform-best-practices)
- [Standard Module Structure](https://developer.hashicorp.com/terraform/language/modules/develop/structure)

## 今後作成予定の記事
- Terraform Plan・ApplyのCIを作成
- セキュリティグループの作成