- Published on
SOC 2 Compliance for Backend Engineers — What You Actually Need to Build
- Authors

- Name
- Sanjeev Sharma
- @webcoderspeed1
Introduction
SOC 2 is mandatory for enterprise SaaS. It''s not about "being secure"—it''s about proving you''re secure to auditors. That means evidence: access logs, change management records, encryption keys, incident reports.
This post covers what SOC 2 Type II actually requires, what to build, how to automate evidence collection, and what to expect during audit.
- SOC 2 Type II Requirements for Engineering
- What Auditors Actually Look At
- Automated Evidence Collection
- Encryption at Rest
- Encryption in Transit
- Access Control Review Automation
- Security Monitoring with AWS GuardDuty and CloudTrail
- Vulnerability Management Pipeline
- Incident Response Runbook
- SOC 2 Tools
- Timeline and Cost
- Checklist
- Conclusion
SOC 2 Type II Requirements for Engineering
SOC 2 has five trust principles: CC (Common Criteria), C (Confidentiality), I (Integrity), A (Availability), R (Restricted Use).
Most SaaS pursue Type II CC+C+I (Confidentiality and Integrity, not Availability).
Auditors check:
- Access Control (CC7): Who can access systems? Evidence?
- Encryption (CC6): Data encrypted at rest and in transit?
- Change Management (CC8): How do code changes get deployed? Is there approval?
- Incident Response (SI1): Did you detect and respond to breaches?
- Monitoring (SI3): Are you logging everything? Do you alert on anomalies?
- Vulnerability Management (VS1): Do you scan for vulnerabilities?
What Auditors Actually Look At
Auditors review:
- CloudTrail/audit logs for 3+ months
- Git commits and PR reviews
- Deployment records
- Security patches applied
- Access requests and approvals
- Incident response runbooks
- Password policies
- MFA enforcement
- Vulnerability scan results
They don''t care about code quality or architecture. They care about: Is this documented? Can you prove it happened?
Automated Evidence Collection
Don''t manually compile evidence. Automate it.
1. CloudTrail for AWS actions:
aws cloudtrail start-logging --trail-name my-trail
aws s3api put-bucket-versioning --bucket audit-logs --versioning-configuration Status=Enabled
2. GitHub actions for deployment records:
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm test
- run: |
echo "Deployment: $(date)" >> deployment.log
echo "Commit: $(git rev-parse HEAD)" >> deployment.log
echo "Author: $(git log -1 --pretty=%an)" >> deployment.log
aws s3 cp deployment.log s3://audit-logs/deployments/
- run: npm run deploy
3. Query logs for evidence:
// Audit log schema
interface AuditLog {
timestamp: Date;
actor: string;
action: string; // 'user_created', 'password_changed', 'api_key_rotated'
resource: string;
result: 'success' | 'failure';
ipAddress: string;
}
// Query for 90 days of access logs
const logs = await db.auditLogs.findMany({
where: {
timestamp: {
gte: new Date(Date.now() - 90 * 24 * 60 * 60 * 1000),
},
},
});
// Export for auditor
const csv = logs
.map((log) => `${log.timestamp},${log.actor},${log.action},${log.resource}`)
.join('\n');
fs.writeFileSync('audit-log-export.csv', csv);
Encryption at Rest
All persistent data must be encrypted.
RDS (PostgreSQL):
aws rds create-db-instance \
--db-instance-identifier my-db \
--engine postgres \
--storage-encrypted \
--kms-key-id arn:aws:kms:us-east-1:ACCOUNT:key/KEY_ID
S3:
aws s3api put-bucket-encryption \
--bucket my-bucket \
--server-side-encryption-configuration '{
"Rules": [
{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "arn:aws:kms:us-east-1:ACCOUNT:key/KEY_ID"
}
}
]
}'
DynamoDB:
aws dynamodb update-table \
--table-name my-table \
--sse-specification Enabled=true,SSEType=KMS,KMSMasterKeyId=KEY_ID
Enable encryption on all services. Keep KMS keys in a separate AWS account.
Encryption in Transit
All network traffic must be encrypted. TLS 1.3 minimum.
// Express with TLS 1.3
import https from 'https';
import fs from 'fs';
const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem'),
minVersion: 'TLSv1.3',
};
https.createServer(options, app).listen(443);
AWS ALB:
aws elbv2 modify-listener \
--listener-arn arn:aws:elasticloadbalancing:... \
--protocol HTTPS \
--ssl-policy ELBSecurityPolicy-TLS-1-2-2017-01 # Use TLS 1.3 policy
Test with ssl-labs.com or testssl.sh.
Access Control Review Automation
Quarterly audit: do users still need access?
// List all users with access
interface AccessRecord {
userId: string;
email: string;
role: string;
lastLogin: Date;
grantedAt: Date;
}
export async function auditAccess() {
const users = await db.users.findMany({
include: { roles: true },
});
const report = users.map((user) => ({
userId: user.id,
email: user.email,
role: user.roles.map((r) => r.name).join(','),
lastLogin: user.lastLogin,
daysInactive: Math.floor((Date.now() - user.lastLogin.getTime()) / (1000 * 60 * 60 * 24)),
}));
// Flag users inactive for 90+ days
const risky = report.filter((r) => r.daysInactive > 90);
// Send to security team for review
await sendEmail({
to: 'security@example.com',
subject: 'Access Control Review',
body: `${risky.length} users inactive for 90+ days. Review and remove access.`,
});
return report;
}
// Run quarterly
schedule.scheduleJob('0 0 1 * *', auditAccess); // First of every month
Automated reports reduce manual work.
Security Monitoring with AWS GuardDuty and CloudTrail
GuardDuty detects threats. CloudTrail records all actions.
# Enable GuardDuty
aws guardduty create-detector --enable
# Review findings
aws guardduty list-findings --detector-id DETECTOR_ID --finding-criteria '{
"Criterion": {
"severity": { "Gte": 7 }
}
}'
Set up alerts:
// Lambda function triggered by GuardDuty findings
import { SNSClient, PublishCommand } from '@aws-sdk/client-sns';
export async function handler(event: any) {
const finding = event.detail;
if (finding.severity >= 7) {
const sns = new SNSClient({});
await sns.send(
new PublishCommand({
TopicArn: 'arn:aws:sns:us-east-1:ACCOUNT:security-alerts',
Subject: `Security Alert: ${finding.type}`,
Message: JSON.stringify(finding, null, 2),
})
);
}
}
Vulnerability Management Pipeline
Scan dependencies and container images. Fail the build if critical vulnerabilities exist.
# GitHub Actions
name: Security Scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm ci
- run: npm audit --audit-level=moderate
- run: npm install -g snyk && snyk test
- run: docker build -t app:latest . && docker run --rm aquasec/trivy image app:latest
Incident Response Runbook
Document how you respond to breaches.
# Incident Response Runbook
## Detection Phase
1. GuardDuty alert triggers Lambda
2. Security team notified via Slack
3. Investigate: Is it a false positive or real threat?
## Containment Phase
1. Revoke compromised API keys
2. Force password reset for affected users
3. Block attacker IP if possible
4. Enable enhanced logging
## Eradication Phase
1. Identify root cause
2. Patch vulnerability
3. Remove attacker access
4. Verify logs confirm removal
## Recovery Phase
1. Restore from clean backup if needed
2. Update incident log
3. Monitor for re-compromise
4. Post-mortem with team
## Communication Phase
1. Notify affected users
2. Notify legal and insurance
3. Prepare public statement
4. Document everything
## Timeline
- T+0: Detection
- T+5 min: Containment
- T+2 hours: Root cause identified
- T+24 hours: Eradication complete
- T+7 days: Post-mortem
Keep this updated. Auditors will ask.
SOC 2 Tools
Vanta: Automates evidence collection. ~$500/mo.
# Vanta integrates with AWS, GitHub, Okta
# Automatically pulls CloudTrail, Git commits, access logs
Drata: Similar to Vanta. ~$400/mo.
Tugboat Logic: DIY approach. ~$200/mo + engineering time.
Manual: Spreadsheets and manual reviews. Free but painful.
For early-stage startups, use Vanta or Drata. For scale-ups with strong DevOps, invest in custom automation.
Timeline and Cost
For small team (1-5 engineers):
- Preparation: 2-3 months
- Audit: 1-2 months
- Cost:
$20k-40k (tool subscriptions + auditor fees) - Total: 4-5 months
For medium team (5-15 engineers):
- Preparation: 1-2 months
- Audit: 1 month
- Cost:
$30k-60k - Total: 3-4 months
Ongoing maintenance:
- Monthly: Access control reviews
- Quarterly: Vulnerability scans, log reviews
- Annually: Re-audit (refresh audit)
Checklist
- Enable CloudTrail and S3 versioning
- Enable RDS/S3/DynamoDB encryption with KMS
- Enforce TLS 1.3 on all endpoints
- Enable GuardDuty and configure alerts
- Implement audit logging in application
- Set up automated access control reviews
- Run Snyk and Trivy in CI
- Create incident response runbook
- Choose SOC 2 tool (Vanta, Drata, or manual)
- Schedule audit 3-4 months out
Conclusion
SOC 2 Type II is not hard, but it''s tedious. The hard part isn''t building security—it''s proving you built it. Automate evidence collection with tools like Vanta or Drata. Document your processes. Keep audit logs for 90+ days. Rotate credentials and review access quarterly. When auditors come, you''ll have the receipts.