AI SIEM Helper Scripts 26h4 2026-10-06
============================================

CONNECTING DATA SOURCES (START HERE)
------------------------------------
AI SIEM takes data three different ways. Knowing which applies tells you whether
there is anything to wire.

  1. S3 LOG BUCKETS  -  CloudTrail, VPC Flow Logs
     Delivered as files to an S3 bucket. AI SIEM does not poll; the bucket must
     send s3:ObjectCreated notifications to the ingestion queue.
       - CloudTrail: enter the bucket in the editor (Configure -> Data Sources).
         The editor wires the notification for you when it can. If it reports it
         could not (usually a cross-account bucket), use wire-log-bucket (below).
       - VPC Flow Logs: the stack already owns the flow-log bucket (policy,
         notification, Glue table). run create-flowlogs to turn on flow logs for
         a WORKLOAD VPC you name, delivered to that stack bucket.

  2. AWS-NATIVE EVENTS  -  GuardDuty, Security Hub, AWS Config
     Arrive over EventBridge via rules the stack already created. In the SIEM's
     OWN account nothing is wired. They only produce data when the underlying
     AWS service is enabled and something happens, so zero events on a quiet
     account is normal.
       - CROSS-ACCOUNT: EventBridge findings do NOT cross accounts on their own.
         To bring another account's GuardDuty/Security Hub/Config findings in,
         run wire-events in that account (see CROSS-ACCOUNT EVENTBRIDGE FINDINGS
         below). The central stack must also have been deployed with
         OrganizationId or CrossAccountIds so its event bus accepts them.

  3. PLATFORM CORRELATION  -  AI Monitor, Log Processor
     AI Monitor writes metric anomalies into the shared OpenSearch domain; AI
     SIEM reads them and correlates. Log Processor pattern detections reach the
     SIEM the same way, through AI Monitor. There is NO bucket and NO script for
     this: in the editor (Configure -> Data Sources -> AI Monitor Correlation)
     pick which subscriptions contribute. That is the whole setup.

Case (1) always needs a helper for cross-account, and case (2) needs one only
for cross-account EventBridge findings. Same-account (2) and all of (3) are
wiring-free.

CROSS-ACCOUNT LOG BUCKETS (READ THIS BEFORE WIRING ONE)
-------------------------------------------------------
A log bucket in ANOTHER account (a common setup: an organization CloudTrail in a
log-archive account) needs FOUR things, and getting only some of them produces a
silent failure that is easy to misread as "it works":

  1. Notification: the bucket sends s3:ObjectCreated to the ingestion queue.
  2. Queue policy: the ingestion queue allows the bucket's account to send.
       -> wire-log-bucket does BOTH of these. Run it with --bucket-profile (or
          the 4th positional arg) for the account that OWNS the bucket:
            wire-log-bucket.cmd AISIEM org-trail-logs us-east-1 logarchive

  3. Bucket policy: must allow <stack>-IngestionRole to s3:GetObject on the
     objects. The role already permits it on its side, but a cross-account read
     also needs the bucket policy to allow it.
  4. KMS key policy (only if the bucket is SSE-KMS encrypted): must allow that
     same IngestionRole to kms:Decrypt.

wire-log-bucket does 1 and 2. It does NOT do 3 and 4 - those must be applied by
the bucket's owner. WITHOUT 3 and 4, notifications still arrive and then every
object read fails: the queue drains into the DLQ and nothing is indexed, even
though the source shows as enabled. If a cross-account source looks connected
but no events appear, this is almost always why. As an alternative to 3 and 4,
replicate the bucket into one the SIEM account owns and wire that.

Same-account buckets need only step 1 (the editor or wire-log-bucket handles it);
the queue policy already covers same-account, and no bucket/KMS grant is needed.

CloudTrail on a SHARED bucket: an organization CloudTrail already delivers every
member account to one bucket under AWSLogs/<account-id>/CloudTrail/..., which
ingestion tags per record - so one wire-log-bucket call (prefix AWSLogs/) covers
the whole org. If the SAME bucket also carries flow logs, wire each source on its
own non-overlapping prefix (see PREFIXES ON A SHARED BUCKET under VPC FLOW LOGS).
The four cross-account grants above apply to the CloudTrail bucket exactly as to
any other cross-account log bucket.

