TerraformがAWS SSO(Single Sign-On)に対応してました

2021.02.15

上記エントリを書いた際(2020/10/29時点)には、TerraformでAWS SSO(Single Sign-On)のリソースをプロビジョニングすることはできませんでした。が、その後terraform-provider-awsのv3.23.0、v3.24.0で一部リソースのプロビジョニングができるようになりましたので、使ってみたいと思います。

追加された Resource / Data Source

Resource

Data Source

概要

AWS SSOの設定としてはざっくりとは以下があります。(SSOのIDストアを使う場合です。外部のIDシステムを使う場合「ユーザー・グループを作る」あたりが変わるはずです。)

  1. SSOの有効化
  2. ユーザー・グループを作る
  3. アクセス権限セット(Permission Set)作成
  4. アクセス権限セット(Permission Set)にポリシーをアタッチ
  5. ユーザー・グループ & アカウント & アクセス権限セット紐付け(Assignment)

このうち、今回Terraformでプロビジョニングできるようになったのは下の3つの部分です。
上2つはプロビジョニングはできませんが、Data Sourceを使って参照することができます。

やってみた

前提条件

  • Organization下に3アカウント作成
  • SSO有効化
  • SSOのユーザー・グループ作成

まで行なった状態で、以降の設定をTerraformでやってみます。

ユーザーは以下の2ユーザーを作成しています。 0213-sso-users

それぞれ対応するグループも作成して、ユーザーを配下に所属させています。 0213-sso-groups

Terraformでやることの詳細は以下です。

  • アクセス権限セット(Permission Set)を3つ作成する
  • 上記アクセス権限セット(Permission Set)に適切なポリシーをアタッチする
  • 各グループと各アカウントとアクセス権限セット(Permission Set)を紐付ける(Assignment) = 2グループ x 3アカウントで6個のAssignmentが必要
  • アクセス権限セット(Permission Set)にインラインポリシーを追加する

このあたりのSSOの概念がわからない方は、先に以下エントリをお読みいただければ幸いです。

ではやっていきましょう。

アクセス権限セット作成

data "aws_ssoadmin_instances" "main" {}

resource "aws_ssoadmin_permission_set" "main" {
  for_each = toset([
    "AdministratorAccess",
    "ReadOnlyAccess"
  ])

  name         = each.value
  instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0]
}

data.aws_ssoadmin_instancesarnsはset型なので上記のようにtolist(data.aws_ssoadmin_instances.main.arns)[0]とする必要がある点に注意です。

0213-permission-sets アクセス権限セット(Permission Set)が作成されました。

アクセス権限セット(Permission Set)にポリシーをアタッチ

resource "aws_ssoadmin_managed_policy_attachment" "main" {
  for_each = aws_ssoadmin_permission_set.main

  instance_arn       = tolist(data.aws_ssoadmin_instances.main.arns)[0]
  managed_policy_arn = "arn:aws:iam::aws:policy/${each.key}"
  permission_set_arn = each.value.arn
}

0213-admin-policy

0213-readonly-policy

ユーザー・グループ & アカウント & アクセス権限セット紐付け(Assignment)

data "aws_organizations_organization" "main" {}
data "aws_identitystore_group" "admin" {
  identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0]

  filter {
    attribute_path  = "DisplayName"
    attribute_value = "admin"
  }
}
resource "aws_ssoadmin_account_assignment" "admin" {
  for_each = toset(data.aws_organizations_organization.main.accounts[*].id)

  instance_arn       = tolist(data.aws_ssoadmin_instances.main.arns)[0]
  permission_set_arn = aws_ssoadmin_permission_set.main["AdministratorAccess"].arn

  principal_id   = data.aws_identitystore_group.admin.group_id
  principal_type = "GROUP"

  target_id   = each.value
  target_type = "AWS_ACCOUNT"
}
data "aws_identitystore_group" "readonly" {
  identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0]

  filter {
    attribute_path  = "DisplayName"
    attribute_value = "readonly"
  }
}
resource "aws_ssoadmin_account_assignment" "readonly" {
  for_each = toset(data.aws_organizations_organization.main.accounts[*].id)

  instance_arn       = tolist(data.aws_ssoadmin_instances.main.arns)[0]
  permission_set_arn = aws_ssoadmin_permission_set.main["ReadOnlyAccess"].arn

  principal_id   = data.aws_identitystore_group.readonly.group_id
  principal_type = "GROUP"

  target_id   = each.value
  target_type = "AWS_ACCOUNT"
}

aws_ssoadmin_account_assignment.target_idaws_organizations_organizationData Sourceaccounts[*].id を使うことで、Organizations配下のアカウントをすべて対象にしています。

各アカウントにて、admin・readonlyグループがそれぞれ適切な権限をもってアサインされました。 0213-assingments

インラインポリシーも使ってみる

上記のアクセス権限セット(Permission Set)にアタッチしたポリシーはAWS管理ポリシーでしたが、インラインポリシーも併せてアタッチすることができます。 特定の送信元IP以外からの操作はすべて拒否するインラインポリシーをアタッチしてみましょう。

data "aws_iam_policy_document" "deny_ip" {
  statement {
    effect    = "Deny"
    actions   = ["*"]
    resources = ["*"]
    condition {
      test = "NotIpAddress"
      variable = "aws:SourceIp"
      values = ["xxx.xxx.xxx.xxx/32"]
    }
  }
}
resource "aws_ssoadmin_permission_set_inline_policy" "main" {
  for_each = aws_ssoadmin_permission_set.main

  instance_arn       = tolist(data.aws_ssoadmin_instances.main.arns)[0]
  inline_policy      = data.aws_iam_policy_document.deny_ip.json
  permission_set_arn = each.value.arn
}

admin userでログインしてみます。

0213-deny

0213-allow