# Authorization Patterns for FedRAMP Compliance

A guide for using PyAuthz to meet NIST 800-53 Rev 5 authorization and audit controls in FedRAMP/ATO environments.

---

## Overview

PyAuthz is an embeddable Python authorization library that produces structured, auditable decisions for every access request. This guide maps PyAuthz's features to specific NIST 800-53 controls and shows how to configure the library for federal compliance.

**Key principle:** PyAuthz handles authorization. Authentication (CAC/PIV, MFA, SAML, OIDC) is handled by your identity provider and web server. Certificate validation, OCSP, and CRL checking remain at the infrastructure layer.

---

## NIST 800-53 Control Mapping

### AC-2 — Account Management

**Requirement:** Log account/role changes, manage privileged access.

**How PyAuthz addresses it:**

- All role mutations (`add_role()`, `remove_role()`, `replace_roles()`) emit `MutationEvent` audit records when an `AuditLogger` is attached
- Temporal role assignments have `effective_from` and `expires_at` — no permanent privilege escalation
- Delegation grants and revocations are audited with grantor, grantee, permissions, and reason
- Break-glass emergency access requires justification and is logged at WARNING level

```python
from pyauthz import PyAuthz, AuditLogger, Role
from pyauthz.audit.compliance import ComplianceExporter

rp = PyAuthz()
audit = AuditLogger(exporters=[
    ComplianceExporter(path="logs/compliance.jsonl", service_id="my-api"),
])
rp.set_audit_logger(audit)

# This mutation is now audited with NIST AC-2, CM-3 annotations
rp.add_role(Role(name="analyst", permissions=["reports:read"]))
```

### AC-3 — Access Enforcement

**Requirement:** Enforce approved authorizations at every access point.

**How PyAuthz addresses it:**

- Every `authorize()` call produces a logged `Decision` with full reasoning chain
- Deny-by-default posture — if no policy explicitly allows access, the answer is DENY
- Policy combination algorithms (deny-override, allow-override, priority-based) for complex rule sets
- Framework integrations (FastAPI, Flask, Django, Strawberry) enforce at the request boundary

### AC-5 — Separation of Duties

**Requirement:** Enforce separation through authorization controls.

**How PyAuthz addresses it:**

- Policy-based role restrictions using ABAC conditions
- Conditions can enforce that a single user cannot hold conflicting roles
- Delegation auditing tracks who granted what to whom and why

### AC-6 — Least Privilege

**Requirement:** Authorize only the minimum necessary access.

**How PyAuthz addresses it:**

- Deny-by-default engine posture
- Policy linting (`pyauthz lint`) flags overly broad permissions (L002) and orphan roles (L005)
- Explicit DENY policies with priority ordering for restricting access
- Temporal roles prevent permanent privilege accumulation

### AC-24 — Access Control Decisions

**Requirement:** Make access decisions based on security attributes.

**How PyAuthz addresses it:**

- ABAC conditions evaluate subject, resource, and environment attributes at decision time
- Conditions support operators: `==`, `!=`, `>`, `<`, `>=`, `<=`, `in`, `not_in`, `contains`, `matches`
- Cross-reference conditions (e.g., `resource.owner_id == subject.id`) resolved at evaluation time
- Environment context injection (time, IP, tenant, device posture attributes)

### AU-2 — Event Logging

**Requirement:** Log authorization-relevant events.

**How PyAuthz addresses it:**

- Every authorization decision is automatically logged via the `AuditLogger`
- Configuration mutations (role/policy/temporal/delegation changes) are logged as `MutationEvent` records
- Break-glass bypasses are logged prominently at WARNING level

### AU-3 — Content of Audit Records

**Requirement:** Audit records must include who, what, when, where, and outcome.

**How PyAuthz addresses it:**

The `AuditEvent` model captures:

| Field | NIST Mapping |
|---|---|
| `timestamp` | When |
| `subject_id`, `subject_roles` | Who |
| `action` | What (operation) |
| `resource_type`, `resource_id` | What (target) |
| `decision` | Outcome (ALLOW/DENY) |
| `matched_policies`, `reasoning` | Why |
| `duration_us` | Performance |
| `source_ip` | Where (network location) |
| `request_id` | Correlation |
| `service_id` | Which component |