CROSS-ACCOUNT EVENTBRIDGE FINDINGS (GuardDuty, Security Hub, Config)
--------------------------------------------------------------------
GuardDuty, Security Hub and Config deliver findings to EventBridge only in the
account and region where the service runs. The stack's own rules therefore see
findings from the SIEM account only. To bring in another account's findings,
forward them to the SIEM's event bus. Two sides:

  CENTRAL (SIEM) side - one-time, at deploy:
    Deploy the stack with OrganizationId (any account in the org may forward) OR
    CrossAccountIds (only the listed accounts may forward). This emits the bus
    policy that permits events:PutEvents onto the SIEM's default event bus. The
    policy is source-agnostic, so it covers all three sources at once. Setting
    NEITHER leaves the bus closed - single-account deployments need nothing.

  SOURCE side - run wire-events in the source account:
      wire-events.cmd setup <central-account-id> [region] [--source LIST]
    --source is a comma list of guardduty,securityhub,config (default: all). It
    creates one forwarder role EventBridge assumes and one rule per source,
    sending findings to the central account's default bus. Nothing else on the
    SIEM changes: forwarded events keep their source and originating accountId,
    which ingestion partitions on.

    wire-events.cmd remove [region] [--source LIST]   tears rules down (and the
                                                      shared role when the last
                                                      rule is removed).
    wire-events.cmd status [region] [--source LIST]   shows current wiring.

WHERE TO RUN IT (per source - you may not need it in every account):
  GuardDuty    Run in each source account+region.
               EXCEPTION - delegated administrator: if a source account is your
               org's GuardDuty delegated admin AND the SIEM runs in it, member
               findings already aggregate there and the stack's own rule sees
               them. wire-events detects central == local and no-ops.
  Security Hub If you use Security Hub finding AGGREGATION (an aggregation region
               in an org), all member findings are re-imported into the
               aggregator account already. Run wire-events ONCE in the aggregator
               account - not in every member. If the SIEM IS the aggregator, do
               nothing. Without aggregation, run per source account.
  Config       Run in each source account+region. Forwards Config RULE
               compliance changes only, so the account must actually have Config
               rules that evaluate (Config recording with no rules emits nothing
               to forward). Full Config configuration SNAPSHOTS are a separate,
               S3-delivery dataset and are not ingested today.

MULTI-ACCOUNT SETUP
-------------------
The multi-account model uses cross-account IAM roles for read access to
CloudTrail and VPC Flow Log S3 buckets in remote accounts, plus an optional
response role for enterprise-tier auto-remediation.

Flow:
  1. Remote account: setup-remote-access.cmd setup <central-acct-id>
     Creates AISIEM-remote-read and AISIEM-remote-respond roles
  2. Central account: add-account.cmd <stack> <remote-acct-id> --trail-bucket <bucket>
     Registers the account so ingestion Lambda starts reading from it
  3. Ingestion Lambda assumes AISIEM-remote-read role to list/read S3 objects
  4. Response Lambda assumes AISIEM-remote-respond role for remediation (enterprise)

