compliance governance

Executing the NIST RMF to an Authorization to Operate (ATO)

Drive a federal system through the NIST Risk Management Framework (SP 800-37 Rev 2) to an Authorization to Operate (ATO): Prepare, Categorize (FIPS 199), Select a control baseline (FIPS 200 / SP 800-53 Rev 5), Implement, Assess (SP 800-53A), Authorize, and Monitor continuously. Use when a system needs an ATO or a renewal, when working a FISMA/FedRAMP authorization package, when building or reviewing an SSP, SAR, or POA&M, when categorizing a system as Low/Moderate/High impact, when selecting or tailoring a control baseline, or when standing up continuous monitoring (ConMon) after authorization. Covers ATO, conditional ATO (cATO), and the artifacts assessors expect. Keywords: NIST RMF, 800-37, ATO, authorization to operate, FISMA, FedRAMP, SSP, SAR, POA&M, FIPS 199, FIPS 200, 800-53, 800-53A, control baseline, security categorization, continuous monitoring, authorizing official, system boundary, ongoing authorization.

atocontinuous-monitoringfedrampfips-199fismagovernancenist-800-37nist-800-53
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

  • When a federal or federally-aligned system (or a FedRAMP cloud service) needs an Authorization to Operate, a re-authorization, or has fallen out of authorization.
  • When you must produce or review the core authorization artifacts: System Security Plan (SSP), Security Assessment Report (SAR), and Plan of Action & Milestones (POA&M).
  • When categorizing a system's impact level (Low / Moderate / High) under FIPS 199.
  • When selecting, tailoring, or implementing a NIST SP 800-53 Rev 5 control baseline.
  • When standing up continuous monitoring (ConMon) or pursuing ongoing authorization / cATO after an initial ATO.

