From 13b7c1b0c1d1b8076c0e3abff443602c4dcab172 Mon Sep 17 00:00:00 2001 From: Sean Molenaar Date: Mon, 15 Jul 2024 18:49:19 +0200 Subject: [PATCH] feat: add AWS import Issue GH-2 --- .terraform.lock.hcl | 17 ++++++ aws/iam-sso.tf | 135 +++++++++++++++++++++++++++++++++++++++++++ aws/main.tf | 11 ++++ aws/roles.tf | 61 +++++++++++++++++++ aws/vars.tf | 3 + dnsimple/contacts.tf | 15 ++--- import.tf | 10 ++++ main.tf | 14 +++++ 8 files changed, 259 insertions(+), 7 deletions(-) create mode 100644 aws/iam-sso.tf create mode 100644 aws/main.tf create mode 100644 aws/roles.tf create mode 100644 aws/vars.tf diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl index 2ed4cf2..ee14175 100644 --- a/.terraform.lock.hcl +++ b/.terraform.lock.hcl @@ -1,6 +1,23 @@ # This file is maintained automatically by "tofu init". # Manual edits may be lost in future updates. +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.58.0" + hashes = [ + "h1:04ghxbw3dRpNymtWAbKIdIXtK+mQmXtn5B8mWY8YxrY=", + "zh:2e1c6d710455707c520da58840b0ce24c470437d997ca6843bd0e68ea4c60a4e", + "zh:2f493c86ad9bef82447d0aaa3a17752797e501ca6fb7820964279e8e6e81c8c9", + "zh:8f78e0d3a65213335d1877dacfe05a84f0b4c86de4388ef0a42aa692c7f12df0", + "zh:90f3471a42177db0d7f486698284e6d15bb82c439f2a1b94ae89a0442ff716cc", + "zh:9971dd0b159c8ab5ae16ce3a47b14900040bf7b9ec39b4595c9d2084be65a9ea", + "zh:a3d90643f780c104a0d9e433cfed0658586237d15042c19d7e7038f47adfb1b9", + "zh:ccfb5bc6f860afd0f27562fa10ffa2befa73a23865ff4a904df2f24b77f6dc71", + "zh:daf24a4b651b73d7a0c8fd47d37dd9393d31cb569d1e0cd9917b02f0260df198", + "zh:de574fe5df1d49958f5b14034c30129723b6d1367f7a89eab7e3782320e80f7f", + "zh:fae2e92ea62f41c659a9e26850f1abbb905218358e18a23075a48db73c234eb9", + ] +} + provider "registry.opentofu.org/hashicorp/dnsimple" { version = "1.5.0" hashes = [ diff --git a/aws/iam-sso.tf b/aws/iam-sso.tf new file mode 100644 index 0000000..305875c --- /dev/null +++ b/aws/iam-sso.tf @@ -0,0 +1,135 @@ +data "aws_ssoadmin_instances" "main" {} + +resource "aws_identitystore_group" "group" { + for_each = var.teams + display_name = each.key + identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0] +} + +resource "aws_identitystore_user" "main" { + for_each = merge(nonsensitive(var.teams.PLC), nonsensitive(var.teams.Ops), nonsensitive(var.teams.Security), nonsensitive(var.teams.Analytics)) + identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0] + + display_name = each.key + user_name = each.key + nickname = each.key + + name { + given_name = each.key + family_name = "Brew" + } + + emails { + value = sensitive(each.value) + } + + lifecycle { + ignore_changes = [name, display_name] + } +} + +resource "aws_identitystore_group_membership" "plc" { + for_each = nonsensitive(var.teams.PLC) + + identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0] + group_id = aws_identitystore_group.group["PLC"].group_id + member_id = aws_identitystore_user.main[each.key].user_id +} + +resource "aws_identitystore_group_membership" "ops" { + for_each = nonsensitive(var.teams.Ops) + + identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0] + group_id = aws_identitystore_group.group["Ops"].group_id + member_id = aws_identitystore_user.main[each.key].user_id +} + +resource "aws_identitystore_group_membership" "security" { + for_each = nonsensitive(var.teams.Security) + + identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0] + group_id = aws_identitystore_group.group["Security"].group_id + member_id = aws_identitystore_user.main[each.key].user_id +} + +resource "aws_identitystore_group_membership" "analytics" { + for_each = nonsensitive(var.teams.Analytics) + + identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0] + group_id = aws_identitystore_group.group["Analytics"].group_id + member_id = aws_identitystore_user.main[each.key].user_id +} + +resource "aws_ssoadmin_permission_set" "OpsAccess" { + name = "OpsAccess" + description = "Access for Ops" + instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] +} +resource "aws_ssoadmin_managed_policy_attachment" "OpsAccess" { + depends_on = [aws_ssoadmin_account_assignment.Ops] + + instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] + managed_policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess" + permission_set_arn = aws_ssoadmin_permission_set.OpsAccess.arn +} + +resource "aws_ssoadmin_permission_set" "SecurityTeam" { + name = "SecurityTeam" + description = "Access for the security team" + instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] +} +resource "aws_ssoadmin_managed_policy_attachment" "SecurityTeam" { + depends_on = [aws_ssoadmin_account_assignment.security] + + instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] + managed_policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess" + permission_set_arn = aws_ssoadmin_permission_set.SecurityTeam.arn +} + +resource "aws_ssoadmin_permission_set" "Billing" { + name = "Billing" + description = "Access for the PLC" + instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] +} +resource "aws_ssoadmin_managed_policy_attachment" "Billing" { + depends_on = [aws_ssoadmin_account_assignment.billing] + + instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] + managed_policy_arn = "arn:aws:iam::aws:policy/job-function/Billing" + permission_set_arn = aws_ssoadmin_permission_set.Billing.arn +} + +data "aws_caller_identity" "current" {} + +resource "aws_ssoadmin_account_assignment" "billing" { + instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] + permission_set_arn = aws_ssoadmin_permission_set.Billing.arn + + principal_id = aws_identitystore_group.group["PLC"].group_id + principal_type = "GROUP" + + target_id = data.aws_caller_identity.current.account_id + target_type = "AWS_ACCOUNT" +} + +resource "aws_ssoadmin_account_assignment" "security" { + instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] + permission_set_arn = aws_ssoadmin_permission_set.SecurityTeam.arn + + principal_id = aws_identitystore_group.group["Security"].group_id + principal_type = "GROUP" + + target_id = data.aws_caller_identity.current.account_id + target_type = "AWS_ACCOUNT" +} + +resource "aws_ssoadmin_account_assignment" "Ops" { + instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0] + permission_set_arn = aws_ssoadmin_permission_set.OpsAccess.arn + + principal_id = aws_identitystore_group.group["Ops"].group_id + principal_type = "GROUP" + + target_id = data.aws_caller_identity.current.account_id + target_type = "AWS_ACCOUNT" +} \ No newline at end of file diff --git a/aws/main.tf b/aws/main.tf new file mode 100644 index 0000000..2e42ed1 --- /dev/null +++ b/aws/main.tf @@ -0,0 +1,11 @@ +provider "aws" { + region = "us-east-1" +} + +resource "aws_iam_openid_connect_provider" "github_actions" { + url = "https://token.actions.githubusercontent.com" + + client_id_list = ["sts.amazonaws.com"] + + thumbprint_list = ["1c58a3a8518e8759bf075b76b750d4f2df264fcd"] +} \ No newline at end of file diff --git a/aws/roles.tf b/aws/roles.tf new file mode 100644 index 0000000..450ff16 --- /dev/null +++ b/aws/roles.tf @@ -0,0 +1,61 @@ +data "aws_iam_policy_document" "codebuild_policy_document" { + statement { + actions = [ + "s3:List*", + "s3:Get*", + "s3:Put*", + "s3:DeleteObject", + "s3:DeleteObjectVersion" + ] + resources = [ + "arn:aws:s3:::homebrew-terraform-state/*", + "arn:aws:s3:::homebrew-terraform-state" + ] + effect = "Allow" + } + statement { + effect = "Allow" + actions = [ + "iam:*", + ] + resources = ["*"] + } +} + +resource "aws_iam_policy" "policy" { + name = "OpentofuPolicy" + path = "/" + description = "Policy to allow Opentofu to do it's thing" + + policy = data.aws_iam_policy_document.codebuild_policy_document.json +} + +resource "aws_iam_role" "github_tf" { + name = "GitHubActionsS3Role" + description = "Allow GitHub actions access to S3 to store TF state" + assume_role_policy = jsonencode({ + Statement = [ + { + Action = "sts:AssumeRoleWithWebIdentity" + Effect = "Allow" + Condition = { + StringEquals = { + "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com" + } + StringLike = { + "token.actions.githubusercontent.com:sub" = "repo:Homebrew/homebrew-user-management:*" + } + } + Principal = { + Federated = aws_iam_openid_connect_provider.github_actions.arn + } + }, + ] + Version = "2012-10-17" + }) + managed_policy_arns = [ + "arn:aws:iam::aws:policy/AmazonS3FullAccess", + "arn:aws:iam::aws:policy/AWSSSOReadOnly", + "arn:aws:iam::aws:policy/IAMReadOnlyAccess", + ] +} \ No newline at end of file diff --git a/aws/vars.tf b/aws/vars.tf new file mode 100644 index 0000000..d6bf04e --- /dev/null +++ b/aws/vars.tf @@ -0,0 +1,3 @@ +variable "teams" { + type = map(map(string)) +} \ No newline at end of file diff --git a/dnsimple/contacts.tf b/dnsimple/contacts.tf index 98191aa..1c13801 100644 --- a/dnsimple/contacts.tf +++ b/dnsimple/contacts.tf @@ -4,15 +4,16 @@ resource "dnsimple_contact" "ocf" { last_name = "Maintainers" email = "ops@brew.sh" - phone = "+1 555 1234" - address1 = "123 Homebrew Street" - city = "Homebrew" - state_province = "HB" - postal_code = "00001" - country = "United States" + phone = sensitive("+1 555 1234") + phone_normalized = sensitive("+15551234") + address1 = sensitive("123 Homebrew Street") + city = sensitive("Homebrew") + state_province = sensitive("HB") + postal_code = sensitive("00001") + country = "US" lifecycle { - ignore_changes = [address1, city, state_province, postal_code, phone] + ignore_changes = [address1, city, state_province, postal_code, phone, phone_normalized] } } diff --git a/import.tf b/import.tf index 4adcc9d..122c633 100644 --- a/import.tf +++ b/import.tf @@ -56,3 +56,13 @@ import { to = module.dnsimple.dnsimple_contact.ocf id = 52414 } + +import { + to = module.aws.aws_iam_openid_connect_provider.github_actions + id = "arn:aws:iam::765021812025:oidc-provider/token.actions.githubusercontent.com" +} + +import { + to = module.aws.aws_iam_role.github_tf + id = "GitHubActionsS3Role" +} \ No newline at end of file diff --git a/main.tf b/main.tf index 1a806ec..f3cfa65 100644 --- a/main.tf +++ b/main.tf @@ -31,6 +31,20 @@ module "github" { unmanagable_members = local.unmanagable_members } +locals { + emails = nonsensitive({ for username, email in module.github.member_emails : username => lookup(var.email_overrides, username, email) }) +} + +module "aws" { + source = "./aws" + teams = { + Ops = { for username in var.teams.maintainers.ops : username => local.emails[username] if lookup(local.emails, username, "") != "" } + Security = { for username in var.teams.security : username => local.emails[username] if lookup(local.emails, username, "") != "" } + PLC = { for username in var.teams.plc : username => local.emails[username] if lookup(local.emails, username, "") != "" } + Analytics = { for username in var.teams.maintainers.analytics : username => local.emails[username] if lookup(local.emails, username, "") != "" } + } +} + module "google-cloud" { source = "./google-cloud" ops = module.github.ops