Scripts
-------
  setup-remote-access.cmd/.sh   Run in REMOTE account (creates trust roles)
  add-account.cmd/.sh           Run in CENTRAL account (registers account + buckets)
  users.cmd/.sh                 Cognito user management (create, list, delete, reset, enable/disable)
  groups.cmd/.sh                Cognito group management (init, add/remove, list)
  sso.cmd/.sh                   SSO configuration (SAML/OIDC providers, enterprise tier)
  setup-domain.cmd/.sh          Route 53 CNAME for custom editor domain
  check-quota.cmd               Verify service quotas before deployment (Lambda
                                concurrency, VPC endpoints, Bedrock access/tokens)
  check_quota.py                Same, directly (needs boto3 and the AWS CLI)
  support-bundle.cmd/.sh        Collect diagnostics for support
  create-flowlogs.cmd/.sh       Enable VPC Flow Logs on a WORKLOAD VPC, delivered
                                to the stack-owned flow bucket. Requires a target
                                VPC; never touches the shared LogProcessor/AI
                                Monitor VPC.
  create_flowlogs.py            Same, directly (needs boto3)
  wire-log-bucket.cmd/.sh       Attach a log bucket to the ingestion queue
  wire_log_bucket.py            Same, directly: notification + queue policy (merge-safe)
  sever_sources.py              Detach log sources. The inverse of wire_log_bucket
  cleanup.py                    Full teardown of orphan resources AFTER the stack
                                delete (tables, queues, topics, alarms, dashboard,
                                EventBridge rules, ALB, Cognito, Lambdas + log
                                groups, Glue db, and this stack's own VPC endpoints/
                                ENIs/SG in the shared VPC). Dry-run by default;
                                -confirm or -force to act. S3 buckets are reported
                                only unless -delete-buckets is passed (IRREVERSIBLE,
                                destroys the log/threat archive; types-to-confirm).
                                The WORM audit bucket is ALWAYS preserved by
                                -delete-buckets; removing it needs the separate
                                -delete-audit flag (bypasses Object Lock GOVERNANCE,
                                so your creds must hold s3:BypassGovernanceRetention;
                                impossible under COMPLIANCE until retention lapses).
                                Never touches the shared LogProcessor VPC/OpenSearch
                                or AI Monitor. Needs boto3.
  wire-events.cmd/.sh           Run in a SOURCE account: forward its GuardDuty,
                                Security Hub, and/or Config findings to the
                                central SIEM's event bus (--source LIST;
                                setup/remove/status). Needs the central stack
                                deployed with OrganizationId or CrossAccountIds.
  remediation_docs/             SELF-CONTAINED SUBFOLDER for delegated auto-
                                remediation. It has its OWN files (the two helpers
                                below, the add-on template, the sample runbook
                                YAMLs) and its OWN README.md with the full
                                walkthrough - read that README before running these.
                                Run them in the account where remediations EXECUTE:
                                  deploy-remediation.cmd/.sh <siem-stack>
                                    Creates the AutomationAssumeRole SSM Automation
                                    assumes to run your runbooks (you scope its
                                    permissions) + publishes its ARN to SSM so the
                                    editor auto-fills it. Teardown: same cmd/sh with
                                    --cleanup (deletes the aisiem-remediation-<stack>
                                    add-on stack; sample docs are removed separately).
                                  deploy-sample-runbooks.cmd/.sh [region] [--privileged]
                                    Creates the no-op test runbooks (AISIEM-Ping,
                                    AISIEM-TestRemediation); --privileged also adds
                                    the isolate/attach-deny samples.
                                Other files in the subfolder:
                                  buyer-remediation-addon.yaml  the add-on template
                                  AISIEM-*.yaml                 the sample runbooks
                                  README.md                     full walkthrough +
                                                                teardown
                                AI SIEM only calls ssm:StartAutomationExecution +
                                reads status - it holds no IAM/EC2 power; SSM runs
                                everything under YOUR role.

VPC FLOW LOGS
-------------
VPC Flow Logs are the signal for network-based detections: port scanning,
blocked connections, and (with ALL traffic) large-transfer exfiltration. They
are not on by default because they bill per GB delivered and stored.

The stack ALREADY owns the flow-log bucket. When you deploy AI SIEM it creates
a hardened bucket (lifecycle, encryption, the delivery policy for local AND
cross-account VPCs, the notification to the ingestion queue, and the Athena
Glue table flowlogs_raw over it). create-flowlogs does NOT create or wire a
bucket; it just turns on a flow log for a VPC you choose, pointed at that stack
bucket, with per-hour Hive partitioning so Athena can query it directly:

  set AWS_PROFILE=<your-profile>
  scripts\create-flowlogs.cmd <stack> --vpc <vpc-id>
  scripts\create-flowlogs.cmd <stack> --vpc-from-stack <other-stack> --traffic REJECT

