# GitHub Actions OIDC role for .github/workflows/weekly-menu.yml. # # Trust is pinned three ways (aud, sub to main, job_workflow_ref to the # weekly-menu workflow at main) so no other workflow in the repo can assume it. # Permissions mirror the mgmt github-oidc-deploy-roles weekly-menu role, retargeted # to prod resources and without form-api-key (SigV4 publish path). # # OIDC provider ARN is literal (not a data source): hcptf-meal-order-manager-plan # lacks iam:GetOpenIDConnectProvider, and the provider is account-stable. data "aws_iam_policy_document" "weekly_menu_assume" { statement { effect = "Allow" actions = ["sts:AssumeRoleWithWebIdentity"] principals { type = "Federated" identifiers = [local.github_oidc_provider_arn] } condition { test = "StringEquals" variable = "token.actions.githubusercontent.com:aud" values = ["sts.amazonaws.com"] } condition { test = "StringEquals" variable = "token.actions.githubusercontent.com:sub" values = ["repo:Sea-Haven-Industries/meal-order-manager:ref:refs/heads/main"] } condition { test = "StringEquals" variable = "token.actions.githubusercontent.com:job_workflow_ref" values = ["Sea-Haven-Industries/meal-order-manager/.github/workflows/weekly-menu.yml@refs/heads/main"] } } } resource "aws_iam_role" "weekly_menu" { name = "githubdeploy-meal-order-manager-weekly-menu" path = "/tf-managed/" description = "GitHub Actions weekly-menu scrape/publish for meal-order-manager" assume_role_policy = data.aws_iam_policy_document.weekly_menu_assume.json max_session_duration = 3600 # Not a Lambda execution role. Config omits permissions_boundary so a later # apply will not PutRolePermissionsBoundary the Lambda ceiling back. Live still # has seahaven-lambda-execution-boundary; omitting without ignore_changes would # plan DeleteRolePermissionsBoundary, which hcptf-meal-order-manager is denied # (DenyBoundaryTampering). Ignore the attribute so this apply does not touch # the ceiling. An administrator deletes the live attachment, then a follow-up # drops this lifecycle after refresh-only updates state to null. lifecycle { ignore_changes = [permissions_boundary] } } data "aws_iam_policy_document" "weekly_menu" { statement { sid = "SlackBotSecret" effect = "Allow" actions = [ "secretsmanager:GetSecretValue", ] resources = [var.slack_bot_secret_arn] } statement { sid = "DeployAndAppParams" effect = "Allow" actions = [ "ssm:GetParameter", ] resources = [ "arn:aws:ssm:${var.aws_region}:${local.account_id}:parameter${local.ssm_prefix}/deploy/api-url", "arn:aws:ssm:${var.aws_region}:${local.account_id}:parameter${local.ssm_prefix}/deploy/form-bucket", "arn:aws:ssm:${var.aws_region}:${local.account_id}:parameter${local.ssm_prefix}/deploy/distribution-id", "arn:aws:ssm:${var.aws_region}:${local.account_id}:parameter${local.ssm_prefix}/deploy/form-url", "arn:aws:ssm:${var.aws_region}:${local.account_id}:parameter${local.google_client_id_param}", "arn:aws:ssm:${var.aws_region}:${local.account_id}:parameter${local.slack_channel_param}", "arn:aws:ssm:${var.aws_region}:${local.account_id}:parameter${local.ssm_prefix}/publish-key", ] } statement { sid = "FormObjects" effect = "Allow" actions = [ "s3:PutObject", ] resources = [ "${aws_s3_bucket.form.arn}/index.html", "${aws_s3_bucket.form.arn}/archive/*.html", ] } statement { sid = "InvalidateForm" effect = "Allow" actions = [ "cloudfront:CreateInvalidation", ] resources = [aws_cloudfront_distribution.form.arn] } } resource "aws_iam_role_policy" "weekly_menu" { name = "weekly-menu-publish" role = aws_iam_role.weekly_menu.id policy = data.aws_iam_policy_document.weekly_menu.json }