Skip to content

Configuration baselines

How Changineers configures the in-scope systems and where the baseline lives.

The systems in scope for baselines are AWS resources, the AWS account configuration, the Cognito user pools that authenticate end users, virtual machines, and engineer laptops.

Every AWS resource is provisioned through Terraform in infra/. The Terraform module defaults are the baseline:

  • Encryption at rest is on. S3 buckets, EBS volumes, Aurora databases, DynamoDB tables, Secrets Manager values, and CloudWatch log groups encrypt with KMS.
  • Encryption in transit is enforced through HTTPS on public endpoints and TLS on AWS service APIs.
  • Public exposure is off by default. S3 buckets are private, Security Groups deny inbound by default, and any deviation is explicit in the Terraform.
  • Versioning is on for customer-data buckets. Recordings, uploads, content, and assets buckets keep version history; the Terraform state bucket also has versioning.
  • Cross-region replication is configured for the buckets that need geographic redundancy, using the s3-cross-region-replication module.

If you’re adding a new AWS resource, copy the pattern from a nearby module; the encryption, access, and logging defaults follow.

  • No long-lived AWS keys in human or system hands. Production deploys use OIDC-federated IAM roles. Engineers access AWS through IAM Identity Center, federated from Google Workspace. See Change management § Authorised actors.
  • MFA is enforced on identity through Google Workspace SSO, which gates all SSO-issued AWS sessions.
  • Least privilege. IAM roles are scoped to the resources they need; the DenyIAMAccessKeys SCP at the org level blocks long-lived credentials in the workload accounts.

Aurora Postgres runs with AWS-default parameters and 7-day point-in-time recovery. Changineers hasn’t deviated from AWS defaults; if you’re considering a parameter change, make the case in an ADR. DynamoDB and other managed datastores follow the same approach.

IAM database authentication is enabled on Aurora; the master password is managed by AWS Secrets Manager rather than held in application config.

VMs in the platform boot from Packer-baked AMIs. The AMI is the baseline; patches happen by rebuilding it, not by patching running hosts. Each AMI is single-purpose, and clusters scale to zero when idle. The current example is the GPU transcription workers.

AMIs are rebuilt whenever the software running on them changes or a dependency is patched, and monthly otherwise. The rebuilt AMI replaces the running instances on the next deploy.

Most platform components communicate via AWS public service APIs over TLS, gated by IAM, so the network boundary for them is IAM rather than a subnet. VPC networking applies to Aurora Postgres, the ECS transcription workers, and the QuickSight VPC connection; the controls are defined in Terraform alongside the resources they protect.

UserCloudFront(HTTPS only)API Gateway(HTTPS only)Lambda backend(no VPC attachment)VPC (multi-AZ in ap-southeast-2)RDS Data API(HTTPS + IAM)S3 (AWS service API)Other AWS service APIs(HTTPS + IAM)WAF(AWS Managed Rules)WAF(AWS Managed Rules)AZ ap-southeast-2aAZ ap-southeast-2bVPC Gateway Endpoint(S3)Subnet 172.31.32.0/20Subnet 172.31.0.0/20Aurora Postgreswriter(private)ECS transcription worker(SG: HTTPS egress only,no inbound)Aurora Postgresreplica(private)ECS transcription worker(SG: HTTPS egress only,no inbound) HTTPSHTTPSRDS Data APIreplicationS3 traffic stays on AWS networkOther AWS calls

The diagram shows the inbound path (CloudFront and API Gateway, each fronted by WAF) and the two access patterns to AWS data services: most calls go to AWS public service APIs over TLS gated by IAM, while Aurora Postgres and the ECS transcription workers sit inside the VPC. The transcription worker’s traffic to S3 uses a VPC Gateway Endpoint so it stays on the AWS network.

Public traffic enters through CloudFront and is served by API Gateway, which fronts the Lambda backend. The public endpoints accept HTTPS only.

AWS WAF is attached to CloudFront and the API Gateway, applying AWS Managed Rules. Definitions are in infra/modules/waf.

Workloads that need network-level isolation attach to a VPC and its security groups. Aurora runs inside the VPC and isn’t publicly accessible. Application code reaches it via the RDS Data API, which is HTTPS and IAM-authenticated.

VPC Flow Logs are published to CloudWatch Logs with a 90-day retention.

Each Security Group is defined in Terraform next to the resource it protects. Security Groups deny inbound by default; any allow rule has to be explicit in the Terraform. The transcription worker, for example, has a Security Group with HTTPS-only egress and no inbound rules.

The transcription worker uses a VPC Gateway Endpoint to S3 so its egress traffic to S3 stays on the AWS network. Other AWS service calls go to the AWS public APIs, which fits the IAM-authenticated, TLS-encrypted access pattern.

Workloads in different AWS accounts communicate via AWS APIs over HTTPS, authenticated through IAM. The account boundary is the segregation layer (see Change management § Authorised actors).

User authentication uses Amazon Cognito with its advanced security features in enforced mode. Details on Threat detection § Authentication anomalies.

Keep operating-system security updates on auto-update, and leave the OS-built-in malware protection on (XProtect and Gatekeeper on macOS, Windows Defender on Windows). Turn on FileVault (macOS) or BitLocker (Windows) when you set up your machine.

For incident response when something is detected on a laptop, see Threat detection § Endpoint protection.

AWS handles the patching of the underlying managed services. Application dependencies and CVEs in code we run are handled through Vulnerability management; the CI gate (OSV-Scanner) and Renovate workflow are on Shipping code § Dependency vulnerabilities.

The audit trail is on Threat detection § Audit logging. Operational metrics, log queries, and alarm routing are on Observability.

The baselines above follow AWS best practices, particularly the AWS Well-Architected Framework (Security and Reliability pillars) and the AWS service-specific security guidance for each managed service we use.

The baselines map to controls in CIS AWS Foundations Benchmark v3.0.0 and NIST SP 800-53.

BaselineCIS AWS Foundations v3.0.0NIST 800-53
S3 Public Access blocked2.1.4AC-3
Encryption at rest with KMS (EBS, RDS, CloudTrail logs)2.2.1, 2.3.1, 3.5SC-28
KMS key rotation3.6SC-12
No IAM root access keys1.4IA-5
MFA on root and IAM users1.5, 1.6, 1.10IA-2(1)
Security Groups deny all inbound by default5.4SC-7
Security Groups restrict remote-admin ports5.2, 5.3SC-7
CloudTrail enabled across regions3.1AU-2, AU-12
CloudTrail log file validation3.2AU-9
VPC Flow Logs enabled3.7AU-12
AWS Config enabled3.3CM-8
Threat detection (GuardDuty)-SI-4

A typical S3 bucket definition encoding the encryption, public-access, and versioning baselines at once:

resource "aws_s3_bucket" "example" {
bucket = "example-${var.environment}"
}
resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
bucket = aws_s3_bucket.example.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}
resource "aws_s3_bucket_public_access_block" "example" {
bucket = aws_s3_bucket.example.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_versioning" "example" {
bucket = aws_s3_bucket.example.id
versioning_configuration { status = "Enabled" }
}

The pattern (encryption, public-access block, versioning) is the default for buckets in infra/; deviations require an ADR.