It resolves the stack's FlowLogsBucket output, enables a flow log on that VPC
delivering to it (FileFormat plain-text, HiveCompatiblePartitions, PerHourPartition,
MaxAggregationInterval 60s), and enables the vpcFlowLogs source. Re-running is
harmless (every step is idempotent).

  --vpc / --vpc-from-stack   REQUIRED. Name the workload VPC to monitor, either
                             by id or by another stack's VpcId output. There is
                             no default: this tool never enables flow logs on
                             the shared LogProcessor / AI Monitor VPC that the
                             SIEM itself runs in (that would create a
                             self-surveillance loop), and it refuses to run if
                             the target resolves to that VPC.
  --traffic ALL|REJECT|ACCEPT   ALL (default). S3 delivery is cheap even at ALL
                             volume, and capturing everything is what lets the
                             on-demand Athena flow-query pull exfiltration detail
                             around an incident. Processing cost is bounded by
                             the flow-ingestion duty-cycle + circuit breaker
                             (enable under Configure -> Settings), not by
                             discarding data at capture. Use REJECT only to
                             minimize even S3 storage (you then lose ALL-traffic
                             forensics; port-scan detection still works).
  --bucket <name>            Override the destination bucket. Defaults to the
                             stack's FlowLogsBucket output; you rarely set this.
                             The main use is cross-account: run from a REMOTE
                             account and pass the central stack's FlowLogsBucket
                             so that account's VPC delivers into it.
  --dry-run                  Preview every change without writing.

Flow-log delivery is aggregated, so the first objects can take up to ~10
minutes to appear. The editor's Data Sources panel shows the last event time
once ingestion begins.

ONE OR MANY VPCs, ONE BUCKET
  Point as many VPCs as you like (any account, any region) at the one stack
  bucket. AWS partitions deliveries under a Hive key path
  (AWSLogs/aws-account-id=<id>/aws-service=vpcflowlogs/aws-region=<region>/
  year=/month=/day=/hour=/...), so they never collide and the flowlogs_raw Glue
  table's partition projection (aws_account_id, aws_region, year, month, day,
  hour) resolves them all. Run create-flowlogs once per VPC; every step is
  idempotent.

CROSS-ACCOUNT FLOW-LOG DELIVERY (honors CrossAccountIds / OrganizationId)
  The stack bucket's policy already authorizes cross-account delivery, set at
  deploy time from the central stack's own parameters -- there is no bucket
  policy for this helper to edit:
    - OrganizationId set  -> the whole org may deliver (aws:SourceOrgID). No
                             account list to maintain.
    - CrossAccountIds set -> each listed account may deliver.
  To onboard a remote VPC: run create-flowlogs FROM that account (with its own
  credentials, since a flow log is created where the VPC lives) and pass
  --bucket <central stack's FlowLogsBucket>. The VPC then delivers straight into
  the central bucket. If the account is not covered by OrganizationId /
  CrossAccountIds, redeploy the central stack with it added first.

PREFIXES ON A SHARED BUCKET
  wire-log-bucket keys each notification by prefix, so one bucket can carry
  several sources (e.g. cloudtrail/ and vpcflowlogs/) with distinct, coexisting
  notifications - wiring a second prefix does not overwrite the first. Wire each
  with its own --prefix. One caveat from S3: notification prefix filters for the
  same event type may not OVERLAP. Do not wire both a parent prefix (AWSLogs/)
  and a child (AWSLogs/111/) on one bucket; use non-overlapping prefixes.

AUDIT TRAIL (WORM AUDIT BUCKET)
-------------------------------
Every threat status change (Acknowledge, Investigate, Resolve, False Positive,
Dismiss) and every remediation action is recorded with WHO did it and WHEN, in
two places:
  - DynamoDB (the fast path the editor reads to show "Audit History" per threat).
  - A dedicated S3 bucket <stack>-siem-audit-<acct>-<region> with S3 Object Lock
    (WORM), as the tamper-evident system of record. Each record is a write-once
    object: the application roles can APPEND audit records but have no permission
    to alter or delete them, so even a compromised Lambda cannot rewrite history.

