Cloud Agentics Talk to an engineer

Work / Landing zone

Landing zone, March 2025

From one AWS account to six

A SaaS company ran production, staging and development in one undocumented AWS account. We moved it to six accounts under Control Tower, with 12 permission sets, Terraform modules, canary deployments and fault injection tests.

6accountsfrom 1
85 %fewer production incidentsper month, from 12 to 2
99.99 %uptimefrom 99.5 %
15 minmean time to recoveryfrom 4 hours

The situation

The client is a growing SaaS company. Its whole operation ran in one AWS account with no documentation. We found four problems.

Mixed environments

Production, staging and development shared one account. Resource names such as "prod-maybe" and "test-final-v2" did not say which environment a resource belonged to.

No access control

Developers had administrator access to production. There was no audit trail. Credentials were shared in Slack channels.

More than 200 IAM policies

The policies overlapped. No one could say who had access to what.

Service quotas reached

The account had reached its Lambda, API Gateway and VPC quotas, so workloads could not scale.

ec2-prod-1rds-mainlambda-api
ec2-stg-testrds-staging-2lambda-test
ec2-dev-johnrds-dev-finallambda-poc
All three environments share the same VPCs, security groups and IAM roles

Findings

  • A developer could delete the production RDS database by mistake.
  • Backups had never been tested.
  • Production ran in a single Availability Zone.
  • Secrets were written into Lambda code.
  • No monitoring or alerting was configured.
  • Deployments were made by hand in the AWS console.

Six accounts under Control Tower

We designed a multi-account structure with one account per environment and per shared function. A management account holds Control Tower, single sign-on and billing. Six accounts sit under it.

Management account Control Tower, single sign-on, billing

Security

  • GuardDuty
  • Security Hub
  • CloudTrail

Shared services

  • CI/CD pipelines
  • Build artifacts
  • DNS

Network

  • Transit Gateway
  • VPN
  • Direct Connect

Production

  • Workloads
  • RDS
  • ElastiCache

Staging

  • Pre-production testing
  • Quality assurance

Development

  • Development workloads
  • Sandbox

Fault containment

A fault in development cannot affect production.

Separate service quotas

Each account has its own AWS quotas.

Cost by environment

Each environment's cost is visible on its own.

Audit trail by environment

Each environment has its own CloudTrail record.

Access: 12 permission sets instead of 200 policies

We replaced more than 200 IAM policies with a least-privilege model. Users sign in through IAM Identity Center, formerly AWS SSO, with the client's identity provider. Access is granted through 12 standard permission sets.

  • More than 200 custom IAM policies
  • Inline policies on most roles
  • Shared IAM users with access keys
  • No MFA requirement
  • Administrator access for convenience
  • 12 standard permission sets
  • IAM Identity Center with the identity provider
  • Roles assumed through federation
  • MFA required for every user
  • Elevated access for a limited time, on request
IAM Identity Center identity provider, MFA for every user
Admin management account only DevOps all workload accounts Developer development and staging ReadOnly all accounts

Standard Terraform modules

We wrote reusable Terraform modules that apply the same high availability, security and observability settings in every environment.

vpc-standard

Subnets in several Availability ZonesOne NAT gateway per Availability ZoneVPC Flow LogsPrivate DNS

ecs-service

Fargate SpotAuto scalingApplication Load Balancer integrationCanary deployment

rds-cluster

Multi-AZAutomated backupsPerformance InsightsSecrets rotation

elasticache

Redis clusterReplica in a second Availability ZoneEncryption at restAutomatic failover

All services

Single Availability ZonetoMulti-AZ

RDS and ElastiCache

No failovertoAutomatic failover

Networking

1 NAT gatewayto1 NAT gateway per Availability Zone

Canary deployments

Deployments run through AWS CodeDeploy in four stages. CloudWatch alarms check each stage, and a failed alarm rolls the deployment back without manual action.

1

10 % of traffic

The new version receives 10 % of traffic.

Monitor 5 min
2

30 % of traffic

If no alarm fires, traffic rises to 30 %.

Monitor 5 min
3

60 % of traffic

Traffic rises to 60 %.

Monitor 5 min
4

100 % of traffic

The new version receives all traffic.

Deployment complete

Automatic rollback

Error rate above 5 %p99 latency above 500 ms

The deployment rolls back when either alarm fires. No one has to act.

Rollback

ManualtoAutomatic

Deployment time

30 minto15 min

Failed deployments

5 %to0.1 %

Fault injection with AWS FIS

We used AWS Fault Injection Simulator (FIS) to test the new architecture against four failure cases. All four experiments passed.

ExperimentActionResultStatus
Availability Zone failureStop every EC2 instance and ECS task in Availability Zone ATraffic moved to Availability Zones B and C in 45 sPassed
RDS failoverForce a failover of the RDS primary instanceThe application reconnected in 30 sPassed
ElastiCache node failureStop the primary Redis nodeThe application continued without the cache and read from the databasePassed
Network latencyAdd 200 ms of latency to a downstream serviceThe circuit breaker opened and the service degraded without errorsPassed

Quarterly GameDay

We set up a quarterly GameDay, a planned exercise in which the team injects faults and practises the response.

Scheduled FIS experiments

Automated resilience tests run in staging every week.

Runbook validation

The on-call team practises incident response against the runbooks.

Recovery time tracking

Mean time to recovery is measured at each exercise.

Findings documented

Each weakness found is recorded and fixed.

Resilience in the application

We identified the services the application can run without, such as the cache, and added circuit breakers in the application code. Automated integration tests with fault injection confirm that the application switches to the primary data source within seconds when the cache fails or times out.

Application Circuit breaker closed Cache answers the request Database not read
Application Circuit breaker open Cache down, not called Database answers the request

The circuit closes again when the cache returns.

< 2 sto switch to the databasefault injection tests
100 %requests answeredduring the cache failure
0data lostduring the cache failure
Automaticrecoverywhen the cache returns

The figures

MeasureBeforeAfterChange
Production incidents per month12285 % fewer
Deployment frequencyWeeklyDaily7 times more often
Mean time to recovery4 h15 min94 % shorter
Critical security findings470All resolved
Uptime, %99.599.994 nines
85 %fewer incidentsfrom environment isolation
3 timesfaster deploymentfrom automated pipelines
99.99 %uptimefrom the high-availability architecture

What the client received

  • Six AWS accounts under Control Tower, with a management account for single sign-on and billing.
  • IAM Identity Center with 12 permission sets and MFA for every user.
  • Four Terraform modules: vpc-standard, ecs-service, rds-cluster and elasticache.
  • A CodeDeploy canary pipeline with automatic rollback.
  • Four FIS experiments, a quarterly GameDay and circuit breakers in the application.