Prerequisites

  • A defined system and authorization boundary (what's in, what's inherited, what's a leveraged service).
  • An identified Authorizing Official (AO), System Owner, and ISSO.
  • The information types the system handles (use SP 800-60 to map them to impact levels).
  • For cloud: the provider's Customer Responsibility Matrix (CRM) and any inherited/leveraged ATO.
  • Access to assessment evidence sources (config, scans, policies) for the Assess step.

Workflow

NIST SP 800-37 Rev 2 defines seven steps. Prepare is the foundation; the rest run in order and then loop through Monitor.

0/1. Prepare (organization and system level)

Establish context: roles (AO, SO, ISSO, assessor), risk-management strategy and tolerance (ties to SP 800-39), a control baseline strategy, common controls available for inheritance, and the system's mission/business context. Define the authorization boundary precisely — scope creep here inflates the whole package.

2. Categorize (FIPS 199 + SP 800-60)

Determine the impact level for confidentiality, integrity, and availability for each information type, then take the high-water mark across the three to set the overall system categorization: Low, Moderate, or High. Document in the SSP. This single decision drives the entire control baseline.

3. Select (FIPS 200 + SP 800-53 Rev 5 + SP 800-53B)

Start from the SP 800-53B baseline matching the categorization (Low/Moderate/High). Then tailor: apply scoping guidance, select compensating controls where needed, and assign values to organization-defined parameters. Add overlays (e.g., privacy, FedRAMP). Record the tailored set and the rationale in the SSP. Identify which controls are common (inherited), system-specific, or hybrid.

4. Implement

Deploy the selected controls and document how each is implemented in the SSP — the implementation statement, not just "yes." This is the artifact assessors read first; vague statements generate findings.

5. Assess (SP 800-53A Rev 5)

An independent assessor evaluates controls using the examine / interview / test methods against assessment objectives. Findings of "other than satisfied" become weaknesses. Output is the Security Assessment Report (SAR). Remediate what you can before authorization; the rest flows to the POA&M.

6. Authorize

Assemble the authorization package: SSP + SAR + POA&M (plus supporting artifacts). The AO reviews residual risk and renders a decision:

  • ATO — authorized, typically with a defined term and a ConMon expectation.
  • Conditional / cATO — authorized subject to conditions or operating under an approved ongoing-authorization model.
  • Denial / DATO — risk too high; system may not operate.

The decision and its rationale are captured in the authorization decision document.

7. Monitor (continuous monitoring)

Authorization is not a one-time gate. Maintain an ongoing posture: track control effectiveness, ingest scan/config drift, update the SSP on change, work the POA&M to closure, report per the ConMon plan, and feed significant changes back into reassessment. Mature programs move from periodic re-ATO to ongoing authorization.

Key Concepts

Concept Definition
Authorization boundary The set of components, data flows, and inherited services covered by the authorization.
FIPS 199 categorization Low/Moderate/High per C/I/A; overall = high-water mark across the three.
Control baseline The SP 800-53B starting control set for the categorization, before tailoring.
Tailoring Adjusting the baseline via scoping, compensating controls, and parameter values.
Common / inherited control A control provided by another entity (e.g., the platform) and inherited by the system.
SSP System Security Plan — describes the system, boundary, and how each control is implemented.
SAR Security Assessment Report — the assessor's findings on control effectiveness.
POA&M Plan of Action & Milestones — tracked weaknesses with owners and remediation dates.
ATO / cATO / DATO Authorize / conditional (ongoing) / denial of authorization to operate.
Authorizing Official (AO) The senior official who accepts residual risk and signs the authorization.
ConMon Continuous monitoring — ongoing control-effectiveness and risk tracking post-ATO.

Tools & Systems

  • NIST SP 800-37 Rev 2 — the RMF process (7 steps).
  • FIPS 199 / FIPS 200 / SP 800-60 — categorization and minimum requirements.
  • NIST SP 800-53 Rev 5 / 800-53B — control catalog and baselines.
  • NIST SP 800-53A Rev 5 — assessment procedures (examine/interview/test).
  • OSCAL — machine-readable SSP/SAR/POA&M (NIST's authorization-document format).
  • eMASS (DoD) / FedRAMP templates — package management and submission.
  • GRC platforms — Xacta, ServiceNow, RegScale, etc., to manage the package and ConMon.
  • NIST CSF 2.0 — cross-walks to communicate RMF posture in framework terms.

Common Scenarios

  • New system pre-launch. Run Categorize → Authorize before go-live; ATO is the gate to production.
  • Cloud service (FedRAMP). Inherit the platform's controls, document the CRM split, and authorize the customer-responsible delta.
  • Re-authorization. Triggered by term expiry or significant change; refresh SSP/SAR/POA&M and re-decide.
  • cATO / ongoing authorization. Replace periodic re-ATO with continuous evidence and an approved ConMon model.
  • POA&M review. Triage open weaknesses by risk, assign owners and dates, and report closure trend to the AO.

Output Format

Produce an Authorization Package summary using assets/template.md, containing:

  1. System & boundary — description, components, data flows, inherited services.
  2. Categorization — FIPS 199 C/I/A and overall impact, with information-type rationale.
  3. Control baseline & tailoring — baseline selected, tailoring decisions, common vs system-specific.
  4. Implementation status — per-family implementation summary (from the SSP).
  5. Assessment results (SAR) — findings by severity; what's satisfied vs other-than-satisfied.
  6. POA&M — open weaknesses, risk, owner, milestone dates.
  7. Authorization decision — ATO/cATO/DATO, term, conditions, residual-risk statement, AO.
  8. ConMon plan — what's monitored, how often, reporting cadence, reassessment triggers.

Use scripts/process.py to select the right SP 800-53B baseline from a FIPS 199 categorization, summarize control-implementation status, and generate a POA&M table from a findings JSON.

Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 1

standards.md4.6 KB

NIST RMF / ATO — Standards & Reference

Primary standard

NIST SP 800-37 Revision 2 — Risk Management Framework for Information Systems and Organizations

The seven RMF steps

# Step Core question Key inputs
1 Prepare Are roles, strategy, and boundary set? SP 800-39 risk strategy, common controls
2 Categorize How bad is a loss of C/I/A? FIPS 199, SP 800-60
3 Select Which controls apply? FIPS 200, SP 800-53B baselines, SP 800-53 Rev 5
4 Implement How is each control built? SSP implementation statements
5 Assess Do the controls work? SP 800-53A Rev 5; produces the SAR
6 Authorize Is residual risk acceptable? Package (SSP+SAR+POA&M); AO decision
7 Monitor Is it still effective? ConMon plan, scans, change management

Companion standards

Document Role
FIPS 199 Security categorization — Low/Moderate/High per confidentiality, integrity, availability.
FIPS 200 Minimum security requirements for federal information and systems.
NIST SP 800-60 Vol 1 & 2 Maps information types to impact levels (input to FIPS 199).
NIST SP 800-53 Rev 5 Control catalog — 20 control families.
NIST SP 800-53B Control baselines (Low / Moderate / High) and the privacy baseline.
NIST SP 800-53A Rev 5 Assessment procedures (examine / interview / test).
NIST SP 800-39 Organization-wide risk management context (three tiers).
NIST SP 800-137 Information Security Continuous Monitoring (ISCM) — the Monitor step.
OSCAL Open Security Controls Assessment Language — machine-readable SSP/SAP/SAR/POA&M.

FIPS 199 categorization

For each information type, rate the impact of a loss of:

  • Confidentiality — unauthorized disclosure
  • Integrity — unauthorized modification/destruction
  • Availability — disruption of access/use

Each at Low / Moderate / High. The overall system impact level = the high-water mark (highest single value) across all information types and all three objectives. That overall level selects the SP 800-53B baseline.

SP 800-53 Rev 5 control families (20)

AC (Access Control), AT (Awareness & Training), AU (Audit & Accountability), CA (Assessment, Authorization & Monitoring), CM (Configuration Management), CP (Contingency Planning), IA (Identification & Authentication), IR (Incident Response), MA (Maintenance), MP (Media Protection), PE (Physical & Environmental Protection), PL (Planning), PM (Program Management), PS (Personnel Security), PT (PII Processing & Transparency), RA (Risk Assessment), SA (System & Services Acquisition), SC (System & Communications Protection), SI (System & Information Integrity), SR (Supply Chain Risk Management).

Control allocation

  • Common (inherited) — provided by another provider/platform; the system inherits the implementation and the evidence.
  • System-specific — implemented and owned by this system.
  • Hybrid — partly inherited, partly system-specific (responsibility split documented, e.g., in a FedRAMP CRM).

Core authorization artifacts

Artifact Produced in step Contents
SSP — System Security Plan Select/Implement System description, boundary, categorization, control implementation statements.
SAR — Security Assessment Report Assess Assessor findings: satisfied / other-than-satisfied, with evidence.
POA&M — Plan of Action & Milestones Assess → Authorize Open weaknesses, risk, remediation owner, milestone dates.
Authorization Decision Document Authorize ATO/cATO/DATO, term, conditions, residual-risk acceptance, AO signature.
ConMon Plan Monitor What's monitored, frequency, reporting cadence, reassessment triggers.

Authorization outcomes

  • ATO — Authorization to Operate (often time-bound, e.g., up to 3 years, with ConMon).
  • cATO — Conditional / ongoing authorization under an approved continuous model (increasingly preferred in DoD).
  • DATO — Denial of Authorization to Operate.

NIST CSF 2.0 alignment

CSF 2.0 ID Relevance
GV.OC-03 Legal/regulatory requirements (FISMA) understood and managed.
GV.RM-01 Risk-management objectives established and agreed.
ID.AM-08 Systems managed across the lifecycle (authorization boundary).
ID.RA-05 Risk used to inform prioritization and the authorization decision.
PR.IR-01 Protective technology / controls implemented per the baseline.

Scripts 1

process.py7.7 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
NIST RMF helper: FIPS 199 categorization -> SP 800-53B baseline selection,
control-implementation status summary, and POA&M generation from findings.

Input JSON shape:
{
  "system": {"name": "Customer Portal", "ao": "Jane Roe"},
  "information_types": [
    {"name": "PII", "confidentiality": "Moderate", "integrity": "Moderate", "availability": "Low"},
    {"name": "Authentication data", "confidentiality": "High", "integrity": "High", "availability": "Moderate"}
  ],
  "implementation": {                 # OPTIONAL: per-family implemented/total counts
    "AC": {"implemented": 20, "total": 25},
    "AU": {"implemented": 10, "total": 16}
  },
  "findings": [                       # OPTIONAL: assessor findings -> POA&M
    {
      "id": "F-001", "control": "AC-7", "weakness": "No account lockout on portal",
      "severity": "High", "status": "Other Than Satisfied",
      "remediation": "Configure lockout after 5 failed attempts",
      "owner": "App team", "milestone": "2026-07-15"
    }
  ]
}

Categorization rule (FIPS 199): overall impact = high-water mark across all
information types and all three objectives (C, I, A).

Usage:
  python process.py --input system.json [--output package.md]
  python process.py --input system.json --fail-open-high   # exit 1 if any High finding open
"""

import argparse
import json
import sys

IMPACT = ["Low", "Moderate", "High"]
IMPACT_RANK = {v: i for i, v in enumerate(IMPACT)}
SEVERITY_RANK = {"Low": 0, "Moderate": 1, "Medium": 1, "High": 2, "Critical": 3}

# Indicative SP 800-53B baseline control counts by impact level.
# (Approximate; the authoritative counts live in SP 800-53B. Used here to
#  communicate relative baseline size, not as a substitute for the catalog.)
BASELINE_SIZE = {"Low": "~150 controls", "Moderate": "~260 controls", "High": "~340 controls"}


def categorize(info_types):
    """Return (overall, per_objective_high) using the FIPS 199 high-water mark."""
    highs = {"confidentiality": "Low", "integrity": "Low", "availability": "Low"}
    for it in info_types:
        for obj in highs:
            val = it.get(obj, "Low")
            if val not in IMPACT_RANK:
                raise ValueError(f"information type '{it.get('name','?')}' has invalid {obj} '{val}'")
            if IMPACT_RANK[val] > IMPACT_RANK[highs[obj]]:
                highs[obj] = val
    overall = max(highs.values(), key=lambda v: IMPACT_RANK[v])
    return overall, highs


def render(data):
    sysmeta = data.get("system", {})
    info_types = data.get("information_types", [])
    if not info_types:
        raise ValueError("information_types is required to categorize the system")

    overall, highs = categorize(info_types)

    lines = []
    lines.append(f"# Authorization Package Summary - {sysmeta.get('name','System')}")
    lines.append("")
    if sysmeta.get("ao"):
        lines.append(f"- **Authorizing Official:** {sysmeta['ao']}")
    lines.append("")

    # categorization
    lines.append("## FIPS 199 Categorization")
    lines.append("")
    lines.append("| Objective | High-water mark |")
    lines.append("|---|---|")
    lines.append(f"| Confidentiality | {highs['confidentiality']} |")
    lines.append(f"| Integrity | {highs['integrity']} |")
    lines.append(f"| Availability | {highs['availability']} |")
    lines.append(f"| **Overall system impact** | **{overall}** |")
    lines.append("")
    lines.append(f"**Selected SP 800-53B baseline:** {overall} ({BASELINE_SIZE[overall]}). "
                 "Tailor from this baseline; document scoping, compensating controls, and "
                 "organization-defined parameter values in the SSP.")
    lines.append("")

    lines.append("### Information types")
    lines.append("")
    lines.append("| Information type | C | I | A |")
    lines.append("|---|---|---|---|")
    for it in info_types:
        lines.append(f"| {it.get('name','-')} | {it.get('confidentiality','-')} "
                     f"| {it.get('integrity','-')} | {it.get('availability','-')} |")
    lines.append("")

    # implementation status
    impl = data.get("implementation")
    if impl:
        lines.append("## Control Implementation Status (by family)")
        lines.append("")
        lines.append("| Family | Implemented | Total | % |")
        lines.append("|---|---|---|---|")
        tot_i = tot_t = 0
        for fam, c in sorted(impl.items()):
            i, t = c.get("implemented", 0), c.get("total", 0)
            tot_i += i
            tot_t += t
            pct = f"{(100*i/t):.0f}%" if t else "-"
            lines.append(f"| {fam} | {i} | {t} | {pct} |")
        overall_pct = f"{(100*tot_i/tot_t):.0f}%" if tot_t else "-"
        lines.append(f"| **Total** | **{tot_i}** | **{tot_t}** | **{overall_pct}** |")
        lines.append("")

    # POA&M
    findings = data.get("findings", [])
    open_high = []
    if findings:
        findings_sorted = sorted(
            findings,
            key=lambda f: SEVERITY_RANK.get(f.get("severity", "Low"), 0),
            reverse=True,
        )
        lines.append("## Plan of Action & Milestones (POA&M)")
        lines.append("")
        lines.append("| ID | Control | Weakness | Severity | Status | Remediation | Owner | Milestone |")
        lines.append("|---|---|---|---|---|---|---|---|")
        for f in findings_sorted:
            sev = f.get("severity", "-")
            status = f.get("status", "-")
            is_open = status.strip().lower() != "satisfied"
            is_high = SEVERITY_RANK.get(sev, 0) >= SEVERITY_RANK["High"]
            if is_open and is_high:
                open_high.append(f)
            lines.append("| {id} | {ctl} | {wk} | {sev} | {st} | {rem} | {own} | {ms} |".format(
                id=f.get("id", "-"), ctl=f.get("control", "-"), wk=f.get("weakness", "-"),
                sev=sev, st=status, rem=f.get("remediation", "-"),
                own=f.get("owner", "-"), ms=f.get("milestone", "-"),
            ))
        lines.append("")
        lines.append(f"_Open High/Critical findings: {len(open_high)}_")
        lines.append("")

    # decision scaffold
    lines.append("## Authorization Decision (to be completed by the AO)")
    lines.append("")
    lines.append("- **Decision:** [ ATO | cATO | DATO ]")
    lines.append("- **Term / conditions:** ____")
    lines.append("- **Residual-risk statement:** ____")
    lines.append(f"- **Authorizing Official:** {sysmeta.get('ao','____')}")

    return "\n".join(lines), overall, open_high


def main():
    ap = argparse.ArgumentParser(description="NIST RMF baseline selector + POA&M generator")
    ap.add_argument("--input", "-i", required=True, help="Path to system JSON")
    ap.add_argument("--output", "-o", help="Write Markdown package summary to this path")
    ap.add_argument("--fail-open-high", action="store_true",
                    help="Exit non-zero if any High/Critical finding remains open")
    args = ap.parse_args()

    try:
        with open(args.input) as f:
            data = json.load(f)
    except (OSError, json.JSONDecodeError) as e:
        print(f"ERROR: could not read input JSON: {e}", file=sys.stderr)
        return 2

    try:
        md, overall, open_high = render(data)
    except ValueError as e:
        print(f"ERROR: {e}", file=sys.stderr)
        return 2

    if args.output:
        with open(args.output, "w") as f:
            f.write(md + "\n")
        print(f"Package summary written to {args.output}", file=sys.stderr)
    else:
        print(md)

    print(f"Overall categorization: {overall}. Open High/Critical findings: {len(open_high)}.",
          file=sys.stderr)

    if args.fail_open_high and open_high:
        ids = ", ".join(f.get("id", "?") for f in open_high)
        print(f"FAIL: {len(open_high)} open High/Critical finding(s): {ids}", file=sys.stderr)
        return 1
    return 0


if __name__ == "__main__":
    sys.exit(main())

Assets 1

template.mdtext/markdown · 4.2 KB
Keep exploring