The deploy workflow no longer relies on a missing AWS_ACCOUNT_ID secret, preventing invalid assume-role ARNs and matching the repo's documented AWS setup.
AWS account setup
One-time setup steps for a fresh AWS account. After this is done, every push to main deploys via GitHub Actions OIDC; no human-in-loop AWS commands needed.
For the full onboarding walkthrough (prerequisites, Telegram wiring, cost guardrails), see
../docs/deploy-aws-free-tier-guide.md. This file is the condensed cheatsheet.
Region:
ap-southeast-1(Singapore). Change insamconfig.tomlif needed. Stack name:miti99bot. Change insamconfig.toml.
1. AWS account hygiene
- Enable MFA on the root user.
- Create an IAM admin user
admin(CLI access keys). Use only for the firstsam deploy --guided. - Set CLI default region:
aws configure set region ap-southeast-1 --profile admin aws configure set aws_access_key_id AKIA… --profile admin aws configure set aws_secret_access_key … --profile admin
2. SSM Parameter Store secrets
Create the four required secrets. Names must match template.yaml (/miti99bot/${StackEnv}/…).
aws ssm put-parameter --name /miti99bot/prod/telegram-bot-token \
--value "<bot-father-token>" --type SecureString --profile admin
aws ssm put-parameter --name /miti99bot/prod/telegram-webhook-secret \
--value "$(openssl rand -hex 32)" --type SecureString --profile admin
aws ssm put-parameter --name /miti99bot/prod/gemini-api-key \
--value "<google-ai-studio-key>" --type SecureString --profile admin
aws ssm put-parameter --name /miti99bot/prod/cron-shared-secret \
--value "$(openssl rand -hex 32)" --type SecureString --profile admin
Save the webhook + cron secrets locally — you'll set them on the Telegram side and on the EventBridge schedule headers.
3. GitHub OIDC identity provider
One-time per AWS account:
aws iam create-open-id-connect-provider \
--url https://token.actions.githubusercontent.com \
--client-id-list sts.amazonaws.com \
--thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1 \
--profile admin
(GitHub publishes the canonical thumbprint; verify on docs.github.com if rotated.)
4. Deploy IAM role for GitHub Actions
Edit aws/iam-github-oidc-trust.json if you are changing the AWS account or GitHub repo. This repo is already prefilled for account 225603493174 and tiennm99/miti99bot. If you change accounts, update .github/workflows/deploy.yml to match the same role ARN, then:
aws iam create-role \
--role-name github-deploy-miti99bot \
--assume-role-policy-document file://aws/iam-github-oidc-trust.json \
--profile admin
# Permissions (broad to start; tighten with stack-scoped policies later).
for arn in \
arn:aws:iam::aws:policy/AWSCloudFormationFullAccess \
arn:aws:iam::aws:policy/AWSLambda_FullAccess \
arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess \
arn:aws:iam::aws:policy/AmazonEventBridgeFullAccess \
arn:aws:iam::aws:policy/AmazonSQSFullAccess \
arn:aws:iam::aws:policy/AmazonSSMFullAccess \
arn:aws:iam::aws:policy/CloudWatchLogsFullAccess \
arn:aws:iam::aws:policy/AWSBudgetsActionsWithAWSResourceControlAccess \
arn:aws:iam::aws:policy/IAMFullAccess \
arn:aws:iam::aws:policy/AmazonS3FullAccess; do
aws iam attach-role-policy --role-name github-deploy-miti99bot \
--policy-arn "$arn" --profile admin
done
Yes, this is broad. SAM creates IAM roles for the Lambda, so the deploy role needs
iam:CreateRole. Tighten later with custom policies scoped to the stack's resource ARNs.
5. Add GitHub repo secrets
In GitHub repo settings → Secrets and variables → Actions:
| Secret | Value |
|---|---|
ALERT_EMAIL (optional) |
Email for the $1 budget alert |
The deploy workflow now uses the repo's fixed AWS account ID directly for the OIDC role ARN, so AWS_ACCOUNT_ID no longer needs to be stored in GitHub.
6. First deploy (manual)
make build-lambda
AWS_PROFILE=admin sam deploy --template-file template.yaml --guided
Confirm:
- Stack name:
miti99bot - Region:
ap-southeast-1 - Capabilities:
CAPABILITY_IAM - Save to
samconfig.toml: yes (already committed; this just confirms)
After CREATE_COMPLETE:
aws cloudformation describe-stacks --stack-name miti99bot \
--query "Stacks[0].Outputs" --output table --profile admin
Note the FunctionUrl — point the Telegram webhook at it (see ../docs/deploy-aws-free-tier-guide.md Step 5).
7. Tighten — optional but recommended
Once the first deploy succeeds:
- Rotate / delete
adminCLI keys (use only via console for emergencies). - Trigger a workflow_dispatch deploy via GH Actions to confirm OIDC path works without the bootstrap user.
- Replace the broad managed policies on
github-deploy-miti99botwith stack-scoped custom policies.
Lambda Web Adapter layer ARN
Pinned in template.yaml parameter LambdaAdapterLayerArn. Bump by checking:
- https://github.com/awslabs/aws-lambda-web-adapter/releases (look at the
Releasespage for the latest layer version) - Format:
arn:aws:lambda:ap-southeast-1:753240598075:layer:LambdaAdapterLayerArm64:<version>
Cost expectations
After the stack is up but idle, monthly cost should be $0. If you ever see >$0.01 in Cost Explorer, investigate — most likely culprits: CloudWatch Logs ingestion volume, DynamoDB writes from a runaway loop, or accidental egress past the 100 GB free tier.