The lock behavior is chosen at deploy time with the AuditLockMode parameter:

  GOVERNANCE (default)
    Write-once, but a principal explicitly holding s3:BypassGovernanceRetention
    (typically an account admin) can still delete a record early. This leaves a
    controlled decommission path (see cleanup.py -delete-audit). Recommended for
    most deployments.

  COMPLIANCE
    Fully immutable. NO ONE - not the application, not an admin, not the account
    root - can alter or delete a record before its retention date elapses. This
    is what strict regimes (e.g. SEC 17a-4-style requirements) need.

    !! IMPORTANT CONSEQUENCE OF COMPLIANCE MODE:
       An S3 bucket can only be deleted when it is empty, and COMPLIANCE-locked
       objects CANNOT be emptied until their retention passes. So under
       COMPLIANCE the audit bucket - and the S3 storage cost for it - cannot be
       removed until the LAST audit record's retention has elapsed. A live SIEM
       writing records daily keeps the bucket undeletable until it stops writing
       and the retention window then passes. cleanup.py -delete-audit will refuse
       to delete a COMPLIANCE-locked bucket, by design.

    Because COMPLIANCE makes AuditRetentionDays an IRREVERSIBLE commitment (you
    are locking in that many days of storage with no exit), set AuditRetentionDays
    to your actual regulatory requirement - not higher "to be safe". Under
    GOVERNANCE an over-long retention is recoverable via bypass; under COMPLIANCE
    it is not.

Retention length: AuditRetentionDays (default 365; e.g. 2555 for 7 years).
Applies to newly written records; existing records keep the mode and retention
they were written under (you cannot retroactively weaken a lock).

The audit bucket has DeletionPolicy: Retain - a CloudFormation stack delete
leaves it in place (it is the system of record and must outlive the stack). It
is removed only by an explicit, deliberate cleanup.py -delete-audit.


TEARDOWN
--------
Deleting the stack does NOT stop your log sources. Bucket notifications and any
VPC flow logs created for AI SIEM live outside CloudFormation and survive the
delete. Left in place, buckets keep firing notifications at a queue that no
longer exists, and flow logs keep writing to S3 while you keep paying for it.

Run in this order:

  1. python scripts/sever_sources.py <stack> [region]
       Dry run, the default. Changes nothing. Reports:
         - VPC flow logs delivering to S3
         - bucket notifications owned by this stack
         - the CloudTrail trail and whether it is still logging
         - Lambda reserved concurrency (reported, never changed)
       Read this output before going further.

  2. python scripts/sever_sources.py <stack> [region] --apply
       Confirms each item individually. Deletes the flow logs, removes this
       stack's bucket notifications, and STOPS the trail.

       Notification removal is merge-safe. Only Ids belonging to this stack are
       dropped (aisiem-<stack>, aisiem-cloudtrail); anything another tool put
       there is written back untouched and the configuration is never blanked.
       The flow-log bucket's notification is stack-managed and torn down with
       the stack. Doing this by hand with
       put-bucket-notification-configuration is a FULL REPLACE and will
       silently delete other tools' notifications.

       Buckets that cannot be inspected are listed explicitly rather than
       skipped quietly, because a missed notification stays live.

       Flags:
         --delete-trail            Delete the trail instead of stopping it. A
                                   multi-region trail is an audit control and
                                   deleting it breaks CloudTrail history
                                   continuity for the whole account. Stopping
                                   is the default for that reason.
         --bucket-profile <name>   For buckets in another account. Use the same
                                   profile you passed to wire_log_bucket.py,
                                   once per account. Cross-account buckets are
                                   unreachable with default credentials and
                                   will otherwise only appear as skipped.
         --delete-buckets          IRREVERSIBLE. Also empty and delete the log
                                   buckets AI SIEM created, destroying the raw
                                   log archive they hold.

                                   Deliberately narrow. A bucket qualifies only
                                   if its name starts with aisiem-cloudtrail-,
                                   or it is the destination of a flow log or
                                   trail found in step 1 or 3. The stack-owned
                                   flow-log bucket (<stack>-siem-flowlogs-*) is
                                   never a candidate - CloudFormation deletes it
                                   with the stack. A bucket that merely carries
                                   one of our notifications is NEVER deleted -
                                   that is most likely YOUR archive, wired in via
                                   the editor or wire_log_bucket.py. Those are
                                   reported as left alone.

                                   Versioning is enabled on these buckets, so
                                   every version and delete marker is removed
                                   before the bucket goes. Each bucket prints
                                   its version count, delete marker count, and
                                   size, then requires you to type the bucket
                                   name back before anything is destroyed.

  3. Delete the CloudFormation stack
       aws cloudformation delete-stack --stack-name <stack> --region <region>
       aws cloudformation wait stack-delete-complete --stack-name <stack> --region <region>

       Or delete it from the CloudFormation console. Buckets with content and
       any resource still in use can hold the delete up; the stack events tab
       names whatever is blocking.

  4. (Optional) Remove anything CloudFormation left behind
       python scripts/cleanup.py <stack> <region>
         Dry run, the default. Lists orphan resources still bearing the stack
         name and reports (but KEEPS) the S3 buckets. Changes nothing. It covers
         DynamoDB, SQS, SNS, CloudWatch alarms + dashboard, EventBridge rules,
         the editor ALB, the Cognito user pool, Lambda functions + their log
         groups, the Glue database, and - scoped strictly to THIS stack's
         CloudFormation tag so Log Processor and AI Monitor are never touched -
         the interface VPC endpoints, available ENIs, and Lambda security group
         this stack created in the shared VPC.

       python scripts/cleanup.py <stack> <region> -confirm     (prompt each)
       python scripts/cleanup.py <stack> <region> -force       (delete, no prompt)
         Deletes everything above. The shared LogProcessor VPC, subnets, route
         tables, gateways, and OpenSearch domain are NEVER deleted - AI SIEM is
         a guest in that VPC. S3 buckets are still only reported, not deleted.

       Add -delete-buckets to ALSO empty and delete the S3 buckets:
         python scripts/cleanup.py <stack> <region> -force -delete-buckets
         WARNING: this permanently destroys the raw log + threat archive those
         buckets hold (all object versions and delete markers). It is IRREVERSIBLE.
         Each bucket prints its object count and size and requires you to type the
         bucket name back before anything is deleted - even under -force. Omit the
         flag and your buckets are left intact.

       The WORM audit bucket is NEVER touched by -delete-buckets. To decommission
       it (the tamper-evident trail of status changes + remediations), pass the
       separate -delete-audit flag:
         python scripts/cleanup.py <stack> <region> -force -delete-buckets -delete-audit
         Under GOVERNANCE this bypasses Object Lock retention, so YOUR credentials
         must hold s3:BypassGovernanceRetention; it types-to-confirm like the
         others. Under COMPLIANCE it cannot succeed until every record's retention
         has elapsed (the script reports this and leaves the bucket). See the
         AUDIT TRAIL section above.

