SOC 2 Overview

SOC 2 Technical Controls

SOC 2 audits trust service criteria: Security, Availability, Processing Integrity, Confidentiality, and Privacy. Technical controls are essential for meeting these criteria.

Logging and Monitoring

Comprehensive logging is the foundation of SOC 2:

import structlog

from datetime import datetime

class SOC2Logger:

def init(self):

self.logger = structlog.get_logger()

self.required_fields = [

"timestamp", "user_id", "action", "resource",

"source_ip", "outcome", "correlation_id"

]

def log_access(self, user_id, action, resource, outcome, metadata=None):

log_entry = {

"timestamp": datetime.utcnow().isoformat(),

"user_id": user_id,

"action": action,

"resource": resource,

"source_ip": metadata.get("ip", "unknown"),

"outcome": outcome,

"correlation_id": metadata.get("correlation_id", str(uuid.uuid4())),

"user_agent": metadata.get("user_agent"),

"geo_location": metadata.get("geo"),

"auth_method": metadata.get("auth_method")

}

self.logger.info("access_log", **log_entry)

self.store_immutable(log_entry)

return log_entry

def store_immutable(self, log_entry):

"""Store logs in immutable storage for audit"""

Write to append-only log

with open("/var/log/soc2/access.log", "a") as f:

f.write(json.dumps(log_entry) + "\n")

Also send to SIEM

self.send_to_siem(log_entry)

Access Review Automation

Automate periodic access reviews:

class AccessReviewAutomation:

def init(self, identity_provider):

self.idp = identity_provider

self.reviewers = {

"engineering": "eng-manager@example.com",

"sales": "sales-director@example.com",

"finance": "cfo@example.com"

}

def generate_review(self, department):

users = self.idp.get_users_by_department(department)

review = {

"department": department,

"review_date": datetime.utcnow().isoformat(),

"reviewer": self.reviewers[department],

"users": []

}

for user in users:

review["users"].append({

"name": user["name"],

"email": user["email"],

"roles": user["roles"],

"last_login": user["last_login"],

"access_keys_count": user.get("access_keys", 0),

"days_since_last_access": (

datetime.utcnow() - user["last_login"]

).days if user["last_login"] else None

})

return review

def auto_disable_inactive(self, days_threshold=90):

cutoff = datetime.utcnow() - timedelta(days=days_threshold)

disabled = []

for user in self.idp.get_all_users():

if user.get("last_login", datetime.min) < cutoff:

self.idp.disable_user(user["email"])

disabled.append(user["email"])

return disabled

Change Management

Track and approve all infrastructure changes:

change-management-pipeline.yaml

change_management:

required_for:

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- infrastructure_changes

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- code_deployments

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- configuration_changes

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- access_policy_changes

workflow:

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- request:

fields:

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- change_description

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- risk_assessment

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- rollback_plan

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- testing_completed

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- review:

required_approvals:

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- technical_reviewer

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- security_reviewer

auto_approve:

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- risk: low

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- owner: same_team

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- implementation:

window: business_hours

blackout_periods:

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- end_of_month

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- holiday_season

require_change_window: high_risk

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- verification:

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- monitoring_metrics_normal

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- smoke_tests_passed

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- no_security_events

Change management API

class ChangeManager:

def init(self):

self.changes = []

def create_change(self, request):

change = {

"id": str(uuid.uuid4()),

"description": request["description"],

"risk": request.get("risk", "medium"),

"requester": request["requester"],

"status": "pending_review",

"created_at": datetime.utcnow().isoformat(),

"approvals": [],

"rollback_plan": request["rollback_plan"]

}

self.changes.append(change)

self.notify_reviewers(change)

return change

def approve_change(self, change_id, reviewer, decision, comments):

change = self.find_change(change_id)

change["approvals"].append({

"reviewer": reviewer,

"decision": decision,

"comments": comments,

"timestamp": datetime.utcnow().isoformat()

})

if decision == "approved":

change["status"] = "approved"

self.schedule_implementation(change)

else:

change["status"] = "rejected"

def post_implementation_review(self, change_id):

change = self.find_change(change_id)

change["status"] = "completed"

change["completed_at"] = datetime.utcnow().isoformat()

Conclusion

SOC 2 technical controls require systematic implementation across logging, access review, and change management. Implement immutable audit logging, automate access recertification, and enforce change management workflows. Continuous monitoring provides evidence for auditors and early detection of control failures. Automate evidence collection to reduce audit burden.