feat(iam): add scoped OIDC role for the meal-order-manager weekly-menu job

This commit is contained in:
Adam Moussa 2026-07-28 18:58:51 -04:00
parent 3f74677422
commit c2c1b80b60
No known key found for this signature in database

View file

@ -7,6 +7,10 @@ Parameters:
GitHubOrg:
Type: String
Default: Sea-Haven-Industries
# No glob metacharacters: this value is interpolated into StringLike trust
# conditions, where a '*' override would silently open every role's trust
# to any GitHub org with a same-named repo.
AllowedPattern: "^[A-Za-z0-9-]+$"
CreateOIDCProvider:
Type: String
Default: "false"
@ -1376,6 +1380,78 @@ Resources:
Resource:
- !Sub arn:aws:iam::${AWS::AccountId}:role/cdk-hnb659fds-*
# Scoped runtime role for the meal-order-manager weekly-menu workflow
# (Monday scrape + order-form publish). Deliberately narrower than the
# repo's deploy role: the scheduled job reads stack outputs and app config,
# writes menu items and the published form, and invalidates the form's
# CloudFront path. It deploys nothing, so it gets no CloudFormation write
# actions, no PassRole, and no access outside the form bucket.
MealOrderManagerWeeklyMenuRole:
Type: AWS::IAM::Role
Properties:
RoleName: github-meal-order-manager-weekly-menu
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Federated: !Sub arn:aws:iam::${AWS::AccountId}:oidc-provider/token.actions.githubusercontent.com
Action: sts:AssumeRoleWithWebIdentity
Condition:
# StringEquals (not the sibling roles' StringLike): no wildcard is
# intended, and job_workflow_ref pins this runtime role to the ONE
# workflow it serves — unlike the deploy roles, any main-branch
# workflow must NOT be able to mint these credentials.
StringEquals:
token.actions.githubusercontent.com:aud: sts.amazonaws.com
token.actions.githubusercontent.com:sub: !Sub repo:${GitHubOrg}/meal-order-manager:ref:refs/heads/main
token.actions.githubusercontent.com:job_workflow_ref: !Sub ${GitHubOrg}/meal-order-manager/.github/workflows/weekly-menu.yml@refs/heads/main
Policies:
- PolicyName: weekly-menu-publish
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- cloudformation:DescribeStacks
Resource:
- !Sub arn:aws:cloudformation:us-east-1:${AWS::AccountId}:stack/meal-order-manager/*
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
# Secrets Manager appends a random 6-char suffix to every secret
# ARN, so a name-based match needs a glob — but exactly six '?'
# (one char each), NOT '-*', which would also match any future
# secret extending the name (e.g. form-api-key-backup).
Resource:
- !Sub arn:aws:secretsmanager:us-east-1:${AWS::AccountId}:secret:meal-order-manager/form-api-key-??????
- !Sub arn:aws:secretsmanager:us-east-1:${AWS::AccountId}:secret:meal-order-manager/slack-bot-token-??????
- Effect: Allow
Action:
- ssm:GetParameter
Resource:
- !Sub arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/meal-order-manager/google-client-id
- !Sub arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/meal-order-manager/slack-channel-id
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
Resource:
- !Sub arn:aws:dynamodb:us-east-1:${AWS::AccountId}:table/meal-order-manager-orders
- Effect: Allow
Action:
- s3:PutObject
Resource:
- !Sub arn:aws:s3:::meal-order-manager-form-${AWS::AccountId}/index.html
- !Sub arn:aws:s3:::meal-order-manager-form-${AWS::AccountId}/archive/*.html
- Effect: Allow
Action:
- cloudfront:CreateInvalidation
# Distribution ID = the meal-order-manager stack's DistributionId
# output (stable for the life of the distribution).
Resource:
- !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/E314J1CJJ9ZTRA
Outputs:
LambdaExecutionBoundaryArn:
Value: !Ref LambdaExecutionBoundary
@ -1410,3 +1486,5 @@ Outputs:
Value: !GetAtt ApmWoAnalysisDeployRole.Arn
SeahavenAccountBaselineDeployRoleArn:
Value: !GetAtt SeahavenAccountBaselineDeployRole.Arn
MealOrderManagerWeeklyMenuRoleArn:
Value: !GetAtt MealOrderManagerWeeklyMenuRole.Arn