Control template: SOC 2 Type II Trust Services Criteria
Status: Stable · Version: soc2-type-ii/v1.0.0
A bundle of CALM control snippets covering the architecturally
enforceable subset of the AICPA 2017 Trust Services Criteria
(TSC) that SOC 2 Type II auditors test. You copy these into your
*.calm.json files on the nodes that are in your SOC 2 audit scope.
Who SOC 2 applies to
Any service organization that wants to demonstrate to customers (usually enterprise customers via security questionnaires or vendor- risk assessments) that it maintains effective controls over relevant trust criteria. There is no regulatory requirement for SOC 2 — it's buyer-driven. Common drivers: - SaaS companies selling to enterprise / Fortune 500 - Cloud service providers, MSPs, MSSPs - Payment processors, fintech infrastructure - Healthcare-adjacent SaaS that also pursues HITRUST - Anyone responding to "send us your SOC 2" in a procurement RFP
What this template covers
The 2017 TSC has 5 categories. Only Security (CC1–CC9 Common Criteria) is mandatory for every audit; the other four (Availability, Processing Integrity, Confidentiality, Privacy) are optional and only in scope if the firm elects to include them.
The architectural surface lives mostly in CC6 (Logical Access), CC7 (System Operations), and CC8 (Change Management). CC1–CC5 are governance and process — document those in your SOC 2 readiness package, not in your CALM.
| TSC Criterion | Architectural surface | Control alias |
|---|---|---|
| CC6.1 | Logical access security | access-control |
| CC6.3 | Role-based authorization | rbac |
| CC6.7 | Transmission security (encryption in transit) | soc2-transmission-security + edge protocol |
| CC6.8 / C1.1 (optional) | Data encryption + confidentiality designation | data-encryption |
3 controls in the mandatory Security category + 1 control in the most common optional category (Confidentiality). Skip the optional one if you haven't elected that category.
About the control key names. Most snippets above use bare control keys (access-control, rbac, etc.) rather than soc2-* prefixes. That's because ArchRails ships dedicated SOC 2 framework validators that fire on these exact keys; using the bare name lets the validator find your control. The SOC 2 regulatory tag is preserved in each snippet's config as a soc2-citation field for audit pivot. One snippet retains the soc2-* prefix — that's a documentation tag whose enforcement keys off a different mechanism (transmission-security edges).
The audit-scope pattern
A node is SOC 2-in-scope if it is part of the system boundary defined in your auditor's report. Tag those nodes:
{
"unique-id": "tenant-data-api",
"node-type": "service",
"name": "Tenant Data API",
"metadata": {
"soc2-in-scope": true,
"soc2-categories": ["security", "availability", "confidentiality"],
"data-classification": "customer-confidential"
}
}
Then attach the relevant controls below.
data-encryption.
Control snippets
Copy each block under the controls key of the node it applies to.
CC6.1 — Logical access security (access-control)
Per-node. The control key access-control is what the SOC 2 CC6.1 framework validator looks for; the soc2-citation field preserves the regulatory tag for audit pivot.
"access-control": {
"description": "SOC 2 TSC CC6.1 — logical access security software and procedures restrict access to information assets, data, software, and physical resources.",
"requirements": [
{
"requirement-url": "https://archrails.io/catalog/req/soc2/logical-access",
"config": {
"control-id": "access-control",
"soc2-citation": "CC6.1",
"access-mechanism": "saml-sso-plus-mfa",
"identity-provider": "okta",
"session-timeout-minutes": 30,
"access-review-frequency": "quarterly"
}
}
]
}
CC6.3 — RBAC (rbac)
Per-node. The control key rbac is an alias accepted by the CC6.1 access-control validator, so this snippet satisfies both CC6.1 (access control) and CC6.3 (role-based authorization) intent.
"rbac": {
"description": "SOC 2 TSC CC6.3 — entity authorizes, modifies, or removes access to data, software, functions based on roles, responsibilities, or system design.",
"requirements": [
{
"requirement-url": "https://archrails.io/catalog/req/soc2/rbac",
"config": {
"control-id": "rbac",
"soc2-citation": "CC6.3",
"principle": "least-privilege",
"allowed-roles": ["tenant-read", "tenant-write", "tenant-admin", "support-read-only"],
"review-frequency": "quarterly",
"joiner-mover-leaver-process-url": "https://internal.example.com/soc2/jml"
}
}
]
}
CC6.7 — Transmission security (soc2-transmission-security)
Relationship-level. Attach to edges that cross trust boundaries.
// On a relationship:
"controls": {
"soc2-transmission-security": {
"description": "SOC 2 TSC CC6.7 — entity restricts transmission of information to authorized internal/external users and processes; in-transit encryption required across trust boundaries.",
"requirements": [
{
"requirement-url": "https://archrails.io/catalog/req/soc2/transmission-security",
"config": {
"control-id": "soc2-transmission-security",
"soc2-citation": "CC6.7",
"minimum-tls-version": ["1.2", "1.3"],
"forbidden-fields": ["http", "ftp", "telnet", "smtp-plain", "ws"],
"mutual-auth-on-organization-boundary": true
}
}
]
}
}
soc2-transmission-security — they walk every edge in the graph and fire on (a) any edge using a plaintext protocol (http, ftp, telnet, ws, smtp, etc.) and (b) any edge pinning TLS < 1.2. So the substantive enforcement keys off the edge's protocol field, not this control snippet. The snippet records the regulatory tag against the edge for audit pivot and pins your TLS-version + forbidden-protocols intent so the constraint engine fires if an agent's declared_pattern claims to use a forbidden protocol.
CC6.8 / C1.1 — Data encryption + confidentiality (data-encryption)
Per-node (attach to data-store nodes). The control key data-encryption is what the CC6.8 + C1.1 framework validator looks for. The validator fires when a data-store node in SOC 2 scope doesn't declare this control.
"data-encryption": {
"description": "SOC 2 TSC CC6.8 + C1.1 — entity identifies and maintains confidential information; data at rest and in transit are encrypted as a measure proportionate to the classification.",
"requirements": [
{
"requirement-url": "https://archrails.io/catalog/req/soc2/confidentiality",
"config": {
"control-id": "data-encryption",
"soc2-citation": "CC6.8 + C1.1",
"data-classification-applied": "customer-confidential",
"encryption-at-rest": "AES-256-GCM",
"encryption-in-transit": "tls-1.2-or-1.3",
"access-restricted-to-roles": ["tenant-admin", "support-escalation"],
"data-retention-policy-url": "https://internal.example.com/soc2/data-retention",
"data-disposal-procedure-url": "https://internal.example.com/soc2/data-disposal"
}
}
]
}
What the engine actually enforces
SOC 2 is the only framework in ArchRails with dedicated framework validators (12 of them) on top of the generic constraint engine that handles every framework template. Enforcement is graph-driven: you attach a control where you want it enforced, and the absence of an attach is opt-out by silence. To trigger the framework validators, the graph must declare metadata.compliance-frameworks: ["soc2"]; without that, only the constraint-engine attestation layer fires.
For the 4 SOC 2 controls above, here is the honest split:
Enforced via dedicated SOC 2 framework validators
When SOC 2 is declared on the graph and a node is in scope (soc2-in-scope: true or sensitive data-classification), the validator fires if the node doesn't declare the listed control. PR-time only.
access-control/rbac— CC6.1 (per-scope-node)- Edge protocol — CC6.7 (per edge touching scope; fires on plaintext protocol OR TLS < 1.2 — keys off the edge's
protocolfield, not a control snippet) data-encryption— CC6.8 + C1.1 (per scope data-store)
Enforced via attestation only (constraint engine)
Every snippet's config block is read by the constraint engine: presence / exact / enum / set_required / set_forbidden shapes are inferred from what you authored, and the agent's declared_pattern must satisfy them. This applies to every snippet's value-level checks (TLS version, retention days, RPO/RTO, SLA uptime, forbidden protocols, required logging events) regardless of whether the control has a framework validator.
Documentation / audit metadata (no engine enforcement)
None today — every snippet on this page is covered by either a SOC 2 framework validator or the constraint engine (or both).
All checks are deterministic — pure function over your CALM JSON. Verdicts are replayable byte-for-byte. The same constraint engine handles PCI DSS, GDPR, HIPAA, MiFID II, ISO 27001:2022, NIST CSF 2, NYDFS Part 500, and any controls you author yourself.
Type I vs Type II
- Type I assesses the design of controls at a point in time — "do you have the controls defined?"
- Type II assesses the operating effectiveness of controls over a period (usually 6–12 months) — "have your controls operated as designed throughout the period?"
This template helps with both, but more so with Type I (design) because that's what an architecture declaration captures. Type II requires evidence over time (logs, exception records, test results), which is your SOC 2 readiness program's job — not architectural. Your auditor's testing of operating effectiveness is the Type II story.
Versioning
This is soc2-type-ii/v1.0.0 — the first stable cut. Each surviving control has per-validator firing tests + cross-language coverage across 11 Tier A languages (Python, Java, C#, TypeScript, Go, Kotlin, Scala, Rust, Ruby, Swift, PHP). Future bumps: v1.x.y for additive controls and substantive validator coverage; v2.0.0 for breaking changes (control retired, semantics changed). Updates as authoritative guidance or enforcement priorities materially shift.
Out of scope for this template
- Governance criteria (CC1–CC5) — control environment, communication, risk assessment, monitoring activities, control activities. These are organizational and process-based; document in your SOC 2 readiness package.
- CC6.8 (threat protection) — anti-malware, IDS endpoint controls are out of architectural scope; pair with Crowdstrike / SentinelOne / similar.
- Privacy category (P1–P8) — the Privacy category overlaps with GDPR / HIPAA / CCPA; if you've elected Privacy in scope, see the GDPR template or work with your readiness advisor.
- Type II evidence over the audit period — operating- effectiveness testing happens in your auditor's workpapers, not in CALM.
- The SOC 2 report itself — your CPA firm authors and signs the report; ArchRails does not produce or sign SOC 2 reports.
For those surfaces, pair this template with your SOC 2 readiness program and engage a CPA firm for the audit.