Engineering Leader | SRE | DevOps | Platform Engineering
What SOC 2 and ISO 27001 actually mean for SREs, the technical controls you need to implement, and how to maintain compliance without losing your mind.
Both are security frameworks, but they serve different purposes and markets:
SOC 2 (Service Organization Control 2)
ISO 27001
Key Difference: SOC 2 is a report showing you have controls. ISO 27001 is a certification proving you have a management system.
Get SOC 2 if:
Get ISO 27001 if:
Get Both if:
Good news: most controls overlap. Implement once, satisfy both frameworks:
| SOC 2 Criteria | ISO 27001 Controls | Implementation |
|---|---|---|
| Security - Access Control | A.9 Access Control | MFA, RBAC, least privilege |
| Security - Encryption | A.10 Cryptography | TLS, encryption at rest |
| Security - Logging | A.12.4 Logging and monitoring | Centralized logs, SIEM |
| Availability - Monitoring | A.12.1 Operational procedures | Prometheus, Datadog |
| Availability - Backup | A.12.3 Backup | Automated backups, DR testing |
| Security - Vulnerability Mgmt | A.12.6 Technical vulnerability | Scanning, patching |
| Security - Incident Response | A.16 Incident management | On-call, runbooks, post-mortems |
| Security - Change Management | A.12.1.2 Change management | GitOps, approval workflows |
| Confidentiality - Network Security | A.13 Communications security | Firewalls, network segmentation |
| Security - Physical Security | A.11 Physical security | Data center controls (cloud provider) |
Type I: Point-in-time assessment
Type II: Period-of-time assessment
Stage 1 Audit: Documentation review
Stage 2 Audit: Implementation verification
Surveillance Audits: Annual reviews
Requirements (Both Frameworks):
SOC 2 Focus: Proving access is restricted and monitored ISO 27001 Focus: Documented access control policy and procedures
Implementation:
# AWS IAM policy example - least privilege
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeSecurityGroups"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": "us-east-1"
}
}
}
]
}
# Enforce MFA for AWS CLI access
aws iam create-virtual-mfa-device --virtual-mfa-device-name MyMFADevice
# Kubernetes RBAC - read-only access
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list"]
Evidence Collection:
Requirements (Both Frameworks):
SOC 2 Focus: Demonstrating logs are collected and retained ISO 27001 Focus: Log review procedures and incident detection
Implementation:
# CloudWatch Logs retention
aws logs put-retention-policy \
--log-group-name /aws/lambda/production \
--retention-in-days 365
# Kubernetes audit logging
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps"]
- group: "rbac.authorization.k8s.io"
resources: ["roles", "rolebindings"]
# Prometheus alerting rules
groups:
- name: security_alerts
rules:
- alert: UnauthorizedAccessAttempt
expr: rate(http_requests_total{status="401"}[5m]) > 10
for: 5m
annotations:
summary: "High rate of 401 errors detected"
Evidence Collection:
Requirements (Both Frameworks):
SOC 2 Focus: Proving data is encrypted ISO 27001 Focus: Cryptographic controls policy and key management procedures
Implementation:
# AWS KMS key creation and rotation
aws kms create-key \
--description "Production data encryption key" \
--key-policy file://key-policy.json
aws kms enable-key-rotation --key-id <key-id>
# RDS encryption at rest
aws rds create-db-instance \
--db-instance-identifier prod-db \
--storage-encrypted \
--kms-key-id <kms-key-id>
# Enforce TLS in nginx
server {
listen 443 ssl http2;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
}
Evidence Collection:
Requirements (Both Frameworks):
SOC 2 Focus: Network controls are in place and monitored ISO 27001 Focus: Network security policy and architecture documentation
Implementation:
# AWS Security Group - restrictive ingress
aws ec2 create-security-group \
--group-name production-app \
--description "Production application security group" \
--vpc-id vpc-xxxxx
aws ec2 authorize-security-group-ingress \
--group-id sg-xxxxx \
--protocol tcp \
--port 443 \
--source-group sg-alb-xxxxx
# Kubernetes Network Policies
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
spec:
podSelector:
matchLabels:
app: backend
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
Evidence Collection:
Requirements (Both Frameworks):
SOC 2 Focus: Vulnerabilities are identified and remediated ISO 27001 Focus: Vulnerability management process and risk treatment
Implementation:
# Container image scanning with Trivy
trivy image --severity HIGH,CRITICAL nginx:latest
# Automated patching with AWS Systems Manager
aws ssm create-patch-baseline \
--name production-baseline \
--operating-system AMAZON_LINUX_2 \
--approval-rules 'PatchRules=[{PatchFilterGroup={PatchFilters=[{Key=CLASSIFICATION,Values=[Security]}]},ApproveAfterDays=7}]'
Evidence Collection:
Requirements (Both Frameworks):
SOC 2 Focus: Backups work and are tested ISO 27001 Focus: Business continuity and disaster recovery plans
Implementation:
# AWS Backup plan
aws backup create-backup-plan --backup-plan '{
"BackupPlanName": "production-daily",
"Rules": [{
"RuleName": "daily-backup",
"TargetBackupVaultName": "production-vault",
"ScheduleExpression": "cron(0 2 * * ? *)",
"StartWindowMinutes": 60,
"CompletionWindowMinutes": 120,
"Lifecycle": {
"DeleteAfterDays": 30,
"MoveToColdStorageAfterDays": 7
}
}]
}'
# Velero for Kubernetes backup
velero schedule create daily-backup \
--schedule="0 2 * * *" \
--ttl 720h0m0s
Evidence Collection:
Requirements (Both Frameworks):
SOC 2 Focus: Changes are approved and tracked ISO 27001 Focus: Change management procedure and risk assessment
Implementation:
# GitOps with ArgoCD
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: production-app
spec:
project: production
source:
repoURL: https://github.com/company/infrastructure
targetRevision: main
path: k8s/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: false
selfHeal: false
Evidence Collection:
Requirements (Both Frameworks):
SOC 2 Focus: Incidents are detected, tracked, and resolved ISO 27001 Focus: Incident management process and continuous improvement
Implementation:
# Incident response runbook template
## Incident: [TITLE]
**Severity**: P1 / P2 / P3 / P4
**Detected**: YYYY-MM-DD HH:MM UTC
**Resolved**: YYYY-MM-DD HH:MM UTC
### Timeline
- HH:MM - Incident detected
- HH:MM - On-call paged
- HH:MM - Root cause identified
- HH:MM - Fix deployed
- HH:MM - Resolved
### Root Cause
[Technical explanation]
### Impact
- Users affected: X
- Services impacted: [list]
### Action Items
- [ ] Implement monitoring
- [ ] Update runbook
Evidence Collection:
ISO 27001 requires a formal risk assessment process:
Risk Assessment Process:
Risk Treatment Options:
Statement of Applicability (SoA): Document which of the 114 Annex A controls apply to your organization and why.
# Example SoA Entry
## A.9.2.1 User registration and de-registration
**Applicable**: Yes
**Justification**: We manage user access to production systems and must ensure proper provisioning and deprovisioning.
**Implementation**:
- Automated user provisioning via Okta
- Quarterly access reviews
- Automated deprovisioning on termination
- RBAC with least privilege
**Evidence**:
- Access review reports
- Provisioning/deprovisioning logs
- RBAC policy documentation
ISO 27001 requires regular internal audits:
Audit Schedule:
Audit Process:
ISO 27001 requires management to review the ISMS:
Review Frequency: At least annually
Review Topics:
Manual compliance is unsustainable. Automate evidence collection:
# Automated compliance evidence collector
import boto3
import json
from datetime import datetime
def collect_iam_evidence():
"""Collect IAM access review evidence"""
iam = boto3.client('iam')
users = iam.list_users()['Users']
evidence = []
for user in users:
mfa_devices = iam.list_mfa_devices(UserName=user['UserName'])
evidence.append({
'UserName': user['UserName'],
'MFAEnabled': len(mfa_devices['MFADevices']) > 0,
'CreatedDate': user['CreateDate'].isoformat()
})
return evidence
def collect_encryption_evidence():
"""Collect encryption configuration evidence"""
s3 = boto3.client('s3')
evidence = {'s3_buckets': []}
buckets = s3.list_buckets()['Buckets']
for bucket in buckets:
try:
encryption = s3.get_bucket_encryption(Bucket=bucket['Name'])
evidence['s3_buckets'].append({
'Bucket': bucket['Name'],
'Encrypted': True
})
except:
evidence['s3_buckets'].append({
'Bucket': bucket['Name'],
'Encrypted': False
})
return evidence
def generate_compliance_report():
"""Generate monthly compliance report"""
report = {
'report_date': datetime.now().isoformat(),
'iam_evidence': collect_iam_evidence(),
'encryption_evidence': collect_encryption_evidence()
}
# Save to S3 for auditor access
s3 = boto3.client('s3')
s3.put_object(
Bucket='compliance-evidence',
Key=f'reports/{datetime.now().strftime("%Y-%m")}/report.json',
Body=json.dumps(report, indent=2)
)
return report
Use IaC to enforce compliance controls:
# Terraform module for compliant S3 bucket
module "compliant_s3_bucket" {
source = "./modules/s3-compliant"
bucket_name = "production-data"
# Encryption required (SOC 2 + ISO 27001)
enable_encryption = true
kms_key_id = aws_kms_key.production.id
# Versioning required (SOC 2 + ISO 27001)
enable_versioning = true
# Logging required (SOC 2 + ISO 27001)
enable_logging = true
log_bucket = "audit-logs"
# Block public access (SOC 2 + ISO 27001)
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
tags = {
Compliance = "SOC2-ISO27001"
Environment = "Production"
}
}
Pre-Audit (2-3 months):
Audit (2-4 weeks):
Post-Audit:
Pre-Certification (6-12 months):
Stage 1 Audit (1-2 days):
Stage 2 Audit (3-5 days):
Post-Certification:
Finding: Insufficient access reviews Fix: Automate quarterly reviews with evidence collection Applies to: Both SOC 2 and ISO 27001
Finding: Incomplete logging Fix: Centralize all logs with proper retention Applies to: Both SOC 2 and ISO 27001
Finding: Missing MFA on production accounts Fix: Enforce MFA via IAM policies Applies to: Both SOC 2 and ISO 27001
Finding: No risk assessment (ISO 27001 specific) Fix: Conduct formal risk assessment with documented methodology
Finding: Missing internal audits (ISO 27001 specific) Fix: Schedule and conduct internal audits quarterly
Finding: No management review (ISO 27001 specific) Fix: Hold annual management review meetings with documentation
If pursuing both, optimize your approach:
Phase 1: Foundation (Months 1-3)
Phase 2: SOC 2 Prep (Months 4-6)
Phase 3: ISO 27001 Prep (Months 7-12)
Phase 4: Audits (Months 13-15)
Phase 5: Maintenance (Ongoing)
1. Start with Overlapping Controls Implement controls that satisfy both frameworks first. You’ll get 60-70% coverage for both.
2. Automate Everything Manual compliance doesn’t scale. Invest in automation and IaC from day one.
3. Use Compliance Platforms Tools like Vanta and Drata support both SOC 2 and ISO 27001, saving hundreds of hours.
4. Document as You Go Don’t wait until audit prep. Document procedures when you create them.
5. Get Executive Buy-In Both frameworks require significant investment. Make sure leadership understands cost and timeline.
6. Treat It as Security Improvement These frameworks force you to implement controls that prevent outages and breaches.