LoginSignup
4
2

More than 1 year has passed since last update.

お題は不問!Qiita Engineer Festa 2023で記事投稿!

Terraformで実践するAWS IAM Identity Center(AWS Single Sign-On)のユーザー管理戦略

Last updated at Posted at 2023-06-21

はじめに

AWS IAM Identity Center(AWS Single Sign-On)を使用して、ユーザー管理を考えていく上で、Terraformを使用して構成管理を実現しようと思います。

作成したコードはgithub上に上がっているので、ご参考ください。
(※*.tfstate.gitignoreに記載し、git管理外としています。)

構成図

スクリーンショット 2023-06-16 17.10.49.png

構成管理にはStateファイルの管理をサーバレスに行える点を考慮してTerraform Cloudを使用します

なお、今回は複数環境へのデプロイ含むCI/CDの設計などは考慮していません。

実装

Terraform Cloud と Githubの接続

こちらを参考にVSC接続を行う

AWS SSO 有効化/ユーザー・グループの作成

最初に AWS SSO を有効にする必要がありますが、残念ながら 2023/6/21 時点で Terraformを使用したコードでの有効化設定は非対応です。 そのため、コンソール上から有効化したいリージョンを選択し、手動で有効にします

続いて、AWS IAM Identity Centerでユーザー/グループを作成しますが、こちらも Terraform で作成することはできません。 そのため、マネジメントコンソールで作成します。

また、グループにアタッチしたいユーザーもここでアタッチしておきます。

スクリーンショット 2023-06-21 12.13.29.png

スクリーンショット 2023-06-21 12.13.37.png

方針

今回は、Admin,Developer,Guest,Systemと4つのグループを用意し、それぞれのグループにアタッチするポリシーをあらかじめ決定。

Admin: SREチームのユーザーが属するグループ。AdministratorAccessの権限を付与。
Developer: SREチーム以外の開発者用グループ。開発作業に必要最低限のアクセスを付与。
Guest: 開発チーム以外のグループ。ReadOnlyが主となるアクセス。
System: システム系で使用するIAMポリシーをまとめたもの。

例:AdminグループにはAdminのアクセス権限セットをアタッチするように設定。

tarraform

実装したものが、以下。

※マネージドポリシーとカスタマー管理ポリシーでは作成に使用するterraform resourceが異なるので、variableを別々で定義した。

aws-sso.tf
########################################
# Terraformできないこと
# 下記に示すものはTerraformではできないので、手動でコンソール上(IAM Identity Center)から設定する必要がある

# 1. グループの作成・削除
# 2. ユーザーの追加・削除
# 3. グループにユーザーを追加・削除
########################################

data "aws_ssoadmin_instances" "example" {}

locals {
  groups = var.aws_sso_group
  policies = {
    Admin = {
      managed  = var.aws_sso_admin_managed_policies
      customer = var.aws_sso_admin_customer_policies
    }
    Guest = {
      managed  = var.aws_sso_guest_managed_policies
      customer = var.aws_sso_guest_customer_policies
    }
    Developer = {
      managed  = var.aws_sso_developer_managed_policies
      customer = var.aws_sso_developer_customer_policies
    }
    System = {
      managed  = var.aws_sso_system_managed_policies
      customer = var.aws_sso_system_customer_policies
    }
  }
  managed_policy_attachments = flatten([
    for group, policies in local.policies : [
      for policy in policies.managed : {
        group  = group
        policy = policy
      }
    ]
  ])
  customer_policy_attachments = flatten([
    for group, policies in local.policies : [
      for policy in policies.customer : {
        group  = group
        policy = policy
      }
    ]
  ])
}

########################################
# IAM Identity Center グループを取得
########################################
data "aws_identitystore_group" "group" {
  for_each = toset(local.groups)

  identity_store_id = tolist(data.aws_ssoadmin_instances.example.identity_store_ids)[0]

  alternate_identifier {
    unique_attribute {
      attribute_path  = "DisplayName"
      attribute_value = each.value
    }
  }
}
########################################
# アクセス許可セット作成
########################################
resource "aws_ssoadmin_permission_set" "PermissionSet" {
  for_each = toset(local.groups)

  name         = each.value
  description  = each.value
  instance_arn = tolist(data.aws_ssoadmin_instances.example.arns)[0]
}
locals {
  groups_to_permission_set = var.groups_to_permission_set
  assignment = [
    for tmp in setproduct(local.groups, values(data.aws_identitystore_group.group)) : {
      group_name          = tmp[0]
      group_id            = tmp[1].group_id
      permission_set_name = local.groups_to_permission_set[tmp[0]]
    }
  ]
}
########################################
# アクセス許可セットにポリシーをアタッチ
########################################
resource "aws_ssoadmin_managed_policy_attachment" "managed_policy_attachment" {
  for_each = { for item in local.managed_policy_attachments : "${item.group}.${item.policy}" => item }

  instance_arn       = aws_ssoadmin_permission_set.PermissionSet[each.value.group].instance_arn
  managed_policy_arn = each.value.policy
  permission_set_arn = aws_ssoadmin_permission_set.PermissionSet[each.value.group].arn
}

