LANDING ZONE · AWS ORGANIZATION Management account billing · SCPs · no workloads OU · Security Log archive CloudTrail · Config · 365 d Audit GuardDuty · Security Hub OU · Workloads prod VPC · ECS · RDS staging same shape, smaller OU · Sandbox dev-* per engineer · budget alarms data-science no production data IAM Identity Center SSO · MFA · permission sets Just-in-time access approval in Teams · 2 h · break-glass Cost control budgets · anomaly alerts · tags SERVICE CONTROL POLICIES deny leaving the organization · deny disabling CloudTrail · deny regions outside eu-* · deny root user actions require encryption on S3 and EBS · require IMDSv2 · deny public S3 unless tagged public=true LANDING ZONE · AWS ORGANIZATION Management account billing · SCPs · no workloads OU · Security Log archive CloudTrail · 365 d Audit GuardDuty · SecHub OU · Workloads prod VPC · ECS · RDS staging same shape, smaller OU · Sandbox dev-* per engineer, budgets data-science no production data IAM Identity Center SSO · MFA · permission sets Just-in-time access approval in Teams · 2 h · break-glass Cost control budgets · anomaly alerts · tags SERVICE CONTROL POLICIES deny leaving the organization deny disabling CloudTrail deny regions outside eu-* deny root user actions require encryption on S3 and EBS · IMDSv2 deny public S3 unless tagged public=true
IDENTITY · ZERO TRUST ON MICROSOFT ENTRA People staff, contractors Conditional Access MFA, device, location PIM just-in-time, 2 h Approval Teams · logged Microsoft 365 mail · files · DLP labels Azure subscriptions · RBAC SaaS apps SSO and SCIM POLICY SET # Policy Applies to Result CA-01 Require MFA for all users everyone enforced CA-02 Block legacy authentication everyone enforced CA-03 Compliant device for admins admin roles enforced CA-04 Sign-in risk high: block everyone enforced PIM-1 Global Admin: 0 standing, 2 h JIT admin roles enforced PIM-2 Break-glass: 2 accounts, alerts emergency monitored ACCESS REVIEW · quarterly owners confirm privileged access assignments reviewed 142 removed 19 converted to eligible 31 evidence: signed report, 4 pages IDENTITY · ZERO TRUST ON ENTRA People staff, contractors Conditional Access MFA, device, location PIM just-in-time, 2 h Approval Teams · logged Microsoft 365 mail · files · DLP Azure subscriptions · RBAC SaaS apps SSO and SCIM POLICY SET # Policy Result CA-01 Require MFA for all users enforced CA-02 Block legacy authentication enforced CA-03 Compliant device for admins enforced CA-04 Sign-in risk high: block enforced PIM-1 Global Admin: 0 standing, 2 h enforced PIM-2 Break-glass: 2 accounts monitored ACCESS REVIEW · quarterly owners confirm privileged access assignments reviewed 142 removed 19 converted to eligible 31 evidence: signed report, 4 pages
.github/workflows/deploy.yml name: deploy on: push: { branches: [main] } permissions: id-token: write contents: read jobs: plan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ vars.DEPLOY_ROLE }} aws-region: eu-central-1 - run: terraform init -input=false - run: terraform plan -out=tfplan - run: terraform show -no-color tfplan|tee plan.txt apply: needs: plan environment: production # approval required steps: - run: terraform apply tfplan - run: ./scripts/smoke.sh - run: ./scripts/log-change.sh "$GITHUB_SHA" PIPELINE · every change, one path commit signed plan diff reviewed approve a human, logged apply with rollback smoke checks pass log change + rollback PIPELINE · every change, one path commit signed plan diff reviewed approve a human, logged apply with rollback smoke checks pass log change + rollback .github/workflows/deploy.yml on: push: { branches: [main] } permissions: { id-token: write } jobs: plan: - uses: actions/checkout@v4 - uses: aws-actions/configure-aws-credentials@v4 with: aws-region: eu-central-1 - run: terraform plan -out=tfplan apply: needs: plan environment: production # approval - run: terraform apply tfplan - run: ./scripts/smoke.sh - run: ./scripts/log-change.sh "$GITHUB_SHA"
DECISION PAPER · 04 Database engine for the rebuilt platform Question which managed engine carries the platform for the next five years Options A managed PostgreSQL, Multi-AZ B keep MySQL, managed C serverless Decided A, on the evidence below; not B, despite less adviser work Criterion A PostgreSQL B MySQL C Serverless Migration risk rehearsed twice none schema rewrite Cost, 3 yr known, fixed known, fixed variable Failover automatic, 60 s automatic, 60 s automatic Team skills 2 of 3 engineers 3 of 3 0 of 3 Reversibility high n/a low Due-diligence position - architecture diagram with data flows, current and target - security findings register with closure evidence - infrastructure as code, reviewed, owned by the company - runbooks: deploy, rollback, restore, incident REVIEW · read-only 171 files · 3 days · findings 23 critical 2 high 6 medium 9 low 6 decision brief: 4 pages DECISION PAPER · 04 Database engine for the platform Question which managed engine carries the platform for five years Options A PostgreSQL, Multi-AZ B MySQL, managed C serverless Decided A, on the evidence below Criterion A PostgreSQL B MySQL Migration risk rehearsed twice none Cost, 3 yr known, fixed known, fixed Failover automatic, 60 s automatic, 60 s Team skills 2 of 3 engineers 3 of 3 Reversibility high n/a Due-diligence position - architecture diagram with data flows - findings register with closure evidence - infrastructure as code, company-owned - runbooks: deploy, rollback, restore REVIEW · read-only 171 files · 3 days · findings 23 critical 2 · high 6 · medium 9 · low 6 decision brief: 4 pages
TARGET ARCHITECTURE · AWS · eu-central-1 VPC 10.20.0.0/16 public subnets · 2 AZ private subnets · 2 AZ ALB https :443 NAT egress only CloudFront WAF · TLS 1.2+ Route 53 apex, www ECS Fargate api · 2 tasks ECS Fargate worker RDS PostgreSQL Multi-AZ, encrypted, PITR 15 min ElastiCache sessions Secrets rotation 30 d S3 uploads · private · signed URLs CloudWatch · GuardDuty alerts to on-call infra/prod/ecs.tf resource "aws_ecs_service" "api"{ name = "api" cluster = local.cluster_id task_definition = ...api.arn desired_count = 2 launch_type = "FARGATE" network_configuration { subnets = module.vpc.subnets security_groups = [sg.api.id] assign_public_ip = false } deployment_circuit_breaker { enable = true rollback = true } } resource "aws_db_instance" "db" { engine = "postgres" multi_az = true storage_encrypted = true backup_retention_period = 14 deletion_protection = true } TARGET ARCHITECTURE · AWS · eu-central-1 VPC 10.20.0.0/16 public subnets · 2 AZ CloudFront WAF · TLS 1.2+ Route 53 apex, www ALB https :443 NAT egress only private subnets · 2 AZ ECS Fargate api · 2 tasks ECS Fargate worker RDS PostgreSQL Multi-AZ, encrypted, PITR 15 min ElastiCache sessions Secrets rotation 30 d S3 uploads · private · signed URLs CloudWatch · GuardDuty alerts to on-call infra/prod/ecs.tf resource "aws_ecs_service" "api" { desired_count = 2 deployment_circuit_breaker { enable = true rollback = true } } resource "aws_db_instance" "db" { multi_az = true storage_encrypted = true }
INCIDENT · TIMELINE AND CONTAINMENT 09:14 alert: unusual sign-in, admin account, new country 09:19 session revoked; password and MFA reset; token invalidated 09:26 conditional access: block legacy auth, require admin MFA 09:41 mailbox rules reviewed: 1 forwarding rule removed 10:05 scope confirmed: one account, no data exported (audit log) 11:02 root cause: phished credential, no MFA on the account 11:30 client briefed in plain language: what happened, what changed day 2 PIM enabled: admin rights just-in-time, 2 h, approval in Teams day 3 tabletop with the team; runbook IR-1 updated WHAT CHANGED access · monitoring · training MFA enforced: 100 % of accounts admin standing access: 0 sign-in risk alerts: on-call phishing drill: quarterly log retention: 365 days REPORT · 4 pages non-technical first, evidence appendix INCIDENT · TIMELINE AND CONTAINMENT 09:14 alert: unusual sign-in, admin, new country 09:19 session revoked; password and MFA reset 09:26 CA: block legacy auth, require admin MFA 09:41 mailbox rules: 1 forwarding rule removed 10:05 scope: one account, no data exported 11:02 root cause: phished credential, no MFA 11:30 client briefed in plain language day 2 PIM: admin rights just-in-time, 2 h day 3 tabletop; runbook IR-1 updated WHAT CHANGED access · monitoring · training MFA enforced: 100 % of accounts admin standing access: 0 log retention: 365 days phishing drill: quarterly REPORT · 4 pages non-technical first, evidence appendix
CONTROLS MATRIX · ISO 27001:2022 Annex A (extract) Control Policy In the systems Evidence Owner A.5.15 Access control yes Entra CA, RBAC policy export, review log IT A.5.17 Authentication yes MFA enforced, PIM sign-in logs, PIM report IT A.8.2 Privileged access yes JIT, 2 h, approval activation log Sec A.8.9 Configuration mgmt yes Terraform, reviewed PR history DevOps A.8.13 Backup yes 14 d PITR, drills restore drill 2025-11 DevOps A.8.15 Logging yes central, 365 d retention config Sec A.8.16 Monitoring yes alerts: on-call alert history Sec A.8.24 Cryptography yes KMS, TLS 1.2+ KMS policy, scan Sec A.8.28 Secure coding partial CI checks pipeline config Dev A.8.32 Change mgmt yes PR + change log log with rollback DevOps AUDIT READINESS controls 93 · implemented 89 · gaps 4 EVIDENCE INDEX E-01 access review Q3, signed E-02 PIM activation log, 90 days E-03 restore drill, screenshots and timings E-04 DNS transfer record, before and after E-05 documentation vs live product: 9 defects, fixed QUESTIONNAIRE MAP Q12 encryption at rest : KMS policy, A.8.24 Q27 access reviews : A.5.15, E-01 review log Q41 incident response : runbook IR-1 Q58 backups : A.8.13, E-03 restore drill Answered 61 / 61 evidence 58 · closed 5 · open 2 CONTROLS MATRIX · ISO 27001:2022 (extract) Control In the systems Owner A.5.15 Access control Entra CA, RBAC IT A.5.17 Authentication MFA enforced, PIM IT A.8.2 Privileged access JIT, 2 h, approval Sec A.8.9 Configuration Terraform, reviewed DevOps A.8.13 Backup 14 d PITR, drills DevOps A.8.15 Logging central, 365 d Sec A.8.16 Monitoring alerts: on-call Sec A.8.24 Cryptography KMS, TLS 1.2+ Sec A.8.28 Secure coding CI checks Dev A.8.32 Change mgmt PR + change log DevOps AUDIT READINESS controls 93 · implemented 89 · gaps 4 EVIDENCE INDEX E-01 access review Q3, signed E-02 PIM activation log, 90 days E-03 restore drill, screenshots, timings E-04 DNS transfer record, before and after E-05 docs vs live product: 9 defects, fixed QUESTIONNAIRE MAP Q12 encryption at rest : A.8.24 Q27 access reviews : A.5.15, E-01 Q41 incident response : runbook IR-1 Q58 backups : A.8.13, E-03 Answered 61 / 61 evidence 58 · closed 5 · open 2
AI IN THE BUSINESS · DATA FLOW AND RULES People staff, tools Gateway redact · log · allow-list Model provider no training on data Internal store same permissions RULES, IN ONE PAGE 1 Data leaves the tenant only if redacted. 2 Each allowed tool has an owner and data map. 3 Prompts and outputs are logged like any tool. 4 Internal store access follows existing rules. 5 Anything that acts needs a human approval. 6 Quarterly review of tools, costs, incidents. TOOL SELECTION · evidence, not demos Tool Residency Training opt-out Verdict Assistant A EU yes, contract allowed Assistant B US no blocked Code helper EU yes no secrets Meeting notes US yes pilot, 1 team AI IN THE BUSINESS · DATA FLOW AND RULES People staff, tools Gateway redact · log · allowlist Internal store same permissions Model provider no training on data RULES, IN ONE PAGE 1 Data leaves the tenant only if redacted. 2 Each allowed tool has an owner, data map. 3 Prompts and outputs are logged. 4 Store access follows existing rules. 5 Anything that acts needs human approval. 6 Quarterly review: tools, costs, incidents. TOOL SELECTION · evidence, not demos Tool Residency Verdict Assistant A EU, opt-out allowed Assistant B US, no opt-out blocked Code helper EU, opt-out no secrets Meeting notes US, opt-out pilot, 1 team
RUNBOOK · RB-03 restore database when data loss, corruption, failed migration owner on-call engineer · approver: CTO rpo/rto 15 min / 60 min 1 freeze writes: scale api to 0 2 restore to new instance from PITR, time T 3 verify row counts against ledger (script) 4 switch endpoint; scale api to 2 5 log the change with rollback: re-point to old RESTORE DRILL · 2025-11 · evidence start 10:02 restore complete 10:19 (17 min) row counts 132 / 132 tables match switch 10:23 total 21 min, under RTO 60 min screenshots: 6 · signed by: on-call, CTO CHANGE LOG · written before it ran # Change Rollback Result When C-41 enable PIM for Global Admin disable role policy ok Tue 09:10 C-42 DNS: move apex to new host restore old records ok Tue 14:00 C-43 RDS parameter group v2 revert to v1 ok Wed 08:30 C-44 WAF managed rules on off ok, 0 false hits Wed 11:15 C-45 S3 block public access, all accounts per-bucket exception ok Thu 09:00 RUNBOOK · RB-03 restore database when data loss, corruption, failed migration owner on-call engineer · approver: CTO rpo/rto 15 min / 60 min 1 freeze writes: scale api to 0 2 restore new instance from PITR, time T 3 verify row counts against ledger 4 switch endpoint; scale api to 2 5 log the change with rollback RESTORE DRILL · 2025-11 · evidence start 10:02 restore complete 10:19 (17 min) row counts 132 / 132 tables match switch 10:23 total 21 min, under RTO 60 min screenshots: 6 · signed by: on-call, CTO CHANGE LOG · written before it ran # Change Rollback C-41 enable PIM for Global Admin disable role policy C-42 DNS: move apex to new host restore old records C-43 RDS parameter group v2 revert to v1 C-44 WAF managed rules on off C-45 S3 block public access bucket exception