Cloud Architecture

Designing Production-Ready AWS Infrastructure with Terraform

Network boundaries, state isolation, reviewed changes, and recovery planning for a hypothetical AWS workload.

Start with failure and recovery objectives

Production readiness is not a collection of AWS services. It is the ability to operate a workload within explicit security, availability, and recovery constraints. Before writing Terraform, define the expected users, data sensitivity, peak demand, recovery time objective (RTO), and recovery point objective (RPO). These determine which failures the architecture must tolerate and how much complexity is justified.

This guide uses a hypothetical web application, not a description of a client environment. It has an internet-facing entry point, private application workloads, and a private managed database. The same boundary-first reasoning applies on Azure, although networking, identity, and service semantics differ.

Separate network exposure from application placement

An application load balancer can live in public subnets while its targets remain in private subnets. Public subnets require a route to an internet gateway; private subnets do not expose workloads merely because the application is reachable through the load balancer. Security groups should allow the application port from the load balancer security group, rather than from all internet addresses.

Private workloads may still need outbound connectivity for dependencies or external APIs. NAT gateways provide one option, while VPC endpoints can provide private access to supported AWS services. Neither choice is universally cheaper: evaluate traffic volume, endpoint hourly charges, data processing, and cross-zone traffic.

TierExposureTypical boundary
Entry pointPublic HTTPSLoad balancer and certificate
ApplicationPrivateInbound only from entry-point security group
DataPrivateInbound only from application security group

Use multiple availability zones where failure tolerance requires them. A multi-zone application does not automatically make every dependency resilient. Check database failover, outbound routing, DNS behavior, and available capacity after a zone loss.

Treat Terraform state as sensitive infrastructure

State can contain resource attributes and sensitive values. Marking an output sensitive hides it in normal CLI output; it does not remove it from state. Use a remote backend with encryption, versioning, restricted access, and locking supported by your backend and Terraform version. Separate state by ownership and lifecycle, not by arbitrary file count.

The following fragment illustrates a boundary, not a complete deployable VPC. It assumes an existing VPC and load balancer security group.

HCL · EDUCATIONAL EXAMPLE
resource "aws_security_group" "application" {
  name        = "example-application"
  description = "Application ingress from the load balancer only"
  vpc_id      = var.vpc_id
}

resource "aws_vpc_security_group_ingress_rule" "application_https" {
  security_group_id            = aws_security_group.application.id
  referenced_security_group_id = var.load_balancer_security_group_id
  from_port                   = 8443
  to_port                     = 8443
  ip_protocol                 = "tcp"
}

Pin provider versions with explicit constraints and commit the dependency lock file. Keep modules small enough to reason about. A module that creates networking, databases, IAM, and application deployment at once often couples unrelated lifecycles.

Make the reviewed plan the applied change

A delivery workflow should run formatting, validation, policy checks, and a plan using the target environment's identity. A privileged apply should consume the approved plan rather than silently creating a different one. Saved plans can also contain sensitive information, so store them with restricted access and a short retention period.

Use federated, short-lived identities where available. Restrict who can modify the workflow and who can approve the environment. A well-scoped cloud role does not help if an untrusted pull request can alter the job that assumes it.

Recovery is an exercised capability

Enable database backups, document dependencies, and test restoration into an isolated environment. Verify that the restored application can read required secrets, reach dependent systems, and serve meaningful requests. Record observed recovery time against the chosen RTO; do not turn an untested assumption into an availability claim.

For cost-aware operation, tag resources, establish ownership, and review idle capacity. Right-sizing should consider sustained usage and peak requirements. Commitments make sense for stable baseline demand, not as a substitute for understanding the workload.

Common mistakes and a review checklist

Avoid shared administrator credentials, a single state file for every environment, public database exposure, and manual changes that are never reconciled into code. Drift detection is useful only when someone owns the result.

Before promotion, ask: Can this change be reviewed? Can it be reversed or safely corrected? Is the artifact of the plan protected? Can the system recover from a missing zone or a restored database? Does the monitoring reveal user impact? These questions establish a more meaningful definition of readiness than the number of services in an architecture diagram.

Multi-environment isolation covers account and state boundaries. AWS cost and reliability trade-offs explains when unused capacity is a recovery requirement. See Cloud Infrastructure and the architecture lab.

Related technical guides

LET’S BUILD WHAT’S NEXT

Good engineering starts with a conversation.

Let’s connect