Decide deliberately, no script does these:
  - Log buckets are left alone unless you pass --delete-buckets, and even then
    only the ones AI SIEM created. Buckets you wired in yourself are never
    deleted; verify with `aws s3 ls` that what you expect to keep is still there.
  - Cross-account roles created by setup-remote-access.cmd (AISIEM-remote-read,
    AISIEM-remote-respond) remain in each remote account. Remove them there.
  - The stack's OWN GuardDuty/Security Hub/Config EventBridge rules are in the
    template, so they go with the stack. But any SOURCE-account forwarding set
    up with wire-events (the AISIEM-*-forward rules + AISIEM-eventbridge-forward-
    role) lives in those remote accounts and survives - remove it there with
    `wire-events.cmd remove [region]` in each.
  - The stack's own S3 buckets (config, datalake, access logs) may survive the
    stack delete if they still hold objects. Versioning is enabled, so every
    object version and delete marker has to go before the bucket can be removed.
  - The WORM audit bucket (<stack>-siem-audit-*) ALWAYS survives the stack delete
    (DeletionPolicy: Retain) and is never removed by -delete-buckets. Decommission
    it deliberately with cleanup.py -delete-audit (GOVERNANCE), or wait out the
    retention window (COMPLIANCE). See the AUDIT TRAIL section.
  wire_log_bucket.py            Attach a log bucket to AI SIEM (needs boto3)
  sever_sources.py              Detach every log source before removing AI SIEM

REMOVING AI SIEM
----------------
Deleting the CloudFormation stack does NOT stop your log sources feeding it.
Bucket notifications and any VPC flow logs created for AI SIEM live outside the
stack and survive its deletion. If you skip this step:

  - your buckets keep firing S3 notifications at a queue that no longer exists
  - VPC flow logs keep writing to S3 and you keep paying for that storage

