Skip to main content

Intelligently optimize AWS SCP JSONs to adhere to strict size, statement, and policy count limits.

Project description

scpz

CI PyPI Python Downloads Ruff Checked with mypy License: MIT Docs

Intelligently optimize AWS Service Control Policy (SCP) JSONs to fit within AWS's strict limits.

AWS SCP Limits

Constraint Limit
Policy size 10,240 bytes
Statements per SCP 5
SCPs per target (account/OU) 10

Requirements

Python 3.13 or later.

Installation

pip install scpz

Or with uv (recommended):

uv tool install scpz

Container images

Images are built from this repository’s Dockerfile (compatible with Docker and Podman) and published when a GitHub Release is published.

Tagging (both registries): each release tag (for example v0.3.0) is always published; latest is updated only for stable releases (not GitHub pre-releases).

  • ghcr.io/tsjnsn/scpz:<release-tag> and ghcr.io/tsjnsn/scpz:latest (GHCR)
  • tsjnsn/scpz:<release-tag> and tsjnsn/scpz:latest (Docker Hub)

GitHub Container Registry

Published to GitHub Container Registry as ghcr.io/tsjnsn/scpz.

Example (optimize a policy file in the current directory):

docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/work" ghcr.io/tsjnsn/scpz:latest optimize policy.json

With Podman:

podman run --rm --user "$(id -u):$(id -g)" -v "$PWD:/work:z" ghcr.io/tsjnsn/scpz:latest optimize policy.json

Docker Hub

Published to Docker Hub as tsjnsn/scpz.

# Pin to a release (recommended in production)
docker pull tsjnsn/scpz:v0.3.0

docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/work" tsjnsn/scpz:v0.3.0 optimize policy.json --dry-run

Build locally

docker build -t scpz:local .
docker run --rm scpz:local --version

Maintainer credentials

The Publish release workflow pushes to GHCR (via GITHUB_TOKEN) and Docker Hub (via repository secrets). Container jobs run only after PyPI publish succeeds so a failed package release does not leave tagged images for an incomplete release. If DOCKERHUB_USERNAME / DOCKERHUB_TOKEN are unset, the Docker Hub job skips with a workflow notice instead of failing the release.

Secret Purpose
DOCKERHUB_USERNAME Docker Hub account with push access to tsjnsn/scpz (must be tsjnsn today; the workflow image name is fixed, not derived from this secret)
DOCKERHUB_TOKEN Docker Hub access token with Read & Write scope for that account

Ensure the Docker Hub repository tsjnsn/scpz exists before the first push.

Usage

Optimize

# Optimize a single file in-place (original saved as policy.json.bak)
scpz optimize policy.json

# Optimize all JSON files in a directory
scpz optimize policies/

# Dry run — show diff + summary without writing
scpz optimize policy.json --dry-run

# Summary only — just show what would change
scpz optimize policy.json --summary-only

# Write to a different file
scpz optimize policy.json --output optimized.json

# Error instead of auto-splitting
scpz optimize policy.json --no-split

Validate

# Validate a single file
scpz validate policy.json

# Validate all JSON files in a directory
scpz validate policies/

Check equivalence

# Ensure optimized output did not broaden permissions (catalog model)
scpz check-equivalence policy.json policy.optimized.json

Optimization Passes

scpz runs the following optimizations in order, repeating until the output stops changing (up to 5 rounds):

  1. Statement merging — Combines statements that share the same Effect, Condition, and Resource into a single statement with a unioned Action list.
  2. Action wildcard compression — Replaces groups of actions sharing a common prefix with wildcard patterns (e.g. s3:GetObject + s3:GetBucketPolicys3:Get*). Uses the bundled AWS action catalog in conservative mode to avoid scope broadening.
  3. Condition merging — Deduplicates condition values and merges equivalent condition blocks.
  4. Resource ARN optimization — Collapses multiple specific ARNs into wildcard patterns (e.g. role/Admin + role/ReadOnlyrole/*).
  5. Redundancy elimination (opt-in) — Removes statements wholly subsumed by another statement in the same policy (Action via wildcards; NotAction only when a non-empty action catalog is configured, mirroring catalog safety for NotAction compression). Enable with redundancyEliminate.enabled: true in scpz.yaml.

When a policy still exceeds limits after optimization, scpz automatically splits it into multiple SCP documents (up to 10 per target).

Configuration

Place a scpz.yaml in your project root (scpz walks up from the input file to find it). See examples/scpz.yaml for a fully-annotated reference.

apiVersion: scpz.io/v1alpha1
kind: OptimizerConfig
metadata:
  name: default
spec:
  optimizer:
    actionCompress:
      mode: conservative  # conservative | aggressive
    redundancyEliminate:
      enabled: true       # opt-in
# Print the JSON Schema for editor validation
scpz print-schema

Development

# Install with dev dependencies
uv sync --dev

# Run tests
uv run pytest

# Run tests with coverage
uv run pytest --cov=scpz

# Run a specific test file
uv run pytest tests/test_actions.py -v

# Regenerate the committed schema after model changes
uv run scpz print-schema -o schema/OptimizerConfig.json

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

scpz-0.3.1.tar.gz (245.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

scpz-0.3.1-py3-none-any.whl (150.7 kB view details)

Uploaded Python 3

File details

Details for the file scpz-0.3.1.tar.gz.

File metadata

  • Download URL: scpz-0.3.1.tar.gz
  • Upload date:
  • Size: 245.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for scpz-0.3.1.tar.gz
Algorithm Hash digest
SHA256 76eb25cbd7db4850c81e4af3381e39d4e291094ee1c8c0fe46299b08b08ffe52
MD5 9f2d140adb414125bbf0fec710622110
BLAKE2b-256 dbdc66b5ea20ee073e413333abb77987b538630381e0de8d78e59f6657190e87

See more details on using hashes here.

Provenance

The following attestation bundles were made for scpz-0.3.1.tar.gz:

Publisher: publish.yml on tsjnsn/scpz

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file scpz-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: scpz-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 150.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for scpz-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b506b0539212bd45183228462024c49f3843c3d169b333ceca71c160d4cfcfe7
MD5 8eccb5a0a1734d0440e687f6d1790692
BLAKE2b-256 048853bdd589614767c888cc16eb53c30f34b72a37cb9de5ea1dfc939404d233

See more details on using hashes here.

Provenance

The following attestation bundles were made for scpz-0.3.1-py3-none-any.whl:

Publisher: publish.yml on tsjnsn/scpz

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page