resource "aws_ssoadmin_customer_managed_policy_attachment" "customer_policy_attachment" {
  for_each = { for item in local.customer_policy_attachments : "${item.group}.${item.policy}" => item }

  instance_arn       = aws_ssoadmin_permission_set.PermissionSet[each.value.group].instance_arn
  permission_set_arn = aws_ssoadmin_permission_set.PermissionSet[each.value.group].arn
  customer_managed_policy_reference {
    name = split("/", each.value.policy)[1]
    path = "/"
  }
}
########################################
# IAM Identity Center グループにアクセス許可セットを関連付け
########################################
resource "aws_ssoadmin_account_assignment" "example" {
  for_each = data.aws_identitystore_group.group

  instance_arn       = aws_ssoadmin_permission_set.PermissionSet[each.key].instance_arn
  permission_set_arn = aws_ssoadmin_permission_set.PermissionSet[each.key].arn

  principal_id   = each.value.group_id
  principal_type = "GROUP"

  target_id   = var.account_id
  target_type = "AWS_ACCOUNT"
}

variables.tf
# variables.tfはvariable(変数)の宣言を行うところです。
variable "region" {
  description = "AWS region"
  default     = "ap-northeast-1"
}
# terraform cloudから取得
variable "AWS_ACCESS_KEY_ID" {}
variable "AWS_SECRET_ACCESS_KEY" {}

variable "account_id" {
  description = "The ID of the AWS account"
  type        = string
  # 12桁のアカウントID
  default     = "xxxxxxxxxxxx"
}


########################################
# IAM Identity Centerのグループ・許可セットを定義
# グループには同名の許可セットを関連付ける
########################################
variable "aws_sso_group" {
  description = "The list of identity store group"
  type        = list(string)
  default     = ["Admin", "Guest", "Developer", "System"]
  // Add more if needed
}

variable "groups_to_permission_set" {
  type = map(any)
  default = {
    Admin     = "Admin"
    Guest     = "Guest"
    Developer = "Developer"
    System    = "System"
    // Add more if needed
  }
}
########################################
# グループごとに使用するポリシーのarnを指定
# managedポリシーとカスタマー管理ポリシーでは作成するresourceが異なるので、それぞれvariableを用意
########################################
## Admin
variable "aws_sso_admin_managed_policies" {
  description = "The list of admin managed policies"
  type        = list(string)
  default = [
    "arn:aws:iam::aws:policy/AdministratorAccess"
  ]
}
variable "aws_sso_admin_customer_policies" {
  description = "The list of admin customer policies"
  type        = list(string)
  default     = []
}
## Guest
variable "aws_sso_guest_managed_policies" {
  description = "The list of guest managed policies"
  type        = list(string)
  default = []
}
variable "aws_sso_guest_customer_policies" {
  description = "The list of guest customer policies"
  type        = list(string)
  default = []
}
## Developer
variable "aws_sso_developer_managed_policies" {
  description = "The list of developer managed policies"
  type        = list(string)
  default = []
}
variable "aws_sso_developer_customer_policies" {
  description = "The list of developer customer policies"
  type        = list(string)
  default = []
}
## System
variable "aws_sso_system_managed_policies" {
  description = "The list of system managed policies"
  type        = list(string)
  default = []
}

variable "aws_sso_system_customer_policies" {
  description = "The list of system customer policies"
  type        = list(string)
  default = []
}

git pushをすればmainブランチへのマージをトリガーにterraform plan , terraform applyが実行される

※ git push する前にterraform fmtでフォーマットを整形しておくと良い(もしくはCI/CDに組み込む)

さいごに

今回の実装を通して感じた気づき・学びをシェア

  • Terraform Cloudを使用するとstateファイルの管理がすごく楽
  • Terraformで対応していないリソースのIaCをどのように管理・運用していくかチームで共通認識を作る必要がある
  • どこまでをvariable, localといった変数として扱うかの判断が難しい
  • Terraformは楽しい😁

参考

【Terraform】

【Terraform Cloud】

【AWS SSO】

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2