Run this BEFORE deleting the stack:

  python sever_sources.py <stack> [region]
        Dry run. Reports what is attached and changes nothing.

  python sever_sources.py <stack> [region] --apply
        Deletes the flow logs, removes AI SIEM's bucket notifications, and stops
        logging on the trail if AI SIEM created one. Each change is confirmed
        individually.

        Add --delete-trail to delete the trail instead of stopping it. A
        multi-region trail is an audit control, and deleting it breaks
        CloudTrail history continuity for the whole account, so stopping is the
        default.

        For buckets in another account, pass --bucket-profile <profile> using
        the same profile you used with wire_log_bucket.py. Run once per account.
        Buckets the script cannot inspect are listed explicitly - if any were
        attached to AI SIEM, their notifications are still live.

Then delete the stack in the CloudFormation console, or with:

  aws cloudformation delete-stack --stack-name <stack>

Your log buckets and their contents are never touched. They hold your raw
archive, so remove them yourself once you no longer need the history.

Requires boto3:  pip install boto3

Multi-Region
------------
AI SIEM is deployed in a single region but can ingest CloudTrail logs from
any region (org trails deliver to a single bucket regardless of source region).
VPC Flow Logs are regional — for multi-region coverage, configure flow logs in
each region to deliver to a central S3 bucket (or run setup-remote-access per region).

GuardDuty and Security Hub findings arrive via EventBridge, which is regional
AND per-account. Two ways to get full coverage:
  - Delegated administrator: enable a GuardDuty delegated admin with auto-enable
    across regions; member findings aggregate to the admin account, and if the
    SIEM runs there its own rule sees them with no forwarding.
  - Forwarding: run wire-events in each source account+region (see
    CROSS-ACCOUNT EVENTBRIDGE FINDINGS). Use this when the SIEM is not in the
    delegated-admin/aggregator account or you are not using an org. The same
    script forwards Security Hub and Config too (--source).

Data Flow (per remote account)
------------------------------
  Remote Account                         Central Account (AI SIEM)
  +-----------------+                    +----------------------------+
  | CloudTrail      |  S3 bucket read    | Ingestion Lambda           |
  | (org trail)     |<-------------------| (assumes remote-read role) |
  |                 |                    |                            |
  | VPC Flow Logs   |  S3 bucket read    |      |                    |
  | (S3 delivery)   |<-------------------|      v                    |
  +-----------------+                    | S3 Datalake (cold)         |
                                         | OpenSearch (hot threats)   |
                                         | DynamoDB (baselines)       |
                                         +----------------------------+
                                                    |
                                                    v (enterprise only)
                                         +----------------------------+
                                         | Response Engine             |
                                         | (assumes remote-respond)    |
                                         | -> disable keys             |
                                         | -> revoke sessions          |
                                         | -> isolate instances        |
                                         +----------------------------+

S3 Datalake Partition Structure
-------------------------------
All cold data is partitioned by account_id and region for efficient
Athena queries and per-account lifecycle management:

  s3://<stack>-siem-datalake-<acct>-<region>/
    cloudtrail/account_id=111111111111/region=us-east-1/year=2026/month=08/day=10/*.parquet
    cloudtrail/account_id=222222222222/region=eu-west-1/year=2026/month=08/day=10/*.parquet
    flowlogs/account_id=111111111111/region=us-east-1/year=2026/month=08/day=10/*.parquet
    flowlogs/account_id=111111111111/region=us-west-2/year=2026/month=08/day=10/*.parquet
    guardduty/account_id=111111111111/region=us-east-1/year=2026/month=08/*.parquet
    securityhub/account_id=111111111111/region=us-east-1/year=2026/month=08/*.parquet
    config-changes/account_id=111111111111/region=us-east-1/year=2026/month=08/*.parquet
    threats/account_id=111111111111/year=2026/month=08/*.parquet

Athena queries can filter efficiently:
  SELECT * FROM cloudtrail WHERE account_id='111111111111' AND region='us-east-1' AND year='2026' AND month='08'

================================================================================
SUPPORT
================================================================================

Upload support bundles using link provided in the landing and fulfillment pages.
Documentation: https://perfware.cloud