AWS configuration for deployment
The scripts infrastructure/deploy.sh (microservices) and
infrastructure/deploy-monolith.sh (monolith) use Terraform + AWS CLI + Docker to
provision and deploy the whole platform. They were originally written for AWS
Academy, which provides a temporary account with a preexisting role called
LabRole and session credentials pasted into ~/.aws/credentials.
On a standalone AWS account (freshly created) you must reproduce those two elements:
- The
LabRolerole: an ECS role (execution + task) that Terraform references by name (data.aws_iam_role.lab, variablelab_role_name, defaultLabRole) and which the one-off database initialization task also uses. - A deployment identity with permissions: an IAM user with a policy covering everything the scripts do, and its access keys written to a credentials file.
Access keys belong to an IAM user, not a role. A role is "assumed" and yields
temporary credentials (this is what AWS Academy does). For a .credentials file
with long-lived static keys, the identity must be an IAM user. Here we create
both: the task role LabRole and the deployment user with its keys.
What the scripts do (AWS services involved)
Terraform creates: VPC, subnets, IGW, NAT Gateway, EIP, route tables, security
groups (EC2); ALB, listeners, target groups, mTLS trust store (ELBv2);
repositories and lifecycle policies (ECR); cluster, task definitions and services
(ECS); instance and subnet group (RDS); replication group and subnet group
(ElastiCache); bucket, objects and public access block (S3); log groups
(CloudWatch Logs); and references a certificate (ACM). The scripts also run via
CLI: sts get-caller-identity, ecr get-login-password,
ecs register-task-definition/run-task/update-service/...,
s3 cp/presign/rm, logs tail, and ec2 describe-* queries.
1. Local prerequisites
- Install the tools the script checks (
check_prerequisites):aws(CLI v2),terraform,docker,mvn(Maven) andjq. - Verify:
aws --version && terraform -version && docker --version && mvn -v && jq --version.
2. Create the ECS role LabRole
This role is assumed by ECS (Fargate) tasks to pull images from ECR and write logs; the db-init task uses it as execution and task role.
2.1. Trust policy (who can assume it)
Save as labrole-trust.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "ecs-tasks.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}
2.2. Creation and permissions
# Create the role
aws iam create-role \
--role-name LabRole \
--assume-role-policy-document file://labrole-trust.json
# Standard ECS task execution permissions (ECR pull + logs)
aws iam attach-role-policy \
--role-name LabRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
AmazonECSTaskExecutionRolePolicy does not include logs:CreateLogGroup, and
the db-init task starts with awslogs-create-group: true. Add an inline policy
for it:
aws iam put-role-policy \
--role-name LabRole \
--policy-name AllowCreateLogGroup \
--policy-document '{
"Version": "2012-10-17",
"Statement": [
{ "Effect": "Allow", "Action": "logs:CreateLogGroup", "Resource": "*" }
]
}'
If you prefer a different role name, create it with that name and add
lab_role_name = "<your-role>"toterraform.tfvars.
3. Create the deployment user and its permission policy
3.1. Create the user
aws iam create-user --user-name modelcity-deployer
3.2. Grant permissions
You have three options, from simplest to most restricted.
Option A — Maximum simplicity (personal/academic account): attach
AdministratorAccess. Covers everything the scripts do with no tuning.
aws iam attach-user-policy --user-name modelcity-deployer \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccess
Option B — Scoped by service (recommended): attach the managed policies of the services touched:
for p in \
arn:aws:iam::aws:policy/AmazonEC2FullAccess \
arn:aws:iam::aws:policy/AmazonECS_FullAccess \
arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess \
arn:aws:iam::aws:policy/ElasticLoadBalancingFullAccess \
arn:aws:iam::aws:policy/AmazonRDSFullAccess \
arn:aws:iam::aws:policy/AmazonElastiCacheFullAccess \
arn:aws:iam::aws:policy/AmazonS3FullAccess \
arn:aws:iam::aws:policy/CloudWatchLogsFullAccess \
arn:aws:iam::aws:policy/AWSCertificateManagerFullAccess \
arn:aws:iam::aws:policy/IAMFullAccess ; do
aws iam attach-user-policy --user-name modelcity-deployer --policy-arn "$p"
done
IAMFullAccess is needed because Terraform reads the LabRole role
(iam:GetRole) and assigns it to the task definitions (iam:PassRole). To
restrict IAM, replace it with an inline policy allowing only iam:GetRole,
iam:PassRole and iam:ListRoles on LabRole (see Option C).
Option C — Least-privilege IAM: instead of IAMFullAccess, attach the other
Option B policies and add this inline policy:
aws iam put-user-policy --user-name modelcity-deployer \
--policy-name PassLabRole \
--policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["iam:GetRole", "iam:PassRole", "iam:ListRoles"],
"Resource": "arn:aws:iam::*:role/LabRole"
}
]
}'
4. Generate the access keys and write them to a credentials file
- Create the user's keys:
aws iam create-access-key --user-name modelcity-deployer
- The output contains
AccessKeyIdandSecretAccessKey. The secret is shown only once. - Write those values to your credentials file (
~/.aws/credentialsor the.credentialsyou use). Format:[default]aws_access_key_id = AKIAxxxxxxxxxxxxxxxxaws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxregion = us-east-1Unlike AWS Academy, your own IAM user does not use
aws_session_token: only the first two lines. The scripts' default region isus-east-1(AWS_REGION). - If you use a named profile instead of
[default], exportAWS_PROFILE=<profile>before launching the script.
5. Verification
- Check the identity (exactly what
check_aws_credentialsdoes):It should return the account and the ARN of theaws sts get-caller-identitymodelcity-deployeruser. - Check ECR access (what
check_ecr_accessdoes):aws ecr get-authorization-token --region us-east-1 >/dev/null && echo OK - Confirm the role exists:
aws iam get-role --role-name LabRole
6. Additional requirements before deploy.sh
Independent of IAM, but needed for the deployment to finish (see
terraform.tfvars):
- ACM certificate referenced by
acm_certificate_arn: the ALB needs a TLS certificate. Import it into ACM (Let's Encrypt) with the scriptinfrastructure/scripts/import-cert-to-acm.sh; copy the resulting ARN intoterraform.tfvars. The deployment policy already includesAWSCertificateManagerFullAccess. - Domain (use DuckDNS for testing) (
duckdns_domain. Change the variable name if desired): after deployment, point the domain to the ALB's IP (the script prints the updatecurlcommand at the end). - Complete
terraform.tfvarswith the Stripe, Auth0 and mail secrets (see Stripe, Auth0 and Gmail).
7. Execution
- Fill in
infrastructure/terraform/aws/terraform.tfvars(micro) orinfrastructure/terraform/aws-monolith/terraform.tfvars(monolith). - Launch the interactive menu:
./infrastructure/deploy.sh # microservices./infrastructure/deploy-monolith.sh # monolith
- Choose 1) Initial deployment. The script does:
terraform apply→ DB init (one-off ECS task withLabRole) → build/push images to ECR →ecs update-serviceto deploy. - To tear everything down: option 4) Cleanup (
terraform destroy).
The two stacks share resource names (same ALB/cluster/RDS/domain) and are mutually exclusive: destroy one before deploying the other.