Automation & Code
AnalystCode / policy lab

Controls as Data

Model a control catalog in YAML/JSON and OSCAL so it can be queried, diffed and tested.

45 min 180 XPSkills: Data modeling, OSCAL

A control is a record, not a paragraph

Written as prose, a control can only be read. Written as a record, an id, a title, an owner, a frequency, a list of framework references, and the query that produces its evidence, the same control can be queried, diffed, validated and tested. Nothing about the safeguard changes; what changes is that machines can now participate.

The moment your catalog is data, questions that used to take a week become one command: which controls have no owner, which map to no framework, which claim to be automated but have no evidence query, which changed since the last audit period.

If you cannot answer "how many controls do we have" with a command, you do not have a catalog. You have a folder.

Diagram showing a prose control document converted into a YAML record with id, title, framework refs, owner, frequency, automated flag and evidence query, feeding query, diff and test operations.
The same safeguard, expressed so that tooling can act on it.

The fields that earn their place

Every field should have a consumer. `id` is the join key everything else references, so it must be stable and unique for the life of the program: never reuse it, never renumber. `framework_refs` is the crosswalk that lets one implemented control satisfy SOC 2, ISO 27001 and 800-53 at once. `owner` must resolve to a real identity, not a team alias nobody reads.

`automated` and `evidence_query` are the pair that keeps the catalog honest. A control marked automated with no query is a claim; a control with a query is a control that can produce its own evidence on demand.

OSCAL, and when you actually need it

NIST's Open Security Controls Assessment Language is the standard machine-readable format for catalogs, profiles and assessment results. It is verbose and it is worth it when you exchange control data with someone else: a regulator, a customer, a federal program, an assessor's tooling.

For an internal catalog, plain YAML with a schema you validate in CI is usually the right first move. Design your fields so an OSCAL export is a transform rather than a rewrite: keep ids stable, keep framework references explicit, and never encode meaning in free text.

Integrity checks are the whole point

Data you never validate rots faster than prose, because nobody reads it. Run three families of check on every pull request: schema validation (every record has the required fields, of the right type), uniqueness (no two records share an id), and referential integrity (every framework reference resolves to a requirement that exists, every owner resolves to a real person).

The failure mode this prevents is quiet. Two catalog branches merge, an id ends up on two records, and from that point mappings, evidence and test results attach to whichever record the tooling happens to read first. Nothing errors. The numbers are simply wrong.

A catalog that cannot fail a build cannot be trusted in an audit. Wire the checks before you grow the catalog.

Table of control records with a duplicated AC-2 id highlighted after a merge, beside a panel of integrity checks for unique id, schema validation and referential integrity, one of them failing.
Duplicate ids never announce themselves. A check has to go looking.

Catalog reality, not aspiration

The last discipline is reconciliation: periodically comparing what the catalog claims against what the systems actually show. Controls disappear from reality long before anyone edits the record: a scheduled job is disabled, a repo is archived, an owner leaves.

Treat the reconciliation itself as a control. It runs on a cadence, it produces output, and its output is evidence that the catalog you handed the auditor describes the company you actually run.

Tasks

Answers are graded on the server: the answer key never reaches your browser.

Task 1: Two controls, one id

Scenario sim+60 XP

Name the record property the merge broke, then the check family that would have refused it.

Incident brief

Two engineers split the catalog work. One rewrites the account-management control in the `iam` branch, the other rewrites it in `access`. Both merge cleanly on Friday: YAML merges rarely conflict when the edits are in different files.

On Monday the coverage report shows 61 controls instead of 60, the SOC 2 mapping for CC6.1 points at a record with no owner, and the evidence job for account management runs twice with different queries.

Both records read `id: AC-2`. Nothing errored. The pipeline is green.

Term bank, not all of these are right

unique idschema validationreferential integritycrosswalkreconciliationframework refs

1.1Name the record property the merge violated. (two words)

1.2Name the check family that would have refused the merge. (two words)

Task 2: The mapping the customer asked for

Scenario sim+60 XP

Name the catalog structure being requested, then the standard format for exchanging it.

Incident brief

A federal-adjacent customer asks for "your control catalog, machine-readable, with the 800-53 linkage". The security lead exports the internal YAML to a spreadsheet and adds a column of comma-separated NIST identifiers typed by hand.

Two weeks later the customer's assessor rejects it: the identifiers do not parse, three point at withdrawn controls, and there is no way to tell an implemented control from an inherited one.

The engineer's response: "It is machine-readable, it is a CSV."

Term bank, not all of these are right

crosswalkoscalprofilebaselineschemacsv

2.1Name the structure the customer is really asking for. (one word)

2.2Name the standard format it should be exchanged in. (one word)

Task 3: Automated, allegedly

Scenario sim+60 XP

Name the missing field, then the recurring activity that would have caught the claim.

