Metadata-Version: 2.5
Name: standstill
Version: 0.2.0
Summary: AWS Control Tower management CLI
Project-URL: Homepage, https://github.com/dbnz-io/standstill
Project-URL: Repository, https://github.com/dbnz-io/standstill
Project-URL: Issues, https://github.com/dbnz-io/standstill/issues
Project-URL: Changelog, https://github.com/dbnz-io/standstill/blob/main/CHANGELOG.md
License: Mozilla Public License Version 2.0
        ==================================
        
        1. Definitions
        --------------
        
        1.1. "Contributor"
            means each individual or legal entity that creates, contributes to
            the creation of, or owns Covered Software.
        
        1.2. "Contributor Version"
            means the combination of the Contributions of others (if any) used
            by a Contributor and that particular Contributor's Contribution.
        
        1.3. "Contribution"
            means Covered Software of a particular Contributor.
        
        1.4. "Covered Software"
            means Source Code Form to which the initial Contributor has attached
            the notice in Exhibit A, the Executable Form of such Source Code
            Form, and Modifications of such Source Code Form, in each case
            including portions thereof.
        
        1.5. "Incompatible With Secondary Licenses"
            means
        
            (a) that the initial Contributor has attached the notice described
                in Exhibit B to the Covered Software; or
        
            (b) that the Covered Software was made available under the terms of
                version 1.1 or earlier of the License, but not also under the
                terms of a Secondary License.
        
        1.6. "Executable Form"
            means any form of the work other than Source Code Form.
        
        1.7. "Larger Work"
            means a work that combines Covered Software with other material, in
            a separate file or files, that is not Covered Software.
        
        1.8. "License"
            means this document.
        
        1.9. "Licensable"
            means having the right to grant, to the maximum extent possible,
            whether at the time of the initial grant or subsequently, any and
            all of the rights conveyed by this License.
        
        1.10. "Modifications"
            means any of the following:
        
            (a) any file in Source Code Form that results from an addition to,
                deletion from, or modification of the contents of Covered
                Software; or
        
            (b) any new file in Source Code Form that contains any Covered
                Software.
        
        1.11. "Patent Claims" of a Contributor
            means any patent claim(s), including without limitation, method,
            process, and apparatus claims, in any patent Licensable by such
            Contributor that would be infringed, but for the grant of the
            License, by the making, using, selling, offering for sale, having
            made, import, or transfer of either its Contributions or its
            Contributor Version.
        
        1.12. "Secondary License"
            means either the GNU General Public License, Version 2.0, the GNU
            Lesser General Public License, Version 2.1, the GNU Affero General
            Public License, Version 3.0, or any later versions of those
            licenses.
        
        1.13. "Source Code Form"
            means the form of the work preferred for making modifications.
        
        1.14. "You" (or "Your")
            means an individual or a legal entity exercising rights under this
            License. For legal entities, "You" includes any entity that
            controls, is controlled by, or is under common control with You. For
            purposes of this definition, "control" means (a) the power, direct
            or indirect, to cause the direction or management of such entity,
            whether by contract or otherwise, or (b) ownership of more than
            fifty percent (50%) of the outstanding shares or beneficial
            ownership of such entity.
        
        2. License Grants and Conditions
        --------------------------------
        
        2.1. Grants
        
        Each Contributor hereby grants You a world-wide, royalty-free,
        non-exclusive license:
        
        (a) under intellectual property rights (other than patent or trademark)
            Licensable by such Contributor to use, reproduce, make available,
            modify, display, perform, distribute, and otherwise exploit its
            Contributions, either on an unmodified basis, with Modifications, or
            as part of a Larger Work; and
        
        (b) under Patent Claims of such Contributor to make, use, sell, offer
            for sale, have made, import, and otherwise transfer either its
            Contributions or its Contributor Version.
        
        2.2. Effective Date
        
        The licenses granted in Section 2.1 with respect to any Contribution
        become effective for each Contribution on the date the Contributor first
        distributes such Contribution.
        
        2.3. Limitations on Grant Scope
        
        The licenses granted in this Section 2 are the only rights granted under
        this License. No additional rights or licenses will be implied from the
        distribution or licensing of Covered Software under this License.
        Notwithstanding Section 2.1(b) above, no patent license is granted by a
        Contributor:
        
        (a) for any code that a Contributor has removed from Covered Software;
            or
        
        (b) for infringements caused by: (i) Your and any other third party's
            modifications of Covered Software, or (ii) the combination of its
            Contributions with other software (except as part of its Contributor
            Version); or
        
        (c) under Patent Claims infringed by Covered Software in the absence of
            its Contributions.
        
        This License does not grant any rights in the trademarks, service marks,
        or logos of any Contributor (except as may be necessary to comply with
        the notice requirements in Section 3.4).
        
        2.4. Subsequent Licenses
        
        No Contributor makes additional grants as a result of Your choice to
        distribute the Covered Software under a subsequent version of this
        License (see Section 10.2) or under the terms of a Secondary License (if
        permitted under the terms of Section 3.3).
        
        2.5. Representation
        
        Each Contributor represents that the Contributor believes its
        Contributions are its original creation(s) or it has sufficient rights
        to grant the rights to its Contributions conveyed by this License.
        
        2.6. Fair Use
        
        This License is not intended to limit any rights You have under
        applicable copyright doctrines of fair use, fair dealing, or other
        equivalents.
        
        2.7. Conditions
        
        Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
        in Section 2.1.
        
        3. Responsibilities
        -------------------
        
        3.1. Distribution of Source Form
        
        All distribution of Covered Software in Source Code Form, including any
        Modifications that You create or to which You contribute, must be under
        the terms of this License. You must inform recipients that the Source
        Code Form of the Covered Software is governed by the terms of this
        License, and how they can obtain a copy of this License. You may not
        attempt to alter or restrict the recipients' rights in the Source Code
        Form.
        
        3.2. Distribution of Executable Form
        
        If You distribute Covered Software in Executable Form then:
        
        (a) such Covered Software must also be made available in Source Code
            Form, as described in Section 3.1, and You must inform recipients of
            the Executable Form how they can obtain a copy of such Source Code
            Form by reasonable means in a timely manner, at a charge no more
            than the cost of distribution to the recipient; and
        
        (b) You may distribute such Executable Form under the terms of this
            License, or sublicense it under different terms, provided that the
            license for the Executable Form does not attempt to limit or alter
            the recipients' rights in the Source Code Form under this License.
        
        3.3. Distribution of a Larger Work
        
        You may create and distribute a Larger Work under terms of Your choice,
        provided that You also comply with the requirements of this License for
        the Covered Software. If the Larger Work is a combination of Covered
        Software with a work governed by one or more Secondary Licenses, and the
        Covered Software is not Incompatible With Secondary Licenses, this
        License permits You to additionally distribute such Covered Software
        under the terms of such Secondary License(s), so that the recipient of
        the Larger Work may, at their option, further distribute the Covered
        Software under the terms of either this License or such Secondary
        License(s).
        
        3.4. Notices
        
        You may not remove or alter the substance of any license notices
        (including copyright notices, patent notices, disclaimers of warranty,
        or limitations of liability) contained within the Source Code Form of
        the Covered Software, except that You may alter any license notices to
        the extent required to remedy known factual inaccuracies.
        
        3.5. Application of Additional Terms
        
        You may choose to offer, and to charge a fee for, warranty, support,
        indemnity or liability obligations to one or more recipients of Covered
        Software. However, You may do so only on Your own behalf, and not on
        behalf of any Contributor. You must make it absolutely clear that any
        such warranty, support, indemnity, or liability obligation is offered by
        You alone, and You hereby agree to indemnify every Contributor for any
        liability incurred by such Contributor as a result of warranty, support,
        indemnity or liability terms You offer. You may include additional
        disclaimers of warranty and limitations of liability specific to any
        jurisdiction.
        
        4. Inability to Comply Due to Statute or Regulation
        ---------------------------------------------------
        
        If it is impossible for You to comply with any of the terms of this
        License with respect to some or all of the Covered Software due to
        statute, judicial order, or regulation then You must: (a) comply with
        the terms of this License to the maximum extent possible; and (b)
        describe the limitations and the code they affect. Such description must
        be placed in a text file included with all distributions of the Covered
        Software under this License. Except to the extent prohibited by statute
        or regulation, such description must be sufficiently detailed for a
        recipient of ordinary skill to be able to understand it.
        
        5. Termination
        --------------
        
        5.1. The rights granted under this License will terminate automatically
        if You fail to comply with any of its terms. However, if You become
        compliant, then the rights granted under this License from a particular
        Contributor are reinstated (a) provisionally, unless and until such
        Contributor explicitly and finally terminates Your grants, and (b) on an
        ongoing basis, if such Contributor fails to notify You of the
        non-compliance by some reasonable means prior to 60 days after You have
        come back into compliance. Moreover, Your grants from a particular
        Contributor are reinstated on an ongoing basis if such Contributor
        notifies You of the non-compliance by some reasonable means, this is the
        first time You have received notice of non-compliance with this License
        from such Contributor, and You become compliant prior to 30 days after
        Your receipt of the notice.
        
        5.2. If You initiate litigation against any entity by asserting a patent
        infringement claim (excluding declaratory judgment actions,
        counter-claims, and cross-claims) alleging that a Contributor Version
        directly or indirectly infringes any patent, then the rights granted to
        You by any and all Contributors for the Covered Software under Section
        2.1 of this License shall terminate.
        
        5.3. In the event of termination under Sections 5.1 or 5.2 above, all
        end user license agreements (excluding distributors and resellers) which
        have been validly granted by You or Your distributors under this License
        prior to termination shall survive termination.
        
        ************************************************************************
        *                                                                      *
        *  6. Disclaimer of Warranty                                           *
        *  -------------------------                                           *
        *                                                                      *
        *  Covered Software is provided under this License on an "as is"       *
        *  basis, without warranty of any kind, either expressed, implied, or  *
        *  statutory, including, without limitation, warranties that the       *
        *  Covered Software is free of defects, merchantable, fit for a        *
        *  particular purpose or non-infringing. The entire risk as to the     *
        *  quality and performance of the Covered Software is with You.        *
        *  Should any Covered Software prove defective in any respect, You     *
        *  (not any Contributor) assume the cost of any necessary servicing,   *
        *  repair, or correction. This disclaimer of warranty constitutes an   *
        *  essential part of this License. No use of any Covered Software is   *
        *  authorized under this License except under this disclaimer.         *
        *                                                                      *
        ************************************************************************
        
        ************************************************************************
        *                                                                      *
        *  7. Limitation of Liability                                          *
        *  --------------------------                                          *
        *                                                                      *
        *  Under no circumstances and under no legal theory, whether tort      *
        *  (including negligence), contract, or otherwise, shall any           *
        *  Contributor, or anyone who distributes Covered Software as          *
        *  permitted above, be liable to You for any direct, indirect,         *
        *  special, incidental, or consequential damages of any character      *
        *  including, without limitation, damages for lost profits, loss of    *
        *  goodwill, work stoppage, computer failure or malfunction, or any    *
        *  and all other commercial damages or losses, even if such party      *
        *  shall have been informed of the possibility of such damages. This   *
        *  limitation of liability shall not apply to liability for death or   *
        *  personal injury resulting from such party's negligence to the       *
        *  extent applicable law prohibits such limitation. Some               *
        *  jurisdictions do not allow the exclusion or limitation of           *
        *  incidental or consequential damages, so this exclusion and          *
        *  limitation may not apply to You.                                    *
        *                                                                      *
        ************************************************************************
        
        8. Litigation
        -------------
        
        Any litigation relating to this License may be brought only in the
        courts of a jurisdiction where the defendant maintains its principal
        place of business and such litigation shall be governed by laws of that
        jurisdiction, without reference to its conflict-of-law provisions.
        Nothing in this Section shall prevent a party's ability to bring
        cross-claims or counter-claims.
        
        9. Miscellaneous
        ----------------
        
        This License represents the complete agreement concerning the subject
        matter hereof. If any provision of this License is held to be
        unenforceable, such provision shall be reformed only to the extent
        necessary to make it enforceable. Any law or regulation which provides
        that the language of a contract shall be construed against the drafter
        shall not be used to construe this License against a Contributor.
        
        10. Versions of the License
        ---------------------------
        
        10.1. New Versions
        
        Mozilla Foundation is the license steward. Except as provided in Section
        10.3, no one other than the license steward has the right to modify or
        publish new versions of this License. Each version will be given a
        distinguishing version number.
        
        10.2. Effect of New Versions
        
        You may distribute the Covered Software under the terms of the version
        of the License under which You originally received the Covered Software,
        or under the terms of any subsequent version published by the license
        steward.
        
        10.3. Modified Versions
        
        If you create software not governed by this License, and you want to
        create a new license for such software, you may create and use a
        modified version of this License if you rename the license and remove
        any references to the name of the license steward (except to note that
        such modified license differs from this License).
        
        10.4. Distributing Source Code Form that is Incompatible With Secondary
        Licenses
        
        If You choose to distribute Source Code Form that is Incompatible With
        Secondary Licenses under the terms of this version of the License, the
        notice described in Exhibit B of this License must be attached.
        
        Exhibit A - Source Code Form License Notice
        -------------------------------------------
        
          This Source Code Form is subject to the terms of the Mozilla Public
          License, v. 2.0. If a copy of the MPL was not distributed with this
          file, You can obtain one at https://mozilla.org/MPL/2.0/.
        
        If it is not possible or desirable to put the notice in a particular
        file, then You may include the notice in a location (such as a LICENSE
        file in a relevant directory) where a recipient would be likely to look
        for such a notice.
        
        You may add additional accurate notices of copyright ownership.
        
        Exhibit B - "Incompatible With Secondary Licenses" Notice
        ---------------------------------------------------------
        
          This Source Code Form is "Incompatible With Secondary Licenses", as
          defined by the Mozilla Public License, v. 2.0.
