Rename: - Go module github.com/tiennm99/miti99bot-go → github.com/tiennm99/miti99bot - CloudFormation stack miti99bot-aws-port → miti99bot - Drop "port", "Cloud Run", "GCP", "cutover", "Phase NN" framing from active code and docs — project reads as canonical AWS-Lambda from now on. AWS deploy guide + flow fix: - New docs/deploy-aws-free-tier-guide.md — Ubuntu 24.04 ARM64 onboarding with project-local venv (pip awscli + sam-cli), SSM secrets via read -s, idempotent OIDC provider + role creation, $1 budget alarm. - Drop sam build from the pipeline — provided.al2023 + makefile builder expects a Makefile in CodeUri (build/lambda/, the output dir), so the step always fails. sam deploy --template-file template.yaml now reads the raw template and zips build/lambda/ directly. - Rollback section rewritten — use continue-update-rollback / cancel-update-stack / git-SHA redeploy. Drop the broken --use-previous-template recipe. - DynamoDB free-tier row corrected (on-demand is 2.5M read / 1M write request units, not 25 RCU/WCU). Updated: - README.md fully rewritten (drops port/legacy framing, lists modules, points new users at the free-tier guide). - aws/README.md retitled "AWS account setup", phase numbers stripped. - Makefile / .github/workflows/deploy.yml — sam deploy flow. - samconfig.toml — stack_name = "miti99bot". - Go comments — Cloud Run → Lambda, Cloud Scheduler → EventBridge Scheduler, Cloud Logging → CloudWatch Logs. - Struct field GCPProject → FirestoreProject (env GOOGLE_CLOUD_PROJECT unchanged). Plus advisory reports under plans/reports/ from the code-reviewer + researcher passes that informed the fixes. Verified: go vet ./..., go build ./..., go test ./... all green.
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 to set your AWS account ID and GitHub repo, 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 |
|---|---|
AWS_ACCOUNT_ID |
12-digit AWS account ID |
ALERT_EMAIL (optional) |
Email for the $1 budget alert |
AWS_ACCOUNT_ID is not a credential — it's hidden only to keep the ARN out of the workflow file.
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.