mirror of
https://github.com/Sea-Haven-Industries/procurement-ingest.git
synced 2026-09-30 08:23:14 +00:00
* feat(iam): import hcptf roles into app Terraform (PLAT-146) Move the existing hcptf pair into this repo so app Terraform owns prod IAM after the substrate handoff. * fix(iam): attach scoped IAM as a managed policy (PLAT-146) The apply role's services inline already uses 6894 of 10240 bytes, so a second inline policy cannot hold scoped IAM. * fix(iam): add apply-role IAM list permissions (PLAT-146) IamReadOnly omitted ListRoleTags and ListInstanceProfilesForRole needed after detaching the substrate guardrail. * fix(iam): allow ListPolicyTags on scoped IAM policy (PLAT-146) tagged managed scoped IAM is refreshed with ListPolicyTags; apply IamReadOnly and plan-refresh omitted it.
877 lines
27 KiB
HCL
877 lines
27 KiB
HCL
# HCP plan/apply roles imported from seahaven-terraform-substrate (PLAT-146).
|
|
# Import, do not recreate. Role names stay hcptf-procurement-ingest / hcptf-procurement-ingest-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 procurement-ingest-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 IAM as a customer-managed policy).
|
|
# 4. Point TFC_AWS_* back at hcptf-procurement-ingest / hcptf-procurement-ingest-plan.
|
|
# 5. Re-run the script without --allow-workspace to pin trust back to
|
|
# iam-bootstrap-prod only.
|
|
# seahaven-lambda-execution-boundary remains seahaven-lambda-execution-boundary-procurement-ingest.
|
|
|
|
import {
|
|
to = aws_iam_role.hcptf_apply
|
|
id = "hcptf-procurement-ingest"
|
|
}
|
|
|
|
import {
|
|
to = aws_iam_role.hcptf_plan
|
|
id = "hcptf-procurement-ingest-plan"
|
|
}
|
|
|
|
import {
|
|
to = aws_iam_role_policy.hcptf_apply_services
|
|
id = "hcptf-procurement-ingest:procurement-ingest-services"
|
|
}
|
|
|
|
import {
|
|
to = aws_iam_role_policy.hcptf_plan_refresh
|
|
id = "hcptf-procurement-ingest-plan:procurement-ingest-plan-refresh"
|
|
}
|
|
|
|
import {
|
|
to = aws_iam_role_policy_attachments_exclusive.hcptf_apply
|
|
id = "hcptf-procurement-ingest"
|
|
}
|
|
|
|
import {
|
|
to = aws_iam_role_policy_attachment.hcptf_plan_viewonly
|
|
id = "hcptf-procurement-ingest-plan/arn:aws:iam::aws:policy/job-function/ViewOnlyAccess"
|
|
}
|
|
|
|
import {
|
|
to = aws_iam_role_policy_attachments_exclusive.hcptf_plan
|
|
id = "hcptf-procurement-ingest-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:procurement-ingest-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:procurement-ingest-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 = "CreateExecRoleWithBoundary"
|
|
effect = "Allow"
|
|
actions = ["iam:CreateRole"]
|
|
resources = ["arn:aws:iam::${local.account_id}:role/tf-managed/po-*",
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/workorder-*",
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/procurement-api"]
|
|
|
|
condition {
|
|
test = "StringLike"
|
|
variable = "iam:PermissionsBoundary"
|
|
values = [
|
|
"arn:aws:iam::${local.account_id}:policy/tf-managed/po-*",
|
|
"arn:aws:iam::${local.account_id}:policy/tf-managed/workorder-*",
|
|
"arn:aws:iam::${local.account_id}:policy/tf-managed/procurement-api",
|
|
"arn:aws:iam::${local.account_id}:policy/seahaven-lambda-execution-boundary-procurement-ingest"
|
|
]
|
|
}
|
|
}
|
|
|
|
statement {
|
|
sid = "MutateExecRoleWithBoundary"
|
|
effect = "Allow"
|
|
actions = [
|
|
"iam:AttachRolePolicy",
|
|
"iam:PutRolePolicy",
|
|
"iam:PutRolePermissionsBoundary",
|
|
]
|
|
resources = ["arn:aws:iam::${local.account_id}:role/tf-managed/po-*",
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/workorder-*",
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/procurement-api"]
|
|
|
|
condition {
|
|
test = "StringLike"
|
|
variable = "iam:PermissionsBoundary"
|
|
values = [
|
|
"arn:aws:iam::${local.account_id}:policy/tf-managed/po-*",
|
|
"arn:aws:iam::${local.account_id}:policy/tf-managed/workorder-*",
|
|
"arn:aws:iam::${local.account_id}:policy/tf-managed/procurement-api",
|
|
"arn:aws:iam::${local.account_id}:policy/seahaven-lambda-execution-boundary-procurement-ingest"
|
|
]
|
|
}
|
|
}
|
|
|
|
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/po-*",
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/workorder-*",
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/procurement-api"]
|
|
}
|
|
|
|
statement {
|
|
sid = "PassExecRolesToLambda"
|
|
effect = "Allow"
|
|
actions = ["iam:PassRole"]
|
|
resources = ["arn:aws:iam::${local.account_id}:role/tf-managed/po-*",
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/workorder-*",
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/procurement-api"]
|
|
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "iam:PassedToService"
|
|
values = ["lambda.amazonaws.com"]
|
|
}
|
|
}
|
|
|
|
statement {
|
|
sid = "IamReadOnly"
|
|
effect = "Allow"
|
|
actions = [
|
|
"iam:GetPolicy",
|
|
"iam:GetPolicyVersion",
|
|
"iam:GetRole",
|
|
"iam:GetRolePolicy",
|
|
"iam:ListAttachedRolePolicies",
|
|
"iam:ListInstanceProfilesForRole",
|
|
"iam:ListPolicies",
|
|
"iam:ListPolicyTags",
|
|
"iam:ListPolicyVersions",
|
|
"iam:ListRolePolicies",
|
|
"iam:ListRoles",
|
|
"iam:ListRoleTags",
|
|
]
|
|
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 = "procurement-ingest-services"
|
|
role = aws_iam_role.hcptf_apply.id
|
|
policy = jsonencode({
|
|
Version = "2012-10-17"
|
|
Statement = [
|
|
{
|
|
Action = [
|
|
"lambda:*",
|
|
]
|
|
Resource = [
|
|
"arn:aws:lambda:us-east-1:${local.account_id}:function:po-*",
|
|
"arn:aws:lambda:us-east-1:${local.account_id}:function:workorder-*",
|
|
"arn:aws:lambda:us-east-1:${local.account_id}:function:procurement-api",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "LambdaAll"
|
|
},
|
|
{
|
|
Action = [
|
|
"lambda:GetEventSourceMapping",
|
|
"lambda:ListTags",
|
|
"lambda:TagResource",
|
|
"lambda:UntagResource",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "LambdaEventSourceMappingRead"
|
|
},
|
|
{
|
|
Condition = {
|
|
"ForAnyValue:StringLike" = {
|
|
"lambda:FunctionArn" = [
|
|
"arn:aws:lambda:us-east-1:${local.account_id}:function:po-*",
|
|
"arn:aws:lambda:us-east-1:${local.account_id}:function:workorder-*",
|
|
"arn:aws:lambda:us-east-1:${local.account_id}:function:procurement-api",
|
|
]
|
|
}
|
|
}
|
|
Action = [
|
|
"lambda:CreateEventSourceMapping",
|
|
"lambda:DeleteEventSourceMapping",
|
|
"lambda:UpdateEventSourceMapping",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "LambdaEventSourceMappings"
|
|
},
|
|
{
|
|
Action = [
|
|
"lambda:ListFunctions",
|
|
"lambda:ListEventSourceMappings",
|
|
"lambda:GetAccountSettings",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "LambdaList"
|
|
},
|
|
{
|
|
Action = [
|
|
"ssm:GetParameter",
|
|
"ssm:GetParameters",
|
|
]
|
|
Resource = [
|
|
"arn:aws:ssm:us-east-1:${local.account_id}:parameter/seahaven/dynamodb/cmk-arn",
|
|
"arn:aws:ssm:us-east-1:${local.account_id}:parameter/procurement-api/custom-domain/certificate-arn",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "SsmRead"
|
|
},
|
|
{
|
|
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/po-*",
|
|
"arn:aws:logs:us-east-1:${local.account_id}:log-group:/aws/lambda/workorder-*",
|
|
"arn:aws:logs:us-east-1:${local.account_id}:log-group:/aws/lambda/procurement-api*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "CloudWatchLogs"
|
|
},
|
|
{
|
|
Action = [
|
|
"logs:DescribeLogGroups",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "CloudWatchLogsDescribe"
|
|
},
|
|
{
|
|
Action = [
|
|
"s3:*",
|
|
]
|
|
Resource = [
|
|
"arn:aws:s3:::procurement-ingest-artifacts-${local.account_id}",
|
|
"arn:aws:s3:::procurement-ingest-artifacts-${local.account_id}/*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "ArtifactsBucket"
|
|
},
|
|
{
|
|
Action = [
|
|
"s3:*",
|
|
]
|
|
Resource = [
|
|
"arn:aws:s3:::po-ingest-emails-${local.account_id}",
|
|
"arn:aws:s3:::po-ingest-emails-${local.account_id}/*",
|
|
"arn:aws:s3:::workorder-ingest-emails-${local.account_id}",
|
|
"arn:aws:s3:::workorder-ingest-emails-${local.account_id}/*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "EmailBuckets"
|
|
},
|
|
{
|
|
Action = [
|
|
"dynamodb:*",
|
|
]
|
|
Resource = [
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/purchase-orders",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/purchase-orders/*",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/verified-sites",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/verified-sites/*",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/pending-site-review",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/pending-site-review/*",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/work-orders",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/work-orders/*",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/work-order-comments",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/work-order-comments/*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "DynamoDBTables"
|
|
},
|
|
{
|
|
Action = [
|
|
"dynamodb:ListTables",
|
|
"dynamodb:ListStreams",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "DynamoDBList"
|
|
},
|
|
{
|
|
Action = [
|
|
"sqs:*",
|
|
]
|
|
Resource = [
|
|
"arn:aws:sqs:us-east-1:${local.account_id}:po-ingest-*",
|
|
"arn:aws:sqs:us-east-1:${local.account_id}:WorkorderIngestStack-*",
|
|
"arn:aws:sqs:us-east-1:${local.account_id}:workorder-shoc-emitter-*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "SqsQueues"
|
|
},
|
|
{
|
|
Action = [
|
|
"cloudwatch:*",
|
|
]
|
|
Resource = [
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:po-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:workorder-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:procurement-api-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:purchase-orders-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:verified-sites-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:pending-site-review-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:work-orders-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:work-order-comments-*",
|
|
]
|
|
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 = "SiteAlertsSns"
|
|
},
|
|
{
|
|
Action = [
|
|
"apigateway:*",
|
|
]
|
|
Resource = [
|
|
"arn:aws:apigateway:us-east-1::/restapis/mvul1efda2",
|
|
"arn:aws:apigateway:us-east-1::/restapis/mvul1efda2/*",
|
|
"arn:aws:apigateway:us-east-1::/domainnames/procurement-api.seahaven.com",
|
|
"arn:aws:apigateway:us-east-1::/domainnames/procurement-api.seahaven.com/*",
|
|
"arn:aws:apigateway:us-east-1::/tags/*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "ApiGateway"
|
|
},
|
|
{
|
|
Action = [
|
|
"ses:CreateReceiptRule",
|
|
"ses:UpdateReceiptRule",
|
|
"ses:DeleteReceiptRule",
|
|
"ses:DescribeReceiptRule",
|
|
"ses:SetReceiptRulePosition",
|
|
]
|
|
Resource = [
|
|
"arn:aws:ses:us-east-1:${local.account_id}:receipt-rule-set/INBOUND_MAIL:receipt-rule/ExistingRuleSetPoEmailRuleAC8E9C87-qwGDj9lBoL1G",
|
|
"arn:aws:ses:us-east-1:${local.account_id}:receipt-rule-set/INBOUND_MAIL:receipt-rule/ExistingRuleSetWorkorderEmailRuleEA29F845-PKtaDBvIg61a",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "SesReceiptRules"
|
|
},
|
|
{
|
|
Action = [
|
|
"ses:DescribeReceiptRuleSet",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "SesDescribeRuleSet"
|
|
},
|
|
{
|
|
Action = [
|
|
"kms:DescribeKey",
|
|
"kms:GetKeyPolicy",
|
|
"kms:GetKeyRotationStatus",
|
|
"kms:ListResourceTags",
|
|
"kms:PutKeyPolicy",
|
|
"kms:EnableKeyRotation",
|
|
"kms:DisableKeyRotation",
|
|
"kms:ScheduleKeyDeletion",
|
|
"kms:CancelKeyDeletion",
|
|
"kms:TagResource",
|
|
"kms:UntagResource",
|
|
"kms:EnableKey",
|
|
"kms:DisableKey",
|
|
]
|
|
Resource = [
|
|
"arn:aws:kms:us-east-1:${local.account_id}:key/d10fd1f0-a61a-4405-8568-85e9fd11ba18",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "ShocKms"
|
|
},
|
|
{
|
|
Action = [
|
|
"kms:ListAliases",
|
|
"kms:ListKeys",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "KmsList"
|
|
},
|
|
{
|
|
Action = [
|
|
"kms:CreateAlias",
|
|
"kms:DeleteAlias",
|
|
"kms:UpdateAlias",
|
|
]
|
|
Resource = [
|
|
"arn:aws:kms:us-east-1:${local.account_id}:alias/workorder-ingest-shoc-webhook-kms",
|
|
"arn:aws:kms:us-east-1:${local.account_id}:key/d10fd1f0-a61a-4405-8568-85e9fd11ba18",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "ShocKmsAlias"
|
|
},
|
|
{
|
|
Action = [
|
|
"secretsmanager:DeleteSecret",
|
|
"secretsmanager:DescribeSecret",
|
|
"secretsmanager:GetResourcePolicy",
|
|
"secretsmanager:PutResourcePolicy",
|
|
"secretsmanager:DeleteResourcePolicy",
|
|
"secretsmanager:TagResource",
|
|
"secretsmanager:UntagResource",
|
|
"secretsmanager:RotateSecret",
|
|
"secretsmanager:CancelRotateSecret",
|
|
"secretsmanager:UpdateSecretVersionStage",
|
|
]
|
|
Resource = [
|
|
"arn:aws:secretsmanager:us-east-1:${local.account_id}:secret:workorder-ingest/shoc-webhook-hmac-*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "ShocSecretShell"
|
|
},
|
|
{
|
|
Condition = {
|
|
StringEquals = {
|
|
"secretsmanager:Name" = "workorder-ingest/shoc-webhook-hmac"
|
|
}
|
|
}
|
|
Action = [
|
|
"secretsmanager:CreateSecret",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "ShocSecretCreate"
|
|
},
|
|
{
|
|
Action = [
|
|
"secretsmanager:DescribeSecret",
|
|
"secretsmanager:GetResourcePolicy",
|
|
]
|
|
Resource = [
|
|
"arn:aws:secretsmanager:us-east-1:${local.account_id}:secret:procurement-ingest/web-ui-auth-token-*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "WebUiSecretDescribe"
|
|
},
|
|
]
|
|
})
|
|
}
|
|
|
|
resource "aws_iam_role_policy" "hcptf_plan_refresh" {
|
|
name = "procurement-ingest-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",
|
|
]
|
|
Resource = [
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/po-*",
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/workorder-*",
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/procurement-api",
|
|
"arn:aws:iam::${local.account_id}:role/hcptf-procurement-ingest",
|
|
"arn:aws:iam::${local.account_id}:role/hcptf-procurement-ingest-plan",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "RefreshIamRoles"
|
|
},
|
|
{
|
|
Action = [
|
|
"iam:GetPolicy",
|
|
"iam:GetPolicyVersion",
|
|
"iam:ListPolicyTags",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "RefreshManagedPolicies"
|
|
},
|
|
{
|
|
Action = [
|
|
"lambda:Get*",
|
|
]
|
|
Resource = [
|
|
"arn:aws:lambda:us-east-1:${local.account_id}:function:po-*",
|
|
"arn:aws:lambda:us-east-1:${local.account_id}:function:workorder-*",
|
|
"arn:aws:lambda:us-east-1:${local.account_id}:function:procurement-api",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "RefreshLambda"
|
|
},
|
|
{
|
|
Action = [
|
|
"lambda:ListFunctions",
|
|
"lambda:ListEventSourceMappings",
|
|
"lambda:GetEventSourceMapping",
|
|
"lambda:GetAccountSettings",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "RefreshLambdaList"
|
|
},
|
|
{
|
|
Action = [
|
|
"s3:Get*",
|
|
"s3:ListBucket",
|
|
]
|
|
Resource = [
|
|
"arn:aws:s3:::procurement-ingest-artifacts-${local.account_id}",
|
|
"arn:aws:s3:::procurement-ingest-artifacts-${local.account_id}/*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "RefreshArtifactsBucket"
|
|
},
|
|
{
|
|
Action = [
|
|
"s3:Get*",
|
|
"s3:ListBucket",
|
|
"s3:GetBucketNotification",
|
|
"s3:GetBucketPolicy",
|
|
"s3:GetEncryptionConfiguration",
|
|
"s3:GetBucketTagging",
|
|
"s3:GetBucketVersioning",
|
|
"s3:GetBucketPublicAccessBlock",
|
|
]
|
|
Resource = [
|
|
"arn:aws:s3:::po-ingest-emails-${local.account_id}",
|
|
"arn:aws:s3:::po-ingest-emails-${local.account_id}/*",
|
|
"arn:aws:s3:::workorder-ingest-emails-${local.account_id}",
|
|
"arn:aws:s3:::workorder-ingest-emails-${local.account_id}/*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "RefreshEmailBuckets"
|
|
},
|
|
{
|
|
Action = [
|
|
"dynamodb:DescribeTable",
|
|
"dynamodb:DescribeTimeToLive",
|
|
"dynamodb:DescribeContinuousBackups",
|
|
"dynamodb:DescribeStream",
|
|
"dynamodb:ListTagsOfResource",
|
|
]
|
|
Resource = [
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/purchase-orders",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/purchase-orders/*",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/verified-sites",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/pending-site-review",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/work-orders",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/work-orders/*",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/work-order-comments",
|
|
"arn:aws:dynamodb:us-east-1:${local.account_id}:table/work-order-comments/*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "RefreshDynamoDB"
|
|
},
|
|
{
|
|
Action = [
|
|
"dynamodb:ListStreams",
|
|
"dynamodb:ListTables",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "RefreshDynamoDBList"
|
|
},
|
|
{
|
|
Action = [
|
|
"sqs:GetQueueAttributes",
|
|
"sqs:GetQueueUrl",
|
|
"sqs:ListQueueTags",
|
|
]
|
|
Resource = [
|
|
"arn:aws:sqs:us-east-1:${local.account_id}:po-ingest-*",
|
|
"arn:aws:sqs:us-east-1:${local.account_id}:WorkorderIngestStack-*",
|
|
"arn:aws:sqs:us-east-1:${local.account_id}:workorder-shoc-emitter-*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "RefreshSqs"
|
|
},
|
|
{
|
|
Action = [
|
|
"cloudwatch:DescribeAlarms",
|
|
"cloudwatch:ListTagsForResource",
|
|
]
|
|
Resource = [
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:po-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:workorder-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:procurement-api-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:purchase-orders-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:verified-sites-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:pending-site-review-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:work-orders-*",
|
|
"arn:aws:cloudwatch:us-east-1:${local.account_id}:alarm:work-order-comments-*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "RefreshCloudWatchAlarms"
|
|
},
|
|
{
|
|
Action = [
|
|
"apigateway:GET",
|
|
]
|
|
Resource = [
|
|
"arn:aws:apigateway:us-east-1::/restapis/mvul1efda2",
|
|
"arn:aws:apigateway:us-east-1::/restapis/mvul1efda2/*",
|
|
"arn:aws:apigateway:us-east-1::/domainnames/procurement-api.seahaven.com",
|
|
"arn:aws:apigateway:us-east-1::/domainnames/procurement-api.seahaven.com/*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "RefreshApiGateway"
|
|
},
|
|
{
|
|
Action = [
|
|
"kms:DescribeKey",
|
|
"kms:GetKeyPolicy",
|
|
"kms:GetKeyRotationStatus",
|
|
"kms:ListResourceTags",
|
|
]
|
|
Resource = [
|
|
"arn:aws:kms:us-east-1:${local.account_id}:key/*",
|
|
"arn:aws:kms:us-east-1:${local.account_id}:alias/workorder-ingest-shoc-webhook-kms",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "RefreshKms"
|
|
},
|
|
{
|
|
Action = [
|
|
"kms:ListAliases",
|
|
"kms:ListKeys",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "RefreshKmsList"
|
|
},
|
|
{
|
|
Action = [
|
|
"secretsmanager:DescribeSecret",
|
|
"secretsmanager:GetResourcePolicy",
|
|
"secretsmanager:ListSecretVersionIds",
|
|
]
|
|
Resource = [
|
|
"arn:aws:secretsmanager:us-east-1:${local.account_id}:secret:workorder-ingest/shoc-webhook-hmac-*",
|
|
"arn:aws:secretsmanager:us-east-1:${local.account_id}:secret:procurement-ingest/web-ui-auth-token-*",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "RefreshSecrets"
|
|
},
|
|
{
|
|
Action = [
|
|
"ssm:GetParameter",
|
|
"ssm:GetParameters",
|
|
]
|
|
Resource = [
|
|
"arn:aws:ssm:us-east-1:${local.account_id}:parameter/seahaven/dynamodb/cmk-arn",
|
|
"arn:aws:ssm:us-east-1:${local.account_id}:parameter/procurement-api/custom-domain/certificate-arn",
|
|
]
|
|
Effect = "Allow"
|
|
Sid = "RefreshSsm"
|
|
},
|
|
{
|
|
Action = [
|
|
"ses:DescribeReceiptRule",
|
|
"ses:DescribeReceiptRuleSet",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "RefreshSes"
|
|
},
|
|
{
|
|
Action = [
|
|
"logs:DescribeLogGroups",
|
|
"logs:DescribeMetricFilters",
|
|
"logs:ListTagsForResource",
|
|
]
|
|
Resource = "*"
|
|
Effect = "Allow"
|
|
Sid = "RefreshLogs"
|
|
},
|
|
]
|
|
})
|
|
}
|
|
|
|
resource "aws_iam_role" "hcptf_apply" {
|
|
name = "hcptf-procurement-ingest"
|
|
assume_role_policy = data.aws_iam_policy_document.hcptf_apply_trust.json
|
|
max_session_duration = 3600
|
|
|
|
tags = {
|
|
Project = "procurement-ingest"
|
|
Owner = "adam@seahavenind.com"
|
|
ManagedBy = "terraform"
|
|
}
|
|
}
|
|
|
|
# Services inline is 6894 bytes; a second inline for scoped IAM exceeds the
|
|
# 10240 role quota. Attach scoped IAM as a customer-managed policy instead.
|
|
# 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_scoped_iam.arn,
|
|
]
|
|
}
|
|
|
|
resource "aws_iam_role" "hcptf_plan" {
|
|
name = "hcptf-procurement-ingest-plan"
|
|
assume_role_policy = data.aws_iam_policy_document.hcptf_plan_trust.json
|
|
max_session_duration = 3600
|
|
|
|
tags = {
|
|
Project = "procurement-ingest"
|
|
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_policy" "hcptf_scoped_iam" {
|
|
name = "hcptf-procurement-ingest-scoped-iam"
|
|
path = "/tf-managed/"
|
|
policy = data.aws_iam_policy_document.hcptf_scoped_iam.json
|
|
|
|
tags = {
|
|
Project = "procurement-ingest"
|
|
Owner = "adam@seahavenind.com"
|
|
ManagedBy = "terraform"
|
|
}
|
|
}
|
|
|
|
resource "aws_iam_role_policy_attachment" "hcptf_scoped_iam" {
|
|
role = aws_iam_role.hcptf_apply.name
|
|
policy_arn = aws_iam_policy.hcptf_scoped_iam.arn
|
|
}
|