# HCP plan/apply roles imported from seahaven-terraform-substrate (PLAT-146). # Import, do not recreate. Role names stay hcptf-meal-order-manager / hcptf-meal-order-manager-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|dev --allow-workspace meal-order-manager- # 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-meal-order-manager / hcptf-meal-order-manager-plan. # 5. Re-run the script without --allow-workspace to pin trust back to # iam-bootstrap- only. # seahaven-lambda-execution-boundary remains seahaven-lambda-execution-boundary-meal-order-manager. import { to = aws_iam_role.hcptf_apply id = "hcptf-meal-order-manager" } import { to = aws_iam_role.hcptf_plan id = "hcptf-meal-order-manager-plan" } import { to = aws_iam_role_policy.hcptf_plan_refresh id = "hcptf-meal-order-manager-plan:meal-order-manager-plan-refresh" } import { to = aws_iam_role_policy_attachments_exclusive.hcptf_apply id = "hcptf-meal-order-manager" } import { to = aws_iam_role_policy_attachment.hcptf_plan_viewonly id = "hcptf-meal-order-manager-plan/arn:aws:iam::aws:policy/job-function/ViewOnlyAccess" } import { to = aws_iam_role_policy_attachments_exclusive.hcptf_plan id = "hcptf-meal-order-manager-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:${local.hcp_project}:workspace:${local.hcp_workspace}: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:${local.hcp_project}:workspace:${local.hcp_workspace}:run_phase:plan", ] } } } data "aws_iam_policy_document" "hcptf_scoped_iam" { statement { sid = "DenyCreatePolicy" effect = "Deny" actions = ["iam:CreatePolicy", "iam:CreatePolicyVersion"] resources = ["*"] } statement { sid = "CreateExecRoleWithBoundary" effect = "Allow" actions = ["iam:CreateRole"] resources = ["arn:aws:iam::${local.account_id}:role/tf-managed/meal-order-manager-*"] condition { test = "StringLike" variable = "iam:PermissionsBoundary" values = [ "arn:aws:iam::${local.account_id}:policy/tf-managed/meal-order-manager-*", "arn:aws:iam::${local.account_id}:policy/seahaven-lambda-execution-boundary-meal-order-manager" ] } } statement { sid = "MutateExecRoleWithBoundary" effect = "Allow" actions = [ "iam:AttachRolePolicy", "iam:PutRolePolicy", "iam:PutRolePermissionsBoundary", ] resources = ["arn:aws:iam::${local.account_id}:role/tf-managed/meal-order-manager-*"] condition { test = "StringLike" variable = "iam:PermissionsBoundary" values = [ "arn:aws:iam::${local.account_id}:policy/tf-managed/meal-order-manager-*", "arn:aws:iam::${local.account_id}:policy/seahaven-lambda-execution-boundary-meal-order-manager" ] } } statement { sid = "WriteExecRoles" effect = "Allow" actions = [ "iam:DeleteRole", "iam:DeleteRolePolicy", "iam:DetachRolePolicy", "iam:TagRole", "iam:UntagRole", "iam:UpdateAssumeRolePolicy", "iam:UpdateRole", "iam:UpdateRoleDescription", ] resources = ["arn:aws:iam::${local.account_id}:role/tf-managed/meal-order-manager-*"] } statement { sid = "PassExecRolesToCompute" effect = "Allow" actions = ["iam:PassRole"] resources = ["arn:aws:iam::${local.account_id}:role/tf-managed/meal-order-manager-*"] condition { test = "StringEquals" variable = "iam:PassedToService" values = ["ecs-tasks.amazonaws.com", "scheduler.amazonaws.com"] } } statement { sid = "CreateDeployRole" effect = "Allow" actions = ["iam:CreateRole"] resources = ["arn:aws:iam::${local.account_id}:role/tf-managed/githubdeploy-meal-order-manager"] condition { test = "StringEquals" variable = "iam:PermissionsBoundary" values = [aws_iam_policy.github_deploy_boundary.arn] } } statement { sid = "WriteGithubDeployRole" effect = "Allow" actions = [ "iam:DeleteRole", "iam:DeleteRolePolicy", "iam:TagRole", "iam:UntagRole", "iam:UpdateAssumeRolePolicy", "iam:UpdateRole", "iam:UpdateRoleDescription", ] resources = ["arn:aws:iam::${local.account_id}:role/tf-managed/githubdeploy-meal-order-manager"] } statement { sid = "MutateGithubDeployRoleWithBoundary" effect = "Allow" actions = [ "iam:PutRolePolicy", "iam:PutRolePermissionsBoundary", ] resources = ["arn:aws:iam::${local.account_id}:role/tf-managed/githubdeploy-meal-order-manager"] condition { test = "StringEquals" variable = "iam:PermissionsBoundary" values = [aws_iam_policy.github_deploy_boundary.arn] } } statement { sid = "DenyGithubDeployAttach" effect = "Deny" actions = [ "iam:AttachRolePolicy", "iam:DetachRolePolicy", ] resources = ["arn:aws:iam::${local.account_id}:role/tf-managed/githubdeploy-meal-order-manager"] } # Kept so this apply can delete githubdeploy-meal-order-manager-weekly-menu. # Drop the statement after that role is gone. statement { sid = "WriteDeployRoles" effect = "Allow" actions = [ "iam:AttachRolePolicy", "iam:CreateRole", "iam:DeleteRole", "iam:DeleteRolePolicy", "iam:DetachRolePolicy", "iam:PutRolePolicy", "iam:TagRole", "iam:UntagRole", "iam:UpdateAssumeRolePolicy", "iam:UpdateRole", "iam:UpdateRoleDescription", ] resources = ["arn:aws:iam::${local.account_id}:role/tf-managed/githubdeploy-meal-order-manager-weekly-menu"] } statement { sid = "IamReadOnly" effect = "Allow" actions = [ "iam:GetPolicy", "iam:GetPolicyVersion", "iam:GetRole", "iam:GetRolePolicy", "iam:ListAttachedRolePolicies", "iam:ListInstanceProfilesForRole", "iam:ListPolicies", "iam:ListPolicyVersions", "iam:ListRolePolicies", "iam:ListRoleTags", "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_policy" "hcptf_apply_compute" { name = "meal-order-manager-apply-compute" path = "/tf-managed/" policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = [ "ecs:*", ] Resource = [ "arn:aws:ecs:us-east-1:${local.account_id}:cluster/meal-order-manager", "arn:aws:ecs:us-east-1:${local.account_id}:service/meal-order-manager/meal-order-manager", "arn:aws:ecs:us-east-1:${local.account_id}:task-definition/meal-order-manager:*", "arn:aws:ecs:us-east-1:${local.account_id}:task-definition/meal-order-manager", ] Effect = "Allow" Sid = "EcsWorkload" }, { Action = [ "ecs:CreateCluster", "ecs:CreateService", "ecs:DeleteService", "ecs:DeregisterTaskDefinition", "ecs:DescribeClusters", "ecs:DescribeServices", "ecs:DescribeTaskDefinition", "ecs:ListClusters", "ecs:ListServices", "ecs:ListTaskDefinitions", "ecs:RegisterTaskDefinition", "ecs:TagResource", "ecs:UntagResource", "ecs:UpdateService", ] Resource = "*" Effect = "Allow" Sid = "EcsAccount" }, { Action = [ "elasticloadbalancing:*", ] Resource = [ "arn:aws:elasticloadbalancing:us-east-1:${local.account_id}:loadbalancer/app/meal-order-manager/*", "arn:aws:elasticloadbalancing:us-east-1:${local.account_id}:targetgroup/meal-order-manager-api/*", "arn:aws:elasticloadbalancing:us-east-1:${local.account_id}:listener/app/meal-order-manager/*", ] Effect = "Allow" Sid = "ElbWorkload" }, { Action = [ "elasticloadbalancing:Describe*", "elasticloadbalancing:CreateLoadBalancer", "elasticloadbalancing:CreateTargetGroup", "elasticloadbalancing:CreateListener", "elasticloadbalancing:CreateRule", "elasticloadbalancing:AddTags", "elasticloadbalancing:ModifyLoadBalancerAttributes", "elasticloadbalancing:ModifyTargetGroup", "elasticloadbalancing:ModifyTargetGroupAttributes", "elasticloadbalancing:ModifyListener", "elasticloadbalancing:SetSecurityGroups", "elasticloadbalancing:SetSubnets", ] Resource = "*" Effect = "Allow" Sid = "ElbDescribe" }, { Action = [ "ecr:*", ] Resource = [ "arn:aws:ecr:us-east-1:${local.account_id}:repository/meal-order-manager", ] Effect = "Allow" Sid = "EcrRepo" }, { Action = [ "ecr:DescribeRepositories", "ecr:GetAuthorizationToken", ] Resource = "*" Effect = "Allow" Sid = "EcrAccount" }, { Action = [ "sqs:*", ] Resource = [ "arn:aws:sqs:us-east-1:${local.account_id}:meal-order-manager-jobs", "arn:aws:sqs:us-east-1:${local.account_id}:meal-order-manager-jobs-dlq", ] Effect = "Allow" Sid = "JobsQueues" }, { Action = [ "scheduler:*", ] Resource = [ "arn:aws:scheduler:us-east-1:${local.account_id}:schedule/meal-order-manager/*", "arn:aws:scheduler:us-east-1:${local.account_id}:schedule-group/meal-order-manager", ] Effect = "Allow" Sid = "SchedulerJobs" }, { Action = [ "scheduler:CreateScheduleGroup", "scheduler:ListScheduleGroups", "scheduler:ListSchedules", ] Resource = "*" Effect = "Allow" Sid = "SchedulerAccount" }, ] }) } resource "aws_iam_policy" "hcptf_apply_services" { name = "meal-order-manager-apply-services" path = "/tf-managed/" policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = [ "lambda:*", ] Resource = [ "arn:aws:lambda:us-east-1:${local.account_id}:function:meal-order-manager-*", "arn:aws:lambda:us-east-1:${local.account_id}:layer:meal-order-manager-*", ] Effect = "Allow" Sid = "LambdaAll" }, { Action = [ "lambda:ListFunctions", "lambda:ListLayers", "lambda:GetAccountSettings", ] Resource = "*" Effect = "Allow" Sid = "LambdaList" }, { Action = [ "events:*", ] Resource = [ "arn:aws:events:us-east-1:${local.account_id}:rule/meal-order-manager-*", ] Effect = "Allow" Sid = "EventBridgeRules" }, { Action = [ "logs:CreateLogGroup", "logs:DeleteLogGroup", "logs:PutRetentionPolicy", "logs:DeleteRetentionPolicy", "logs:TagResource", "logs:UntagResource", "logs:ListTagsForResource", "logs:PutMetricFilter", "logs:DeleteMetricFilter", "logs:DescribeMetricFilters", ] Resource = [ "arn:aws:logs:us-east-1:${local.account_id}:log-group:/aws/lambda/meal-order-manager-*", "arn:aws:logs:us-east-1:${local.account_id}:log-group:/aws/apigateway/meal-order-manager*", "arn:aws:logs:us-east-1:${local.account_id}:log-group:/ecs/meal-order-manager", "arn:aws:logs:us-east-1:${local.account_id}:log-group:/ecs/meal-order-manager:*", ] Effect = "Allow" Sid = "CloudWatchLogs" }, { Action = [ "logs:DescribeLogGroups", ] Resource = "*" Effect = "Allow" Sid = "CloudWatchLogsDescribe" }, { Action = [ "logs:CreateLogDelivery", "logs:GetLogDelivery", "logs:UpdateLogDelivery", "logs:DeleteLogDelivery", "logs:ListLogDeliveries", "logs:DescribeResourcePolicies", ] Resource = "*" Effect = "Allow" Sid = "MealOrderApiGwAccessLogDelivery" }, { Action = [ "s3:*", ] Resource = [ "arn:aws:s3:::meal-order-manager-artifacts-${local.account_id}", "arn:aws:s3:::meal-order-manager-artifacts-${local.account_id}/*", "arn:aws:s3:::meal-order-manager-form-${local.account_id}", "arn:aws:s3:::meal-order-manager-form-${local.account_id}/*", "arn:aws:s3:::meal-order-manager-reports-${local.account_id}", "arn:aws:s3:::meal-order-manager-reports-${local.account_id}/*", ] Effect = "Allow" Sid = "StackBuckets" }, { Action = [ "dynamodb:*", ] Resource = [ "arn:aws:dynamodb:us-east-1:${local.account_id}:table/meal-order-manager-orders", "arn:aws:dynamodb:us-east-1:${local.account_id}:table/meal-order-manager-orders/*", ] Effect = "Allow" Sid = "DynamoDBTable" }, { Action = [ "dynamodb:ListTables", ] Resource = "*" Effect = "Allow" Sid = "DynamoDBList" }, { Action = [ "apigateway:*", ] Resource = [ "arn:aws:apigateway:us-east-1::/apis", "arn:aws:apigateway:us-east-1::/apis/*", "arn:aws:apigateway:us-east-1::/tags/*", "arn:aws:apigateway:us-east-1::/vpclinks", "arn:aws:apigateway:us-east-1::/vpclinks/*", ] Effect = "Allow" Sid = "HttpApiManage" }, { Action = [ "cloudfront:*", ] Resource = "*" Effect = "Allow" Sid = "CloudFrontManage" }, { Condition = { StringEquals = { "aws:RequestTag/Project" = "meal-order-manager" } } Action = [ "acm:RequestCertificate", ] Resource = "*" Effect = "Allow" Sid = "AcmCreate" }, { Action = [ "acm:ListCertificates", "acm:ListTagsForCertificate", ] Resource = "*" Effect = "Allow" Sid = "AcmList" }, { Condition = { StringEquals = { "aws:ResourceTag/Project" = "meal-order-manager" } } Action = [ "acm:DescribeCertificate", "acm:GetCertificate", "acm:DeleteCertificate", "acm:AddTagsToCertificate", "acm:RemoveTagsFromCertificate", "acm:RenewCertificate", ] Resource = "*" Effect = "Allow" Sid = "AcmManageTagged" }, { Action = [ "ssm:GetParameter", "ssm:GetParameters", ] Resource = [ "arn:aws:ssm:us-east-1:${local.account_id}:parameter/seahaven/waf/app-web-acl-arn", ] Effect = "Allow" Sid = "ReadAppWebAclSsm" }, { Action = [ "ssm:GetParameter", "ssm:GetParameters", "ssm:PutParameter", "ssm:DeleteParameter", "ssm:AddTagsToResource", "ssm:RemoveTagsFromResource", "ssm:ListTagsForResource", ] Resource = [ "arn:aws:ssm:us-east-1:${local.account_id}:parameter/meal-order-manager/*", ] Effect = "Allow" Sid = "MealOrderSsm" }, { Action = [ "ssm:DescribeParameters", ] Resource = "*" Effect = "Allow" Sid = "MealOrderSsmDescribeParameters" }, { Condition = { StringEquals = { "iam:PassedToService" = "apigateway.amazonaws.com" } } Action = [ "iam:PassRole", ] Resource = [ "arn:aws:iam::${local.account_id}:role/tf-managed/meal-order-manager-*", ] Effect = "Allow" Sid = "MealOrderPassRoleApiGateway" }, { Action = [ "wafv2:GetWebACL", "wafv2:GetWebACLForResource", "wafv2:ListWebACLs", "wafv2:ListResourcesForWebACL", ] Resource = "*" Effect = "Allow" Sid = "ReadWafWebAcl" }, { Action = [ "cloudwatch:PutMetricAlarm", "cloudwatch:DeleteAlarms", "cloudwatch:DescribeAlarms", "cloudwatch:TagResource", "cloudwatch:UntagResource", "cloudwatch:ListTagsForResource", ] Resource = [ "arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:meal-order-manager-*", ] Effect = "Allow" Sid = "CloudWatchAlarms" }, { Action = [ "sns:Publish", "sns:GetTopicAttributes", "sns:ListTagsForResource", ] Resource = [ "arn:aws:sns:us-east-1:${local.account_id}:site-alerts", ] Effect = "Allow" Sid = "SnsPublishSiteAlerts" }, { Action = [ "ses:GetIdentityVerificationAttributes", "ses:GetSendQuota", ] Resource = "*" Effect = "Allow" Sid = "SesIdentityRead" }, ] }) } resource "aws_iam_role_policy" "hcptf_apply_ec2" { name = "meal-order-manager-ec2" role = aws_iam_role.hcptf_apply.id policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = [ "ec2:AssociateRouteTable", "ec2:AttachInternetGateway", "ec2:AuthorizeSecurityGroupEgress", "ec2:AuthorizeSecurityGroupIngress", "ec2:CreateInternetGateway", "ec2:CreateRoute", "ec2:CreateRouteTable", "ec2:CreateSecurityGroup", "ec2:CreateSubnet", "ec2:CreateTags", "ec2:CreateVpc", "ec2:DeleteInternetGateway", "ec2:DeleteRoute", "ec2:DeleteRouteTable", "ec2:DeleteSecurityGroup", "ec2:DeleteSubnet", "ec2:DeleteTags", "ec2:DeleteVpc", "ec2:DescribeAccountAttributes", "ec2:DescribeAvailabilityZones", "ec2:DescribeInternetGateways", "ec2:DescribeNetworkInterfaces", "ec2:DescribeRouteTables", "ec2:DescribeSecurityGroupRules", "ec2:DescribeSecurityGroups", "ec2:DescribeSubnets", "ec2:DescribeTags", "ec2:DescribeVpcAttribute", "ec2:DescribeVpcs", "ec2:DetachInternetGateway", "ec2:DisassociateRouteTable", "ec2:ModifySubnetAttribute", "ec2:ModifyVpcAttribute", "ec2:RevokeSecurityGroupEgress", "ec2:RevokeSecurityGroupIngress", ] Resource = "*" Effect = "Allow" Sid = "Ec2VpcManagement" }, ] }) } resource "aws_iam_role_policy" "hcptf_plan_refresh" { name = "meal-order-manager-plan-refresh" role = aws_iam_role.hcptf_plan.id policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = [ "iam:GetRole", "iam:GetRolePolicy", "iam:ListRolePolicies", "iam:ListAttachedRolePolicies", "iam:ListRoleTags", ] Resource = [ "arn:aws:iam::${local.account_id}:role/tf-managed/meal-order-manager-*", "arn:aws:iam::${local.account_id}:role/tf-managed/githubdeploy-meal-order-manager*", "arn:aws:iam::${local.account_id}:role/hcptf-meal-order-manager", "arn:aws:iam::${local.account_id}:role/hcptf-meal-order-manager-plan", ] Effect = "Allow" Sid = "RefreshIamRoles" }, { Action = [ "iam:GetPolicy", "iam:GetPolicyVersion", ] Resource = "*" Effect = "Allow" Sid = "RefreshManagedPolicies" }, { Action = [ "events:DescribeRule", "events:ListTargetsByRule", "events:ListTagsForResource", ] Resource = [ "arn:aws:events:us-east-1:${local.account_id}:rule/meal-order-manager-*", ] Effect = "Allow" Sid = "RefreshEventBridge" }, { Action = [ "lambda:Get*", "lambda:List*", ] Resource = [ "arn:aws:lambda:us-east-1:${local.account_id}:function:meal-order-manager-*", "arn:aws:lambda:us-east-1:${local.account_id}:layer:meal-order-manager-*", ] Effect = "Allow" Sid = "RefreshLambda" }, { Action = [ "ecs:DescribeClusters", "ecs:DescribeServices", "ecs:DescribeTaskDefinition", "ecs:DescribeTaskSets", "ecs:ListClusters", "ecs:ListServices", "ecs:ListTaskDefinitions", "ecs:ListTagsForResource", ] Resource = "*" Effect = "Allow" Sid = "RefreshEcs" }, { Action = [ "elasticloadbalancing:DescribeLoadBalancers", "elasticloadbalancing:DescribeLoadBalancerAttributes", "elasticloadbalancing:DescribeListeners", "elasticloadbalancing:DescribeListenerAttributes", "elasticloadbalancing:DescribeTargetGroups", "elasticloadbalancing:DescribeTargetGroupAttributes", "elasticloadbalancing:DescribeTags", "elasticloadbalancing:DescribeRules", ] Resource = "*" Effect = "Allow" Sid = "RefreshElb" }, { Action = [ "ecr:DescribeRepositories", "ecr:DescribeImages", "ecr:GetLifecyclePolicy", "ecr:ListTagsForResource", ] Resource = [ "arn:aws:ecr:us-east-1:${local.account_id}:repository/meal-order-manager", ] Effect = "Allow" Sid = "RefreshEcr" }, { Action = [ "sqs:GetQueueAttributes", "sqs:GetQueueUrl", "sqs:ListQueueTags", ] Resource = [ "arn:aws:sqs:us-east-1:${local.account_id}:meal-order-manager-jobs", "arn:aws:sqs:us-east-1:${local.account_id}:meal-order-manager-jobs-dlq", ] Effect = "Allow" Sid = "RefreshJobsQueues" }, { Action = [ "scheduler:GetSchedule", "scheduler:GetScheduleGroup", "scheduler:ListSchedules", "scheduler:ListScheduleGroups", "scheduler:ListTagsForResource", ] Resource = "*" Effect = "Allow" Sid = "RefreshScheduler" }, { Action = [ "ec2:DescribeAccountAttributes", "ec2:DescribeAvailabilityZones", "ec2:DescribeInternetGateways", "ec2:DescribeNetworkInterfaces", "ec2:DescribeRouteTables", "ec2:DescribeSecurityGroupRules", "ec2:DescribeSecurityGroups", "ec2:DescribeSubnets", "ec2:DescribeTags", "ec2:DescribeVpcAttribute", "ec2:DescribeVpcs", ] Resource = "*" Effect = "Allow" Sid = "RefreshVpc" }, { Action = [ "s3:Get*", "s3:ListBucket", ] Resource = [ "arn:aws:s3:::meal-order-manager-artifacts-${local.account_id}", "arn:aws:s3:::meal-order-manager-artifacts-${local.account_id}/*", "arn:aws:s3:::meal-order-manager-form-${local.account_id}", "arn:aws:s3:::meal-order-manager-form-${local.account_id}/*", "arn:aws:s3:::meal-order-manager-reports-${local.account_id}", "arn:aws:s3:::meal-order-manager-reports-${local.account_id}/*", ] Effect = "Allow" Sid = "RefreshBuckets" }, { Action = [ "dynamodb:DescribeTable", "dynamodb:DescribeTimeToLive", "dynamodb:DescribeContinuousBackups", "dynamodb:ListTagsOfResource", ] Resource = [ "arn:aws:dynamodb:us-east-1:${local.account_id}:table/meal-order-manager-orders", ] Effect = "Allow" Sid = "RefreshDynamoDB" }, { Action = [ "logs:DescribeLogGroups", "logs:ListTagsForResource", ] Resource = "*" Effect = "Allow" Sid = "RefreshLogs" }, { Action = [ "cloudfront:DescribeFunction", "cloudfront:Get*", "cloudfront:List*", ] Resource = "*" Effect = "Allow" Sid = "RefreshCloudFront" }, { Action = [ "acm:DescribeCertificate", "acm:ListCertificates", "acm:ListTagsForCertificate", "acm:GetCertificate", ] Resource = "*" Effect = "Allow" Sid = "RefreshAcm" }, { Action = [ "ssm:GetParameter", "ssm:GetParameters", "ssm:ListTagsForResource", ] Resource = [ "arn:aws:ssm:us-east-1:${local.account_id}:parameter/seahaven/waf/app-web-acl-arn", "arn:aws:ssm:us-east-1:${local.account_id}:parameter/meal-order-manager/*", ] Effect = "Allow" Sid = "RefreshAppWebAclSsm" }, { Action = [ "ssm:DescribeParameters", ] Resource = "*" Effect = "Allow" Sid = "RefreshSsmDescribeParameters" }, { Action = [ "wafv2:GetWebACL", "wafv2:ListWebACLs", ] Resource = "*" Effect = "Allow" Sid = "RefreshWafWebAcl" }, { Action = [ "apigateway:GET", ] Resource = [ "arn:aws:apigateway:us-east-1::/apis/*", "arn:aws:apigateway:us-east-1::/tags/*", ] Effect = "Allow" Sid = "RefreshHttpApi" }, { Action = [ "cloudwatch:DescribeAlarms", "cloudwatch:ListTagsForResource", ] Resource = "*" Effect = "Allow" Sid = "RefreshAlarms" }, ] }) } resource "aws_iam_role" "hcptf_apply" { name = "hcptf-meal-order-manager" assume_role_policy = data.aws_iam_policy_document.hcptf_apply_trust.json max_session_duration = 3600 tags = { Project = "meal-order-manager" Owner = "adam@seahavenind.com" ManagedBy = "terraform" } # Apply role cannot iam:TagRole on itself. Provider default_tags # merge into tags_all, so ignoring tags alone still 403s mid-apply. lifecycle { ignore_changes = [tags, tags_all] } } # 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 = [ aws_iam_policy.hcptf_apply_services.arn, aws_iam_policy.hcptf_apply_compute.arn, ] } resource "aws_iam_role" "hcptf_plan" { name = "hcptf-meal-order-manager-plan" assume_role_policy = data.aws_iam_policy_document.hcptf_plan_trust.json max_session_duration = 3600 tags = { Project = "meal-order-manager" Owner = "adam@seahavenind.com" ManagedBy = "terraform" } # Same self-tag restriction as hcptf_apply. lifecycle { ignore_changes = [tags, tags_all] } } 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 }