Infrastructure Design: [Platform or workload name]
Complete infrastructure design for a workload built and run with
Infrastructure as Code: environments, network, compute, storage,
managed services, repository and module conventions, state, CI/CD for
infrastructure, secrets, identity and access, tagging and cost
allocation, scaling, backup and disaster recovery, observability,
security baselines with policy as code, change management and a cost
estimate. Based on common industry practice for cloud infrastructure
design. Replace every [bracketed] value and every row marked
Example. Worked examples use a web application on a public cloud with
Terraform or OpenTofu.
Document control
| Field | Value |
|---|
| Document ID | [INFRA-DES-WEBAPP-001] |
| Platform / workload | [Customer portal] |
| Cloud provider(s) | [Provider] |
| Accounts / subscriptions / projects | [portal-dev, portal-stg, portal-prod, shared-network, security-logs] |
| Version | [0.1] |
| Status | [Draft / In review / Approved / Superseded] |
| Owner | [@platform-lead] |
| Classification | [Internal / Confidential] |
| Last updated | YYYY-MM-DD |
| Related | [System design], [Security architecture], [IaC repository URL] |
Approvals
| Role | Name | Decision | Date |
|---|
| Platform lead | [@name] | [Approved / Changes requested] | YYYY-MM-DD |
| Application tech lead | [@name] | [Decision] | YYYY-MM-DD |
| Security | [@name] | [Decision] | YYYY-MM-DD |
| FinOps / budget owner | [@name] | [Decision] | YYYY-MM-DD |
Revision history
| Version | Date | Author | Change summary |
|---|
| 0.1 | YYYY-MM-DD | [@name] | First draft |
| 0.2 | YYYY-MM-DD | [@name] | Example: Added second region for disaster recovery |
| 1.0 | YYYY-MM-DD | [@name] | Example: Approved; implemented in IaC release v1.0.0 |
Contents
1. Introduction
1.1 Purpose and scope
[What this design covers. Example: "Infrastructure for the customer
portal: networking, compute, data stores and supporting services in
three environments, provisioned entirely from the infra-portal
repository."]
1.2 Requirements driving the design
| ID | Requirement | Source | Design response |
|---|
| IR-01 | Example: 99.9% monthly availability | System design NFR-02 | Three availability zones; managed database with standby |
| IR-02 | Example: RPO 15 min, RTO 4 hours | Business continuity plan | Cross-region backups; scripted rebuild in DR region |
| IR-03 | Example: Personal data stays in the EU | Data protection assessment | EU regions only; policy blocks other regions |
| IR-04 | Example: Monthly run cost under EUR 12 000 in production | Budget | Right-sizing, commitments, non-production schedules |
| [IR-nn] | [Requirement] | [Source] | [Response] |
1.3 Key decisions
| ID | Decision | Alternatives | Rationale | ADR |
|---|
| ID-01 | Example: Terraform-compatible IaC (OpenTofu) | Provider-native templates, Pulumi | Team skills; multi-provider modules | [ADR-012] |
| ID-02 | Example: Managed Kubernetes for services | Serverless containers, VMs | Existing platform tooling | [ADR-013] |
| [ID-nn] | [Decision] | [Alternatives] | [Rationale] | [Link] |
2. Environments and account structure
| Environment | Account / project | Region(s) | Purpose | Data | Parity with production |
|---|
| dev | portal-dev | [eu-west-1] | Feature development, ephemeral stacks | Synthetic | Reduced sizes, single AZ |
| staging | portal-stg | [eu-west-1] | Pre-production tests, load tests | Masked copy | Same topology, smaller sizes |
| production | portal-prod | [eu-west-1] primary, [eu-central-1] DR | Live service | Live | n/a |
| shared-network | shared-network | Both | Transit gateway, DNS, egress | None | n/a |
| security-logs | security-logs | [eu-west-1] | Central immutable logs | Logs | n/a |
Each environment is a separate account so that a mistake in one cannot
change another. Ephemeral dev stacks are named dev-<branch> and
destroyed after [72 hours] of inactivity.
3. Network design
3.1 Address plan
| Network | Environment | CIDR | Usable addresses | Notes |
|---|
| Corporate (reserved) | n/a | 10.0.0.0/12 | n/a | Do not use in cloud |
| VPC portal-prod | production | 10.32.0.0/16 | 65 536 | Primary region |
| VPC portal-prod-dr | production DR | 10.33.0.0/16 | 65 536 | DR region |
| VPC portal-stg | staging | 10.34.0.0/16 | 65 536 | |
| VPC portal-dev | dev | 10.35.0.0/16 | 65 536 | |
| [VPC] | [Environment] | [CIDR] | [n] | [Notes] |
3.2 Subnets (production primary region)
| Subnet | Tier | AZ | CIDR | Addresses | Route to internet |
|---|
| public-a | Public (load balancers, NAT) | a | 10.32.0.0/24 | 256 | Internet gateway |
| public-b | Public | b | 10.32.1.0/24 | 256 | Internet gateway |
| public-c | Public | c | 10.32.2.0/24 | 256 | Internet gateway |
| app-a | Private (compute) | a | 10.32.16.0/20 | 4 096 | NAT in same AZ |
| app-b | Private | b | 10.32.32.0/20 | 4 096 | NAT in same AZ |
| app-c | Private | c | 10.32.48.0/20 | 4 096 | NAT in same AZ |
| data-a | Isolated (databases) | a | 10.32.64.0/24 | 256 | None |
| data-b | Isolated | b | 10.32.65.0/24 | 256 | None |
| data-c | Isolated | c | 10.32.66.0/24 | 256 | None |
Application subnets are sized for pod networking. With p pods per node
and n nodes per zone at peak, each zone needs at least:
Naddr≥1.5×n×(p+1) For n=20 and p=58, Naddr≥1770, so a /20 (4 096
addresses) leaves room for growth.
3.3 Topology and traffic flow
The diagram shows the production topology in one region.
3.4 Connectivity and controls
| Control | Design |
|---|
| Ingress | Only through WAF and load balancer on 443 |
| East-west | Security groups by tier; Kubernetes network policies default deny |
| Egress | NAT per AZ; DNS firewall allow-list for external domains |
| Private access to provider services | Private endpoints for storage, secrets, registry, logs |
| Hybrid | Site-to-site VPN [and dedicated link] via transit gateway |
| DNS | Private hosted zone portal.internal; public zone portal.example.com |
4. Compute
| Workload | Platform | Instance / size | Min / max | Image / AMI source | Patching |
|---|
| Web and API services | Managed Kubernetes [version] | Example: 4 vCPU / 16 GB, ARM | 6 / 60 nodes | Provider-optimised node image | Node image rolled monthly |
| Background jobs | Same cluster, separate node pool | 8 vCPU / 32 GB, spot | 0 / 20 | Same | Same |
| Scheduled reports | Serverless functions | 1 GB memory | n/a | Managed runtime | Provider |
| [Workload] | [Platform] | [Size] | [Min / max] | [Image] | [Process] |
5. Storage and data services
| Store | Service | Size / class | HA | Encryption | Lifecycle |
|---|
| Application database | Managed PostgreSQL [version] | Example: 8 vCPU / 32 GB, 500 GB gp3 | Multi-AZ standby | Customer-managed key | PITR 14 days |
| Cache | Managed Redis | 2 nodes, 13 GB | Replica in second AZ | In transit and at rest | n/a |
| User uploads | Object storage bucket | Standard, then infrequent access after 30 days | Regional | Customer-managed key | Delete after 2 years |
| Logs archive | Object storage, security-logs account | Archive class after 90 days | Regional, replicated | Customer-managed key, object lock | Retain 1 year |
| [Store] | [Service] | [Size] | [HA] | [Encryption] | [Lifecycle] |
6. Managed and shared services
| Service | Purpose | Owned by | Shared with |
|---|
| Container registry | Images, signed | Platform team | All workloads |
| Secrets manager | Application secrets | This workload | none |
| Key management service | Encryption keys | Security team | All workloads |
| DNS | Public and private zones | Platform team | All workloads |
| Certificate manager | TLS certificates | This workload | none |
| Email sending service | Transactional email | This workload | none |
| [Service] | [Purpose] | [Owner] | [Sharing] |
7. IaC repository structure and module conventions
7.1 Repository layout
Reusable modules are separated from the root modules that instantiate
them per environment and layer:
infra-portal/
modules/
network/ # VPC, subnets, routes, endpoints
eks-cluster/ # cluster, node pools, add-ons
postgres/ # database, parameter group, alarms
bucket/ # object storage with policy and lifecycle
live/
dev/
network/ # root module: calls modules/network
cluster/
data/
stg/
prod/
prod-dr/
policies/ # policy-as-code rules (section 16)
.ci/ # pipeline definitions
7.2 Conventions
| Topic | Convention |
|---|
| Tool and version | Example: OpenTofu [1.x], pinned in .tool-versions; provider versions pinned with lock file committed |
| Module sources | Internal modules by Git tag (?ref=v1.4.2); public modules only from an approved list, pinned to exact versions |
| Root modules | One per environment and layer (network, cluster, data); small blast radius |
| Variables | Typed, with descriptions and validation blocks; no defaults for environment-specific values |
| Outputs | Only what other layers need; read through remote state or parameter store |
| Naming | <app>-<env>-<component>[-<az>], for example portal-prod-db |
| Formatting and linting | fmt, validate and a linter run in CI and pre-commit |
| Documentation | Each module has a README generated from variables and outputs |
| Module versioning | Semantic versioning; breaking changes in a major version with upgrade notes |
8. State management
| Topic | Design |
|---|
| Backend | Example: Object storage bucket per environment in a dedicated state account |
| Locking | Native lock file or lock table |
| Encryption | Bucket encryption with customer-managed key; TLS only |
| Access | Pipeline role read and write; engineers read-only for plan in non-production only |
| Versioning | Object versioning on; 90 days of history |
| Key layout | <env>/<layer>/terraform.tfstate |
| Drift detection | Scheduled plan every [6 hours]; drift raises a ticket |
| Recovery | Restore previous object version; documented in runbook |
9. CI/CD for infrastructure
The pipeline below runs for every pull request and every merge to the
main branch.
| Stage | Tooling | Gate |
|---|
| Static checks | [fmt, validate, linter] | Must pass |
| Security and policy | [IaC scanner], policy engine (section 16) | High findings block |
| Plan | Pipeline with read-only role | Plan attached to pull request |
| Cost diff | [Cost estimation tool] | Increases above [EUR 500 per month] need budget owner approval |
| Apply non-production | Pipeline role per environment | Automatic after merge |
| Apply production | Pipeline role, OIDC federation | Approval by platform lead; change window rules in section 17 |
10. Identity and access management
| Principal | Access | Environments | Mechanism |
|---|
| CI pipeline (plan) | Read-only | All | OIDC federation, short-lived role |
| CI pipeline (apply) | Admin on workload resources, no IAM on organisation | Per environment | OIDC, separate role per environment |
| Platform engineers | Read-only console; write via pipeline | All | SSO groups |
| Platform engineers (break-glass) | Admin, time-limited | Production | Just-in-time elevation, approval and alert |
| Application workloads | Least privilege per service | All | Workload identity (service account to cloud role) |
| [Principal] | [Access] | [Environments] | [Mechanism] |
11. Secrets management
| Topic | Design |
|---|
| Store | Secrets manager in each environment account |
| Creation | IaC creates the secret container; values set by rotation function or by an operator, never in code |
| Delivery to workloads | CSI driver or external secrets operator; mounted as files |
| Rotation | Database credentials every [30 days] automatically; third-party keys every [90 days] |
| State hygiene | Use data sources and generated passwords marked sensitive; state encrypted (section 8) |
| Detection | Secret scanning on the IaC repository in CI |
12. Tagging and cost allocation
| Tag key | Required | Allowed values | Example | Used for |
|---|
app | Yes | Registered application IDs | portal | Cost allocation |
env | Yes | dev, stg, prod, prod-dr | prod | Cost, policy scope |
owner | Yes | Team handle | team-portal | Contact |
cost-centre | Yes | Finance codes | CC-4120 | Chargeback |
data-class | Yes for data stores | public, internal, confidential, personal | personal | Security policy |
managed-by | Yes | iac, manual | iac | Drift and exception reports |
schedule | No | office-hours, always-on | office-hours | Automated shutdown |
Default tags are applied at provider level in every root module. Policy
rejects resources missing required tags; shared costs (NAT, transit,
logging) are allocated by [traffic share / fixed split] each month.
13. Scaling
| Tier | Mechanism | Signal | Limits | Quota to watch |
|---|
| Pods | Horizontal autoscaler | CPU 60%, requests per pod | 3 to 120 per service | n/a |
| Nodes | Cluster autoscaler / node provisioner | Pending pods | 6 to 60 nodes | vCPU quota per region |
| Database | Vertical, planned; read replicas | CPU above 70% for a week | Largest class [x] | Storage max |
| Cache | Add shard | Memory above 75% | [n] shards | n/a |
| [Tier] | [Mechanism] | [Signal] | [Limits] | [Quota] |
14. Backup and disaster recovery
| Component | Backup method | Frequency | Retention | Copy to DR region | RPO | RTO |
|---|
| PostgreSQL | Automated snapshots and PITR | Continuous | 14 days PITR, 12 monthly | Yes, every 15 min | 15 min | 2 hours |
| Object storage | Versioning and cross-region replication | Continuous | 30 days of versions | Yes | Minutes | 1 hour |
| Kubernetes workloads | Rebuilt from IaC and GitOps manifests | n/a | n/a | Images replicated | 0 | 3 hours |
| IaC state | Object versioning | Every change | 90 days | Yes | 0 | 30 min |
| [Component] | [Method] | [Frequency] | [Retention] | [Y / N] | [RPO] | [RTO] |
DR strategy: [Example: "Pilot light. Network, cluster control plane and
database replica exist in the DR region; node pools scale from zero
during failover."] Last DR drill: YYYY-MM-DD, measured RTO [n] hours.
15. Observability
| Signal | Source | Destination | Retention | Alert example |
|---|
| Metrics | Cloud metrics, node exporter, cluster metrics | [Monitoring system] | 13 months | Node CPU above 85% for 15 min |
| Logs | Control plane, load balancer, VPC flow logs, application | Central log store | 30 days hot, 1 year archive | Spike in 5xx at load balancer |
| Audit | Cloud audit trail, Kubernetes audit | security-logs account | 1 year, immutable | IAM change outside pipeline |
| Cost | Billing export | Cost dashboard | 24 months | Daily spend above forecast by 20% |
| Synthetic | External probes | [Monitoring system] | 13 months | Login page down from 2 locations |
16. Security baselines and policy as code
| ID | Baseline control | Enforced by | Stage |
|---|
| PC-01 | No public object storage buckets | Policy engine rule; account-level public access block | Plan and runtime |
| PC-02 | All storage and databases encrypted with customer-managed keys | Policy rule | Plan |
| PC-03 | No security group allows 0.0.0.0/0 except on load balancers port 443 | Policy rule | Plan |
| PC-04 | Required tags present (section 12) | Policy rule | Plan |
| PC-05 | Only approved regions | Organisation-level guardrail | Runtime |
| PC-06 | Audit logging cannot be disabled | Organisation-level guardrail | Runtime |
| PC-07 | Container images signed and scanned | Admission controller | Deploy |
| PC-08 | Benchmark compliance (for example CIS) monitored | Cloud security posture tool | Runtime |
| [PC-nn] | [Control] | [Mechanism] | [Stage] |
Policy rules live in policies/, are versioned with the IaC and have
unit tests. Exceptions require an entry in 19.2 with an expiry date.
17. Change management
| Change type | Examples | Approval | Window | Rollback |
|---|
| Standard | Scaling limits, tags, new alarms | Pull request review | Any time | Revert commit and apply |
| Normal | New data store, network rule change | Pull request plus platform lead | Business hours, not Friday afternoon | Documented in pull request |
| High risk | Database major version, CIDR change, cluster upgrade | Change advisory review | Agreed window with on-call present | Tested rollback plan |
| Emergency | Fix for active incident | Incident commander | Any time | Retrospective review within 2 days |
Freeze periods: [peak trading weeks, financial year end].
18. Cost estimate
Prices as of YYYY-MM-DD, [region], on-demand unless stated.
| Item | Unit | Unit price (EUR) | Quantity | Monthly cost (EUR) |
|---|
| Kubernetes control plane | cluster-month | [70] | 1 | [70] |
| Worker nodes (4 vCPU / 16 GB, ARM) | node-hour | [0.15] | 12 nodes x 730 h | [1 314] |
| Managed PostgreSQL, multi-AZ | instance-month | [1 100] | 1 | [1 100] |
| Database storage | GB-month | [0.25] | 500 | [125] |
| Managed Redis | node-month | [180] | 2 | [360] |
| NAT gateways | gateway-hour plus data | [0.05 + 0.05/GB] | 3 x 730 h, 2 TB | [210] |
| Load balancer | hour plus capacity units | [0.03] | 730 h | [40] |
| Object storage | GB-month | [0.023] | 3 000 | [69] |
| Logs and metrics | GB ingested | [0.60] | 800 | [480] |
| DR region pilot light | various | | | [600] |
| Non-production environments | various | | | [1 400] |
| Total before discounts | | | | [5 768] |
| Commitment discount on baseline compute and database | | [30%] | | [-725] |
| Estimated total | | | | [5 043] |
Monthly cost for a node pool is C=N×h×p, where N is
nodes, h hours per month (730) and p the hourly price.
19. Appendices
19.1 Glossary
| Term | Meaning |
|---|
| IaC | Infrastructure as Code: infrastructure defined in versioned files and applied by tools |
| Root module | Directory where plan and apply run, combining modules for one environment and layer |
| State | Record the IaC tool keeps of the resources it manages |
| Drift | Difference between the real infrastructure and the code |
| Pilot light | DR approach with minimal standby resources scaled up during failover |
| [Term] | [Meaning] |
19.2 Exceptions and manual resources
| ID | Resource or rule | Reason | Compensating control | Owner | Expires |
|---|
| EXC-01 | Example: DNS zone created manually | Created before IaC adoption | Import planned in sprint [n] | [@name] | YYYY-MM-DD |
| [EXC-nn] | [Item] | [Reason] | [Control] | [@name] | YYYY-MM-DD |
19.3 References
| Reference | Use |
|---|
| [Cloud provider documentation] | Service limits and configuration |
| [IaC tool documentation] | State, modules and providers |
| [Organisation cloud landing zone standard] | Account structure and guardrails |
| [Security architecture document] | Controls referenced in section 16 |
Standard and licence note
Based on common industry practice for cloud infrastructure design and
Infrastructure as Code. Original text written for this collection;
prices, sizes and ranges are illustrative and must be checked against
your provider's current offering. Template licence: MIT.