# HCP plan/apply roles imported from seahaven-terraform-substrate (PLAT-146). # Import, do not recreate. Role names stay hcptf-sh-openswe-traces / hcptf-sh-openswe-traces-plan. # # Live seahaven-hcptf-iam-management DenySelfMutation blocks DetachRolePolicy # and PutRolePolicy on hcptf-* (including this role). Import apply sequence: # 1. seahaven-org-baseline scripts/create-hcptf-bootstrap-roles.sh # --account prod --allow-workspace sh-openswe-traces-prod # 2. Point this workspace's TFC_AWS_* at hcptf-bootstrap / # hcptf-bootstrap-plan (workspace vars, never a project set). # 3. One Manual apply (import + detach seahaven-hcptf-iam-management + # put scoped inline). # 4. Point TFC_AWS_* back at hcptf-sh-openswe-traces / hcptf-sh-openswe-traces-plan. # 5. Re-run the script without --allow-workspace to pin trust back to # iam-bootstrap-prod only. # This stack has no Lambda execution-role boundary pin. import { to = aws_iam_role.hcptf_apply id = "hcptf-sh-openswe-traces" } import { to = aws_iam_role.hcptf_plan id = "hcptf-sh-openswe-traces-plan" } import { to = aws_iam_role_policy.hcptf_apply_services id = "hcptf-sh-openswe-traces:sh-openswe-traces-services" } import { to = aws_iam_role_policy.hcptf_plan_refresh id = "hcptf-sh-openswe-traces-plan:sh-openswe-traces-plan-refresh" } import { to = aws_iam_role_policy_attachments_exclusive.hcptf_apply id = "hcptf-sh-openswe-traces" } import { to = aws_iam_role_policy_attachment.hcptf_plan_viewonly id = "hcptf-sh-openswe-traces-plan/arn:aws:iam::aws:policy/job-function/ViewOnlyAccess" } import { to = aws_iam_role_policy_attachments_exclusive.hcptf_plan id = "hcptf-sh-openswe-traces-plan" } data "aws_iam_policy_document" "hcptf_apply_trust" { statement { sid = "HcpApply" effect = "Allow" actions = ["sts:AssumeRoleWithWebIdentity"] principals { type = "Federated" identifiers = ["arn:aws:iam::${local.account_id}:oidc-provider/app.terraform.io"] } condition { test = "StringEquals" variable = "app.terraform.io:aud" values = ["aws.workload.identity"] } condition { test = "StringEquals" variable = "app.terraform.io:sub" values = [ "organization:seahaven:project:seahaven-prod:workspace:sh-openswe-traces-prod:run_phase:apply", ] } } } data "aws_iam_policy_document" "hcptf_plan_trust" { statement { sid = "HcpPlan" effect = "Allow" actions = ["sts:AssumeRoleWithWebIdentity"] principals { type = "Federated" identifiers = ["arn:aws:iam::${local.account_id}:oidc-provider/app.terraform.io"] } condition { test = "StringEquals" variable = "app.terraform.io:aud" values = ["aws.workload.identity"] } condition { test = "StringEquals" variable = "app.terraform.io:sub" values = [ "organization:seahaven:project:seahaven-prod:workspace:sh-openswe-traces-prod:run_phase:plan", ] } } } data "aws_iam_policy_document" "hcptf_scoped_iam" { statement { sid = "DenyCreatePolicy" effect = "Deny" actions = ["iam:CreatePolicy", "iam:CreatePolicyVersion"] resources = ["*"] } statement { sid = "IamReadOnly" effect = "Allow" actions = [ "iam:GetPolicy", "iam:GetPolicyVersion", "iam:GetRole", "iam:GetRolePolicy", "iam:ListAttachedRolePolicies", "iam:ListPolicies", "iam:ListPolicyVersions", "iam:ListRolePolicies", "iam:ListRoles", ] resources = ["*"] } statement { sid = "DenySelfMutation" effect = "Deny" actions = [ "iam:AttachRolePolicy", "iam:DeleteRole", "iam:DeleteRolePolicy", "iam:DeleteRolePermissionsBoundary", "iam:DetachRolePolicy", "iam:PutRolePolicy", "iam:PutRolePermissionsBoundary", "iam:UpdateAssumeRolePolicy", "iam:UpdateRole", "iam:UpdateRoleDescription", ] resources = [ "arn:aws:iam::${local.account_id}:role/hcptf-*", "arn:aws:iam::${local.account_id}:role/github-cfn-execution-role", "arn:aws:iam::${local.account_id}:role/githubdeploy-*", "arn:aws:iam::${local.account_id}:role/cdk-hnb659fds-*", "arn:aws:iam::${local.account_id}:role/OrganizationAccountAccessRole", "arn:aws:iam::${local.account_id}:role/seahaven-*", ] } statement { sid = "DenyBoundaryTampering" effect = "Deny" actions = [ "iam:DeleteRolePermissionsBoundary", "iam:DeleteUserPermissionsBoundary", ] resources = [ "arn:aws:iam::${local.account_id}:role/*", "arn:aws:iam::${local.account_id}:user/*", ] } statement { sid = "DenyBoundaryPolicyEdit" effect = "Deny" actions = [ "iam:CreatePolicyVersion", "iam:DeletePolicy", "iam:DeletePolicyVersion", "iam:SetDefaultPolicyVersion", ] resources = ["arn:aws:iam::${local.account_id}:policy/seahaven-*"] } } resource "aws_iam_role_policy" "hcptf_apply_services" { name = "sh-openswe-traces-services" role = aws_iam_role.hcptf_apply.id policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = [ "s3:*", ] Resource = [ "arn:aws:s3:::sh-openswe-traces-${local.account_id}", "arn:aws:s3:::sh-openswe-traces-${local.account_id}/*", "arn:aws:s3:::sh-openswe-traces-logs-${local.account_id}", "arn:aws:s3:::sh-openswe-traces-logs-${local.account_id}/*", ] Effect = "Allow" Sid = "TracesBuckets" }, { Condition = { StringEquals = { "aws:RequestTag/Project" = "sh-openswe-traces" } } Action = [ "kms:CreateKey", ] Resource = "*" Effect = "Allow" Sid = "TracesKmsCreate" }, { Action = [ "kms:ListAliases", ] Resource = "*" Effect = "Allow" Sid = "TracesKmsList" }, { Action = [ "kms:CreateAlias", "kms:UpdateAlias", "kms:DeleteAlias", ] Resource = [ "arn:aws:kms:us-east-1:${local.account_id}:alias/sh-openswe-traces", ] Effect = "Allow" Sid = "TracesKmsAlias" }, { Condition = { StringEquals = { "aws:ResourceTag/Project" = "sh-openswe-traces" } } Action = [ "kms:TagResource", "kms:UntagResource", "kms:ScheduleKeyDeletion", "kms:CancelKeyDeletion", "kms:EnableKeyRotation", "kms:DisableKeyRotation", "kms:PutKeyPolicy", "kms:DescribeKey", "kms:GetKeyPolicy", "kms:GetKeyRotationStatus", "kms:ListResourceTags", "kms:EnableKey", "kms:DisableKey", "kms:CreateAlias", "kms:UpdateAlias", "kms:DeleteAlias", ] Resource = "*" Effect = "Allow" Sid = "TracesKmsKey" }, { Action = [ "iam:CreateUser", "iam:DeleteUser", "iam:GetUser", "iam:TagUser", "iam:UntagUser", "iam:UpdateUser", "iam:PutUserPolicy", "iam:DeleteUserPolicy", "iam:GetUserPolicy", "iam:ListUserPolicies", "iam:ListAttachedUserPolicies", "iam:ListUserTags", "iam:ListAccessKeys", ] Resource = [ "arn:aws:iam::${local.account_id}:user/sh-openswe-langsmith-export", ] Effect = "Allow" Sid = "ExportIamUser" }, { Action = [ "iam:ListUsers", "iam:GetAccountSummary", ] Resource = "*" Effect = "Allow" Sid = "ExportIamUserList" }, { Action = [ "secretsmanager:DeleteSecret", "secretsmanager:DescribeSecret", "secretsmanager:GetResourcePolicy", "secretsmanager:PutResourcePolicy", "secretsmanager:DeleteResourcePolicy", "secretsmanager:TagResource", "secretsmanager:UntagResource", ] Resource = [ "arn:aws:secretsmanager:us-east-1:${local.account_id}:secret:sh-openswe/langsmith-export-s3-*", ] Effect = "Allow" Sid = "ExportSecretShell" }, { Condition = { StringEquals = { "secretsmanager:Name" = "sh-openswe/langsmith-export-s3" } } Action = [ "secretsmanager:CreateSecret", ] Resource = "*" Effect = "Allow" Sid = "ExportSecretCreate" }, ] }) } resource "aws_iam_role_policy" "hcptf_plan_refresh" { name = "sh-openswe-traces-plan-refresh" role = aws_iam_role.hcptf_plan.id policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = [ "iam:GetUser", "iam:GetUserPolicy", "iam:ListUserPolicies", "iam:ListAttachedUserPolicies", "iam:ListUserTags", "iam:GetAccessKeyLastUsed", "iam:ListAccessKeys", ] Resource = [ "arn:aws:iam::${local.account_id}:user/sh-openswe-langsmith-export", ] Effect = "Allow" Sid = "RefreshIamUser" }, { Action = [ "iam:GetPolicy", "iam:GetPolicyVersion", ] Resource = "*" Effect = "Allow" Sid = "RefreshManagedPolicies" }, { Action = [ "s3:Get*", "s3:ListBucket", ] Resource = [ "arn:aws:s3:::sh-openswe-traces-${local.account_id}", "arn:aws:s3:::sh-openswe-traces-${local.account_id}/*", "arn:aws:s3:::sh-openswe-traces-logs-${local.account_id}", "arn:aws:s3:::sh-openswe-traces-logs-${local.account_id}/*", ] Effect = "Allow" Sid = "RefreshBuckets" }, { Action = [ "kms:Describe*", "kms:GetKeyPolicy", "kms:GetKeyRotationStatus", "kms:ListResourceTags", "kms:ListAliases", ] Resource = "*" Effect = "Allow" Sid = "RefreshKms" }, { Action = [ "secretsmanager:DescribeSecret", "secretsmanager:GetResourcePolicy", "secretsmanager:ListSecretVersionIds", ] Resource = [ "arn:aws:secretsmanager:us-east-1:${local.account_id}:secret:sh-openswe/langsmith-export-s3-*", ] Effect = "Allow" Sid = "RefreshSecret" }, { Sid = "RefreshHcptfRoles" Effect = "Allow" Action = [ "iam:GetRole", "iam:GetRolePolicy", "iam:ListRolePolicies", "iam:ListAttachedRolePolicies", ] Resource = [ "arn:aws:iam::${local.account_id}:role/hcptf-sh-openswe-traces", "arn:aws:iam::${local.account_id}:role/hcptf-sh-openswe-traces-plan", ] }, ] }) } resource "aws_iam_role" "hcptf_apply" { name = "hcptf-sh-openswe-traces" assume_role_policy = data.aws_iam_policy_document.hcptf_apply_trust.json max_session_duration = 3600 tags = { Project = "sh-openswe-traces" Owner = "adam@seahavenind.com" ManagedBy = "terraform" } } # Empty exclusive set keeps seahaven-hcptf-iam-management detached. resource "aws_iam_role_policy_attachments_exclusive" "hcptf_apply" { role_name = aws_iam_role.hcptf_apply.name policy_arns = [] } resource "aws_iam_role" "hcptf_plan" { name = "hcptf-sh-openswe-traces-plan" assume_role_policy = data.aws_iam_policy_document.hcptf_plan_trust.json max_session_duration = 3600 tags = { Project = "sh-openswe-traces" Owner = "adam@seahavenind.com" ManagedBy = "terraform" } } resource "aws_iam_role_policy_attachment" "hcptf_plan_viewonly" { role = aws_iam_role.hcptf_plan.name policy_arn = "arn:aws:iam::aws:policy/job-function/ViewOnlyAccess" } resource "aws_iam_role_policy_attachments_exclusive" "hcptf_plan" { role_name = aws_iam_role.hcptf_plan.name policy_arns = [ aws_iam_role_policy_attachment.hcptf_plan_viewonly.policy_arn, ] } resource "aws_iam_role_policy" "hcptf_scoped_iam" { name = "scoped-iam-management" role = aws_iam_role.hcptf_apply.id policy = data.aws_iam_policy_document.hcptf_scoped_iam.json }