### AU-9 — Protection of Audit Information

**Requirement:** Protect logs from unauthorized modification.

**How PyAuthz addresses it:**

- `HmacExporter` signs each log line with HMAC-SHA256, enabling downstream verification
- `HmacExporter.verify()` validates individual log entries against the signing key
- For production: ship logs to immutable stores (CloudWatch, Splunk, S3 with Object Lock)

```python
from pyauthz.audit.integrity import HmacExporter

exporter = HmacExporter(path="logs/signed-audit.jsonl", key=b"your-secret-key")
```

### CM-3 — Configuration Change Control

**Requirement:** Track and audit configuration changes.

**How PyAuthz addresses it:**

- Policy-as-code in Git — changes go through pull request review
- `pyauthz lint` validates policies before deployment
- `pyauthz diff` shows access impact of every change
- Policy and role mutations emit audited `MutationEvent` records

---

## ComplianceExporter Setup

The `ComplianceExporter` enriches every audit event with NIST 800-53 control IDs and event categories:

```python
from pyauthz import PyAuthz, AuditLogger
from pyauthz.audit.compliance import ComplianceExporter

exporter = ComplianceExporter(
    path="logs/compliance.jsonl",
    service_id="authorization-service",
)
audit = AuditLogger(exporters=[exporter])

rp = PyAuthz()
rp.set_audit_logger(audit)
```

Each log line includes:
- `event_category`: `"authorization"` or `"configuration_change"`
- `nist_controls`: List of applicable NIST 800-53 control IDs (e.g., `["AC-3", "AC-24", "AU-2"]`)

---

## CAC/PIV Integration Pattern

CAC/PIV authentication happens at the TLS layer. PyAuthz consumes the authenticated identity through a subject resolver:

```python
from pyauthz.contrib.x509 import subject_from_dn

# FastAPI example
async def cac_subject_resolver(request: Request) -> Subject:
    dn = request.headers["X-Client-Cert-DN"]
    roles = lookup_roles_from_directory(dn)  # your LDAP/directory lookup
    return subject_from_dn(dn, roles=roles)

setup_pyauthz(app, engine=rp, subject_resolver=cac_subject_resolver)
```

The `pyauthz.contrib.x509` module provides:
- `parse_dn()` — parse X.509 DN strings into structured fields
- `extract_dod_id()` — extract the 10-digit EDIPI from a Common Name
- `subject_from_dn()` — build a complete `Subject` from a DN string

---

## HMAC Log Integrity

For AU-9 compliance, use the `HmacExporter` to produce tamper-evident logs:

```python
from pyauthz.audit.integrity import HmacExporter
import os

key = os.environ["AUDIT_HMAC_KEY"].encode()
exporter = HmacExporter(path="logs/signed.jsonl", key=key)
```

Verify individual log entries:

```python
with open("logs/signed.jsonl") as f:
    for line in f:
        if not HmacExporter.verify(line, key):
            alert("Tampered log entry detected!")
```

---

## Policy Testing in CI

Authorization tests run alongside unit tests in CI:

```python
from pyauthz.testing import AuthScenario, must_allow, must_deny

def test_analysts_can_read_unclassified(rp):
    with AuthScenario(rp) as s:
        analyst = s.subject("jane.doe", roles=["analyst"], clearance="SECRET")
        report = s.resource("report-1", type="reports", classification="UNCLASSIFIED")
        s.assert_that(analyst, "reports:read", report, must_allow)
```

Policy changes that break access expectations fail the build before reaching production.

---

## ATO Evidence Generation

To generate evidence for an ATO package:

1. **Enable ComplianceExporter** on all services using PyAuthz
2. **Collect compliance logs** — each line is annotated with NIST control IDs
3. **Use policy linting reports** — `pyauthz lint policies/ --json` produces machine-readable results
4. **Export policy diff reports** — `pyauthz diff old/ new/` shows access impact of changes
5. **Include authorization test results** — pytest output showing policy test coverage

The compliance log format is designed for direct ingestion by SIEM tools (Splunk, ELK, etc.).