Incident brief

The catalog reports that 38 of 60 controls are automated, and leadership quotes the number in a board deck. The auditor samples six of the 38 and asks each owner to produce this quarter's output.

Four produce it. One produces output from eight months ago. One owner says the check "is in the catalog, so it must be running somewhere": the record has `automated: true`, a title, an owner and framework refs, and nothing else.

No record in the catalog has ever been compared against the systems it describes.

Term bank, not all of these are right

evidence queryreconciliationownerfrequencyattestationsampling

3.1Name the field whose absence makes the automation claim unverifiable. (two words)

3.2Name the recurring activity that keeps catalog and reality aligned. (one word)

Labs

110 bonus XP

Hands-on work. You edit the artefact, the server runs the checks: the expectations and the reference solution never reach your browser.

Lab 1 · YAML lab

Turn a Word control into data

Briefing 40 XP

Your compliance lead sends you a control lifted from a Word policy: "Access to production is reviewed regularly by management to ensure appropriateness." She calls it "already automated" because a Jira ticket reminds someone to do it every quarter.

A reminder is not automation, and "regularly" is not a frequency. Rewrite the control as structured data a pipeline can act on: it needs a stable id, an owner, a machine-readable frequency, the system it runs against, and an assertion an evaluator can test.

Source control (as written in the policy)

title: Production access review
text: >
  Access to production is reviewed regularly by management
  to ensure appropriateness.
owner: "whoever runs the review"
evidence: "screenshot of the review meeting"

Checks

  • Has a stable, uppercase control id
  • Owner is a team, not a person or a role-in-prose
  • Frequency is a machine-readable enum value
  • Assertion states a testable condition
  • Evidence is a query, not a screenshot
  • Marked automated once it has a query and an assertion
Lab 2 · YAML lab

Map one control to three frameworks

Briefing 30 XP

An auditor asks you to "map the MFA control to SOC 2, ISO and NIST". A colleague has already started and mapped everything to CC6.1 because, in his words, "CC6.1 covers all the access stuff".

Mappings are many-to-many and framework-specific. Add a mappings block that names each framework and its own control identifier: a SOC 2 trust services criterion, an ISO 27001 Annex A control, and a NIST 800-53 control id.

Framework identifier formats

soc2:   CC6.1, CC6.6, CC7.2      (trust services criteria)
iso27001: A.5.15, A.5.17, A.8.5    (Annex A, 2022 numbering)
nist80053: AC-2, IA-2, AC-6        (control family + number)

Control under mapping: multi-factor authentication
enforced for all administrative console access.

Checks

  • Three mappings, one per framework
  • Frameworks named soc2, iso27001 and nist80053
  • SOC 2 reference is a trust services criterion
  • ISO reference uses Annex A numbering
  • NIST reference is an authentication control id
Lab 3 · Review lab

Review the control library records

Briefing 40 XP

Six control records have been merged into the library as YAML. The team lead says they are all machine-readable because they parse.

Parsing is not the bar. Accept the records a scheduler and an evaluator could actually act on; reject the ones whose fields are prose in a data costume.

Verdicts are accept or reject. Every rejection needs one reason code from: prose-assertion | unstable-id | unschedulable-frequency | evidence-not-rerunnable.

controls/*.yaml (field summary)

Y-1  id: AC-PROD-MFA | owner: platform-security | frequency: daily | assertion: "zero admin accounts without mfa" | evidence_query: okta-api /admins
Y-2  id: AC-REVIEW | owner: platform-security | frequency: quarterly | assertion: "access is reviewed appropriately by management" | evidence_query: okta-api /admins
Y-3  id: control 7 (new) | owner: risk-office | frequency: monthly | assertion: "no bucket is publicly readable" | evidence_query: aws-config query
Y-4  id: EV-RETENTION | owner: data-platform | frequency: monthly | assertion: "every evidence object is retained at least 2555 days" | evidence_query: s3-api lifecycle rules
Y-5  id: VM-PATCH | owner: platform-security | frequency: "as needed" | assertion: "zero critical findings older than 24 hours" | evidence_query: scanner-api /findings
Y-6  id: VN-REVIEW | owner: vendor-management | frequency: annually | assertion: "every tier-1 vendor has a current assessment" | evidence_query: screenshot of the vendor tracker

Checks

  • Every line in the fixture carries a verdict
  • Accept and reject land on the right lines
  • Each rejection cites a valid reason code

Next on your path · Automation & Code

Policy as Code with OPA/Rego

Write Rego policies that evaluate cloud configuration against your control catalog.

Analyst 60 min 250 XP
Start next room

Community

Discussion & writeups

Sign in to post

Share how you approached the room or ask where you got stuck. Never paste task answers or full lab solutions: write the reasoning, not the key.

Loading discussion…