License-File: LICENSE
Keywords: aws,cli,control-tower,organizations,security
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Systems Administration
Requires-Python: >=3.11
Requires-Dist: boto3<2,>=1.34
Requires-Dist: botocore<2,>=1.34
Requires-Dist: pydantic<3,>=2
Requires-Dist: pyyaml<7,>=6
Requires-Dist: rich<15,>=13
Requires-Dist: typer<0.16,>=0.12
Provides-Extra: dev
Requires-Dist: bandit[toml]<2,>=1.7; extra == 'dev'
Requires-Dist: moto[controltower,iam,organizations,sts]<6,>=5; extra == 'dev'
Requires-Dist: mypy<2,>=1.8; extra == 'dev'
Requires-Dist: pytest-cov<7,>=5; extra == 'dev'
Requires-Dist: pytest<9,>=8; extra == 'dev'
Requires-Dist: ruff<1,>=0.4; extra == 'dev'
Requires-Dist: types-pyyaml<7,>=6; extra == 'dev'
Description-Content-Type: text/markdown

# standstill

[![CI / Release](https://github.com/dbnz-io/standstill/actions/workflows/release.yml/badge.svg)](https://github.com/dbnz-io/standstill/actions/workflows/release.yml)
[![Python](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/)
[![License: MPL 2.0](https://img.shields.io/badge/license-MPL%202.0-brightgreen)](LICENSE)
[![Coverage](docs/coverage.svg)](docs/coverage.svg)

**standstill** is a CLI designed to manage AWS security at scale.

---

## What problem it solves

AWS provides the building blocks for a strong organizational security posture: over 1,200 Control Tower controls spanning preventive, detective, and proactive behaviors, plus GuardDuty, Security Hub, Macie, Inspector, and Access Analyzer for threat detection and compliance posture. The challenge is not knowing what exists — it is deploying and managing all of it systematically across dozens or hundreds of accounts without a dedicated team.

The AWS console does not scale. Raw SDK scripts do not compose. Terraform modules exist but are not aware of the Control Tower operational model, its async behavior, or the relationship between OU baselines, control enrollment, and the pending operations journal.

standstill is built around that operational model. It treats the desired security state as something that can be declared, planned, diffed, and applied — the same way infrastructure engineers think about Terraform — but specifically for the security controls and services that AWS organizations are built on.

---

## Why standstill instead of the Control Tower console?

The console is fine for a handful of clicks. It does not scale to enrolling hundreds of controls across dozens of OUs, or configuring five security services org-wide across every account and region. standstill is a power-user operations layer on top of Control Tower — it does not replace the console, it makes the repetitive, at-scale work sane and repeatable (the same way Terraform relates to the AWS console).

| Task | standstill CLI | Control Tower console | Winner |
|------|----------------|-----------------------|--------|
| Enroll controls across many OUs / behaviors | `apply --enable-detective --ou … --dry-run` | Click each control, each OU, one at a time | **CLI, decisively** |
| Plan / diff before changing | `--dry-run` shows the plan | No preview at all | **CLI** |
| Declarative, version-controlled, reviewable state | YAML in git, `apply --file` | Clicks, no artifact | **CLI** |
| Configure 5 security services org-wide | one `security apply` (two-phase, cross-account) | Bounce between GuardDuty / Security Hub / Macie / Inspector / Access Analyzer consoles, per region | **CLI** |
| Config recorders across N accounts | `recorder setup --all` fan-out | Per-account, per-region clicks | **CLI** |
| Auditing / scripting / CI integration | `--output json` → pipe | Not possible | **CLI** |
| First-time setup / guided landing zone | Manual flags | Guided wizard, validation, visual | **Console** |
| Provisioning new accounts | Account Factory automation | Account Factory works | **Console** |
| Visual security posture, findings drill-down, compliance scores | Static tables | Rich dashboards, resource-level links | **Console** |
| Discoverability for a new user | Must know IDs / ARNs | Point-and-click | **Console** |

**The rule of thumb:** for bulk, repeatable, auditable control and security-service management at org scale, the CLI wins. For guided first-run setup and *visual* posture and findings investigation, stay in the console.

---

## Account maturity model

Mature AWS organizations separate account infrastructure into layers with distinct ownership
boundaries. standstill is designed around this model: each layer has a dedicated tool and a
dedicated team, and lower layers are treated as immutable by the layers above them.

| Layer | Name | What it contains | Managed by | Owned by |
|-------|------|-----------------|------------|----------|
| 0 | Organization & security controls | CT controls (SCPs, detective, proactive), GuardDuty, Security Hub, Macie, Inspector, Access Analyzer, Config recorders | standstill | Security / platform team |
| 1 | Account foundation | VPC, subnets, route tables, Transit Gateway attachment, DNS resolver rules, default security groups, break-glass IAM roles | standstill blueprints | DevOps / platform team |
| 2 | Application infrastructure | Compute (ECS/EKS/Lambda), databases, storage, application-specific resources | Terraform / CloudFormation / CDK | Dev / DevOps teams |

Layer 0 and Layer 1 are set once per account and treated as immutable by Layer 2. Application
teams reference foundation resources via data sources or SSM Parameter Store — they never own or
modify them. A `terraform plan` will see the VPC already exists and has no opinion about it.

CloudFormation is used for Layer 1 rather than Terraform precisely because it creates a hard
governance boundary: foundation resources do not exist in any application state file, cannot be
drifted by a `terraform apply`, and can be protected with stack termination protection and a
deny-delete SCP. GuardDuty, CloudTrail, and Config belong to Layer 0 — they are org-wide services
managed centrally by standstill, not per-account Terraform resources. Application infrastructure
has to live with both layers, which is the intended design.

Layer 1 is applied via blueprints — YAML files that describe one or more CloudFormation stacks to
deploy into a new account at creation time:

```bash
standstill blueprint apply --file blueprints/networking.yaml --account 123456789012
standstill accounts create --name "ClientA" --email a@client.com --ou ou-xxx --blueprint blueprints/networking.yaml
```

---

## The security layers standstill manages

### Preventive controls — Service Control Policies

SCPs attached to OUs that block non-compliant API calls before they happen. No IAM policy in a member account can override an SCP. Once in place, the control is ambient: it requires no agent, no scheduled evaluation, and no alerting pipeline. It simply denies the action.

### Detective controls — AWS Config rules

Managed Config rules deployed across the organization that continuously evaluate resource configuration. When a resource drifts out of compliance — a security group opens an unrestricted port, an S3 bucket loses its block-public-access setting, a root access key gets created — the rule flags it. Detective controls are the primary mechanism for catching configuration drift that happened before preventive controls were enrolled or that slipped through other gaps.

### Proactive controls — CloudFormation hooks

Hooks that intercept CloudFormation stack deployments before non-compliant resources are created. They operate at the infrastructure-as-code layer, blocking stacks that would provision resources violating the defined security policies before anything is provisioned in AWS.

### Security services — threat detection and posture

- **GuardDuty** — Analyzes CloudTrail, VPC Flow Logs, DNS logs, and runtime environments for active threats: unauthorized access, crypto mining, credential exfiltration, lateral movement. Deploys org-wide via a delegated administrator account with configurable protection plans (S3, RDS, EKS, ECS, EC2 malware scanning, Lambda network logs).
- **Security Hub** — Aggregates findings from GuardDuty, Config, Macie, and Inspector into a unified compliance posture. Standards include AWS Foundational Security Best Practices (FSBP), CIS Benchmarks (v1.4 and v3.0), PCI-DSS, and NIST 800-53. Supports cross-region aggregation.
- **Macie** — Discovers and classifies sensitive data in S3: PII, credentials, financial records. Includes automated discovery with configurable sampling depth and managed identifier sets.
- **Inspector** — Continuous vulnerability scanning for EC2 instances, container images in ECR, and Lambda functions. Surfaces CVEs, network reachability issues, and software package vulnerabilities.
- **Access Analyzer** — Identifies IAM roles, S3 buckets, KMS keys, SQS queues, and other resources with resource-based policies that grant access to external principals. Supports organization-level analyzers and unused access analysis.

---

## Core capabilities

### Declarative control management

Controls are declared in a YAML file that maps OUs to the list of controls that should be active on them. standstill diffs the desired state against what is currently enrolled in Control Tower, skips already-enabled controls, validates that target OUs have an active CT baseline, and applies only the delta.

```yaml
targets:
  - ou_id: ou-ab12-34cd5678
    controls:
      - arn:aws:controltower:us-east-1::control/AWS-GR_RESTRICT_ROOT_USER
      - arn:aws:controltower:us-east-1::control/AWS-GR_ENCRYPTED_VOLUMES
      - arn:aws:controltower:us-east-1::control/AWS-GR_CLOUDTRAIL_ENABLED

  - ou_id: ou-cd34-56ef7890
    controls:
      - arn:aws:controltower:us-east-1::control/AWS-GR_ENCRYPTED_VOLUMES
      - arn:aws:controltower:us-east-1::control/AWS-GR_S3_BUCKET_PUBLIC_READ_PROHIBITED
```

```bash
standstill apply --file controls.yaml --dry-run   # plan
standstill apply --file controls.yaml             # apply
```

The same file format works for disabling controls:

```bash
standstill disable --file controls.yaml --dry-run
standstill disable --file controls.yaml
```

### Bulk enablement and disable

For bootstrapping a new OU or landing zone, entire control tiers can be enrolled in a single command:

```bash
standstill apply --enable-detective  --ou ou-ab12-34cd5678
standstill apply --enable-preventive --ou ou-ab12-34cd5678
standstill apply --enable-proactive  --ou ou-ab12-34cd5678
standstill apply --enable-all        --ou ou-ab12-34cd5678
```

Disabling by tier works symmetrically:

```bash
standstill disable --disable-detective  --ou ou-ab12-34cd5678
standstill disable --disable-preventive --ou ou-ab12-34cd5678
standstill disable --disable-all        --ou ou-ab12-34cd5678
```

### Interactive control selection

When you want to enable or disable a subset of controls without writing a YAML file, `--category` launches an interactive picker. It prompts for a primary filter dimension (behavior, AWS service, or common control) and then an optional severity filter:

```bash
standstill apply   --category --ou ou-ab12-34cd5678
standstill disable --category --ou ou-ab12-34cd5678
```

The picker only shows behaviors and severities that exist in the loaded catalog, so every selection produces at least one control.

### Parallel apply

Control Tower operations are asynchronous. standstill submits all enable operations concurrently in a configurable thread pool, then polls all of them simultaneously. The total wall-clock time is bounded by the slowest single operation rather than the sum — which makes the difference between hours and minutes when enrolling the full catalog.

```bash
standstill apply --enable-detective --ou ou-ab12-34cd5678 --concurrency 20
```

### Pending operations journal

If AWS credentials expire during a long-running apply, standstill catches the expiry, writes all in-flight operations to a local journal (`~/.standstill/pending_operations.yaml`), and exits cleanly. The journal can be checked in a subsequent session:

```bash
standstill operations list
standstill operations check           # poll status; does not modify the journal
standstill operations check --clear   # poll status and remove completed entries
standstill operations clear           # remove all entries immediately
```

### Security services configuration

An interactive wizard generates a YAML configuration file covering all five security services with cost annotations at each step. The generated file can be version-controlled and applied idempotently:

```bash
standstill security init                                    # interactive wizard → generates YAML
standstill security apply --file security_services.yaml    # deploy org-wide
standstill security status                                  # current state
standstill security assess                                  # member account health
```

If you have security services already deployed and want to bring them under standstill management, `security pull` snapshots the live configuration into a local YAML file:

```bash
standstill security pull --account 123456789012
standstill security apply --file security_services.yaml --dry-run
```

**Regions.** GuardDuty, Security Hub, Macie, and Inspector are *regional* services — delegation and configuration apply only to the region they run in. `security apply` targets the current region (`--region`/`AWS_DEFAULT_REGION`) by default; pass `--regions` to configure several in one run. Access Analyzer's organization analyzer and delegated-admin registration are region-scoped too, so run every region you operate in:

```bash
standstill security apply -f security_services.yaml --regions us-east-1,eu-west-1,ap-southeast-2 -y
```

`security status` and `security assess` report a single region at a time; re-run them with `--region` to inspect each.

### Config recorder management

Detective controls depend on AWS Config recorders being active in every account. AWS Config is also the most common source of unexpected cost in a Control Tower deployment — the default `allSupported` mode records every resource type AWS supports, including high-volume types like CloudFormation stacks, ENIs, and SSM compliance items, that generate millions of configuration items per month without adding meaningful security coverage.

standstill sidesteps this by configuring recorders in `INCLUSION_BY_RESOURCE_TYPES` mode, recording only the specific types that Security Hub standards and the enrolled detective controls actually evaluate. The bundled list is tuned to exclude high-churn types. It can be inspected and customized before any recorder is touched:

```bash
standstill recorder types list              # show the active inclusion list
standstill recorder types add TYPE          # add a resource type
standstill recorder types remove TYPE       # remove a resource type
standstill recorder types reset             # revert to bundled Security Hub defaults
```

Once the inclusion list reflects what you need, auditing and configuring recorders across the organization is a two-step operation:

```bash
standstill recorder status --all
standstill recorder setup  --all
```

### Organization visibility

```bash
standstill view ous               # OU hierarchy as a tree
standstill view accounts          # all accounts with OU and status
standstill view controls          # enabled controls per OU with status breakdown
standstill accounts check-roles   # verify CT execution role reachability across all accounts
```

### Audit log

Every invocation is appended as one JSON line to `~/.standstill/audit.log` (override with `STANDSTILL_AUDIT_LOG`), recording the timestamp, the command and its arguments, the active profile and region, and the exit code. The log is written centrally at the CLI entry point, so it captures every mutation without per-command wiring — and writing is best-effort, so an audit failure never breaks a command.

```jsonc
{"ts": "2026-08-31T18:22:04.512Z", "args": ["scp", "detach", "-n", "DenyDeleteLogging", "-t", "ou-ab12-34cd5678"], "exit_code": 0, "profile": "org-management", "region": "us-east-1", "pid": 40122}
```

---

## Prerequisites

- An AWS organization with a Control Tower landing zone already deployed
- Credentials for the **management account** (or a role that can assume into it)
- The caller needs at least the following IAM permissions:

```
controltower:ListEnabledControls
controltower:EnableControl
controltower:DisableControl
controltower:GetControlOperation
controltower:ListControlOperations
organizations:ListRoots
organizations:ListOrganizationalUnitsForParent
organizations:ListAccountsForParent
organizations:ListAccounts
organizations:DescribeOrganization
sts:GetCallerIdentity
```

Additional permissions are required for security services commands (`guardduty:*`, `securityhub:*`, `macie2:*`, `inspector2:*`, `accessanalyzer:*`) scoped to the delegated admin account.

Run `standstill check` after installation to verify connectivity and permissions before doing anything else.

---

## Quick start

```bash
# 1. Install
git clone https://github.com/dbnz-io/standstill
cd standstill && pip install -e .

# 2. Configure your management account profile (stored in ~/.standstill/config.yaml)
standstill config set-profile my-mgmt-profile
standstill config set-delegated-admin 123456789012   # your security tooling account

# 3. Verify connectivity
standstill check

# 4. Explore your org
standstill view ous
standstill view accounts

# 5. Verify execution roles are reachable in all accounts
standstill accounts check-roles

# 6. Ensure Config recorders are running everywhere (required for detective controls)
standstill recorder status --all
standstill recorder setup  --all

# 7. Dry-run before applying anything
standstill apply --file examples/controls.yaml --dry-run

# 8. Apply
standstill apply --file examples/controls.yaml
```

---

## Installation

```bash
git clone https://github.com/dbnz-io/standstill
cd standstill
pip install -e .
```

Requires Python 3.11+.

---

## Command reference

```
standstill [--profile PROFILE] [--region REGION] [--output table|json|csv] COMMAND

  check                          Verify AWS connectivity and CT permissions

  view ous                       Render the OU hierarchy as a tree
  view accounts                  List all accounts with OU membership and status
  view controls [--ou OU]        Show enabled controls per OU

  apply --file FILE              Apply controls declared in a YAML file
  apply --enable-all      --ou   Enable every control in the catalog
  apply --enable-preventive --ou Enable all Preventive controls
  apply --enable-detective  --ou Enable all Detective controls
  apply --enable-proactive  --ou Enable all Proactive controls
  apply --category        --ou   Interactively select controls to enable
    --dry-run                    Preview changes without applying
    --yes / -y                   Skip confirmation prompt
    --concurrency N              Parallel submissions (default: 10)
    --no-wait                    Submit and return immediately

  disable --file FILE                  Disable controls declared in a YAML file
  disable --disable-all      --ou      Disable every enabled control on the OU
  disable --disable-preventive --ou    Disable all enabled Preventive controls
  disable --disable-detective  --ou    Disable all enabled Detective controls
  disable --disable-proactive  --ou    Disable all enabled Proactive controls
  disable --category           --ou    Interactively select controls to disable
    --dry-run                          Preview changes without applying
    --yes / -y                         Skip confirmation prompt
    --concurrency N                    Parallel submissions (default: 10)
    --no-wait                          Submit and return immediately

  catalog info                   Show catalog metadata
  catalog build                  Refresh catalog from the live CT API

  operations list                Show pending CT operations
  operations check [--clear]     Poll live status; --clear removes completed entries
  operations clear               Remove all entries from the journal

  security init [--output FILE]              Interactive config wizard
  security pull [--account ID]               Snapshot live config to a YAML file
  security apply --file FILE [--dry-run]     Deploy security services org-wide
    --yes / -y                               Skip confirmation prompt
  security status [--account ID | --file F]  Current state of all security services
  security assess [--account ID | --file F]  Member account health across all services

  recorder status --all | --account ID       Show recorder state
  recorder setup  --all | --account ID       Configure and start recorders
  recorder types list                        List recorded resource types
  recorder types add TYPE                    Add a resource type
  recorder types remove TYPE                 Remove a resource type
  recorder types reset                       Revert to bundled Security Hub defaults

  accounts check-roles [--role-name NAME]    Verify CT execution role in every account
  accounts list                              List all accounts with OU membership and status
  accounts describe --account ID             Show account details and parent OU
  accounts create --name N --email E --ou OU Create a new account via CT Account Factory
    --blueprint FILE                         Apply a blueprint after the account is ready
    --no-wait                                Submit and return immediately (skips blueprint)
  accounts enroll --account ID --ou OU       Enroll an existing account into Control Tower
    --blueprint FILE                         Apply a blueprint after enrollment completes
    --no-wait                                Submit and return immediately (skips blueprint)
  accounts deregister --account ID           Deregister an account from Control Tower
  accounts move --account ID --ou OU         Move an account to a different OU

  ou create --parent ID --name NAME          Create a new OU
  ou delete --ou OU                          Delete an empty OU
  ou rename --ou OU --name NAME              Rename an OU
  ou describe --ou OU                        Show OU details, child OUs, and accounts

  blueprint list                             List blueprints in ~/.standstill/blueprints/
  blueprint validate --file FILE             Validate a blueprint YAML without deploying
  blueprint apply --file FILE                Apply a blueprint to accounts
    --account ACCOUNT_ID                     Target a single account
    --ou OU_ID                               Target all active accounts in an OU
    --dry-run                                Preview stacks without deploying
    --param KEY=VALUE                        Override a parameter (repeatable)
    --role-name NAME                         IAM role to assume (default: AWSControlTowerExecution)
    --yes / -y                               Skip confirmation prompt

  lz status                      Show landing zone status, version, and drift state
  lz reset                       Remediate landing zone drift
  lz update                      Upgrade the landing zone to the latest version
  lz settings                    Show landing zone service settings
  lz settings-set                Update landing zone service settings

  config set-profile PROFILE                 Set the default AWS profile
  config unset-profile                       Remove the default AWS profile
  config set-delegated-admin ACCOUNT_ID      Set the default delegated security admin account
  config unset-delegated-admin               Remove the default delegated security admin account
  config show                                Show current CLI configuration
```

---

## Recommended hardening sequence

```bash
standstill check
standstill view ous
standstill accounts check-roles
standstill recorder status --all && standstill recorder setup --all
standstill apply --file examples/preventive_controls.yaml --dry-run
standstill apply --file examples/preventive_controls.yaml
standstill security init && standstill security apply --file security_services.yaml
standstill view controls && standstill security status
```

---

## Docker

### Building locally

```bash
docker build -t standstill .
```

### Running with AWS credentials

Pass credentials via environment variables or mount your `~/.aws` directory:

```bash
# Environment variables
docker run --rm \
  -e AWS_ACCESS_KEY_ID \
  -e AWS_SECRET_ACCESS_KEY \
  -e AWS_SESSION_TOKEN \
  -e AWS_DEFAULT_REGION=us-east-1 \
  standstill check

# Mounted credentials file
docker run --rm \
  -v "$HOME/.aws:/root/.aws:ro" \
  -e AWS_PROFILE=my-mgmt-profile \
  -e AWS_DEFAULT_REGION=us-east-1 \
  standstill check
```

---

## Development

```bash
pip install -e ".[dev]"
pytest
pytest --cov=standstill --cov-report=term-missing --cov-fail-under=80
ruff check .
```

Tests mock all AWS calls — no real AWS account required. See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.

---

## License

[Mozilla Public License 2.0](LICENSE)
