Files
miti99bot/aws
tiennm99 f3b9891a54 refactor: rename module to miti99bot, canonicalize AWS deploy path
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.
2026-05-13 22:05:38 +07:00
..

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 in samconfig.toml if needed. Stack name: miti99bot. Change in samconfig.toml.


1. AWS account hygiene

  1. Enable MFA on the root user.
  2. Create an IAM admin user admin (CLI access keys). Use only for the first sam deploy --guided.
  3. 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).

Once the first deploy succeeds:

  1. Rotate / delete admin CLI keys (use only via console for emergencies).
  2. Trigger a workflow_dispatch deploy via GH Actions to confirm OIDC path works without the bootstrap user.
  3. Replace the broad managed policies on github-deploy-miti99bot with stack-scoped custom policies.

Lambda Web Adapter layer ARN

Pinned in template.yaml parameter LambdaAdapterLayerArn. Bump by checking:

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.