# StackToIT Assess — default

> PROPOSAL — generated by StackToIT Assess. Architect review required before any decision.

Generated 2026-11-02 12:08 UTC by stacktoit 0.6.0-11562-g1966ddf116 (1966ddf116) · knowledge base 0.384.0 · STACKIT provider 0.121.0 · schema 0.24.0

Run `f6267c3f-2848-4aa5-89df-5fee8b15b3b9` · source digest `sha256:812c5ae3f6cc8530163abbf5b6fbe305ed3b363c4886ec6b87623db857ea0c70`

Run status: COMPLETE (report published)

Global verification: 12 of 12 invariants PASS — the table is in index.html (Evidence), the verdicts in workspace.json (`verification`) and manifest.json (`verification`).

**Validation matrix** — What has been established about this draft, row by row, and what has not. Nothing here approves the draft, asserts that it is equivalent to the source, or says it is safe to apply.

- Source completeness: PARTIAL (source status RUNTIME_TOPOLOGY_PARTIAL)
- Draft generation: GENERATED (the draft is in terraform/)
- StackToIT draft checks: PASSED (100 checks, none found a violation)
- Global invariants: PASSED (12 of 12 invariants PASS)
- OpenTofu validation: PASSED (tofu init -backend=false and tofu validate accepted the draft; tofu 1.13.1)
- Output schema validation: PASSED (verified at publish: every JSON file that has a schema is validated against it (see run_verification in manifest.json))
- STACKIT plan: NOT RUN (this build runs no plan against a STACKIT project)
- Architect approval: NOT PROVIDED (no review decision is recorded for this run)
- Semantic equivalence: NOT ASSESSED (this build has no measure for it)
- Safe to apply: NOT ASSERTED (StackToIT never asserts it)

**Run summary** — the numbers the console prints at the end of a run, from the same model as `workspace.json` (`run_summary`).

- Package state: Partially executable migration package
- Plan steps: 49 generated automatically · 4 generated with decisions · 238 manual carry-over · 3 unsupported · 3 units left to the architect for redesign (manual carry-over here includes the cutover, verification and retirement steps; STACKIT API steps, and Terraform steps that no decision can free, are in none of these counts, which the Execution line below states; manual carry-over counts the longest method of each open data-movement choice)
- Source unit fate: 34 Terraform-only · 4 hybrid · 0 API-only · 3 manual · 11 no resource (of 52 units the draft considered: 44 known-present, 8 decided only when OpenTofu plans) (what becomes of each unit the draft considered; the five add up to the units considered, and Terraform-only and hybrid together are the units generated)
- Execution: 48 of the 57 automated steps (OpenTofu or a script) can run now (1 waits for a manual prerequisite, 8 require a design decision) · 9 of those 48 rest on a default you have not confirmed (public endpoint, size derived from the source) · stages of 57 automated steps: 57 can be generated, 48 can run now, 39 rest on no default left to confirm, 0 are approved (every decision and default confirmed in the decisions file) · 49 Terraform (1 after a manual prerequisite) · 4 API (4 wait for the opt-in) · 4 design inputs · 154 manual migration work (272 settings in 69 review steps) (counting the longest method of each open data-movement choice; 16 steps of the other methods not counted) · 84 lifecycle (cutover/verify/retire) · 3 refused (of 314 plan steps) (what each step of the plan is; the categories add up to the plan's steps)
- Defaults: the default of 8 decisions nobody has answered: public endpoint (5), size derived from the source (3); confirm or change each in decisions.yaml; confirming one accepts what the draft does as it stands: the steps that rest on it then count among those that rest on no default left to confirm, and as approved once every decision they rest on is answered in the decisions file; decisions are counted one by one here, while the register's decisions to make and defaults to confirm count the records that group them (the steps that can run now may stand on them; the decision register lists each decision)
- Inputs: 4 design inputs wait · 47 open requests (14 block the draft, 4 are preferences this build cannot apply — inputs-template.yaml, NOT APPLICABLE IN THIS BUILD, says where to set each) (design inputs are steps of the plan; requests are what the run asks the customer, listed one by one when the run is given an inputs file or a project)
- Source units: 44 (known-present migration units; 8 more decided only when OpenTofu plans: 3 off with the defaults of their variables (a variable can switch them on), 5 decided by data OpenTofu reads when it plans, 41 switched off)
- Critical open settings: 283 (282 to decide, 1 confirm only; 36 resolved of the 319 the units state; 25 more are open on 5 units decided when OpenTofu plans, not counted here but listed in the decision register (marked: applies only if))
- Decisions to review: 16 decisions to make (9 plan decisions, 5 manual actions, 2 plan statements, 2 of them with the draft's DEFAULT to confirm or change) · 2 defaults to confirm (other records, no step waits for them) · 48 units to review (308 critical settings: 307 to decide (25 of them are conditional), 1 confirm only) (a decision to make is a record of an open plan decision, manual action or plan statement; a default to confirm is such a record whose default option the draft carries out (no step waits for it: a person confirms it or changes it); a unit to review is the review record of the critical settings of one unit that the knowledge base cannot decide (one record for each owner role, each setting an item of it); conditional settings are on units decided only when OpenTofu plans (decisions.json))
- Draft coverage: 38 of 52 units with a generated resource (11 need no resource · 3 left for the architect · 60 variables · the 52 are the 44 source units and 8 conditional units)
- Global draft invariants: 12/12 PASS (consistency checks over the draft; not target behaviour)
- tofu validate: PASSED (static validation; not target behaviour)
- Architect approval: NOT PROVIDED
- Safe to apply: NOT ASSERTED

Next:

1. Review the 307 open critical settings: a person decides each (index.html, Decisions page; assurance/critical-semantics.json, critical_semantic_resolution.open). 25 of them belong to units that exist only if a plan-time input holds (critical_semantic_resolution.conditional_open). 1 more is carried by the draft already: confirm only.
2. Review the 9 open plan decisions and 5 manual actions of the draft (index.html, Architecture, Deployment prerequisites). Confirm the 2 defaults the draft carries out (index.html, Decisions page): no step waits for the answer, a person confirms each or changes it.
3. Review the draft in terraform/: it is a proposal, and an architect has to review it before any use.
4. Open index.html in a browser for the unit-by-unit view (offline, nothing is loaded).

**Target platform baseline:** STACKIT Terraform provider 0.121.0 (released 2026-10-22). Every mapping, capability statement and draft refers to this release; the date a newer STACKIT release was last looked for is not recorded in this build, so a release published after the one named here is not reflected here. The JSON files of this run are checked against their published schemas by `stacktoit verify RUN_DIR`; the assess run does not run that check itself.

Source providers: aws not locked (UNPINNED; band UNPINNED; knowledge base checked against 5.100.0; identity evidence: PINNED_REGISTRY) · random not locked (UNVERIFIED; no pinned source schema)

> Note (info; aws): No lock file entry pins this provider, so the version a plan would use is not proven; the knowledge base was checked against one version only. Until the exact version is pinned (commit .terraform.lock.hcl), the units of this provider are capped at MEDIUM confidence and are not automation eligible.

> Note (info; random): The knowledge base holds no pinned source schema of this provider, so its version cannot be checked (UNVERIFIED); the row records that the configuration uses it and changes no decision.

Input maturity: **AWS — primary** (broadest rule coverage, measured on large real estates).

## How to read this report

This report uses three different scales. Each answers a different question, and they can disagree on the same unit — that is expected, not a contradiction.

- **Confidence** (HIGH/MEDIUM/LOW, per unit below) — how sure the matched rule is about *this* unit's configuration. Answers: *is this specific mapping decision reliable?*
- **Feasibility** (SUPPORTED/CONDITIONAL/UNSUPPORTED/UNKNOWN, per unit below) — whether the source configuration can be represented on STACKIT at all, and how cleanly. Answers, together with Confidence: *is this mapping usable today?*
- **Target maturity** (GA/BETA/EXPERIMENTAL, shown only when not GA) — a STACKIT provider notice about the target Terraform resource itself. Answers: *will the STACKIT provider change this resource under me, independently of whether the mapping is right?*

This report states each decision, its reason and what you have to do. The working behind it — the semantic surface and property accounting of every unit, every critical-property entry, and the engine's own text for a decision that depends on relations it could not resolve — is in `engineering/analysis-details.md` next to this file; `assessment.json` has all of it in machine-readable form.

## Summary

| | |
|---|---|
| Source files | 105 |
| Resources scanned | 282 |
| Migration units | 44 known-present (44 instances) · 8 conditional (+41 absent) |
| Disabled units (count/for_each = 0) | 41 |
| Unit dependencies | 109 |
| Source checks | Built-in source checks passed — OpenTofu validation of the source did not run (LOCK_FILE) |
| Source completeness | RUNTIME_TOPOLOGY_PARTIAL — 8 unit(s) have a count/for_each that is not known statically; whether and how often they exist is decided at plan time |
| Support resources (IAM policies, target groups, role assignments, … — used by the units above) | 34 — the draft creates nothing for them; 23 went through the critical-property gate and **40 critical setting(s)** of theirs are left to a person (see "Support resources" below) |
| Terraform helpers (`random_*`, `time_*`, `null_resource`, `local_file`, `tls_*`, …) | 12 — out of scope unless it provisions a unit (0 do): they steer the Terraform run, nothing of them exists in the source cloud |

**Generated secrets (3).** These resources produce a secret when Terraform applies: `module.dependencies.module.catalog_rds.random_password.master_password`, `module.dependencies.module.orders_rds.random_password.master_password`, `module.dependencies.random_password.mq_password`. The draft neither recreates them nor carries their value — it exists only in the source Terraform state. Decide for each whether the secret is moved by hand or rotated.

**Source placement (whole estate):** provider regions aws (no region declared in the configuration — no provider block or none sets it: taken from the environment at plan time). Every resource without a region of its own sits there; the draft places every unit in `var.region` (a STACKIT region) — the data residency of the estate changes: confirm it once for the estate.

**Semantic accounting:** 44 of 44 units have a semantic contract (what their source family can state); 0 leave a critical semantic unaccounted, 43 leave one for review or as an accepted loss. 0 units are linked to a resource the knowledge base does not know (uncatalogued-related) and are therefore not decided with certainty.

**Critical resolution:** 36 of 319 critical semantics are resolved; 283 are open in 43 units; 25 more are open on 5 units decided when OpenTofu plans, not counted here but listed in the decision register (marked: applies only if). Accounted is not resolved: the open ones are listed in `assurance/critical-semantics.json`, `critical_semantic_resolution`.

**Property accounting** (a separate, wider check than semantic accounting above: every property value the source sets, not only business-critical semantics — measured because this run wrote a draft): 404 of 404 meaningful properties are accounted for across 38 generated units (11 units the draft writes no block of — no resource needed, carried by a STACKIT API call or left for the architect — are not accounted per property); 0 are **UNACCOUNTED** (silent-drop candidates) in 0 of those units — see each unit's "Property accounting" line below (every UNACCOUNTED property is named there), the counts per unit in engineering/analysis-details.md, or `units[].property_accounting.unaccounted` in assessment.json.

**Critical-property gate:** 341 property entries across the estate need attention (a CRITICAL property with no evidence-backed disposition, an unresolved contradiction, or a property left for review/measured only); 44 of 44 units are not automation-eligible (because of such a property, or an open critical semantic that reads no property of the unit) — see each unit's "critical setting(s) left to you" lines below (grouped by category; every entry in engineering/analysis-details.md), or `units[].property_accounting.critical`/`automation_eligible` in assessment.json.

| Class | Units | Share |
|---|---:|---:|
| DIRECT | 0 | 0% |
| RECONFIGURE | 34 | 77% |
| REPLATFORM | 9 | 20% |
| CONTAINERIZE | 0 | 0% |
| REDESIGN | 1 | 2% |
| MANUAL_REVIEW | 0 | 0% |
| BLOCKED | 0 | 0% |

Confidence: HIGH 0 · MEDIUM 35 · LOW 9

The classes and the confidence count the 44 known-present unit(s); the 8 conditional unit(s) — whether they exist is decided only when a plan runs — are listed under "Uncertainty by cause" with the class each would get; 5 of the known-present unit(s) have a facet that is decided only when a plan runs (or may not belong to them): they count here, their configuration is conditional and they are not automation-eligible.

## Critical findings

- 1× Engine version DOWNGRADE: the source runs OpenSearch 3.3 (engine_version); STACKIT OpenSearch in eu01 offers 2 (service catalogue of eu01, read 2026-10-18), older than the source. (module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this)

## Target maturity

Units whose proposed STACKIT target is not generally available in the pinned provider (0.121.0): the provider may change these resources incompatibly or remove them.

| Unit | Target | Maturity | Lifecycle |
|---|---|---|---|
| `module.retail_app_ecs.module.carts_service.aws_iam_role.task_execution_role` | STACKIT service account for the workload | EXPERIMENTAL | active |
| `module.retail_app_ecs.module.checkout_service.aws_iam_role.task_execution_role` | STACKIT service account for the workload | EXPERIMENTAL | active |
| `module.retail_app_ecs.module.ui_service.aws_iam_role.task_execution_role` | STACKIT service account for the workload | EXPERIMENTAL | active |
| `module.retail_app_ecs.module.carts_service.aws_iam_role.task_role` | STACKIT service account for the workload | EXPERIMENTAL | active |
| `module.retail_app_ecs.module.catalog_service.aws_iam_role.task_role` | STACKIT service account for the workload | EXPERIMENTAL | active |
| `module.retail_app_ecs.module.checkout_service.aws_iam_role.task_role` | STACKIT service account for the workload | EXPERIMENTAL | active |
| `module.retail_app_ecs.module.orders_service.aws_iam_role.task_role` | STACKIT service account for the workload | EXPERIMENTAL | active |
| `module.retail_app_ecs.module.ui_service.aws_iam_role.task_role` | STACKIT service account for the workload | EXPERIMENTAL | active |
| `module.retail_app_ecs.module.catalog_service.aws_iam_role.task_execution_role` | STACKIT service account for the workload | EXPERIMENTAL | active |
| `module.retail_app_ecs.module.orders_service.aws_iam_role.task_execution_role` | STACKIT service account for the workload | EXPERIMENTAL | active |

BETA: the provider marks the resources beta — "may be subject to breaking changes in the future". EXPERIMENTAL: part of an experimental provider feature — "likely going to undergo significant changes or be removed in the future". Both are notices of the STACKIT Terraform provider, not StackToIT's judgement of the service.

## Target lifecycle

Lifecycle evidence for the STACKIT capabilities some units land on. A state is derived from published dates only, as of the day the sources were read; it is not a verdict on a cluster, and a version or capability without a date has the state UNKNOWN. This report does not read the clock: compare the dates with today.

### SKE Kubernetes versions

Units whose target uses it: `module.retail_app_ecs.aws_ecs_cluster.cluster`, `module.retail_app_ecs.module.carts_service.aws_ecs_service.this`, `module.retail_app_ecs.module.catalog_service.aws_ecs_service.this`, `module.retail_app_ecs.module.orders_service.aws_ecs_service.this`, `module.retail_app_ecs.module.checkout_service.aws_ecs_service.this`, `module.retail_app_ecs.module.ui_service.aws_ecs_service.this`.

State as of **2026-10-08** (the day the pages were read). Not vouched for after **2027-01-06**: re-read the sources then.

| Version | State | Released | Deprecated | Expires | Production suitability | Upgrade action | Migration timing risk |
|---|---|---|---|---|---|---|---|
| 1.36 | SUPPORTED | 2026-08-27 | not stated | not stated | SUITABLE | NONE_PUBLISHED | UNKNOWN |
| 1.35 | UNKNOWN | not stated | not stated | 2027-02-10 | UNKNOWN | UNKNOWN | UNKNOWN |
| 1.34 | EXPIRING | 2025-12-16 | 2026-08-28 | 2026-10-14 | NOT_SUITABLE | UPGRADE_BEFORE_EXPIRY | HIGH |
| 1.33 | EXPIRED | 2025-07-29 | 2026-06-09 | 2026-06-10 (sources disagree: 2026-07-08) | NOT_SUITABLE | MANDATORY_UPDATE_APPLIES | HIGH |
| 1.32 | EXPIRED | not stated | 2026-02-20 | 2026-04-15 | NOT_SUITABLE | MANDATORY_UPDATE_APPLIES | HIGH |

- **Production suitability: SUITABLE.** Suitable as a landing: 1.36. Review before use: none. Not suitable as a landing (ended or ending inside 30 days): 1.34, 1.33, 1.32. No date evidence, so not assessed: 1.35.
- **Upgrade action.** Upgrade before the expiry: 1.34. Plan the upgrade (an end is announced): none. Already expired, the provider's mandatory update applies: 1.33, 1.32. No end published, nothing due that the sources show: 1.36.
- **Migration timing risk** (that the end of the landing version falls inside the migration). HIGH: 1.34, 1.33, 1.32. MEDIUM: none. LOW: none. UNKNOWN (an unpublished end is not safety): 1.36, 1.35.
- **Day-2 responsibility.** When a version reaches its expiry the update is performed by the provider (STACKIT): "If the Kubernetes or OS version of a cluster has reached its expiration date, SKE starts a mandatory update to the highest available patch version of the current minor version, or to the highest patch version of the consecutive minor version that is not classified as preview version." and "mandatory version updates run, even if the auto update for the Kubernetes version is deactivated". Automatic updates otherwise "only update to higher patch levels" in the cluster's maintenance window. Notice: "As a SKE user you will get informed via release notes and via email in case you are operating a cluster with a deprecated Kubernetes version." Customer: "you can check the exact expiration dates for your current Kubernetes and node pool versions in the cluster.status.expiration field via the SKE API". The page does not assign any further duty (workload readiness for the update, testing) to the customer or to STACKIT: not stated.
- **1.36:** No expiry or EOL for 1.36 is stated in the pages read; the lifecycle table does not list it. An unpublished end is reported as such, not as safe.
- **1.35:** The pages read give no release date for 1.35 (no release-note entry), so the state stays UNKNOWN: a future expiry date does not say that a version is offered. The 1.34 deprecation entry names 1.35 as the upgrade target.
- **1.34:** Clusters still on 1.34 are upgraded to 1.35 by the mandatory update (release note of 2026-08-28); the day it runs inside the maintenance window is not stated, so no forced-update date is recorded.
- **1.33:** The expiry day differs between the lifecycle page (2026-06-10) and the release note (2026-07-08); the state is EXPIRED under either.
- **1.32:** No release date for 1.32 appears in the pages read.

The 30-day window that makes a version EXPIRING is a StackToIT presentation parameter, not a provider fact.

Sources (read 2026-10-08): https://docs.stackit.cloud/products/runtime/kubernetes-engine/basics/operations/version-updates/; https://docs.stackit.cloud/products/runtime/kubernetes-engine/reference/lifecycle/; https://docs.stackit.cloud/products/runtime/kubernetes-engine/release-notes/.

**Decision axes** (derived from the class, findings and contract): feasibility SUPPORTED 1 · CONDITIONAL 43 · UNSUPPORTED 0 · UNKNOWN 0 (the 44 units counted in the totals). Not counted in the totals, decided only when OpenTofu plans: 5 units — feasibility SUPPORTED 0 · CONDITIONAL 5 · UNSUPPORTED 0 · UNKNOWN 0.

## Modules

The module calls of the source, each read from the units inside it (nested calls are counted in the call that contains them). A module row is a reading of its units' decisions; every unit keeps its own class, confidence and accounting below — nothing is decided at module level. "Depends on" names the module calls whose outputs the call's inputs read — a reading of the source: it orders nothing, the waves stay each unit's own.

| Module call | Source → version | Resources | Units (known-present · conditional · absent) | Classes | Worst | Automation-eligible | Waves | Internals | STACKIT targets | Depends on |
|---|---|---:|---|---|---|---|---|---|---|---|
| `module.dependencies` (+10 nested calls) | ../../lib/dependencies | 77 | 11 · 0 · 13 | RECONFIGURE 7 · REPLATFORM 3 · REDESIGN 1 | class REDESIGN · confidence LOW | 0 of 11 | 1, 3, 4 | 24 — see Unit mapping (13 switched off: Disabled by configuration) | STACKIT Key Value Store (Valkey), STACKIT MariaDB, STACKIT MongoDB Flex (alternative — data-model redesign; PostgreSQL Flex JSONB is the other option), STACKIT OpenSearch (+3 more) | `module.retail_app_ecs`, `module.vpc` |
| `module.retail_app_ecs` (+8 nested calls) | ../../lib/ecs | 126 | 30 · 3 · 3 | RECONFIGURE 24 · REPLATFORM 6 | class REPLATFORM · confidence LOW | 0 of 30 | 1, 2, 3, 5, 6, 7, 8, 9 | 36 — see Unit mapping (3 switched off: Disabled by configuration) | STACKIT Application Load Balancer, STACKIT KMS, STACKIT Kubernetes Engine (SKE), STACKIT Logs (+3 more) | `module.dependencies`, `module.vpc` |
| `module.tags` | ../../lib/tags | 0 | 0 · 0 · 0 | — | — | 0 of 0 | — | 0 — see Unit mapping | — | — |
| `module.vpc` (+1 nested call) | ../../lib/vpc | 79 | 3 · 5 · 25 | RECONFIGURE 3 | class RECONFIGURE · confidence MEDIUM | 0 of 3 | 1, 2 | 33 — see Unit mapping (25 switched off: Disabled by configuration) | STACKIT project networking / Network Area (SNA) | — |

## Source status

- **5 unit(s) have a count/for_each that is not known statically**, so whether and how many instances exist is open: `module.vpc.module.vpc.aws_internet_gateway.this`, `module.vpc.module.vpc.aws_route_table.private`, `module.vpc.module.vpc.aws_route_table.public`, `module.vpc.module.vpc.aws_subnet.private`, `module.vpc.module.vpc.aws_subnet.public`. The migration plan lists them as prerequisites, not as wave members.

## Uncertainty by cause

8 unit(s) exist only if a plan says so: their count/for_each is not known from the source. They are not counted in the unit totals and the classes above, they are not wave members (the migration plan lists them as prerequisites), they are not automation-eligible (gate blocker `TOPOLOGY:unknown`), and the class shown for them is the one they would get if they exist. Below, they are grouped by the kind of cause; each group names what decides them and the remedy.

By precision state (`summary.presence.conditional_by_state`; no state says the unit exists): 3 off with the defaults of their variables (a variable can switch them on), 5 decided by data OpenTofu reads when it plans.

### A data source, read when a plan runs — 5 unit(s)

**Remedy.** The deciding data source is read when a plan runs, so only a plan resolves it. Produce a plan in your environment (`tofu plan -out p && tofu show -json p > plan.json`): a plan would resolve this value, but StackToIT does not read plans.

**Source constraint.** 5 of these unit(s) have a count that rests on a call the source may not be valid for, so it is an interval, never an exact number (POSSIBLE_SOURCE_ERROR: `slice(…, 3)` fails in Terraform and OpenTofu when the list has fewer than 3 elements (the source proves none), so the count is not exact). A plan that succeeds settles it.

| Decided by | Units | Which |
|---|---:|---|
| `module.vpc.data.aws_availability_zones.available` | 5 | `module.vpc.module.vpc.aws_internet_gateway.this`, `module.vpc.module.vpc.aws_route_table.private`, `module.vpc.module.vpc.aws_route_table.public`, `module.vpc.module.vpc.aws_subnet.private` and 1 more |

### A root variable that a variable file or the command line can override — 3 unit(s)

**Remedy.** Only the default of a root variable decides whether this exists on the defaults (a default of 0, false or an empty set switches it off) and how often, and a default is not a fact of the source: a variable file, `-var` or `TF_VAR_<name>` can change it, so it is never read as existing now. Give the variable its value — `--var-file FILE`, or a `terraform.tfvars` / `*.auto.tfvars` next to the source — and assess again; StackToIT then reads that value as the source's.

| Decided by | Units | Which |
|---|---:|---|
| the defaults of the variables `var.container_insights_setting`, `var.lifecycle_events_enabled` | 3 | `module.retail_app_ecs.aws_cloudwatch_event_rule.ecs_events`, `module.retail_app_ecs.aws_cloudwatch_log_group.ecs_container_insights`, `module.retail_app_ecs.aws_cloudwatch_log_resource_policy.eventbridge_ecs` |

## Resources a default switches off

11 resource(s) are switched off by the default of a root variable (or by the workspace): their count/for_each reads zero there, a variable file or `-var` can change it, so whether they exist is decided when a plan runs. They are no migration unit, they are not drafted, and the unit that carries one lists it in its Configuration line. Give the variable its value — `--var-file FILE`, or a `terraform.tfvars` / `*.auto.tfvars` next to the source — and they are decided.

| Decided by | Resources | Which |
|---|---:|---|
| the default of variable `var.opentelemetry_enabled` | 10 | `module.retail_app_ecs.module.carts_service.aws_iam_policy.cloudwatch_agent`, `module.retail_app_ecs.module.carts_service.aws_iam_role_policy_attachment.cloudwatch_agent`, `module.retail_app_ecs.module.catalog_service.aws_iam_policy.cloudwatch_agent`, `module.retail_app_ecs.module.catalog_service.aws_iam_role_policy_attachment.cloudwatch_agent` and 6 more |
| the defaults of the variables `var.container_insights_setting`, `var.lifecycle_events_enabled` | 1 | `module.retail_app_ecs.aws_cloudwatch_event_target.ecs_events_target` |

## Blockers

No unit is classified BLOCKED.

## Architect review queue

Units that need a human decision, most severe first.

| Unit | Module | Class | Confidence | Why |
|---|---|---|---|---|
| `module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this` | `module.dependencies.module.dynamodb_carts` | REDESIGN | MEDIUM | There is no DynamoDB-compatible service on STACKIT. WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.carts_service.aws_ecs_service.this` | `module.retail_app_ecs.module.carts_service` | REPLATFORM | LOW | Containers already exist; ECS task definitions and services are rewritten as Kubernetes Deployments/Services on SKE (or pushed to Cloud Foundry for simple web apps). WARNING (ecs-service-discovery): Services find each other through Cloud Map / Service Connect; on SKE this becomes Kubernetes Services and DNS. WARNING (source-provider-unpinned): root: source-provider-unpinned:aws WARNING (linked-dependency-unread): This unit names module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this (aws_dynamodb_table), whose own decision the target does not carry (it is REDESIGN), and the semantic contract of aws_ecs_service does not read aws_dynamodb_table, so what the reference becomes is not assessed. |
| `module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this` | `module.dependencies.module.catalog_opensearch` | REPLATFORM | LOW | Indices move to STACKIT OpenSearch by reindexing from the source; a snapshot restores only into the same or a newer OpenSearch version, never an older one, so a source newer than the version STACKIT offers cannot be restored (engine-version-downgrade finding). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.dependencies.module.catalog_rds.aws_rds_cluster.this` | `module.dependencies.module.catalog_rds` | REPLATFORM | LOW | Aurora MySQL has no MySQL target on STACKIT; MariaDB is the closest engine and needs compatibility testing. WARNING (aurora-storage-encrypted-mariadb): Storage is encrypted at rest with an AWS-managed key. WARNING (aurora-mysql-mariadb-auth): The source engine is MySQL 8 and its accounts do not move. WARNING (aurora-mysql-mariadb-json): MariaDB stores JSON as text, not in a binary format as MySQL: its JSON data type is an alias for LONGTEXT, so the JSON columns of the source become text columns and JSON values are compared as strings, where MySQL compares them as JSON values. +3 more |
| `module.retail_app_ecs.module.catalog_service.aws_ecs_service.this` | `module.retail_app_ecs.module.catalog_service` | REPLATFORM | LOW | Containers already exist; ECS task definitions and services are rewritten as Kubernetes Deployments/Services on SKE (or pushed to Cloud Foundry for simple web apps). WARNING (ecs-service-discovery): Services find each other through Cloud Map / Service Connect; on SKE this becomes Kubernetes Services and DNS. WARNING (source-provider-unpinned): root: source-provider-unpinned:aws WARNING (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret_version.catalog_db (aws_secretsmanager_secret_version), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_ecs_service does not read aws_secretsmanager_secret_version, so what the reference becomes is not assessed. +1 more |
| `module.retail_app_ecs.module.orders_service.aws_ecs_service.this` | `module.retail_app_ecs.module.orders_service` | REPLATFORM | LOW | Containers already exist; ECS task definitions and services are rewritten as Kubernetes Deployments/Services on SKE (or pushed to Cloud Foundry for simple web apps). WARNING (ecs-service-discovery): Services find each other through Cloud Map / Service Connect; on SKE this becomes Kubernetes Services and DNS. WARNING (source-provider-unpinned): root: source-provider-unpinned:aws WARNING (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret_version.mq (aws_secretsmanager_secret_version), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_ecs_service does not read aws_secretsmanager_secret_version, so what the reference becomes is not assessed. +1 more |
| `module.retail_app_ecs.aws_ecs_cluster.cluster` | `module.retail_app_ecs` | REPLATFORM | MEDIUM | Containers already exist; ECS task definitions and services are rewritten as Kubernetes Deployments/Services on SKE (or pushed to Cloud Foundry for simple web apps). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.dependencies.module.orders_rds.aws_rds_cluster.this` | `module.dependencies.module.orders_rds` | REPLATFORM | MEDIUM | Aurora PostgreSQL is wire-compatible PostgreSQL; it lands on PostgreSQL Flex. WARNING (aurora-storage-encrypted): Storage is encrypted at rest with an AWS-managed key; the PostgreSQL Flex encryption block covers customer keys only (the pinned STACKIT provider) and STACKIT does not state the default without it: no STACKIT fact is documented, so at-rest encryption is UNKNOWN until the PostgreSQL Flex product pages or a test on a STACKIT project state it. WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.checkout_service.aws_ecs_service.this` | `module.retail_app_ecs.module.checkout_service` | REPLATFORM | MEDIUM | Containers already exist; ECS task definitions and services are rewritten as Kubernetes Deployments/Services on SKE (or pushed to Cloud Foundry for simple web apps). WARNING (ecs-service-discovery): Services find each other through Cloud Map / Service Connect; on SKE this becomes Kubernetes Services and DNS. WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.ui_service.aws_ecs_service.this` | `module.retail_app_ecs.module.ui_service` | REPLATFORM | MEDIUM | Containers already exist; ECS task definitions and services are rewritten as Kubernetes Deployments/Services on SKE (or pushed to Cloud Foundry for simple web apps). WARNING (ecs-service-discovery): Services find each other through Cloud Map / Service Connect; on SKE this becomes Kubernetes Services and DNS. WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.carts_service.aws_iam_role.task_role` | `module.retail_app_ecs.module.carts_service` | RECONFIGURE | LOW | Execution role of an application (Lambda function or ECS task). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws WARNING (linked-dependency-unread): This unit names module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this (aws_dynamodb_table), whose own decision the target does not carry (it is REDESIGN), and the semantic contract of aws_iam_role does not read aws_dynamodb_table, so what the reference becomes is not assessed. |
| `module.retail_app_ecs.module.checkout_service.aws_iam_role.task_role` | `module.retail_app_ecs.module.checkout_service` | RECONFIGURE | LOW | Execution role of an application (Lambda function or ECS task). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws WARNING (linked-dependency-unread): This unit names module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this (aws_dynamodb_table), whose own decision the target does not carry (it is REDESIGN), and the semantic contract of aws_iam_role does not read aws_dynamodb_table, so what the reference becomes is not assessed. |
| `module.retail_app_ecs.module.catalog_service.aws_iam_role.task_execution_role` | `module.retail_app_ecs.module.catalog_service` | RECONFIGURE | LOW | Execution role of an application (Lambda function or ECS task). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws WARNING (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret.catalog_db (aws_secretsmanager_secret), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_iam_role does not read aws_secretsmanager_secret, so what the reference becomes is not assessed. WARNING (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch (aws_secretsmanager_secret), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_iam_role does not read aws_secretsmanager_secret, so what the reference becomes is not assessed. |
| `module.retail_app_ecs.module.orders_service.aws_iam_role.task_execution_role` | `module.retail_app_ecs.module.orders_service` | RECONFIGURE | LOW | Execution role of an application (Lambda function or ECS task). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws WARNING (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret.mq (aws_secretsmanager_secret), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_iam_role does not read aws_secretsmanager_secret, so what the reference becomes is not assessed. WARNING (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret.orders_db (aws_secretsmanager_secret), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_iam_role does not read aws_secretsmanager_secret, so what the reference becomes is not assessed. |
| `module.vpc.module.vpc.aws_route_table.private` | `module.vpc.module.vpc` | RECONFIGURE | LOW | A route of the table sends traffic to a NAT gateway (the others, if any, to an internet gateway), and the draft's project is outside a Network Area. WARNING (topology-route-table-not-drafted): This route table is created with count or for_each. WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this route table names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (rt-private-subnet-association): A subnet uses a route table whose default route goes through a NAT gateway — a private subnet in AWS. +1 more |
| `module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks` | `module.retail_app_ecs` | RECONFIGURE | MEDIUM | Log groups become label sets in a STACKIT Logs instance (a label-based Grafana Loki store written over OTLP or the Loki API, retention in days for the whole instance). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.aws_kms_key.cmk` | `module.retail_app_ecs` | RECONFIGURE | MEDIUM | Keys are re-created in STACKIT KMS (keyring + key); key material generated in AWS KMS cannot be exported, so encrypted data is re-encrypted during migration. WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.carts_service.aws_iam_role.task_execution_role` | `module.retail_app_ecs.module.carts_service` | RECONFIGURE | MEDIUM | Execution role of an application (Lambda function or ECS task). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.checkout_service.aws_iam_role.task_execution_role` | `module.retail_app_ecs.module.checkout_service` | RECONFIGURE | MEDIUM | Execution role of an application (Lambda function or ECS task). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.ui_service.aws_iam_role.task_execution_role` | `module.retail_app_ecs.module.ui_service` | RECONFIGURE | MEDIUM | Execution role of an application (Lambda function or ECS task). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.vpc.module.vpc.aws_eip.nat` | `module.vpc.module.vpc` | RECONFIGURE | MEDIUM | This Elastic IP only exists for a NAT gateway; it goes away together with the NAT gateway. WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.vpc.module.vpc.aws_vpc.this` | `module.vpc.module.vpc` | RECONFIGURE | MEDIUM | STACKIT has no VPC container object in its GA model: each subnet becomes a stackit_network in a project, and networks that must talk to each other privately join a Network Area. WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: a resource of the estate (a subnet, route table, security group, network ACL, flow log, peering connection, a Cloud Control twin of those, ...) names a VPC by a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (vpc-main-table-undecided): The scan cannot say which route table is the main route table of this VPC: the VPC has count or for_each (or may be absent), an aws_main_route_table_association may name it through a value the scan cannot resolve (a variable, a literal ID, a conditional, a value from a module call), two resources set it (two main associations, or a main association and an aws_default_route_table on one VPC, which the provider documents as conflicting), or the table is a variable or lies outside the configuration. WARNING (vpc-default-sg-no-egress-rules): The adopted default security group states no egress rule. +1 more |
| `module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch` | `module.retail_app_ecs` | RECONFIGURE | MEDIUM | Secrets move to STACKIT Secrets Manager (a Vault-compatible KV store). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.alb.aws_security_group.this` | `module.retail_app_ecs.module.alb` | RECONFIGURE | MEDIUM | STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this security group names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (sg-egress-restricted): The source restricts egress (the AWS provider removes AWS's default allow-all egress rule; only the listed egress rules apply). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix` | `module.retail_app_ecs.module.alb_sg` | RECONFIGURE | MEDIUM | STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this security group names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws WARNING (sg-rule-not-rendered): At least one rule of this group is not in the draft as the source has it. |
| `module.retail_app_ecs.module.carts_service.aws_security_group.this` | `module.retail_app_ecs.module.carts_service` | RECONFIGURE | MEDIUM | STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this security group names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.catalog_service.aws_iam_role.task_role` | `module.retail_app_ecs.module.catalog_service` | RECONFIGURE | MEDIUM | Execution role of an application (Lambda function or ECS task). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.catalog_service.aws_security_group.this` | `module.retail_app_ecs.module.catalog_service` | RECONFIGURE | MEDIUM | STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this security group names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.checkout_service.aws_security_group.this` | `module.retail_app_ecs.module.checkout_service` | RECONFIGURE | MEDIUM | STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this security group names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.orders_service.aws_iam_role.task_role` | `module.retail_app_ecs.module.orders_service` | RECONFIGURE | MEDIUM | Execution role of an application (Lambda function or ECS task). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.orders_service.aws_security_group.this` | `module.retail_app_ecs.module.orders_service` | RECONFIGURE | MEDIUM | STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this security group names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.ui_service.aws_iam_role.task_role` | `module.retail_app_ecs.module.ui_service` | RECONFIGURE | MEDIUM | Execution role of an application (Lambda function or ECS task). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.module.ui_service.aws_security_group.this` | `module.retail_app_ecs.module.ui_service` | RECONFIGURE | MEDIUM | STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this security group names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.vpc.module.vpc.aws_nat_gateway.this` | `module.vpc.module.vpc` | RECONFIGURE | MEDIUM | STACKIT has no discrete NAT gateway resource. WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: a resource of the estate (a subnet, route table, security group, network ACL, flow log, peering connection, a Cloud Control twin of those, ...) names a VPC by a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.dependencies.aws_security_group.catalog_opensearch_sg` | `module.dependencies` | RECONFIGURE | MEDIUM | This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this security group names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (sg-egress-restricted): The source restricts egress (the AWS provider removes AWS's default allow-all egress rule; only the listed egress rules apply). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws +1 more |
| `module.dependencies.aws_security_group.mq` | `module.dependencies` | RECONFIGURE | MEDIUM | This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this security group names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (sg-egress-restricted): The source restricts egress (the AWS provider removes AWS's default allow-all egress rule; only the listed egress rules apply). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws +1 more |
| `module.dependencies.module.catalog_rds.aws_security_group.this` | `module.dependencies.module.catalog_rds` | RECONFIGURE | MEDIUM | This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this security group names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (sg-egress-restricted): The source restricts egress (the AWS provider removes AWS's default allow-all egress rule; only the listed egress rules apply). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws +1 more |
| `module.dependencies.module.checkout_elasticache_redis.module.aws_security_group.aws_security_group.cbd` | `module.dependencies.module.checkout_elasticache_redis.module.aws_security_group` | RECONFIGURE | MEDIUM | This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this security group names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws WARNING (sg-rule-not-rendered): At least one rule of this group is not in the draft as the source has it. |
| `module.dependencies.module.orders_rds.aws_security_group.this` | `module.dependencies.module.orders_rds` | RECONFIGURE | MEDIUM | This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this security group names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (sg-egress-restricted): The source restricts egress (the AWS provider removes AWS's default allow-all egress rule; only the listed egress rules apply). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws +1 more |
| `module.retail_app_ecs.module.alb.aws_lb.this` | `module.retail_app_ecs.module.alb` | RECONFIGURE | MEDIUM | An application load balancer maps to the STACKIT Application Load Balancer (HTTP/HTTPS listeners, target pools with health checks, optional WAF). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.dependencies.aws_mq_broker.mq` | `module.dependencies` | RECONFIGURE | MEDIUM | Same broker software: exchanges, queues and bindings are exported from the Amazon MQ definitions and imported into STACKIT RabbitMQ (the eu01 catalogue lists version 4.1, read 2026-10-18; STACKIT's lifecycle page, last updated 2026-03-11, lists 4.0 and no 4.1, so confirm the version the instance accepts before the cutover); clients change host and credentials, and the broker users are not carried (STACKIT generates the credentials). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws WARNING (engine-version-upgrade): Engine version UPGRADE: the source runs RabbitMQ 3.13 (engine_version); STACKIT RabbitMQ in eu01 offers 4.1 (service catalogue of eu01, read 2026-10-18), none of them the source's version. |
| `module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default` | `module.dependencies.module.checkout_elasticache_redis` | RECONFIGURE | MEDIUM | Redis/Valkey caches move to STACKIT Key Value Store (Valkey, Redis-protocol compatible, GA since August 2026). WARNING (redis-transit-encryption-off): The source cache runs without TLS (transit_encryption_enabled = false). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws WARNING (engine-version-upgrade): Engine version UPGRADE: the source runs Valkey 4.0.10 (engine_version); STACKIT Valkey in eu01 offers 8 (service catalogue of eu01, read 2026-10-18), none of them the source's version. |
| `module.retail_app_ecs.aws_secretsmanager_secret.catalog_db` | `module.retail_app_ecs` | RECONFIGURE | MEDIUM | Secrets move to STACKIT Secrets Manager (a Vault-compatible KV store). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.aws_secretsmanager_secret.mq` | `module.retail_app_ecs` | RECONFIGURE | MEDIUM | Secrets move to STACKIT Secrets Manager (a Vault-compatible KV store). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.retail_app_ecs.aws_secretsmanager_secret.orders_db` | `module.retail_app_ecs` | RECONFIGURE | MEDIUM | Secrets move to STACKIT Secrets Manager (a Vault-compatible KV store). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.vpc.module.vpc.aws_internet_gateway.this` | `module.vpc.module.vpc` | RECONFIGURE | MEDIUM | There is no internet-gateway object on STACKIT; a routed network with a gateway reaches the internet and inbound access is given per resource with public IPs and security groups. WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: a resource of the estate (a subnet, route table, security group, network ACL, flow log, peering connection, a Cloud Control twin of those, ...) names a VPC by a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.vpc.module.vpc.aws_route_table.public` | `module.vpc.module.vpc` | RECONFIGURE | MEDIUM | Every route of the table sends traffic to an internet gateway (a reference to an aws_internet_gateway, or an ID that is not a virtual private gateway's) and the draft's project is outside a Network Area. WARNING (topology-route-table-not-drafted): This route table is created with count or for_each. WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this route table names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws |
| `module.vpc.module.vpc.aws_subnet.private` | `module.vpc.module.vpc` | RECONFIGURE | MEDIUM | A subnet becomes a stackit_network with the same IPv4 prefix. WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this subnet names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws WARNING (subnet-egress-ipv4-unproven): PRIVATE_EGRESS_EQUIVALENCE_UNPROVEN (IPv4, not proven). |
| `module.vpc.module.vpc.aws_subnet.public` | `module.vpc.module.vpc` | RECONFIGURE | MEDIUM | A subnet becomes a stackit_network with the same IPv4 prefix. WARNING (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this subnet names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). WARNING (subnet-route-table-undecided): The scan cannot say which route table this subnet follows: a route table association may name it through a value the scan cannot resolve (a variable, a literal ID, a conditional, a value from a module call), an association names only some of its instances or repeats by a count or for_each that is not the subnet's own (aws_subnet.x[0].id for a counted subnet, fewer association instances than subnet instances), an association may create no instance (a count or for_each that a variable decides, count = var.on ? 1 : 0, whatever the variable's default: the subnet then follows the main route table), the VPC of the subnet or its main route table is not decided (count or for_each, two resources that set the main table, a main association and an aws_default_route_table on one VPC, a table or VPC outside the configuration). WARNING (source-provider-unpinned): root: source-provider-unpinned:aws +1 more |

## Unit mapping

### Compute

#### `module.retail_app_ecs.aws_ecs_cluster.cluster`

- **Source:** `aws_ecs_cluster` — ../../lib/ecs/cluster.tf:1
- **Module:** `module.retail_app_ecs` (../../lib/ecs)
- **Candidate target:** STACKIT Kubernetes Engine (SKE) (`stackit_ske_cluster`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Target lifecycle:** provider GA · SKE Kubernetes versions as of 2026-10-08: 1 SUPPORTED, 1 EXPIRING, 2 EXPIRED, 1 UNKNOWN (1.34 expires 2026-10-14) — see "Target lifecycle"
- **Classification:** REPLATFORM · **Confidence:** MEDIUM · rule `aws.ecs/ecs-to-ske`
- **Feasibility:** SUPPORTED — blocked by a point the scan could not establish
- **Why:** Containers already exist; ECS task definitions and services are rewritten as Kubernetes Deployments/Services on SKE (or pushed to Cloud Foundry for simple web apps).
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Property accounting:** 3 of 3 meaningful properties accounted
- **Review:**
  - [ ] Translate task definitions (CPU/memory, env, secrets, health checks) into Kubernetes manifests.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; found compatible through 0.121.0 by the release check): https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/ske_cluster

#### `module.retail_app_ecs.module.carts_service.aws_ecs_service.this`

- **Source:** `aws_ecs_service` — ../../lib/ecs/service/ecs.tf:136
- **Module:** `module.retail_app_ecs.module.carts_service` (./service)
- **Candidate target:** STACKIT Kubernetes Engine (SKE) (`stackit_ske_cluster`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Target lifecycle:** provider GA · SKE Kubernetes versions as of 2026-10-08: 1 SUPPORTED, 1 EXPIRING, 2 EXPIRED, 1 UNKNOWN (1.34 expires 2026-10-14) — see "Target lifecycle"
- **Classification:** REPLATFORM · **Confidence:** LOW · rule `aws.ecs/ecs-to-ske`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (check ecs-service-discovery, semantic service-discovery, semantic task-definition, semantic service-task-definition and 13 more); a point the scan could not establish
- **Why:** Containers already exist; ECS task definitions and services are rewritten as Kubernetes Deployments/Services on SKE (or pushed to Cloud Foundry for simple web apps).
- **Includes:** `module.retail_app_ecs.module.carts_service.aws_ecs_task_definition.this`
- **Depends on:** `module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this`, `module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`, `module.retail_app_ecs.aws_ecs_cluster.cluster`, `module.retail_app_ecs.module.carts_service.aws_iam_role.task_execution_role`, `module.retail_app_ecs.module.carts_service.aws_iam_role.task_role`, `module.retail_app_ecs.module.carts_service.aws_security_group.this`, `module.vpc.module.vpc.aws_subnet.private`, `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (ecs-service-discovery): Services find each other through Cloud Map / Service Connect; on SKE this becomes Kubernetes Services and DNS.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (linked-dependency-unread): This unit names module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this (aws_dynamodb_table), whose own decision the target does not carry (it is REDESIGN), and the semantic contract of aws_ecs_service does not read aws_dynamodb_table, so what the reference becomes is not assessed.
- **Critical semantics left to you to decide or accept (15):** service-connect-values, service-desired-count, service-discovery, service-execute-command, service-network-placement, service-public-ip-setting, service-task-definition, task-definition and 7 more (engineering/analysis-details.md) (**not automation-eligible**: no property the unit sets is read by linked-dependency:aws_dynamodb_table, service-discovery)
- **Property accounting:** 24 of 24 meaningful properties accounted
- **16 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (10; REVIEW 10): `network_configuration.assign_public_ip`, `network_configuration.security_groups`, `network_configuration.subnets`, `service_connect_configuration.enabled`, `service_connect_configuration.namespace` and 5 more — NOT CARRIED (module.retail_app_ecs.module.carts_service.aws_ecs_service.this): network_configuration — the tasks have their own network interface in the subnets and security groups of this block (awsvpc); pods use the cluster network and the security group rules are not translated into network policies — decide the network policy of the pods.
  - identity access (4; REVIEW 4): `enable_execute_command`, `task_definition`, `module.retail_app_ecs.module.carts_service.aws_ecs_task_definition.this.execution_role_arn`, `module.retail_app_ecs.module.carts_service.aws_ecs_task_definition.this.task_role_arn` — NOT CARRIED (module.retail_app_ecs.module.carts_service.aws_ecs_service.this): enable_execute_command = true, tags, wait_for_steady_state = true — a service setting with no counterpart in the draft manifests: Kubernetes has its own rollout (maxSurge, maxUnavailable), health, scheduling and exec behaviour, and tags are not labels here.
  - availability durability (1; REVIEW 1): `desired_count`
  - secret handling (1; REVIEW 1): `module.retail_app_ecs.module.carts_service.aws_ecs_task_definition.this.container_definitions`
- **Why those are open, and what closes them:**
  - `service-discovery`: A check of the knowledge base (ecs service discovery) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The setting states how ECS services find each other: AWS Cloud Map registries and namespaces, or ECS Service Connect. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded. A person replaces the lookups with Kubernetes Services and cluster DNS on SKE.
  - `task-definition`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The ECS task definition: the containers a service runs, with their CPU and memory, environment, secrets and health checks. Closes when: A person translates the task definition into Kubernetes Deployments and Services on SKE (CPU and memory, environment, secrets and health checks become manifest fields); the rule names a Cloud Foundry push as the other way for a simple web app.
  - `service-task-definition`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The task definition the service runs (family:revision or ARN) becomes the Deployment's pod template; ecs_service.task_definition names it as a string, the definition itself is a separate resource a person translates. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-desired-count`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. desired_count is the number of tasks ECS keeps running (ecs_service docs: 'Number of instances of the task definition to place and keep running'); on SKE it becomes Deployment replicas or a HorizontalPodAutoscaler floor. The draft writes it as the replicas of the Deployment in kubernetes/<service>/manifests.yaml when it is a literal number (a HorizontalPodAutoscaler owns the count where the service has a scaling target and policy the draft translates; a number that is not visible statically is a REQUIRED_ token) — a person confirms the number, REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-execute-command`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. ECS Exec opens a shell in a running task; kubectl exec (and who may use it through RBAC) is the counterpart and is not part of the draft. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-network-placement`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The subnets and security groups the tasks' network interfaces use (awsvpc mode); on SKE pods take the cluster's network and NetworkPolicies decide reachability — a person re-expresses the security group rules. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - and 9 kinds of reason more (engineering/analysis-details.md)
- **Review:**
  - [ ] Translate task definitions (CPU/memory, env, secrets, health checks) into Kubernetes manifests.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; found compatible through 0.121.0 by the release check): https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/ske_cluster

#### `module.retail_app_ecs.module.catalog_service.aws_ecs_service.this`

- **Source:** `aws_ecs_service` — ../../lib/ecs/service/ecs.tf:136
- **Module:** `module.retail_app_ecs.module.catalog_service` (./service)
- **Candidate target:** STACKIT Kubernetes Engine (SKE) (`stackit_ske_cluster`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Target lifecycle:** provider GA · SKE Kubernetes versions as of 2026-10-08: 1 SUPPORTED, 1 EXPIRING, 2 EXPIRED, 1 UNKNOWN (1.34 expires 2026-10-14) — see "Target lifecycle"
- **Classification:** REPLATFORM · **Confidence:** LOW · rule `aws.ecs/ecs-to-ske`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (check ecs-service-discovery, semantic service-discovery, semantic task-definition, semantic service-task-definition and 13 more); a point the scan could not establish
- **Why:** Containers already exist; ECS task definitions and services are rewritten as Kubernetes Deployments/Services on SKE (or pushed to Cloud Foundry for simple web apps).
- **Includes:** `module.retail_app_ecs.module.catalog_service.aws_ecs_task_definition.this`
- **Depends on:** `module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this`, `module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`, `module.retail_app_ecs.aws_ecs_cluster.cluster`, `module.retail_app_ecs.aws_secretsmanager_secret.catalog_db`, `module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch`, `module.retail_app_ecs.module.catalog_service.aws_iam_role.task_execution_role`, `module.retail_app_ecs.module.catalog_service.aws_iam_role.task_role`, `module.retail_app_ecs.module.catalog_service.aws_security_group.this`, `module.vpc.module.vpc.aws_subnet.private`, `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (ecs-service-discovery): Services find each other through Cloud Map / Service Connect; on SKE this becomes Kubernetes Services and DNS.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret_version.catalog_db (aws_secretsmanager_secret_version), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_ecs_service does not read aws_secretsmanager_secret_version, so what the reference becomes is not assessed.
- **WARNING** (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret_version.catalog_opensearch (aws_secretsmanager_secret_version), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_ecs_service does not read aws_secretsmanager_secret_version, so what the reference becomes is not assessed.
- **Critical semantics left to you to decide or accept (15):** service-connect-values, service-desired-count, service-discovery, service-execute-command, service-network-placement, service-public-ip-setting, service-task-definition, task-definition and 7 more (engineering/analysis-details.md) (**not automation-eligible**: no property the unit sets is read by linked-dependency:aws_secretsmanager_secret_version, service-discovery)
- **Property accounting:** 24 of 24 meaningful properties accounted
- **16 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (10; REVIEW 10): `network_configuration.assign_public_ip`, `network_configuration.security_groups`, `network_configuration.subnets`, `service_connect_configuration.enabled`, `service_connect_configuration.namespace` and 5 more — NOT CARRIED (module.retail_app_ecs.module.catalog_service.aws_ecs_service.this): network_configuration — the tasks have their own network interface in the subnets and security groups of this block (awsvpc); pods use the cluster network and the security group rules are not translated into network policies — decide the network policy of the pods.
  - identity access (4; REVIEW 4): `enable_execute_command`, `task_definition`, `module.retail_app_ecs.module.catalog_service.aws_ecs_task_definition.this.execution_role_arn`, `module.retail_app_ecs.module.catalog_service.aws_ecs_task_definition.this.task_role_arn` — NOT CARRIED (module.retail_app_ecs.module.catalog_service.aws_ecs_service.this): enable_execute_command = true, tags, wait_for_steady_state = true — a service setting with no counterpart in the draft manifests: Kubernetes has its own rollout (maxSurge, maxUnavailable), health, scheduling and exec behaviour, and tags are not labels here.
  - availability durability (1; REVIEW 1): `desired_count`
  - secret handling (1; REVIEW 1): `module.retail_app_ecs.module.catalog_service.aws_ecs_task_definition.this.container_definitions`
- **Why those are open, and what closes them:**
  - `service-discovery`: A check of the knowledge base (ecs service discovery) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The setting states how ECS services find each other: AWS Cloud Map registries and namespaces, or ECS Service Connect. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded. A person replaces the lookups with Kubernetes Services and cluster DNS on SKE.
  - `task-definition`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The ECS task definition: the containers a service runs, with their CPU and memory, environment, secrets and health checks. Closes when: A person translates the task definition into Kubernetes Deployments and Services on SKE (CPU and memory, environment, secrets and health checks become manifest fields); the rule names a Cloud Foundry push as the other way for a simple web app.
  - `service-task-definition`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The task definition the service runs (family:revision or ARN) becomes the Deployment's pod template; ecs_service.task_definition names it as a string, the definition itself is a separate resource a person translates. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-desired-count`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. desired_count is the number of tasks ECS keeps running (ecs_service docs: 'Number of instances of the task definition to place and keep running'); on SKE it becomes Deployment replicas or a HorizontalPodAutoscaler floor. The draft writes it as the replicas of the Deployment in kubernetes/<service>/manifests.yaml when it is a literal number (a HorizontalPodAutoscaler owns the count where the service has a scaling target and policy the draft translates; a number that is not visible statically is a REQUIRED_ token) — a person confirms the number, REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-execute-command`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. ECS Exec opens a shell in a running task; kubectl exec (and who may use it through RBAC) is the counterpart and is not part of the draft. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-network-placement`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The subnets and security groups the tasks' network interfaces use (awsvpc mode); on SKE pods take the cluster's network and NetworkPolicies decide reachability — a person re-expresses the security group rules. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - and 9 kinds of reason more (engineering/analysis-details.md)
- **Review:**
  - [ ] Translate task definitions (CPU/memory, env, secrets, health checks) into Kubernetes manifests.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; found compatible through 0.121.0 by the release check): https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/ske_cluster

#### `module.retail_app_ecs.module.orders_service.aws_ecs_service.this`

- **Source:** `aws_ecs_service` — ../../lib/ecs/service/ecs.tf:136
- **Module:** `module.retail_app_ecs.module.orders_service` (./service)
- **Candidate target:** STACKIT Kubernetes Engine (SKE) (`stackit_ske_cluster`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Target lifecycle:** provider GA · SKE Kubernetes versions as of 2026-10-08: 1 SUPPORTED, 1 EXPIRING, 2 EXPIRED, 1 UNKNOWN (1.34 expires 2026-10-14) — see "Target lifecycle"
- **Classification:** REPLATFORM · **Confidence:** LOW · rule `aws.ecs/ecs-to-ske`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (check ecs-service-discovery, semantic service-discovery, semantic task-definition, semantic service-task-definition and 13 more); a point the scan could not establish
- **Why:** Containers already exist; ECS task definitions and services are rewritten as Kubernetes Deployments/Services on SKE (or pushed to Cloud Foundry for simple web apps).
- **Includes:** `module.retail_app_ecs.module.orders_service.aws_ecs_task_definition.this`
- **Depends on:** `module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`, `module.retail_app_ecs.aws_ecs_cluster.cluster`, `module.retail_app_ecs.aws_secretsmanager_secret.mq`, `module.retail_app_ecs.aws_secretsmanager_secret.orders_db`, `module.retail_app_ecs.module.orders_service.aws_iam_role.task_execution_role`, `module.retail_app_ecs.module.orders_service.aws_iam_role.task_role`, `module.retail_app_ecs.module.orders_service.aws_security_group.this`, `module.vpc.module.vpc.aws_subnet.private`, `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (ecs-service-discovery): Services find each other through Cloud Map / Service Connect; on SKE this becomes Kubernetes Services and DNS.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret_version.mq (aws_secretsmanager_secret_version), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_ecs_service does not read aws_secretsmanager_secret_version, so what the reference becomes is not assessed.
- **WARNING** (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret_version.orders_db (aws_secretsmanager_secret_version), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_ecs_service does not read aws_secretsmanager_secret_version, so what the reference becomes is not assessed.
- **Critical semantics left to you to decide or accept (15):** service-connect-values, service-desired-count, service-discovery, service-execute-command, service-network-placement, service-public-ip-setting, service-task-definition, task-definition and 7 more (engineering/analysis-details.md) (**not automation-eligible**: no property the unit sets is read by linked-dependency:aws_secretsmanager_secret_version, service-discovery)
- **Property accounting:** 24 of 24 meaningful properties accounted
- **16 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (10; REVIEW 10): `network_configuration.assign_public_ip`, `network_configuration.security_groups`, `network_configuration.subnets`, `service_connect_configuration.enabled`, `service_connect_configuration.namespace` and 5 more — NOT CARRIED (module.retail_app_ecs.module.orders_service.aws_ecs_service.this): network_configuration — the tasks have their own network interface in the subnets and security groups of this block (awsvpc); pods use the cluster network and the security group rules are not translated into network policies — decide the network policy of the pods.
  - identity access (4; REVIEW 4): `enable_execute_command`, `task_definition`, `module.retail_app_ecs.module.orders_service.aws_ecs_task_definition.this.execution_role_arn`, `module.retail_app_ecs.module.orders_service.aws_ecs_task_definition.this.task_role_arn` — NOT CARRIED (module.retail_app_ecs.module.orders_service.aws_ecs_service.this): enable_execute_command = true, tags, wait_for_steady_state = true — a service setting with no counterpart in the draft manifests: Kubernetes has its own rollout (maxSurge, maxUnavailable), health, scheduling and exec behaviour, and tags are not labels here.
  - availability durability (1; REVIEW 1): `desired_count`
  - secret handling (1; REVIEW 1): `module.retail_app_ecs.module.orders_service.aws_ecs_task_definition.this.container_definitions`
- **Why those are open, and what closes them:**
  - `service-discovery`: A check of the knowledge base (ecs service discovery) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The setting states how ECS services find each other: AWS Cloud Map registries and namespaces, or ECS Service Connect. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded. A person replaces the lookups with Kubernetes Services and cluster DNS on SKE.
  - `task-definition`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The ECS task definition: the containers a service runs, with their CPU and memory, environment, secrets and health checks. Closes when: A person translates the task definition into Kubernetes Deployments and Services on SKE (CPU and memory, environment, secrets and health checks become manifest fields); the rule names a Cloud Foundry push as the other way for a simple web app.
  - `service-task-definition`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The task definition the service runs (family:revision or ARN) becomes the Deployment's pod template; ecs_service.task_definition names it as a string, the definition itself is a separate resource a person translates. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-desired-count`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. desired_count is the number of tasks ECS keeps running (ecs_service docs: 'Number of instances of the task definition to place and keep running'); on SKE it becomes Deployment replicas or a HorizontalPodAutoscaler floor. The draft writes it as the replicas of the Deployment in kubernetes/<service>/manifests.yaml when it is a literal number (a HorizontalPodAutoscaler owns the count where the service has a scaling target and policy the draft translates; a number that is not visible statically is a REQUIRED_ token) — a person confirms the number, REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-execute-command`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. ECS Exec opens a shell in a running task; kubectl exec (and who may use it through RBAC) is the counterpart and is not part of the draft. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-network-placement`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The subnets and security groups the tasks' network interfaces use (awsvpc mode); on SKE pods take the cluster's network and NetworkPolicies decide reachability — a person re-expresses the security group rules. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - and 9 kinds of reason more (engineering/analysis-details.md)
- **Review:**
  - [ ] Translate task definitions (CPU/memory, env, secrets, health checks) into Kubernetes manifests.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; found compatible through 0.121.0 by the release check): https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/ske_cluster

#### `module.retail_app_ecs.module.checkout_service.aws_ecs_service.this`

- **Source:** `aws_ecs_service` — ../../lib/ecs/service/ecs.tf:136
- **Module:** `module.retail_app_ecs.module.checkout_service` (./service)
- **Candidate target:** STACKIT Kubernetes Engine (SKE) (`stackit_ske_cluster`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Target lifecycle:** provider GA · SKE Kubernetes versions as of 2026-10-08: 1 SUPPORTED, 1 EXPIRING, 2 EXPIRED, 1 UNKNOWN (1.34 expires 2026-10-14) — see "Target lifecycle"
- **Classification:** REPLATFORM · **Confidence:** MEDIUM · rule `aws.ecs/ecs-to-ske`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (check ecs-service-discovery, semantic service-discovery, semantic task-definition, semantic service-task-definition and 12 more); a point the scan could not establish
- **Why:** Containers already exist; ECS task definitions and services are rewritten as Kubernetes Deployments/Services on SKE (or pushed to Cloud Foundry for simple web apps).
- **Includes:** `module.retail_app_ecs.module.checkout_service.aws_ecs_task_definition.this`
- **Depends on:** `module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default`, `module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`, `module.retail_app_ecs.aws_ecs_cluster.cluster`, `module.retail_app_ecs.module.checkout_service.aws_iam_role.task_execution_role`, `module.retail_app_ecs.module.checkout_service.aws_iam_role.task_role`, `module.retail_app_ecs.module.checkout_service.aws_security_group.this`, `module.retail_app_ecs.module.orders_service.aws_ecs_service.this`, `module.vpc.module.vpc.aws_subnet.private`, `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (ecs-service-discovery): Services find each other through Cloud Map / Service Connect; on SKE this becomes Kubernetes Services and DNS.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (15):** service-discovery, task-definition, service-task-definition, service-desired-count, service-execute-command, service-network-placement, service-public-ip-setting, service-connect-values and 7 more (engineering/analysis-details.md) (**not automation-eligible**: no property the unit sets is read by service-discovery)
- **Property accounting:** 24 of 24 meaningful properties accounted
- **16 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (10; REVIEW 10): `network_configuration.assign_public_ip`, `network_configuration.security_groups`, `network_configuration.subnets`, `service_connect_configuration.enabled`, `service_connect_configuration.namespace` and 5 more — NOT CARRIED (module.retail_app_ecs.module.checkout_service.aws_ecs_service.this): network_configuration — the tasks have their own network interface in the subnets and security groups of this block (awsvpc); pods use the cluster network and the security group rules are not translated into network policies — decide the network policy of the pods.
  - identity access (4; REVIEW 4): `enable_execute_command`, `task_definition`, `module.retail_app_ecs.module.checkout_service.aws_ecs_task_definition.this.execution_role_arn`, `module.retail_app_ecs.module.checkout_service.aws_ecs_task_definition.this.task_role_arn` — NOT CARRIED (module.retail_app_ecs.module.checkout_service.aws_ecs_service.this): enable_execute_command = true, tags, wait_for_steady_state = true — a service setting with no counterpart in the draft manifests: Kubernetes has its own rollout (maxSurge, maxUnavailable), health, scheduling and exec behaviour, and tags are not labels here.
  - availability durability (1; REVIEW 1): `desired_count`
  - secret handling (1; REVIEW 1): `module.retail_app_ecs.module.checkout_service.aws_ecs_task_definition.this.container_definitions`
- **Why those are open, and what closes them:**
  - `service-discovery`: A check of the knowledge base (ecs service discovery) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The setting states how ECS services find each other: AWS Cloud Map registries and namespaces, or ECS Service Connect. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded. A person replaces the lookups with Kubernetes Services and cluster DNS on SKE.
  - `task-definition`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The ECS task definition: the containers a service runs, with their CPU and memory, environment, secrets and health checks. Closes when: A person translates the task definition into Kubernetes Deployments and Services on SKE (CPU and memory, environment, secrets and health checks become manifest fields); the rule names a Cloud Foundry push as the other way for a simple web app.
  - `service-task-definition`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The task definition the service runs (family:revision or ARN) becomes the Deployment's pod template; ecs_service.task_definition names it as a string, the definition itself is a separate resource a person translates. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-desired-count`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. desired_count is the number of tasks ECS keeps running (ecs_service docs: 'Number of instances of the task definition to place and keep running'); on SKE it becomes Deployment replicas or a HorizontalPodAutoscaler floor. The draft writes it as the replicas of the Deployment in kubernetes/<service>/manifests.yaml when it is a literal number (a HorizontalPodAutoscaler owns the count where the service has a scaling target and policy the draft translates; a number that is not visible statically is a REQUIRED_ token) — a person confirms the number, REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-execute-command`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. ECS Exec opens a shell in a running task; kubectl exec (and who may use it through RBAC) is the counterpart and is not part of the draft. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-network-placement`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The subnets and security groups the tasks' network interfaces use (awsvpc mode); on SKE pods take the cluster's network and NetworkPolicies decide reachability — a person re-expresses the security group rules. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - and 9 kinds of reason more (engineering/analysis-details.md)
- **Review:**
  - [ ] Translate task definitions (CPU/memory, env, secrets, health checks) into Kubernetes manifests.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; found compatible through 0.121.0 by the release check): https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/ske_cluster

#### `module.retail_app_ecs.module.ui_service.aws_ecs_service.this`

- **Source:** `aws_ecs_service` — ../../lib/ecs/service/ecs.tf:136
- **Module:** `module.retail_app_ecs.module.ui_service` (./service)
- **Candidate target:** STACKIT Kubernetes Engine (SKE) (`stackit_ske_cluster`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Target lifecycle:** provider GA · SKE Kubernetes versions as of 2026-10-08: 1 SUPPORTED, 1 EXPIRING, 2 EXPIRED, 1 UNKNOWN (1.34 expires 2026-10-14) — see "Target lifecycle"
- **Classification:** REPLATFORM · **Confidence:** MEDIUM · rule `aws.ecs/ecs-to-ske`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (check ecs-service-discovery, semantic service-discovery, semantic task-definition, semantic service-task-definition and 13 more); a point the scan could not establish
- **Why:** Containers already exist; ECS task definitions and services are rewritten as Kubernetes Deployments/Services on SKE (or pushed to Cloud Foundry for simple web apps).
- **Includes:** `module.retail_app_ecs.module.ui_service.aws_ecs_task_definition.this`
- **Depends on:** `module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`, `module.retail_app_ecs.aws_ecs_cluster.cluster`, `module.retail_app_ecs.module.carts_service.aws_ecs_service.this`, `module.retail_app_ecs.module.catalog_service.aws_ecs_service.this`, `module.retail_app_ecs.module.checkout_service.aws_ecs_service.this`, `module.retail_app_ecs.module.orders_service.aws_ecs_service.this`, `module.retail_app_ecs.module.ui_service.aws_iam_role.task_execution_role`, `module.retail_app_ecs.module.ui_service.aws_iam_role.task_role`, `module.retail_app_ecs.module.ui_service.aws_security_group.this`, `module.vpc.module.vpc.aws_subnet.private`, `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (ecs-service-discovery): Services find each other through Cloud Map / Service Connect; on SKE this becomes Kubernetes Services and DNS.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (16):** service-discovery, task-definition, service-task-definition, service-desired-count, service-execute-command, service-load-balancer-target, service-network-placement, service-public-ip-setting and 8 more (engineering/analysis-details.md) (**not automation-eligible**: no property the unit sets is read by service-discovery)
- **Property accounting:** 27 of 27 meaningful properties accounted
- **19 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (13; REVIEW 13): `load_balancer.container_name`, `load_balancer.container_port`, `load_balancer.target_group_arn`, `network_configuration.assign_public_ip`, `network_configuration.security_groups` and 8 more — NOT CARRIED (module.retail_app_ecs.module.ui_service.aws_ecs_service.this): network_configuration — the tasks have their own network interface in the subnets and security groups of this block (awsvpc); pods use the cluster network and the security group rules are not translated into network policies — decide the network policy of the pods.
  - identity access (4; REVIEW 4): `enable_execute_command`, `task_definition`, `module.retail_app_ecs.module.ui_service.aws_ecs_task_definition.this.execution_role_arn`, `module.retail_app_ecs.module.ui_service.aws_ecs_task_definition.this.task_role_arn` — NOT CARRIED (module.retail_app_ecs.module.ui_service.aws_ecs_service.this): enable_execute_command = true, tags, wait_for_steady_state = true — a service setting with no counterpart in the draft manifests: Kubernetes has its own rollout (maxSurge, maxUnavailable), health, scheduling and exec behaviour, and tags are not labels here.
  - availability durability (1; REVIEW 1): `desired_count`
  - secret handling (1; REVIEW 1): `module.retail_app_ecs.module.ui_service.aws_ecs_task_definition.this.container_definitions`
- **Why those are open, and what closes them:**
  - `service-discovery`: A check of the knowledge base (ecs service discovery) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The setting states how ECS services find each other: AWS Cloud Map registries and namespaces, or ECS Service Connect. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded. A person replaces the lookups with Kubernetes Services and cluster DNS on SKE.
  - `task-definition`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The ECS task definition: the containers a service runs, with their CPU and memory, environment, secrets and health checks. Closes when: A person translates the task definition into Kubernetes Deployments and Services on SKE (CPU and memory, environment, secrets and health checks become manifest fields); the rule names a Cloud Foundry push as the other way for a simple web app.
  - `service-task-definition`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The task definition the service runs (family:revision or ARN) becomes the Deployment's pod template; ecs_service.task_definition names it as a string, the definition itself is a separate resource a person translates. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-desired-count`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. desired_count is the number of tasks ECS keeps running (ecs_service docs: 'Number of instances of the task definition to place and keep running'); on SKE it becomes Deployment replicas or a HorizontalPodAutoscaler floor. The draft writes it as the replicas of the Deployment in kubernetes/<service>/manifests.yaml when it is a literal number (a HorizontalPodAutoscaler owns the count where the service has a scaling target and policy the draft translates; a number that is not visible statically is a REQUIRED_ token) — a person confirms the number, REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-execute-command`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. ECS Exec opens a shell in a running task; kubectl exec (and who may use it through RBAC) is the counterpart and is not part of the draft. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `service-load-balancer-target`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The setting states which container and port receive the load balancer's traffic, the target group or classic load balancer name, and the blue/green listener rules and role: the wiring becomes a Kubernetes Service / Ingress selector and a STACKIT load balancer target pool, written by a person (the draft has no service block to carry it). Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - and 10 kinds of reason more (engineering/analysis-details.md)
- **Review:**
  - [ ] Translate task definitions (CPU/memory, env, secrets, health checks) into Kubernetes manifests.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; found compatible through 0.121.0 by the release check): https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/ske_cluster

### Data

#### `module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this`

- **Source:** `aws_dynamodb_table` — .terraform/modules/dependencies.dynamodb_carts/main.tf:1
- **Module:** `module.dependencies.module.dynamodb_carts` (terraform-aws-modules/dynamodb-table/aws 3.3.0)
- **Candidate target:** STACKIT MongoDB Flex (alternative — data-model redesign; PostgreSQL Flex JSONB is the other option) (`stackit_mongodbflex_instance`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Classification:** REDESIGN · **Confidence:** MEDIUM · rule `aws.dynamodb_table/dynamodb`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (semantic key-schema, semantic index-projection-and-name, semantic encryption-at-rest, semantic point-in-time-recovery and 4 more); a point the scan could not establish
- **Why:** There is no DynamoDB-compatible service on STACKIT. The access layer is rewritten against a document store (MongoDB Flex) or relational JSONB (PostgreSQL Flex); key design, capacity modes and conditional writes do not carry over. The draft is an alternative, not an equivalent: one MongoDB Flex instance for the estate's tables, each table a collection with its keys and secondary indexes named as MongoDB indexes.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-DATA-MOVEMENT/module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this` (alias `convert:module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this:data:DATA_MOVEMENT`): Choose how the data of module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this moves from aws_dynamodb_table to STACKIT MongoDB Flex (stackit_mongodbflex_instance.dynamodb_tables): the method, the downtime it needs and the check that the copy is complete · StackToIT moves no data and writes no runbook for aws_dynamodb_table to STACKIT MongoDB Flex; the data-movement register lists module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this with the mechanism UNKNOWN, and the source states neither the size of the data nor the downtime the business tolerates nor the consistency the application needs
- **INFO** (dynamodb-secondary-indexes): Secondary indexes become MongoDB indexes on the collection; projections and the eventual consistency of global secondary indexes do not carry over.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (6):** key-schema, index-projection-and-name, encryption-at-rest, point-in-time-recovery, ttl, tc-dynamodb-table-name
- **Open choice(s) the draft could not make:** `DEC-GEN-CONVERT-DATA-MOVEMENT/module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this` (alias `convert:module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this:data:DATA_MOVEMENT`) — the source does not prove what it means and the draft holds a required variable without a default; a person decides, and until then the unit is **not automation-eligible**.
- **Property accounting:** 13 of 13 meaningful properties accounted
- **11 critical setting(s) left to you** — **not automation-eligible**:
  - encryption (1; REVIEW 1): `server_side_encryption.enabled`
  - backup retention (3; REVIEW 3): `point_in_time_recovery.enabled`, `ttl.attribute_name`, `ttl.enabled`
  - workload compatibility (2; REVIEW 2): `global_secondary_index.name`, `name`
  - data semantics (5; REVIEW 5): `attribute.name`, `attribute.type`, `global_secondary_index.hash_key`, `global_secondary_index.projection_type`, `hash_key` — TABLE module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this (.terraform/modules/dependencies.dynamodb_carts/main.tf:1) → collection "retail-store-ecs-carts": key id → _id (or a unique index on id); GSI idx_global_customerId {customerId: 1} → secondary index (strongly consistent in MongoDB; the projection is not needed); GSI projections and capacities → NOT CARRIED (a MongoDB index finds whole documents; capacity is flavor sizing); billing mode PAY_PER_REQUEST → NOT CARRIED (flavor sizing).
- **Why those are open, and what closes them:**
  - `key-schema`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The draft names the partition/sort key as the collection's unique index; the data model is rewritten by people. Closes when: A person designs the keys and indexes of the replacement collection (partition and sort key, attribute names and types, secondary index keys), because the draft names only the key as the collection's unique index.
  - `index-projection-and-name`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The projection of a secondary index (keys only, INCLUDE with its non_key_attributes, ALL) decides which attributes an index query can return, and the index name is what every Query / Scan on the index selects it by (API Query IndexName). STACKIT has no provider resource for an index (pinned provider), a person re-creates the indexes and the queries that name them in the chosen engine — REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `encryption-at-rest`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. It is not stated in stackit_mongodbflex_instance (no encryption attribute) whether STACKIT MongoDB Flex encrypts data at rest: REVIEW (the customer managed key setting reads the key). Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `point-in-time-recovery`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. MongoDB Flex has a point-in-time window in hours (options.point_in_time_window_hours); its maximum is not documented in the provider schema. The draft carries no value for it. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `ttl`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. DynamoDB TTL reads epoch seconds; a MongoDB TTL index expires only BSON dates, so the attribute changes type. The time-to-live check still fires only for enabled = true; the case handler REVIEW covers the other states. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `tc-dynamodb-table-name`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. aws_dynamodb_table.name: Held CRITICAL: the workload, its clients or its neighbours rely on it (an address, a name, a protocol or an execution contract). No semantic of this family has verified it as carried. Closes when: A person confirms the name the replacement collection carries on the target against what refers to the source name, or accepts the new name.
- **Review:**
  - [ ] Rewrite the data access layer against the MongoDB API (queries, conditional writes, transactions).
  - [ ] Size the instance from the tables' data volume and request load; capacity units do not translate.
- **Evidence** (validated against STACKIT product catalogue 2026-09-23 (no managed key-value NoSQL with a DynamoDB-compatible API); terraform-provider-stackit@0.116.0 (stackit_mongodbflex_instance: flavor, storage, replicas, backup schedule, point-in-time window; no encryption key attribute); STACKIT catalogue eu01 2026-09-24; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/databases/mongodb-flex/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/mongodbflex_instance

#### `module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this`

- **Source:** `aws_opensearch_domain` — .terraform/modules/dependencies.catalog_opensearch/main.tf:29
- **Module:** `module.dependencies.module.catalog_opensearch` (terraform-aws-modules/opensearch/aws 1.5.0)
- **Candidate target:** STACKIT OpenSearch (`stackit_opensearch_instance`, `stackit_opensearch_credential`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Classification:** REPLATFORM · **Confidence:** LOW · rule `aws.opensearch/opensearch`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (check engine-version-downgrade, semantic engine-version, semantic fine-grained-access, semantic private-endpoint and 11 more); a point the scan could not establish
- **Why:** Indices move to STACKIT OpenSearch by reindexing from the source; a snapshot restores only into the same or a newer OpenSearch version, never an older one, so a source newer than the version STACKIT offers cannot be restored (engine-version-downgrade finding). Cluster sizing becomes a STACKIT plan; UltraWarm/cold tiers and fine-grained IAM access have no equivalent.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 3 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-DATA-MOVEMENT/module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this` (alias `convert:module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this:data:DATA_MOVEMENT`): Choose how the data of module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this moves from aws_opensearch_domain to STACKIT OpenSearch (stackit_opensearch_instance.dependencies_catalog_opensearch_this): the method, the downtime it needs and the check that the copy is complete · StackToIT moves no data and writes no runbook for aws_opensearch_domain to STACKIT OpenSearch; the data-movement register lists module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this with the mechanism UNKNOWN, and the source states neither the size of the data nor the downtime the business tolerates nor the consistency the application needs
  - decision `DEC-GEN-CONVERT-EXPOSURE-WIDENED/module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this` (alias `convert:module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this:exposure:EXPOSURE_WIDENED`): Accept a public OpenSearch endpoint for stackit_opensearch_instance.dependencies_catalog_opensearch_this, limited only by its client list (parameters.sgw_acl), where the source module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this is private, or redesign it: stackit_opensearch_instance has no private-network option in the pinned provider (its access is parameters.sgw_acl only) · the source module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this is private (the domain states vpc_options: it is reached from inside its VPC) and the STACKIT OpenSearch instance has its own endpoint outside the project network, limited only by parameters.sgw_acl; a list the plan does not give is replaced by STACKIT's default ACL, which admits every STACKIT customer's addresses (the draft's variable has the empty list as its default, which the block replaces by the egress addresses of stackit_ske_cluster.retail_app_ecs_cluster (its pods)); the endpoint is wider than the source's and the difference is an accepted change in exposure, not a preserved property
  - decision `DEC-GEN-CONVERT-ENGINE-VERSION-DOWNGRADE` (alias `convert:module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this:version:ENGINE_VERSION_DOWNGRADE`): Choose how module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this (OpenSearch 3.3) reaches STACKIT, which offers 2 in eu01: move the data into 2 by re-reading it from the source, run OpenSearch 3.3 yourself on SKE, or wait until STACKIT offers it · the source runs OpenSearch 3.3 (engine_version), newer than every version the eu01 catalogue (2026-10-18) lists for stackit_opensearch_instance (2): a snapshot of 3.3 cannot be restored into 2 (OpenSearch restores a snapshot into the same or a newer version only); reindex from the source, or write to both during the cutover (dual-write), is the path; whether the clients work against 2 is unknown
- **Includes:** `module.dependencies.module.catalog_opensearch.aws_opensearch_domain_policy.this`
- **Depends on:** `module.dependencies.aws_security_group.catalog_opensearch_sg`, `module.vpc.module.vpc.aws_subnet.private`
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **CRITICAL** (engine-version-downgrade): Engine version DOWNGRADE: the source runs OpenSearch 3.3 (engine_version); STACKIT OpenSearch in eu01 offers 2 (service catalogue of eu01, read 2026-10-18), older than the source. A snapshot of 3.3 cannot be restored into 2 (OpenSearch restores a snapshot into the same or a newer version only); reindex from the source, or write to both during the cutover (dual-write), is the path; whether the clients work against 2 is unknown. Options (decision ENGINE_VERSION_DOWNGRADE): move the data into 2 by that path, run OpenSearch 3.3 yourself on SKE (self-managed), or wait until STACKIT offers 3.3; the draft takes none of them for you.
- **Critical semantics left to you to decide or accept (14):** engine-version, fine-grained-access, private-endpoint, encryption-at-rest, domain-settings, domain-credentials-and-keys, access-and-encryption-settings, cluster-layout-settings and 6 more (engineering/analysis-details.md) (**not automation-eligible**: no property the unit sets is read by private-endpoint)
- **Open choice(s) the draft could not make:** `DEC-GEN-CONVERT-DATA-MOVEMENT/module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this` (alias `convert:module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this:data:DATA_MOVEMENT`), `DEC-GEN-CONVERT-ENGINE-VERSION-DOWNGRADE` (alias `convert:module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this:version:ENGINE_VERSION_DOWNGRADE`) — the source does not prove what it means and the draft holds a required variable without a default; a person decides, and until then the unit is **not automation-eligible**.
- **Default(s) the draft carries out:** `DEC-GEN-CONVERT-EXPOSURE-WIDENED/module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this` (alias `convert:module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this:exposure:EXPOSURE_WIDENED`) — the draft carries out the default option `accept-the-public-endpoint` and the decision stays open; a person confirms it or overrides it in the decisions file (decisions.yaml), and until it is confirmed the unit is **not automation-eligible**.
- **Property accounting:** 24 of 24 meaningful properties accounted
- **20 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (2; REVIEW 2): `vpc_options.security_group_ids`, `vpc_options.subnet_ids` — NOT CARRIED (module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this): advanced_options, advanced_security_options, domain_endpoint_options, ebs_options, encrypt_at_rest, engine_version = OpenSearch_3.3, node_to_node_encryption, vpc_options — a stackit_opensearch_instance takes a plan, a version and parameters (an access list of networks, TLS protocols and ciphers, syslog servers, plugins; pinned provider): the domain's storage, network placement, access policy, encryption, endpoint, login, log and engine settings are not generated — a person maps each one to the plan and the parameters.
  - identity access (6; REVIEW 5 · UNSUPPORTED 1): `advanced_options`, `advanced_security_options.anonymous_auth_enabled`, `advanced_security_options.enabled`, `advanced_security_options.internal_user_database_enabled`, `advanced_security_options.master_user_options.master_user_name` and 1 more — NOT CARRIED (module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this): advanced_options, advanced_security_options, domain_endpoint_options, ebs_options, encrypt_at_rest, engine_version = OpenSearch_3.3, node_to_node_encryption, vpc_options — a stackit_opensearch_instance takes a plan, a version and parameters (an access list of networks, TLS protocols and ciphers, syslog servers, plugins; pinned provider): the domain's storage, network placement, access policy, encryption, endpoint, login, log and engine settings are not generated — a person maps each one to the plan and the parameters.
  - encryption (4; REVIEW 4): `domain_endpoint_options.enforce_https`, `domain_endpoint_options.tls_security_policy`, `encrypt_at_rest.enabled`, `node_to_node_encryption.enabled` — NOT CARRIED (module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this): advanced_options, advanced_security_options, domain_endpoint_options, ebs_options, encrypt_at_rest, engine_version = OpenSearch_3.3, node_to_node_encryption, vpc_options — a stackit_opensearch_instance takes a plan, a version and parameters (an access list of networks, TLS protocols and ciphers, syslog servers, plugins; pinned provider): the domain's storage, network placement, access policy, encryption, endpoint, login, log and engine settings are not generated — a person maps each one to the plan and the parameters.
  - availability durability (6; REVIEW 6): `cluster_config.dedicated_master_count`, `cluster_config.dedicated_master_enabled`, `cluster_config.instance_count`, `cluster_config.zone_awareness_enabled`, `ebs_options.ebs_enabled` and 1 more — NOT CARRIED (module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this): cluster_config — the plan (plan_name) sets the size of a stackit_opensearch_instance (pinned provider): the cluster's instance types and counts, dedicated masters and zone awareness are not carried — choose the plan for them.
  - secret handling (1; UNSUPPORTED 1): `advanced_security_options.master_user_options.master_user_password` — NOT CARRIED (module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this): advanced_options, advanced_security_options, domain_endpoint_options, ebs_options, encrypt_at_rest, engine_version = OpenSearch_3.3, node_to_node_encryption, vpc_options — a stackit_opensearch_instance takes a plan, a version and parameters (an access list of networks, TLS protocols and ciphers, syslog servers, plugins; pinned provider): the domain's storage, network placement, access policy, encryption, endpoint, login, log and engine settings are not generated — a person maps each one to the plan and the parameters.
  - workload compatibility (1; REVIEW 1): `domain_name`
- **Why those are open, and what closes them:**
  - `engine-version`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The setting states which engine and version the OpenSearch domain runs: OpenSearch or legacy Elasticsearch, with its version number. Closes when: A person chooses the version of the STACKIT OpenSearch instance, which has a version setting (pinned provider), and checks that the domain's clients work with it.
  - `fine-grained-access`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The setting states whether fine-grained access control, with users, roles and permissions inside the domain, is switched on. Closes when: A person re-creates the access rules another way, because fine-grained IAM access has no equivalent on STACKIT OpenSearch, which offers an access list and credentials per instance.
  - `private-endpoint`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The setting states whether the domain lives inside a VPC, with subnets and security groups, instead of behind a public endpoint. Closes when: A person translates the networks that may reach the domain into the access list (a list of CIDR ranges) of the STACKIT OpenSearch instance, which has no network or subnet input (pinned provider).
  - `encryption-at-rest`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The setting states whether the data the domain stores is encrypted at rest. Closes when: A person confirms the encryption of the STACKIT OpenSearch instance on the target; the instance has no encryption setting (pinned provider), and no STACKIT fact about it is documented here.
  - `domain-settings`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. stackit_opensearch_instance takes a plan (plan_name: nodes and storage), a version and parameters (sgw_acl, syslog, tls_protocols, tls_ciphers, etc.; pinned provider): the domain's node layout, zone awareness, storage, access policy, endpoint TLS and HTTPS settings, internal user database and log publishing are not generated — a person maps them to the plan and parameters — REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `domain-credentials-and-keys`: The mapping rule for this kind of unit found a setting the target has no counterpart for. STACKIT generates the OpenSearch credential (stackit_opensearch_credential username and password are computed), offers no customer KMS key for the instance and no custom endpoint certificate (pinned provider) — UNSUPPORTED. Closes when: A person accepts the difference or the design changes: nothing in the source can make the target carry it.
  - and 8 kinds of reason more (engineering/analysis-details.md)
- **Evidence** (validated against terraform-provider-stackit@0.116.0; found compatible through 0.121.0 by the release check): https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/opensearch_instance · https://docs.opensearch.org/latest/tuning-your-cluster/availability-and-recovery/snapshots/snapshot-restore/

#### `module.dependencies.module.catalog_rds.aws_rds_cluster.this`

- **Source:** `aws_rds_cluster` — .terraform/modules/dependencies.catalog_rds/main.tf:61
- **Module:** `module.dependencies.module.catalog_rds` (terraform-aws-modules/rds-aurora/aws 7.7.1)
- **Candidate target:** STACKIT MariaDB (`stackit_mariadb_instance`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Classification:** REPLATFORM · **Confidence:** LOW · rule `aws.rds_cluster/aurora-mysql`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (check aurora-mysql-mariadb-auth, check aurora-mysql-mariadb-json, check aurora-mysql-mariadb-collation, check aurora-mysql-mariadb-sql-mode and 19 more); a compliance or security control (encryption, key management, audit logging, retention) (check aurora-storage-encrypted-mariadb, semantic storage-encryption); a point the scan could not establish
- **Why:** Aurora MySQL has no MySQL target on STACKIT; MariaDB is the closest engine and needs compatibility testing. (2 conditional relations could not be resolved statically because the value of db_subnet_group_name of module.dependencies.module.catalog_rds.aws_rds_cluster.this may be null (a condition not known statically); the mapping decides the same either way; affected: this unit and `module.dependencies.module.catalog_rds.aws_rds_cluster.this`.)
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 2 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-DATA-MOVEMENT/module.dependencies.module.catalog_rds.aws_rds_cluster.this` (alias `convert:module.dependencies.module.catalog_rds.aws_rds_cluster.this:data:DATA_MOVEMENT`): Choose how the data of module.dependencies.module.catalog_rds.aws_rds_cluster.this moves from aws_rds_cluster to STACKIT MariaDB (stackit_mariadb_instance.dependencies_catalog_rds_this): a dump loaded with the mysql client inside the write freeze, or a tool of your own · the plan defines the one method the STACKIT MariaDB pages document, a dump loaded with the mysql client into the empty instance, and the customer's own tool; the replication of the binary log is refused because no STACKIT page documents it; STACKIT has no managed MySQL, so a MySQL source is an engine change whose collations, DEFINER accounts, accounts and settings the checks of the plan name, and the size of the data, the downtime the business accepts and the consistency the application needs are not in the source; the steps wait for the answer
  - decision `DEC-GEN-CONVERT-EXPOSURE-WIDENED/module.dependencies.module.catalog_rds.aws_rds_cluster.this` (alias `convert:module.dependencies.module.catalog_rds.aws_rds_cluster.this:exposure:EXPOSURE_WIDENED`): Accept a public endpoint for stackit_mariadb_instance.dependencies_catalog_rds_this, limited only by its client list, where the exposure of the source module.dependencies.module.catalog_rds.aws_rds_cluster.this is not readable, or redesign it: stackit_mariadb_instance has no private-network option in the pinned provider · the exposure of the source module.dependencies.module.catalog_rds.aws_rds_cluster.this is not readable (it states no publicly_accessible setting, or one that a variable without a value or a default decides), so the source is not proven publicly accessible and the draft does not take it as public; the STACKIT instance has its own IPv4 endpoint outside the project network, limited by its access list, which is the egress addresses of stackit_ske_cluster.retail_app_ecs_cluster (its pods) by default, so the exposure is a decision and not a preserved property
- **Includes:** `module.dependencies.module.catalog_rds.aws_rds_cluster_instance.this`
- **Depends on:** `module.dependencies.module.catalog_rds.aws_security_group.this`, `module.vpc.module.vpc.aws_subnet.private`
- **WARNING** (aurora-storage-encrypted-mariadb): Storage is encrypted at rest with an AWS-managed key. STACKIT MariaDB lists "data-at-rest encryption" as a feature, but a sandbox instance (MariaDB 10.11, 2026-09-24) had database-level encryption off (innodb_encrypt_tables, innodb_encrypt_log, encrypt_binlog, aria_encrypt_tables = OFF); whether the volumes beneath are encrypted cannot be observed from a client and is not stated: no STACKIT fact is documented, so it is UNKNOWN and is not relied on.
- **WARNING** (aurora-mysql-mariadb-auth): The source engine is MySQL 8 and its accounts do not move. MySQL 8.0's default authentication plugin is caching_sha2_password (system variable default_authentication_plugin), MariaDB 10.11's default is mysql_native_password or unix_socket; users created with MySQL's SHA256 password algorithm cannot be used in MariaDB 10.11 (MDEV-9804), and a caching_sha2_password plugin exists in MariaDB Community Server only from 11.4.9, 11.8.4 and 12.1 and is not installed by default, while STACKIT offers MariaDB 10.11 (catalogue 2026-10-18). Create the accounts on the target and check that every client library authenticates with a plugin MariaDB 10.11 offers: a client setting that requires caching_sha2_password cannot connect.
- **WARNING** (aurora-mysql-mariadb-json): MariaDB stores JSON as text, not in a binary format as MySQL: its JSON data type is an alias for LONGTEXT, so the JSON columns of the source become text columns and JSON values are compared as strings, where MySQL compares them as JSON values. MariaDB 10.11 does not support MySQL's JSON operators -> and ->> (MDEV-13594): a query that uses them is rewritten with the JSON functions (JSON_EXTRACT, JSON_UNQUOTE); JSON_SEARCH given invalid data returns NULL and a warning where MySQL raises an error.
- **WARNING** (aurora-mysql-mariadb-collation): The defaults of the character set and the collation differ: MySQL 8.0 uses utf8mb4 and utf8mb4_0900_ai_ci, MariaDB 10.11 uses latin1 or utf8 and latin1_swedish_ci or utf8_general_ci, and MariaDB names utf8mb4_uca1400_ai_ci as the counterpart default only from 11.4. Not all character sets and collations exist in both products, and the pages read do not list utf8mb4_0900_ai_ci as a MariaDB 10.11 collation: check every collation the schema, the dump and the queries name with SHOW COLLATION on the target, and set the character set of every database explicitly.
- **WARNING** (aurora-mysql-mariadb-sql-mode): The default sql_mode differs: MySQL 8.0 sets ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO and NO_ENGINE_SUBSTITUTION; MariaDB 10.11 sets STRICT_TRANS_TABLES, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER and NO_ENGINE_SUBSTITUTION. Without ONLY_FULL_GROUP_BY the GROUP BY semantics the queries rely on are not enforced the way MySQL enforces them, and zero dates and zero parts in dates are no longer refused by default. A parameter group of the source may set sql_mode itself, and whether the STACKIT instance lets sql_mode be set is not established here: test the queries and the inserts against the target.
- **INFO** (aurora-mysql-mariadb-queries): Common table expressions (non-recursive and recursive) and window functions are supported by both products (window functions since MariaDB 10.2, per MariaDB's compatibility matrix), so no incompatibility is documented for them; the queries are tested anyway. Documented differences in queries: MariaDB 10.11 does not support lateral derived tables (MDEV-19078) or the MAX_EXECUTION_TIME optimizer hint, and the function VALUES() is called VALUE(); INFORMATION_SCHEMA.COLUMNS has slightly different fields and the role views differ; the performance schema is off by default in MariaDB 10.11 and on in MySQL. Generated columns are compatible: tables created with MySQL 5.7 or later that hold generated columns import into MariaDB, and STORED is an alias of PERSISTENT.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (14):** admin-password, admin-username-not-carried, backup-retention, db-network-placement, engine, engine-version, final-snapshot, member-engine and 6 more (engineering/analysis-details.md)
- **Open choice(s) the draft could not make:** `DEC-GEN-CONVERT-DATA-MOVEMENT/module.dependencies.module.catalog_rds.aws_rds_cluster.this` (alias `convert:module.dependencies.module.catalog_rds.aws_rds_cluster.this:data:DATA_MOVEMENT`) — the source does not prove what it means and the draft holds a required variable without a default; a person decides, and until then the unit is **not automation-eligible**.
- **Default(s) the draft carries out:** `DEC-GEN-CONVERT-EXPOSURE-WIDENED/module.dependencies.module.catalog_rds.aws_rds_cluster.this` (alias `convert:module.dependencies.module.catalog_rds.aws_rds_cluster.this:exposure:EXPOSURE_WIDENED`) — the draft carries out the default option `accept-the-public-endpoint` and the decision stays open; a person confirms it or overrides it in the decisions file (decisions.yaml), and until it is confirmed the unit is **not automation-eligible**.
- **Property accounting:** 26 of 26 meaningful properties accounted
- **16 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (3; REVIEW 3): `db_subnet_group_name`, `vpc_security_group_ids`, `module.dependencies.module.catalog_rds.aws_rds_cluster_instance.this.db_subnet_group_name` — NOT CARRIED (module.dependencies.module.catalog_rds.aws_rds_cluster.this): db_subnet_group_name — stackit_mariadb_instance has no subnet, availability-zone or IP-family attribute (pinned provider): clients reach the instance at the endpoint STACKIT assigns.
  - identity access (1; REVIEW 1): `master_username` — NOT CARRIED (module.dependencies.module.catalog_rds.aws_rds_cluster.this): master_username = root — stackit_mariadb_credential takes no username: the username and the password are computed by STACKIT (pinned provider) — clients get new credentials.
  - encryption (3; REVIEW 3): `db_cluster_parameter_group_name`, `storage_encrypted`, `module.dependencies.module.catalog_rds.aws_rds_cluster_instance.this.db_parameter_group_name` — NOT CARRIED (module.dependencies.module.catalog_rds.aws_rds_cluster.this): preferred_maintenance_window = sun:05:00-sun:06:00, allow_major_version_upgrade = true, db_cluster_parameter_group_name — stackit_mariadb_instance has no maintenance window, version-upgrade policy, extended-support, CA-certificate, option-group or parameter-group attribute (pinned provider).
  - backup retention (2; REVIEW 2): `backup_retention_period`, `skip_final_snapshot` — NOT CARRIED (module.dependencies.module.catalog_rds.aws_rds_cluster.this): backup_retention_period = 7, preferred_backup_window = 02:00-03:00 — stackit_mariadb_instance has no backup setting (pinned provider).
  - availability durability (4; REVIEW 4): `engine`, `engine_version`, `module.dependencies.module.catalog_rds.aws_rds_cluster_instance.this.engine`, `module.dependencies.module.catalog_rds.aws_rds_cluster_instance.this.engine_version`
  - secret handling (1; REVIEW 1): `master_password` — NOT CARRIED (module.dependencies.module.catalog_rds.aws_rds_cluster.this): master_password — the source password is not copied: stackit_mariadb_credential has no password input, STACKIT generates it (the password is computed and sensitive, pinned provider) — hand the new one to the application.
  - workload compatibility (2; REVIEW 2): `database_name`, `module.dependencies.module.catalog_rds.aws_rds_cluster_instance.this.identifier` — NOT CARRIED (module.dependencies.module.catalog_rds.aws_rds_cluster.this): database_name = catalog — stackit_mariadb_instance has no database attribute (pinned provider): create the database after connecting.
- **Why those are open, and what closes them:**
  - `engine`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The database engine of the cluster (Aurora PostgreSQL, Aurora MySQL, or a Multi-AZ cluster on PostgreSQL or MySQL), which decides the STACKIT database service it lands on. Closes when: For a MySQL-compatible cluster a person tests the schemas and queries on STACKIT MariaDB, the closest managed engine, because STACKIT has no MySQL product; for a PostgreSQL cluster, which lands on PostgreSQL Flex, a person confirms that no Aurora-only feature (storage auto-scaling, fast clones, global databases, serverless v2 scaling) is relied on.
  - `engine-version`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The version of the database engine that the cluster runs. Closes when: For a PostgreSQL cluster a person picks a major version that PostgreSQL Flex offers (14 to 18; 18 is beta in eu01, so production needs 17 or a generally available 18) and plans an upgrade for any other version. For a MySQL-compatible cluster a person tests the MySQL 8 features in use on STACKIT MariaDB.
  - `backup-retention`: Whether the draft carries this setting is decided by its semantic ledger entry "backup retention", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). A retention not visible statically (a variable) is read by no fact and the draft carries nothing for it: a person compares it with the target's backup retention (REVIEW). Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - `storage-encryption`: A check of the knowledge base (aurora storage encrypted mariadb) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The setting states whether the storage of the database cluster is encrypted at rest, with the AWS-managed key because no customer key is named. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded. A person confirms the at-rest encryption of the target database on STACKIT: the PostgreSQL Flex encryption block covers customer keys only and the default without it is not stated, and a MariaDB sandbox instance had database-level encryption off, so whether its volumes are encrypted is not stated (pinned provider).
  - `db-network-placement`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The STACKIT database resource has no subnet, availability-zone or IP-family attribute (pinned provider): clients reach it at the endpoint STACKIT assigns, restricted by its ACL — a person decides how clients reach it — REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `admin-username-not-carried`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The master username is not a literal of a single cluster that PostgreSQL Flex accepts: a name a variable supplies or that is not visible statically (the draft writes the user with a variable that has no default), a name STACKIT reserves (admin and postgres: the draft writes a variable that rejects them), or a repeated cluster (a user per cluster only when every instance is evaluated). A person chooses the administrator's name on the target — REVIEW. Closes when: A person creates the administrator on the target with a name the target accepts and confirms the application connects with it.
  - and 8 kinds of reason more (engineering/analysis-details.md)
- **Evidence** (validated against terraform-provider-stackit@0.116.0; docs postgresql-flex/mariadb 2026-09-25; aurora-replica and aurora-replica-cross-region review lines re-checked 2026-10-31 against the provider schema 0.119.0 (postgresflex_instance, mariadb_instance: no read replica of another instance), the postgres-flex v3 / mariadb v2 API specs, the PostgreSQL Flex architecture page and the STACKIT regions page; aurora-deletion-protection re-checked 2026-10-07 against provider schema 0.117.0 (stackit_postgresflex_instance: no protection attribute), the postgres-flex v3 API spec (POST .../protections isDeletable) and the PostgreSQL Flex instance-protection docs; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/databases/postgresql-flex/ · https://docs.stackit.cloud/products/databases/mariadb/

#### `module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default`

- **Source:** `aws_elasticache_replication_group` — .terraform/modules/dependencies.checkout_elasticache_redis/main.tf:115
- **Module:** `module.dependencies.module.checkout_elasticache_redis` (cloudposse/elasticache-redis/aws 0.53.0)
- **Candidate target:** STACKIT Key Value Store (Valkey) (`stackit_valkey_instance`, `stackit_valkey_credential`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.elasticache/redis-valkey`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (check engine-version-upgrade, check redis-transit-encryption-off, semantic parameter-group, semantic parameter-group-default and 9 more); a point the scan could not establish
- **Why:** Redis/Valkey caches move to STACKIT Key Value Store (Valkey, Redis-protocol compatible, GA since August 2026). Do not target stackit_redis_instance: it is deprecated and removed after August 2027.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 3 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-DATA-MOVEMENT/module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default` (alias `convert:module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default:data:DATA_MOVEMENT`): Choose how the keys of module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default move from aws_elasticache_replication_group to STACKIT Key Value Store (stackit_valkey_instance.dependencies_checkout_elasticache_redis_default): the keys copied by a client inside the write freeze, or a tool of your own · the plan defines the one method the STACKIT pages and the ElastiCache pages allow together, a copy of the keys by a client (SCAN, DUMP, PTTL, RESTORE) inside the write freeze, and the customer's own tool; loading an exported snapshot is refused because no STACKIT page or API takes an RDB file, and following the source as a replica is refused because neither end offers it; the source does not say whether the cache holds only what the application rebuilds, the size of the data, the downtime the business accepts or the shards the keys are spread over, and the Key Value Store has no sharding; the steps wait for the answer
  - decision `DEC-GEN-CONVERT-SIZE-FROM-SOURCE/module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default` (alias `convert:module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default:dependencies_checkout_elasticache_redis_default_plan_name:SIZE_FROM_SOURCE`): Confirm the plan the draft derived for module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default from the size the source states: option use-the-size-derived-from-the-source (stackit-keyvalue-1.4.10-single, in var.dependencies_checkout_elasticache_redis_default_plan_name) or option choose-the-size (a plan you set in var.dependencies_checkout_elasticache_redis_default_plan_name) · the target sizes by a plan of the catalogue, and the source states a size in the terms of its own offer; the draft proposes the smallest plan that covers it, which leaves out what the source does not state (the disk of a plan, the sustained load, the headroom of a pool), so the value is a proposal and the price of the draft moves with it; unit of the memory figure: the plan table gives its RAM as "GB" and does not say whether a GB is 10^9 or 2^30 bytes, so the plan is chosen to hold the source's memory when a GB is 10^9 bytes, which it then also does when a GB is 2^30 bytes (it is never smaller than the source whichever way the table is read)
  - decision `DEC-GEN-CONVERT-EXPOSURE-WIDENED/module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default` (alias `convert:module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default:exposure:EXPOSURE_WIDENED`): Accept a public Valkey endpoint for stackit_valkey_instance.dependencies_checkout_elasticache_redis_default, limited only by its client list (parameters.sgw_acl), where the source module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default is private, or redesign it: stackit_valkey_instance has no private-network option in the pinned provider (its access is parameters.sgw_acl only) · the source module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default is private (Amazon ElastiCache has no public endpoint: the cache is reached from inside its VPC through its subnet group) and the STACKIT Valkey instance has its own endpoint outside the project network, limited only by parameters.sgw_acl; a list the plan does not give is replaced by STACKIT's default ACL, which admits every STACKIT customer's addresses (the draft's variable has no default and rejects an empty list, so the list is yours); the endpoint is wider than the source's and the difference is an accepted change in exposure, not a preserved property
- **Depends on:** `module.dependencies.module.checkout_elasticache_redis.module.aws_security_group.aws_security_group.cbd`, `module.vpc.module.vpc.aws_subnet.private`
- **WARNING** (redis-transit-encryption-off): The source cache runs without TLS (transit_encryption_enabled = false). STACKIT Key Value Store accepts TLS only: a test on a STACKIT project (Valkey 8, single plan, eu01, 2026-09-24) found a plaintext connection closed by the server, TLS 1.2 and 1.3 accepted, and the how-to connects with rediss:// and valkey-cli --tls. Every client of the cache changes: the scheme redis:// becomes rediss://, the driver's TLS option is switched on and the instance's CA certificate is trusted, before the cutover.
- **INFO** (redis-engine-version): The engine version becomes the Valkey version offered by STACKIT (version attribute); check client compatibility with that version.
- **INFO** (redis-parameter-group): Not verifiable statically (parameter_group_name not visible): A custom parameter group is attached; map each changed parameter to the Valkey parameters block (maxmemory_policy, notify_keyspace_events, …).
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (engine-version-upgrade): Engine version UPGRADE: the source runs Valkey 4.0.10 (engine_version); STACKIT Valkey in eu01 offers 8 (service catalogue of eu01, read 2026-10-18), none of them the source's version. Moving the data upgrades the engine: test the application and the data against the version you choose before the cutover; the draft does not choose it.
- **Critical semantics left to you to decide or accept (9):** parameter-group, parameter-group-default, failover-off, snapshots-off, at-rest-encryption-off, network-placement, seed-snapshot, tcp-elasticache-replication-group-transit-encryption-enabled and 1 more (engineering/analysis-details.md)
- **Open choice(s) the draft could not make:** `DEC-GEN-CONVERT-DATA-MOVEMENT/module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default` (alias `convert:module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default:data:DATA_MOVEMENT`) — the source does not prove what it means and the draft holds a required variable without a default; a person decides, and until then the unit is **not automation-eligible**.
- **Default(s) the draft carries out:** `DEC-GEN-CONVERT-SIZE-FROM-SOURCE/module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default` (alias `convert:module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default:dependencies_checkout_elasticache_redis_default_plan_name:SIZE_FROM_SOURCE`), `DEC-GEN-CONVERT-EXPOSURE-WIDENED/module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default` (alias `convert:module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default:exposure:EXPOSURE_WIDENED`) — the draft carries out the default option `use-the-size-derived-from-the-source`, `accept-the-public-endpoint` and the decision stays open; a person confirms it or overrides it in the decisions file (decisions.yaml), and until it is confirmed the unit is **not automation-eligible**.
- **Property accounting:** 18 of 18 meaningful properties accounted
- **11 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (2; REVIEW 2): `security_group_ids`, `subnet_group_name` — NOT CARRIED (module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default): subnet_group_name, security_group_ids — stackit_valkey_instance has no subnet, security-group, zone or IP-family attribute (pinned provider); the draft limits access with parameters.sgw_acl (CIDRs) from a variable without a default — list the clients.
  - encryption (2; REVIEW 2): `at_rest_encryption_enabled`, `transit_encryption_enabled`
  - backup retention (2; REVIEW 2): `snapshot_arns`, `snapshot_retention_limit` — NOT CARRIED (module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default): snapshot_arns — the instance is created empty: seeding it from an ElastiCache snapshot is not generated — migrate the data (e.g.
  - availability durability (4; REVIEW 4): `automatic_failover_enabled`, `multi_az_enabled`, `num_cache_clusters`, `parameter_group_name` — NOT CARRIED (module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default): num_cache_clusters = 1 — the plan (plan_name) defines the nodes and replicas of a STACKIT Valkey instance (pinned provider).
  - workload compatibility (1; REVIEW 1): `replication_group_id`
- **Why those are open, and what closes them:**
  - `parameter-group`: A check of the knowledge base (redis parameter group) needs a value the scan cannot read statically, so it could not decide. The setting states which custom set of engine parameters (a parameter group) the cache runs with. Closes when: A literal value or a resolved reference in the source lets the check decide, or a person verifies the value.
  - `parameter-group-default`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. A parameter group named default.<family> carries the AWS default settings of that engine family and version, and its name can carry the topology: a group with cluster.on in its name enables cluster mode. Closes when: A person confirms that the defaults of the source parameter group family are what the application needs on the target and, for a cluster-mode group, treats it as the cluster-mode question.
  - `failover-off`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. A single node without failover: the draft asks for the plan (plan_name is a variable), so whether the target is a Single plan is a person's choice — REVIEW, not PRESERVED. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `snapshots-off`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. No snapshots in the source; whether a STACKIT Valkey instance takes snapshots by default (parameters.snapshot, not generated) is not documented — REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `at-rest-encryption-off`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. No at-rest encryption in the source; stackit_valkey_instance states nothing about at-rest encryption (pinned provider) — REVIEW, not PRESERVED. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `network-placement`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. stackit_valkey_instance has no subnet, security-group, zone or IP-family attribute; client access can be limited by CIDR with parameters.sgw_acl, which the draft does not generate — a person decides it. Closes when: A person decides how clients reach the Valkey instance, which has no subnet or security-group setting, for example by limiting client CIDR ranges with its access parameter.
  - and 3 kinds of reason more (engineering/analysis-details.md)
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (stackit_redis_instance deprecated: removed after August 2027; use stackit_valkey_instance); found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/databases/key-value-store/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/valkey_instance · https://registry.terraform.io/providers/hashicorp/aws/6.66.0/docs/resources/elasticache_serverless_cache

#### `module.dependencies.module.orders_rds.aws_rds_cluster.this`

- **Source:** `aws_rds_cluster` — .terraform/modules/dependencies.orders_rds/main.tf:61
- **Module:** `module.dependencies.module.orders_rds` (terraform-aws-modules/rds-aurora/aws 7.7.1)
- **Candidate target:** STACKIT PostgreSQL Flex (`stackit_postgresflex_instance`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Classification:** REPLATFORM · **Confidence:** MEDIUM · rule `aws.rds_cluster/aurora-postgres`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (semantic db-network-placement, semantic admin-username-not-carried, semantic admin-password, semantic security-groups and 11 more); a compliance or security control (encryption, key management, audit logging, retention) (check aurora-storage-encrypted, semantic storage-encryption); a point the scan could not establish
- **Why:** Aurora PostgreSQL is wire-compatible PostgreSQL; it lands on PostgreSQL Flex. Aurora-only features (storage auto-scaling up to 256 TiB, fast clones, global databases, serverless v2 scaling) have no equivalent. (2 conditional relations could not be resolved statically because the value of db_subnet_group_name of module.dependencies.module.orders_rds.aws_rds_cluster.this may be null (a condition not known statically); the mapping decides the same either way; affected: this unit and `module.dependencies.module.orders_rds.aws_rds_cluster.this`.)
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 3 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-DATA-MOVEMENT/module.dependencies.module.orders_rds.aws_rds_cluster.this` (alias `convert:module.dependencies.module.orders_rds.aws_rds_cluster.this:data:DATA_MOVEMENT`): Choose how the data of module.dependencies.module.orders_rds.aws_rds_cluster.this moves from aws_rds_cluster to PostgreSQL Flex (stackit_postgresflex_instance.dependencies_orders_rds_this): a dump restored inside the write freeze, the engine's logical replication, or a tool of your own · the plan defines both methods of the engine (a dump restored inside the write freeze, and a logical replication that follows the changes until the freeze) and keeps them open: which one applies depends on the size of the data, the write rate and the downtime the business accepts, and the source states none of them; the steps of the methods wait for the answer
  - decision `DEC-GEN-CONVERT-SIZE-FROM-SOURCE/module.dependencies.module.orders_rds.aws_rds_cluster.this` (alias `convert:module.dependencies.module.orders_rds.aws_rds_cluster.this:dependencies_orders_rds_this_flavor_id:SIZE_FROM_SOURCE`): Confirm the flavor the draft derived for module.dependencies.module.orders_rds.aws_rds_cluster.this from the size the source states: option use-the-size-derived-from-the-source (2.4, as flavor_id) or option choose-the-size (a flavor you set in var.dependencies_orders_rds_this_flavor_id) · the target sizes by a flavor of the catalogue, and the source states a size in the terms of its own offer; the draft proposes the smallest flavor that covers it, which leaves out what the source does not state (the disk of a plan, the sustained load, the headroom of a pool), so the value is a proposal and the price of the draft moves with it; unit of the memory figure: PostgreSQL Flex states the memory of a flavor in Gibibyte (API v3 spec, flavor.memory), the unit of the source's size, so no unit is assumed
  - decision `DEC-GEN-CONVERT-EXPOSURE-WIDENED/module.dependencies.module.orders_rds.aws_rds_cluster.this` (alias `convert:module.dependencies.module.orders_rds.aws_rds_cluster.this:exposure:EXPOSURE_WIDENED`): Accept a public endpoint for stackit_postgresflex_instance.dependencies_orders_rds_this, limited only by its client list, where the exposure of the source module.dependencies.module.orders_rds.aws_rds_cluster.this is not readable, or choose the network-area-only scope SNA (network.access_scope = SNA; a private preview, permitted for enabled accounts only) · the exposure of the source module.dependencies.module.orders_rds.aws_rds_cluster.this is not readable (it states no publicly_accessible setting, or one that a variable without a value or a default decides), so the source is not proven publicly accessible and the draft does not take it as public; the STACKIT instance has its own IPv4 endpoint outside the project network, limited by its access list, which is the egress addresses of stackit_ske_cluster.retail_app_ecs_cluster (its pods) by default, so the exposure is a decision and not a preserved property
- **Includes:** `module.dependencies.module.orders_rds.aws_rds_cluster_instance.this`
- **Depends on:** `module.dependencies.module.orders_rds.aws_security_group.this`, `module.vpc.module.vpc.aws_subnet.private`
- **INFO** (aurora-pg-version-supported): The PostgreSQL major version is one PostgreSQL Flex offers (14–18).
- **WARNING** (aurora-storage-encrypted): Storage is encrypted at rest with an AWS-managed key; the PostgreSQL Flex encryption block covers customer keys only (the pinned STACKIT provider) and STACKIT does not state the default without it: no STACKIT fact is documented, so at-rest encryption is UNKNOWN until the PostgreSQL Flex product pages or a test on a STACKIT project state it.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (10):** storage-encryption, db-network-placement, admin-username-not-carried, admin-password, security-groups, parameter-and-option-groups, final-snapshot, member-settings and 2 more (engineering/analysis-details.md)
- **Open choice(s) the draft could not make:** `DEC-GEN-CONVERT-DATA-MOVEMENT/module.dependencies.module.orders_rds.aws_rds_cluster.this` (alias `convert:module.dependencies.module.orders_rds.aws_rds_cluster.this:data:DATA_MOVEMENT`) — the source does not prove what it means and the draft holds a required variable without a default; a person decides, and until then the unit is **not automation-eligible**.
- **Default(s) the draft carries out:** `DEC-GEN-CONVERT-SIZE-FROM-SOURCE/module.dependencies.module.orders_rds.aws_rds_cluster.this` (alias `convert:module.dependencies.module.orders_rds.aws_rds_cluster.this:dependencies_orders_rds_this_flavor_id:SIZE_FROM_SOURCE`), `DEC-GEN-CONVERT-EXPOSURE-WIDENED/module.dependencies.module.orders_rds.aws_rds_cluster.this` (alias `convert:module.dependencies.module.orders_rds.aws_rds_cluster.this:exposure:EXPOSURE_WIDENED`) — the draft carries out the default option `use-the-size-derived-from-the-source`, `accept-the-public-endpoint` and the decision stays open; a person confirms it or overrides it in the decisions file (decisions.yaml), and until it is confirmed the unit is **not automation-eligible**.
- **Property accounting:** 27 of 27 meaningful properties accounted
- **11 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (3; REVIEW 3): `db_subnet_group_name`, `vpc_security_group_ids`, `module.dependencies.module.orders_rds.aws_rds_cluster_instance.this.db_subnet_group_name` — NOT CARRIED (module.dependencies.module.orders_rds.aws_rds_cluster.this): db_subnet_group_name — stackit_postgresflex_instance has no subnet, availability-zone or IP-family attribute (pinned provider): clients reach the instance at the endpoint STACKIT assigns.
  - identity access (1; REVIEW 1): `master_username`
  - encryption (3; REVIEW 3): `db_cluster_parameter_group_name`, `storage_encrypted`, `module.dependencies.module.orders_rds.aws_rds_cluster_instance.this.db_parameter_group_name` — NOT CARRIED (module.dependencies.module.orders_rds.aws_rds_cluster.this): preferred_maintenance_window = sun:05:00-sun:06:00, allow_major_version_upgrade = false, db_cluster_parameter_group_name — stackit_postgresflex_instance has no maintenance window, version-upgrade policy, extended-support, CA-certificate, option-group or parameter-group attribute (pinned provider).
  - backup retention (1; REVIEW 1): `skip_final_snapshot` — NOT CARRIED (module.dependencies.module.orders_rds.aws_rds_cluster.this): skip_final_snapshot = true — stackit_postgresflex_instance has no final-snapshot or delete-time backup-retention setting (pinned provider): the instance is deleted immediately (and its automated backups may be removed immediately) when Terraform destroys the resource — export the data first if it must survive the cut-over.
  - secret handling (1; REVIEW 1): `master_password` — NOT CARRIED (module.dependencies.module.orders_rds.aws_rds_cluster.this): master_password — the source password is not copied: stackit_postgresflex_user has no password input, STACKIT generates it (the password is computed and sensitive, pinned provider) — hand the new one to the application.
  - workload compatibility (2; REVIEW 2): `database_name`, `module.dependencies.module.orders_rds.aws_rds_cluster_instance.this.identifier` — NOT CARRIED (module.dependencies.module.orders_rds.aws_rds_cluster_instance.this): identifier = (reads a variable; its default is not printed), db_subnet_group_name, preferred_maintenance_window = sun:05:00-sun:06:00, db_parameter_group_name — cluster members are not separate STACKIT resources — the flavor (flavor_id: single or replica) defines the nodes (pinned provider): member names, failover priority, zone, subnet, windows, upgrade policy, parameter group, CA certificate and instance profile have no attribute.
- **Why those are open, and what closes them:**
  - `storage-encryption`: A check of the knowledge base (aurora storage encrypted) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The setting states whether the storage of the database cluster is encrypted at rest, with the AWS-managed key because no customer key is named. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded. A person confirms the at-rest encryption of the target database on STACKIT: the PostgreSQL Flex encryption block covers customer keys only and the default without it is not stated, and a MariaDB sandbox instance had database-level encryption off, so whether its volumes are encrypted is not stated (pinned provider).
  - `db-network-placement`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The STACKIT database resource has no subnet, availability-zone or IP-family attribute (pinned provider): clients reach it at the endpoint STACKIT assigns, restricted by its ACL — a person decides how clients reach it — REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `admin-username-not-carried`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The master username is not a literal of a single cluster that PostgreSQL Flex accepts: a name a variable supplies or that is not visible statically (the draft writes the user with a variable that has no default), a name STACKIT reserves (admin and postgres: the draft writes a variable that rejects them), or a repeated cluster (a user per cluster only when every instance is evaluated). A person chooses the administrator's name on the target — REVIEW. Closes when: A person creates the administrator on the target with a name the target accepts and confirms the application connects with it.
  - `admin-password`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The source password (or its Secrets Manager management) is never copied, and no STACKIT database user takes a password: stackit_postgresflex_user and stackit_mariadb_credential compute it (password is computed and sensitive, pinned provider) and the create-user API of PostgreSQL Flex has no password field. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `security-groups`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. STACKIT database instances have no security groups: access is a CIDR ACL (network.acl, pinned provider); the draft's ACL variable defaults to the CIDRs of the groups' ingress rules where visible, and group-to-group rules cannot be expressed — a person checks the ACL — REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `parameter-and-option-groups`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The STACKIT database resource has no parameter-group or option-group attribute (pinned provider): the group's settings (even a default.* group of the source engine) must be mapped to the STACKIT instance's options by a person — REVIEW. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - and 4 kinds of reason more (engineering/analysis-details.md)
- **Evidence** (validated against terraform-provider-stackit@0.116.0; docs postgresql-flex/mariadb 2026-09-25; aurora-replica and aurora-replica-cross-region review lines re-checked 2026-10-31 against the provider schema 0.119.0 (postgresflex_instance, mariadb_instance: no read replica of another instance), the postgres-flex v3 / mariadb v2 API specs, the PostgreSQL Flex architecture page and the STACKIT regions page; aurora-deletion-protection re-checked 2026-10-07 against provider schema 0.117.0 (stackit_postgresflex_instance: no protection attribute), the postgres-flex v3 API spec (POST .../protections isDeletable) and the PostgreSQL Flex instance-protection docs; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/databases/postgresql-flex/ · https://docs.stackit.cloud/products/databases/mariadb/

### Identity

#### `module.retail_app_ecs.aws_kms_key.cmk`

- **Source:** `aws_kms_key` — ../../lib/ecs/common.tf:1
- **Module:** `module.retail_app_ecs` (../../lib/ecs)
- **Candidate target:** STACKIT KMS (`stackit_kms_keyring`, `stackit_kms_key`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.kms_key/kms`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic deletion-window); a point the scan could not establish
- **Why:** Keys are re-created in STACKIT KMS (keyring + key); key material generated in AWS KMS cannot be exported, so encrypted data is re-encrypted during migration. Consumers (volumes, PostgreSQL Flex, Secrets Manager) reference the new key.
- **INFO** (kms-deletion-window): The key's deletion window is not 30 days. STACKIT KMS deletes a key scheduled for deletion after 30 days, with no setting (stackit_kms_key has none) — check that a different recovery window is acceptable.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (1):** deletion-window
- **Property accounting:** 1 of 1 meaningful properties accounted
- **1 critical setting(s) left to you** — **not automation-eligible**:
  - deletion protection (1; REVIEW 1): `deletion_window_in_days` — NOT CARRIED (module.retail_app_ecs.aws_kms_key.cmk): deletion_window_in_days = 7 — STACKIT KMS deletes a key scheduled for deletion after 30 days; stackit_kms_key has no deletion window (pinned provider).
- **Why those are open, and what closes them:**
  - `deletion-window`: A check of the knowledge base (kms deletion window) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). STACKIT KMS deletes a key scheduled for deletion after 30 days (docs create-and-manage-keys, 'Delete a key'), with no setting: 30 is PRESERVED, another window REVIEW. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; docs security/kms 2026-09-23 (eu01, eu02 since 2026-04-07); docs security/kms create-and-manage-keys 2026-09-27 (deleted after 30 days, active after creation); found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/security/kms/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/kms_key

#### `module.retail_app_ecs.module.carts_service.aws_iam_role.task_execution_role`

- **Source:** `aws_iam_role` — ../../lib/ecs/service/iam.tf:14
- **Module:** `module.retail_app_ecs.module.carts_service` (./service)
- **Candidate target:** STACKIT service account for the workload (`stackit_service_account`, `stackit_service_account_key`, `stackit_authorization_project_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.iam_role/role-workload-execution`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic trust, semantic permissions, semantic tcfp-iam-role-policy-attachment--policy-arn, semantic iam-trust-service-workload and 1 more); a point the scan could not establish
- **Why:** Execution role of an application (Lambda function or ECS task). The application keeps needing these permissions on STACKIT: it gets a service account (or data-service credentials such as database users and object-storage keys) with equivalent grants.
- **Includes:** `module.retail_app_ecs.module.carts_service.aws_iam_role_policy_attachment.task_execution_role_policy`
- **INFO** (iam-trust-service-workload): Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. On STACKIT the workload runs as a service account (stackit_service_account) and nothing assumes it: it authenticates with a service account key (stackit_service_account_key, key flow) or, on SKE, by Workload Identity Federation (a federated identity provider on the account). What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit).
- **INFO** (iam-managed-ecs): Managed policy of an ECS role (AWS: task execution pulls images from ECR and writes CloudWatch Logs; the container-instance role registers hosts with ECS). STACKIT has no ECS: image pull is a registry credential (Container Registry roles, Guest is read-only) and log shipping a platform or credential setting (stackit_logs_access_token); no STACKIT role replaces these grants. Container Registry: STACKIT offers this service. A public STACKIT API exists for it. The pinned Terraform provider has no resource for it. StackToIT does not draft automation for it yet; extra implementation is needed. (schema checked 2026-10-11: none of the 115 resource types of the pinned STACKIT provider), so the pull credential is not drafted (project roles: docs.stackit.cloud, updated Jul 2, 2026). What to decide: the registry pull credential and the log destination of the replacing workload.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (4):** trust, permissions, iam-trust-service-workload, iam-managed-ecs
- **Property accounting:** 3 of 3 meaningful properties accounted
- **2 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (2; REVIEW 2): `assume_role_policy`, `module.retail_app_ecs.module.carts_service.aws_iam_role_policy_attachment.task_execution_role_policy.policy_arn` — NOT CARRIED (module.retail_app_ecs.module.carts_service.aws_iam_role.task_execution_role): assume_role_policy, name = (reads a variable; its default is not printed) — stackit_service_account has a name and a project only (pinned provider): no trust policy, path, session duration or permissions boundary.
- **Why those are open, and what closes them:**
  - `trust`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The trust policy document of the role (its principals and conditions) has no STACKIT counterpart: stackit_service_account has name and project_id only (pinned provider schema), and the draft names assume_role_policy as not carried. Closes when: A person decides per principal who may assume the role: a federated identity provider (IRSA), a server attachment or a service account key; a role used only by an AWS service is dropped after a person confirms it.
  - `permissions`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. STACKIT IAM grants roles; the policy documents, conditions and resource patterns of the role are translated by a person. Closes when: A person translates each permission of the attached policies into STACKIT roles on the target resources.
  - `iam-trust-service-workload`: A check of the knowledge base (iam trust service workload) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `iam-managed-ecs`: A check of the knowledge base (iam managed ecs) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Managed policy of an ECS role (AWS: task execution pulls images from ECR and writes CloudWatch Logs; the container-instance role registers hosts with ECS). What to decide: the registry pull credential and the log destination of the replacing workload. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Review:**
  - [ ] List what the attached policies allow (tables, buckets, queues) and grant the same on the STACKIT targets.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); SKE workload identity docs 2026-09-15; IAM checks of 2026-10-06: provider 0.117.0 schema, docs.stackit.cloud access-and-identity 2026-10-06; IAM notes wording (Act-As, S3 bucket policy carrier, Container Registry has no resource): provider 0.119.0 schema and the docs.stackit.cloud pages cited in the checks, checked 2026-10-11; iam-managed-ssm-instance wording: provider 0.119.0 schema (stackit_server agent), docs.stackit.cloud server-agent, run-command and server pages and the AWS AmazonSSMManagedInstanceCore and Systems Manager instance-permission pages, fetched 2026-10-12; role-ec2-no-profile: provider 0.119.0 docs stackit_server_service_account_attach and stackit_service_account, read 2026-11-01; role-ec2-no-profile skips a role an awscc_iam_instance_profile names: the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles), read 2026-11-01; role-instance-profile of an awscc_iam_instance_profile that holds the role exactly (2026-11-01): the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles: a Set of String, one role per EC2 instance) and the awscc provider source of the instance profile resource, instance_profile_resource_gen.go:114 (knowledge-base evidence, not in this folder: the primary identifier is the name), read 2026-11-01; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

#### `module.retail_app_ecs.module.checkout_service.aws_iam_role.task_execution_role`

- **Source:** `aws_iam_role` — ../../lib/ecs/service/iam.tf:14
- **Module:** `module.retail_app_ecs.module.checkout_service` (./service)
- **Candidate target:** STACKIT service account for the workload (`stackit_service_account`, `stackit_service_account_key`, `stackit_authorization_project_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.iam_role/role-workload-execution`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic trust, semantic permissions, semantic tcfp-iam-role-policy-attachment--policy-arn, semantic iam-trust-service-workload and 1 more); a point the scan could not establish
- **Why:** Execution role of an application (Lambda function or ECS task). The application keeps needing these permissions on STACKIT: it gets a service account (or data-service credentials such as database users and object-storage keys) with equivalent grants.
- **Includes:** `module.retail_app_ecs.module.checkout_service.aws_iam_role_policy_attachment.task_execution_role_policy`
- **INFO** (iam-trust-service-workload): Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. On STACKIT the workload runs as a service account (stackit_service_account) and nothing assumes it: it authenticates with a service account key (stackit_service_account_key, key flow) or, on SKE, by Workload Identity Federation (a federated identity provider on the account). What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit).
- **INFO** (iam-managed-ecs): Managed policy of an ECS role (AWS: task execution pulls images from ECR and writes CloudWatch Logs; the container-instance role registers hosts with ECS). STACKIT has no ECS: image pull is a registry credential (Container Registry roles, Guest is read-only) and log shipping a platform or credential setting (stackit_logs_access_token); no STACKIT role replaces these grants. Container Registry: STACKIT offers this service. A public STACKIT API exists for it. The pinned Terraform provider has no resource for it. StackToIT does not draft automation for it yet; extra implementation is needed. (schema checked 2026-10-11: none of the 115 resource types of the pinned STACKIT provider), so the pull credential is not drafted (project roles: docs.stackit.cloud, updated Jul 2, 2026). What to decide: the registry pull credential and the log destination of the replacing workload.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (4):** trust, permissions, iam-trust-service-workload, iam-managed-ecs
- **Property accounting:** 3 of 3 meaningful properties accounted
- **2 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (2; REVIEW 2): `assume_role_policy`, `module.retail_app_ecs.module.checkout_service.aws_iam_role_policy_attachment.task_execution_role_policy.policy_arn` — NOT CARRIED (module.retail_app_ecs.module.checkout_service.aws_iam_role.task_execution_role): assume_role_policy, name = (reads a variable; its default is not printed) — stackit_service_account has a name and a project only (pinned provider): no trust policy, path, session duration or permissions boundary.
- **Why those are open, and what closes them:**
  - `trust`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The trust policy document of the role (its principals and conditions) has no STACKIT counterpart: stackit_service_account has name and project_id only (pinned provider schema), and the draft names assume_role_policy as not carried. Closes when: A person decides per principal who may assume the role: a federated identity provider (IRSA), a server attachment or a service account key; a role used only by an AWS service is dropped after a person confirms it.
  - `permissions`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. STACKIT IAM grants roles; the policy documents, conditions and resource patterns of the role are translated by a person. Closes when: A person translates each permission of the attached policies into STACKIT roles on the target resources.
  - `iam-trust-service-workload`: A check of the knowledge base (iam trust service workload) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `iam-managed-ecs`: A check of the knowledge base (iam managed ecs) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Managed policy of an ECS role (AWS: task execution pulls images from ECR and writes CloudWatch Logs; the container-instance role registers hosts with ECS). What to decide: the registry pull credential and the log destination of the replacing workload. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Review:**
  - [ ] List what the attached policies allow (tables, buckets, queues) and grant the same on the STACKIT targets.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); SKE workload identity docs 2026-09-15; IAM checks of 2026-10-06: provider 0.117.0 schema, docs.stackit.cloud access-and-identity 2026-10-06; IAM notes wording (Act-As, S3 bucket policy carrier, Container Registry has no resource): provider 0.119.0 schema and the docs.stackit.cloud pages cited in the checks, checked 2026-10-11; iam-managed-ssm-instance wording: provider 0.119.0 schema (stackit_server agent), docs.stackit.cloud server-agent, run-command and server pages and the AWS AmazonSSMManagedInstanceCore and Systems Manager instance-permission pages, fetched 2026-10-12; role-ec2-no-profile: provider 0.119.0 docs stackit_server_service_account_attach and stackit_service_account, read 2026-11-01; role-ec2-no-profile skips a role an awscc_iam_instance_profile names: the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles), read 2026-11-01; role-instance-profile of an awscc_iam_instance_profile that holds the role exactly (2026-11-01): the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles: a Set of String, one role per EC2 instance) and the awscc provider source of the instance profile resource, instance_profile_resource_gen.go:114 (knowledge-base evidence, not in this folder: the primary identifier is the name), read 2026-11-01; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

#### `module.retail_app_ecs.module.ui_service.aws_iam_role.task_execution_role`

- **Source:** `aws_iam_role` — ../../lib/ecs/service/iam.tf:14
- **Module:** `module.retail_app_ecs.module.ui_service` (./service)
- **Candidate target:** STACKIT service account for the workload (`stackit_service_account`, `stackit_service_account_key`, `stackit_authorization_project_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.iam_role/role-workload-execution`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic trust, semantic permissions, semantic tcfp-iam-role-policy-attachment--policy-arn, semantic iam-trust-service-workload and 1 more); a point the scan could not establish
- **Why:** Execution role of an application (Lambda function or ECS task). The application keeps needing these permissions on STACKIT: it gets a service account (or data-service credentials such as database users and object-storage keys) with equivalent grants.
- **Includes:** `module.retail_app_ecs.module.ui_service.aws_iam_role_policy_attachment.task_execution_role_policy`
- **INFO** (iam-trust-service-workload): Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. On STACKIT the workload runs as a service account (stackit_service_account) and nothing assumes it: it authenticates with a service account key (stackit_service_account_key, key flow) or, on SKE, by Workload Identity Federation (a federated identity provider on the account). What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit).
- **INFO** (iam-managed-ecs): Managed policy of an ECS role (AWS: task execution pulls images from ECR and writes CloudWatch Logs; the container-instance role registers hosts with ECS). STACKIT has no ECS: image pull is a registry credential (Container Registry roles, Guest is read-only) and log shipping a platform or credential setting (stackit_logs_access_token); no STACKIT role replaces these grants. Container Registry: STACKIT offers this service. A public STACKIT API exists for it. The pinned Terraform provider has no resource for it. StackToIT does not draft automation for it yet; extra implementation is needed. (schema checked 2026-10-11: none of the 115 resource types of the pinned STACKIT provider), so the pull credential is not drafted (project roles: docs.stackit.cloud, updated Jul 2, 2026). What to decide: the registry pull credential and the log destination of the replacing workload.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (4):** trust, permissions, iam-trust-service-workload, iam-managed-ecs
- **Property accounting:** 3 of 3 meaningful properties accounted
- **2 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (2; REVIEW 2): `assume_role_policy`, `module.retail_app_ecs.module.ui_service.aws_iam_role_policy_attachment.task_execution_role_policy.policy_arn` — NOT CARRIED (module.retail_app_ecs.module.ui_service.aws_iam_role.task_execution_role): assume_role_policy, name = (reads a variable; its default is not printed) — stackit_service_account has a name and a project only (pinned provider): no trust policy, path, session duration or permissions boundary.
- **Why those are open, and what closes them:**
  - `trust`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The trust policy document of the role (its principals and conditions) has no STACKIT counterpart: stackit_service_account has name and project_id only (pinned provider schema), and the draft names assume_role_policy as not carried. Closes when: A person decides per principal who may assume the role: a federated identity provider (IRSA), a server attachment or a service account key; a role used only by an AWS service is dropped after a person confirms it.
  - `permissions`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. STACKIT IAM grants roles; the policy documents, conditions and resource patterns of the role are translated by a person. Closes when: A person translates each permission of the attached policies into STACKIT roles on the target resources.
  - `iam-trust-service-workload`: A check of the knowledge base (iam trust service workload) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `iam-managed-ecs`: A check of the knowledge base (iam managed ecs) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Managed policy of an ECS role (AWS: task execution pulls images from ECR and writes CloudWatch Logs; the container-instance role registers hosts with ECS). What to decide: the registry pull credential and the log destination of the replacing workload. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Review:**
  - [ ] List what the attached policies allow (tables, buckets, queues) and grant the same on the STACKIT targets.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); SKE workload identity docs 2026-09-15; IAM checks of 2026-10-06: provider 0.117.0 schema, docs.stackit.cloud access-and-identity 2026-10-06; IAM notes wording (Act-As, S3 bucket policy carrier, Container Registry has no resource): provider 0.119.0 schema and the docs.stackit.cloud pages cited in the checks, checked 2026-10-11; iam-managed-ssm-instance wording: provider 0.119.0 schema (stackit_server agent), docs.stackit.cloud server-agent, run-command and server pages and the AWS AmazonSSMManagedInstanceCore and Systems Manager instance-permission pages, fetched 2026-10-12; role-ec2-no-profile: provider 0.119.0 docs stackit_server_service_account_attach and stackit_service_account, read 2026-11-01; role-ec2-no-profile skips a role an awscc_iam_instance_profile names: the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles), read 2026-11-01; role-instance-profile of an awscc_iam_instance_profile that holds the role exactly (2026-11-01): the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles: a Set of String, one role per EC2 instance) and the awscc provider source of the instance profile resource, instance_profile_resource_gen.go:114 (knowledge-base evidence, not in this folder: the primary identifier is the name), read 2026-11-01; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

#### `module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch`

- **Source:** `aws_secretsmanager_secret` — ../../lib/ecs/catalog.tf:82
- **Module:** `module.retail_app_ecs` (../../lib/ecs)
- **Candidate target:** STACKIT Secrets Manager (`stackit_secretsmanager_instance`, `stackit_secretsmanager_user`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.secretsmanager_secret/secret`
- **Feasibility:** CONDITIONAL — blocked by a compliance or security control (encryption, key management, audit logging, retention) (semantic customer-managed-key); identity or access mapping (semantic secret-value, semantic tc-secretsmanager-secret-name); a point the scan could not establish
- **Why:** Secrets move to STACKIT Secrets Manager (a Vault-compatible KV store). Applications switch from the AWS SDK to a Vault client or to injection via the platform (e.g. External Secrets Operator on SKE).
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-API-OPT-IN` (alias `convert:api:secrets-manager-vault:v1:unknown:API_OPT_IN`): Allow calls of the Secrets Manager Vault-compatible API, whose maturity is not established, for this migration (the API may change or vanish)? Accept: the calls of the Secrets Manager Vault-compatible API (WriteSecret) are carried out for module.retail_app_ecs.aws_secretsmanager_secret.catalog_db, module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch, module.retail_app_ecs.aws_secretsmanager_secret.mq, module.retail_app_ecs.aws_secretsmanager_secret.orders_db. Refuse: no call is made, a refusal selects no other path (the draft holds no other carrier of what the calls set), and what they set stays open for module.retail_app_ecs.aws_secretsmanager_secret.catalog_db, module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch, module.retail_app_ecs.aws_secretsmanager_secret.mq, module.retail_app_ecs.aws_secretsmanager_secret.orders_db. · the Secrets Manager Vault-compatible API is of a maturity that is not established (its documentation states no release status and its product documentation does not establish it as generally available): the execution plan executes no call of an API that is not generally available without an explicit opt-in, so the calls of it and the steps of its path for module.retail_app_ecs.aws_secretsmanager_secret.catalog_db, module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch, module.retail_app_ecs.aws_secretsmanager_secret.mq, module.retail_app_ecs.aws_secretsmanager_secret.orders_db wait for this decision; the draft's own blocks do not
- **Includes:** `module.retail_app_ecs.aws_secretsmanager_secret_version.catalog_opensearch`
- **Depends on:** `module.retail_app_ecs.aws_kms_key.cmk`
- **INFO** (secret-cmk): The secret is encrypted with a customer-managed KMS key. STACKIT Secrets Manager can encrypt with a customer-chosen key too, but the AWS key does not move: the instance's kms_key block (stackit_secretsmanager_instance: key_id, key_ring_id, key_version, service_account_email) names a STACKIT KMS key, one key for all secret values of the instance. The draft sets that block only when every source of the shared instance is an AWS secret that references the same drafted key; otherwise it does not set it and names the key NOT CARRIED with the reason. Decide whether to create the key (stackit_kms_keyring, stackit_kms_key) and a service account with at least the Secrets Manager Reader role in the same project and region, put the kms_key block on the instance, and which secrets share an instance when they used different keys (one key per instance, not per secret). Without the block the instance uses STACKIT's default encryption.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (3):** secret-value, customer-managed-key, tc-secretsmanager-secret-name
- **Property accounting:** 3 of 3 meaningful properties accounted
- **3 critical setting(s) left to you** — **not automation-eligible**:
  - encryption (1; REVIEW 1): `kms_key_id` — NOT CARRIED (module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch): kms_key_id — the source encrypts with a customer-managed key that the draft does not set on the Secrets Manager instance: the instance also holds module.retail_app_ecs.aws_secretsmanager_secret.mq, which states no customer-managed key (the default key encrypts it), and it would be encrypted with the key too.
  - secret handling (1; REVIEW 1): `module.retail_app_ecs.aws_secretsmanager_secret_version.catalog_opensearch.secret_string` — NOT CARRIED (module.retail_app_ecs.aws_secretsmanager_secret_version.catalog_opensearch): secret_id, secret_string — a setting of module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch: the API step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
  - workload compatibility (1; REVIEW 1): `name` — NOT CARRIED (module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch): name — the API step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
- **Why those are open, and what closes them:**
  - `secret-value`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The value moves to STACKIT Secrets Manager (Vault-compatible KV). The draft generates the shared instance, and the plan a WriteSecret step for an aws_secretsmanager_secret or a SecureString aws_ssm_parameter that is not repeated. The step writes the document the person supplies and does not carry this setting (the value is the person's document); for a secret repeated by count or for_each whose instances are not all known, and for a parameter whose type is not the literal SecureString, only the instance is generated. What a person decides, per secret: where the value comes from (the same value fetched from a secure source, or a new one — moving is the moment to rotate) and the Vault path the application will read, then writes it with the Vault provider or CLI — REVIEW. History: added with aws_ssm_parameter on 2026-09-24; REVIEW since 2026-09-27 (was TRANSFORMED); 2026-10-29 the wording names the WriteSecret step of the plan; 2026-10-30 the step is also made for a SecureString parameter. Closes when: A person decides per secret where the value comes from (the same value from a secure source, or a new one) and the Vault path the application reads, then writes it with a Vault KV v2 client.
  - `customer-managed-key`: A check of the knowledge base (secret cmk) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Critical and reading the key since 2026-09-27: the draft names it NOT CARRIED, except where it sets the instance's kms_key (below). The AWS key does not move, AWS's key per secret has no per-secret counterpart, and the draft sets the kms_key block (referencing the drafted STACKIT key) only when every source of the shared instance is an AWS secret that references that one key — otherwise it names the key NOT CARRIED with the reason; either way a person decides (REVIEW, see the customer-managed key check). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `tc-secretsmanager-secret-name`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. aws_secretsmanager_secret.name: Friendly name used to address the secret; losing it breaks lookups by name but does not change who may reach or read the value, its encryption or deletion behaviour (IAM statements that scope by name are assessed on the IAM policy). No semantic of this family has verified it as carried. Held CRITICAL: the workload, its clients or its neighbours rely on it (an address, a name, a protocol or an execution contract). Closes when: A person confirms the secret name or path the application looks up on the target, or accepts the new one.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; docs security/secrets-manager 2026-09-23; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/security/secrets-manager/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/secretsmanager_instance

#### `module.retail_app_ecs.module.carts_service.aws_iam_role.task_role`

- **Source:** `aws_iam_role` — ../../lib/ecs/service/iam.tf:31
- **Configuration:** conditional — the unit exists and counts in the totals, but part of what configures it is decided only when a plan runs; it is not automation-eligible (gate blocker `CONFIGURATION:conditional-facet`).
  - `module.retail_app_ecs.module.carts_service.aws_iam_role_policy_attachment.cloudwatch_agent` is switched off by default (the default of variable `var.opentelemetry_enabled`; a root variable that a variable file or the command line can override): nothing of it is drafted, and a variable file or `-var` that gives that input another value creates it
- **Module:** `module.retail_app_ecs.module.carts_service` (./service)
- **Candidate target:** STACKIT service account for the workload (`stackit_service_account`, `stackit_service_account_key`, `stackit_authorization_project_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** LOW · rule `aws.iam_role/role-workload-execution`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic trust, semantic permissions, semantic tcfp-iam-role-policy-attachment--policy-arn, semantic iam-trust-service-workload and 2 more); a point the scan could not establish
- **Why:** Execution role of an application (Lambda function or ECS task). The application keeps needing these permissions on STACKIT: it gets a service account (or data-service credentials such as database users and object-storage keys) with equivalent grants.
- **Includes:** `module.retail_app_ecs.module.carts_service.aws_iam_role_policy_attachment.cloudwatch_logs`, `module.retail_app_ecs.module.carts_service.aws_iam_role_policy_attachment.ecs_exec`, `module.retail_app_ecs.module.carts_service.aws_iam_role_policy_attachment.task_role_additional`
- **Depends on:** `module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this`, `module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`
- **INFO** (iam-trust-service-workload): Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. On STACKIT the workload runs as a service account (stackit_service_account) and nothing assumes it: it authenticates with a service account key (stackit_service_account_key, key flow) or, on SKE, by Workload Identity Federation (a federated identity provider on the account). What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit).
- **INFO** (iam-managed-customer-policy): This attachment names a customer-managed policy of this estate (an aws_iam_policy), not an AWS-managed one. STACKIT has no managed-policy object to attach: the permissions become role assignments of the service account (stackit_authorization_project_role_assignment: resource_id, role, subject), decided from the policy's document, whose shape is reported on the policy itself (a Deny, a Condition and sts:AssumeRole are UNSUPPORTED there; the service families s3, kms, secrets, logs, ec2 and iam name the STACKIT role or credential). What to decide: the roles of this role's service account from the findings of every policy attached here, and whether one policy shared by several roles becomes one set of role assignments or several. — a variable's default, not a fact
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (linked-dependency-unread): This unit names module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this (aws_dynamodb_table), whose own decision the target does not carry (it is REDESIGN), and the semantic contract of aws_iam_role does not read aws_dynamodb_table, so what the reference becomes is not assessed.
- **INFO** (iam-document-hidden): jsonencode: the permission document of `module.retail_app_ecs.module.carts_service.aws_iam_policy.cloudwatch_logs` is not visible statically: jsonencode, first hidden reference data.aws_region.current.name (a data source, read when a plan runs). `module.retail_app_ecs.module.carts_service.aws_iam_role_policy_attachment.cloudwatch_logs` names it. What it allows or denies cannot be read, so the permission findings of this unit (Deny, Condition, sts:AssumeRole, the service families) do not cover it. What to decide: read the effective policy (aws iam get-role-policy, aws iam get-policy-version), or give the value the document is made of, so the document is visible.
- **INFO** (iam-document-hidden): heredoc: the permission document of `module.dependencies.aws_iam_policy.carts_dynamo` is not visible statically: a heredoc, first hidden reference local.aws_partition (a data source, read when a plan runs). `module.retail_app_ecs.module.carts_service.aws_iam_role_policy_attachment.task_role_additional` names it. What it allows or denies cannot be read, so the permission findings of this unit (Deny, Condition, sts:AssumeRole, the service families) do not cover it. What to decide: read the effective policy (aws iam get-role-policy, aws iam get-policy-version), or give the value the document is made of, so the document is visible.
- **Critical semantics left to you to decide or accept (4):** iam-managed-customer-policy, iam-trust-service-workload, permissions, trust (**not automation-eligible**: no property the unit sets is read by linked-dependency:aws_dynamodb_table)
- **Property accounting:** 5 of 5 meaningful properties accounted
- **4 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (4; REVIEW 4): `assume_role_policy`, `module.retail_app_ecs.module.carts_service.aws_iam_role_policy_attachment.cloudwatch_logs.policy_arn`, `module.retail_app_ecs.module.carts_service.aws_iam_role_policy_attachment.ecs_exec.policy_arn`, `module.retail_app_ecs.module.carts_service.aws_iam_role_policy_attachment.task_role_additional.policy_arn` — NOT CARRIED (module.retail_app_ecs.module.carts_service.aws_iam_role.task_role): assume_role_policy, name = (reads a variable; its default is not printed) — stackit_service_account has a name and a project only (pinned provider): no trust policy, path, session duration or permissions boundary.
- **Why those are open, and what closes them:**
  - `trust`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The trust policy document of the role (its principals and conditions) has no STACKIT counterpart: stackit_service_account has name and project_id only (pinned provider schema), and the draft names assume_role_policy as not carried. Closes when: A person decides per principal who may assume the role: a federated identity provider (IRSA), a server attachment or a service account key; a role used only by an AWS service is dropped after a person confirms it.
  - `permissions`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. STACKIT IAM grants roles; the policy documents, conditions and resource patterns of the role are translated by a person. The unit names module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this (aws_dynamodb_table) through this setting (the target does not carry it: it is REDESIGN), so what the reference becomes is part of this setting. Closes when: A person translates each permission of the attached policies into STACKIT roles on the target resources.
  - `iam-trust-service-workload`: A check of the knowledge base (iam trust service workload) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `iam-managed-customer-policy`: A check of the knowledge base (iam managed customer policy) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). This attachment names a customer-managed policy of this estate (an aws_iam_policy), not an AWS-managed one. What to decide: the roles of this role's service account from the findings of every policy attached here, and whether one policy shared by several roles becomes one set of role assignments or several. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Review:**
  - [ ] List what the attached policies allow (tables, buckets, queues) and grant the same on the STACKIT targets.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); SKE workload identity docs 2026-09-15; IAM checks of 2026-10-06: provider 0.117.0 schema, docs.stackit.cloud access-and-identity 2026-10-06; IAM notes wording (Act-As, S3 bucket policy carrier, Container Registry has no resource): provider 0.119.0 schema and the docs.stackit.cloud pages cited in the checks, checked 2026-10-11; iam-managed-ssm-instance wording: provider 0.119.0 schema (stackit_server agent), docs.stackit.cloud server-agent, run-command and server pages and the AWS AmazonSSMManagedInstanceCore and Systems Manager instance-permission pages, fetched 2026-10-12; role-ec2-no-profile: provider 0.119.0 docs stackit_server_service_account_attach and stackit_service_account, read 2026-11-01; role-ec2-no-profile skips a role an awscc_iam_instance_profile names: the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles), read 2026-11-01; role-instance-profile of an awscc_iam_instance_profile that holds the role exactly (2026-11-01): the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles: a Set of String, one role per EC2 instance) and the awscc provider source of the instance profile resource, instance_profile_resource_gen.go:114 (knowledge-base evidence, not in this folder: the primary identifier is the name), read 2026-11-01; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

#### `module.retail_app_ecs.module.catalog_service.aws_iam_role.task_role`

- **Source:** `aws_iam_role` — ../../lib/ecs/service/iam.tf:31
- **Configuration:** conditional — the unit exists and counts in the totals, but part of what configures it is decided only when a plan runs; it is not automation-eligible (gate blocker `CONFIGURATION:conditional-facet`).
  - `module.retail_app_ecs.module.catalog_service.aws_iam_role_policy_attachment.cloudwatch_agent` is switched off by default (the default of variable `var.opentelemetry_enabled`; a root variable that a variable file or the command line can override): nothing of it is drafted, and a variable file or `-var` that gives that input another value creates it
- **Module:** `module.retail_app_ecs.module.catalog_service` (./service)
- **Candidate target:** STACKIT service account for the workload (`stackit_service_account`, `stackit_service_account_key`, `stackit_authorization_project_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.iam_role/role-workload-execution`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic trust, semantic permissions, semantic tcfp-iam-role-policy-attachment--policy-arn, semantic iam-trust-service-workload and 1 more); a point the scan could not establish
- **Why:** Execution role of an application (Lambda function or ECS task). The application keeps needing these permissions on STACKIT: it gets a service account (or data-service credentials such as database users and object-storage keys) with equivalent grants.
- **Includes:** `module.retail_app_ecs.module.catalog_service.aws_iam_role_policy_attachment.cloudwatch_logs`, `module.retail_app_ecs.module.catalog_service.aws_iam_role_policy_attachment.ecs_exec`
- **Depends on:** `module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`
- **INFO** (iam-trust-service-workload): Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. On STACKIT the workload runs as a service account (stackit_service_account) and nothing assumes it: it authenticates with a service account key (stackit_service_account_key, key flow) or, on SKE, by Workload Identity Federation (a federated identity provider on the account). What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit).
- **INFO** (iam-managed-customer-policy): This attachment names a customer-managed policy of this estate (an aws_iam_policy), not an AWS-managed one. STACKIT has no managed-policy object to attach: the permissions become role assignments of the service account (stackit_authorization_project_role_assignment: resource_id, role, subject), decided from the policy's document, whose shape is reported on the policy itself (a Deny, a Condition and sts:AssumeRole are UNSUPPORTED there; the service families s3, kms, secrets, logs, ec2 and iam name the STACKIT role or credential). What to decide: the roles of this role's service account from the findings of every policy attached here, and whether one policy shared by several roles becomes one set of role assignments or several.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **INFO** (iam-document-hidden): jsonencode: the permission document of `module.retail_app_ecs.module.catalog_service.aws_iam_policy.cloudwatch_logs` is not visible statically: jsonencode, first hidden reference data.aws_region.current.name (a data source, read when a plan runs). `module.retail_app_ecs.module.catalog_service.aws_iam_role_policy_attachment.cloudwatch_logs` names it. What it allows or denies cannot be read, so the permission findings of this unit (Deny, Condition, sts:AssumeRole, the service families) do not cover it. What to decide: read the effective policy (aws iam get-role-policy, aws iam get-policy-version), or give the value the document is made of, so the document is visible.
- **Critical semantics left to you to decide or accept (4):** trust, permissions, iam-trust-service-workload, iam-managed-customer-policy
- **Property accounting:** 4 of 4 meaningful properties accounted
- **3 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (3; REVIEW 3): `assume_role_policy`, `module.retail_app_ecs.module.catalog_service.aws_iam_role_policy_attachment.cloudwatch_logs.policy_arn`, `module.retail_app_ecs.module.catalog_service.aws_iam_role_policy_attachment.ecs_exec.policy_arn` — NOT CARRIED (module.retail_app_ecs.module.catalog_service.aws_iam_role.task_role): assume_role_policy, name = (reads a variable; its default is not printed) — stackit_service_account has a name and a project only (pinned provider): no trust policy, path, session duration or permissions boundary.
- **Why those are open, and what closes them:**
  - `trust`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The trust policy document of the role (its principals and conditions) has no STACKIT counterpart: stackit_service_account has name and project_id only (pinned provider schema), and the draft names assume_role_policy as not carried. Closes when: A person decides per principal who may assume the role: a federated identity provider (IRSA), a server attachment or a service account key; a role used only by an AWS service is dropped after a person confirms it.
  - `permissions`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. STACKIT IAM grants roles; the policy documents, conditions and resource patterns of the role are translated by a person. Closes when: A person translates each permission of the attached policies into STACKIT roles on the target resources.
  - `iam-trust-service-workload`: A check of the knowledge base (iam trust service workload) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `iam-managed-customer-policy`: A check of the knowledge base (iam managed customer policy) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). This attachment names a customer-managed policy of this estate (an aws_iam_policy), not an AWS-managed one. What to decide: the roles of this role's service account from the findings of every policy attached here, and whether one policy shared by several roles becomes one set of role assignments or several. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Review:**
  - [ ] List what the attached policies allow (tables, buckets, queues) and grant the same on the STACKIT targets.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); SKE workload identity docs 2026-09-15; IAM checks of 2026-10-06: provider 0.117.0 schema, docs.stackit.cloud access-and-identity 2026-10-06; IAM notes wording (Act-As, S3 bucket policy carrier, Container Registry has no resource): provider 0.119.0 schema and the docs.stackit.cloud pages cited in the checks, checked 2026-10-11; iam-managed-ssm-instance wording: provider 0.119.0 schema (stackit_server agent), docs.stackit.cloud server-agent, run-command and server pages and the AWS AmazonSSMManagedInstanceCore and Systems Manager instance-permission pages, fetched 2026-10-12; role-ec2-no-profile: provider 0.119.0 docs stackit_server_service_account_attach and stackit_service_account, read 2026-11-01; role-ec2-no-profile skips a role an awscc_iam_instance_profile names: the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles), read 2026-11-01; role-instance-profile of an awscc_iam_instance_profile that holds the role exactly (2026-11-01): the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles: a Set of String, one role per EC2 instance) and the awscc provider source of the instance profile resource, instance_profile_resource_gen.go:114 (knowledge-base evidence, not in this folder: the primary identifier is the name), read 2026-11-01; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

#### `module.retail_app_ecs.module.checkout_service.aws_iam_role.task_role`

- **Source:** `aws_iam_role` — ../../lib/ecs/service/iam.tf:31
- **Configuration:** conditional — the unit exists and counts in the totals, but part of what configures it is decided only when a plan runs; it is not automation-eligible (gate blocker `CONFIGURATION:conditional-facet`).
  - `module.retail_app_ecs.module.checkout_service.aws_iam_role_policy_attachment.cloudwatch_agent` is switched off by default (the default of variable `var.opentelemetry_enabled`; a root variable that a variable file or the command line can override): nothing of it is drafted, and a variable file or `-var` that gives that input another value creates it
- **Module:** `module.retail_app_ecs.module.checkout_service` (./service)
- **Candidate target:** STACKIT service account for the workload (`stackit_service_account`, `stackit_service_account_key`, `stackit_authorization_project_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** LOW · rule `aws.iam_role/role-workload-execution`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic trust, semantic permissions, semantic tcfp-iam-role-policy-attachment--policy-arn, semantic iam-trust-service-workload and 2 more); a point the scan could not establish
- **Why:** Execution role of an application (Lambda function or ECS task). The application keeps needing these permissions on STACKIT: it gets a service account (or data-service credentials such as database users and object-storage keys) with equivalent grants.
- **Includes:** `module.retail_app_ecs.module.checkout_service.aws_iam_role_policy_attachment.cloudwatch_logs`, `module.retail_app_ecs.module.checkout_service.aws_iam_role_policy_attachment.ecs_exec`, `module.retail_app_ecs.module.checkout_service.aws_iam_role_policy_attachment.task_role_additional`
- **Depends on:** `module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this`, `module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`
- **INFO** (iam-trust-service-workload): Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. On STACKIT the workload runs as a service account (stackit_service_account) and nothing assumes it: it authenticates with a service account key (stackit_service_account_key, key flow) or, on SKE, by Workload Identity Federation (a federated identity provider on the account). What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit).
- **INFO** (iam-managed-customer-policy): This attachment names a customer-managed policy of this estate (an aws_iam_policy), not an AWS-managed one. STACKIT has no managed-policy object to attach: the permissions become role assignments of the service account (stackit_authorization_project_role_assignment: resource_id, role, subject), decided from the policy's document, whose shape is reported on the policy itself (a Deny, a Condition and sts:AssumeRole are UNSUPPORTED there; the service families s3, kms, secrets, logs, ec2 and iam name the STACKIT role or credential). What to decide: the roles of this role's service account from the findings of every policy attached here, and whether one policy shared by several roles becomes one set of role assignments or several. — a variable's default, not a fact
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (linked-dependency-unread): This unit names module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this (aws_dynamodb_table), whose own decision the target does not carry (it is REDESIGN), and the semantic contract of aws_iam_role does not read aws_dynamodb_table, so what the reference becomes is not assessed.
- **INFO** (iam-document-hidden): jsonencode: the permission document of `module.retail_app_ecs.module.checkout_service.aws_iam_policy.cloudwatch_logs` is not visible statically: jsonencode, first hidden reference data.aws_region.current.name (a data source, read when a plan runs). `module.retail_app_ecs.module.checkout_service.aws_iam_role_policy_attachment.cloudwatch_logs` names it. What it allows or denies cannot be read, so the permission findings of this unit (Deny, Condition, sts:AssumeRole, the service families) do not cover it. What to decide: read the effective policy (aws iam get-role-policy, aws iam get-policy-version), or give the value the document is made of, so the document is visible.
- **INFO** (iam-document-hidden): heredoc: the permission document of `module.dependencies.aws_iam_policy.carts_dynamo` is not visible statically: a heredoc, first hidden reference local.aws_partition (a data source, read when a plan runs). `module.retail_app_ecs.module.checkout_service.aws_iam_role_policy_attachment.task_role_additional` names it. What it allows or denies cannot be read, so the permission findings of this unit (Deny, Condition, sts:AssumeRole, the service families) do not cover it. What to decide: read the effective policy (aws iam get-role-policy, aws iam get-policy-version), or give the value the document is made of, so the document is visible.
- **Critical semantics left to you to decide or accept (4):** iam-managed-customer-policy, iam-trust-service-workload, permissions, trust (**not automation-eligible**: no property the unit sets is read by linked-dependency:aws_dynamodb_table)
- **Property accounting:** 5 of 5 meaningful properties accounted
- **4 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (4; REVIEW 4): `assume_role_policy`, `module.retail_app_ecs.module.checkout_service.aws_iam_role_policy_attachment.cloudwatch_logs.policy_arn`, `module.retail_app_ecs.module.checkout_service.aws_iam_role_policy_attachment.ecs_exec.policy_arn`, `module.retail_app_ecs.module.checkout_service.aws_iam_role_policy_attachment.task_role_additional.policy_arn` — NOT CARRIED (module.retail_app_ecs.module.checkout_service.aws_iam_role.task_role): assume_role_policy, name = (reads a variable; its default is not printed) — stackit_service_account has a name and a project only (pinned provider): no trust policy, path, session duration or permissions boundary.
- **Why those are open, and what closes them:**
  - `trust`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The trust policy document of the role (its principals and conditions) has no STACKIT counterpart: stackit_service_account has name and project_id only (pinned provider schema), and the draft names assume_role_policy as not carried. Closes when: A person decides per principal who may assume the role: a federated identity provider (IRSA), a server attachment or a service account key; a role used only by an AWS service is dropped after a person confirms it.
  - `permissions`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. STACKIT IAM grants roles; the policy documents, conditions and resource patterns of the role are translated by a person. The unit names module.dependencies.module.dynamodb_carts.aws_dynamodb_table.this (aws_dynamodb_table) through this setting (the target does not carry it: it is REDESIGN), so what the reference becomes is part of this setting. Closes when: A person translates each permission of the attached policies into STACKIT roles on the target resources.
  - `iam-trust-service-workload`: A check of the knowledge base (iam trust service workload) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `iam-managed-customer-policy`: A check of the knowledge base (iam managed customer policy) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). This attachment names a customer-managed policy of this estate (an aws_iam_policy), not an AWS-managed one. What to decide: the roles of this role's service account from the findings of every policy attached here, and whether one policy shared by several roles becomes one set of role assignments or several. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Review:**
  - [ ] List what the attached policies allow (tables, buckets, queues) and grant the same on the STACKIT targets.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); SKE workload identity docs 2026-09-15; IAM checks of 2026-10-06: provider 0.117.0 schema, docs.stackit.cloud access-and-identity 2026-10-06; IAM notes wording (Act-As, S3 bucket policy carrier, Container Registry has no resource): provider 0.119.0 schema and the docs.stackit.cloud pages cited in the checks, checked 2026-10-11; iam-managed-ssm-instance wording: provider 0.119.0 schema (stackit_server agent), docs.stackit.cloud server-agent, run-command and server pages and the AWS AmazonSSMManagedInstanceCore and Systems Manager instance-permission pages, fetched 2026-10-12; role-ec2-no-profile: provider 0.119.0 docs stackit_server_service_account_attach and stackit_service_account, read 2026-11-01; role-ec2-no-profile skips a role an awscc_iam_instance_profile names: the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles), read 2026-11-01; role-instance-profile of an awscc_iam_instance_profile that holds the role exactly (2026-11-01): the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles: a Set of String, one role per EC2 instance) and the awscc provider source of the instance profile resource, instance_profile_resource_gen.go:114 (knowledge-base evidence, not in this folder: the primary identifier is the name), read 2026-11-01; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

#### `module.retail_app_ecs.module.orders_service.aws_iam_role.task_role`

- **Source:** `aws_iam_role` — ../../lib/ecs/service/iam.tf:31
- **Configuration:** conditional — the unit exists and counts in the totals, but part of what configures it is decided only when a plan runs; it is not automation-eligible (gate blocker `CONFIGURATION:conditional-facet`).
  - `module.retail_app_ecs.module.orders_service.aws_iam_role_policy_attachment.cloudwatch_agent` is switched off by default (the default of variable `var.opentelemetry_enabled`; a root variable that a variable file or the command line can override): nothing of it is drafted, and a variable file or `-var` that gives that input another value creates it
- **Module:** `module.retail_app_ecs.module.orders_service` (./service)
- **Candidate target:** STACKIT service account for the workload (`stackit_service_account`, `stackit_service_account_key`, `stackit_authorization_project_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.iam_role/role-workload-execution`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic trust, semantic permissions, semantic tcfp-iam-role-policy-attachment--policy-arn, semantic iam-trust-service-workload and 1 more); a point the scan could not establish
- **Why:** Execution role of an application (Lambda function or ECS task). The application keeps needing these permissions on STACKIT: it gets a service account (or data-service credentials such as database users and object-storage keys) with equivalent grants.
- **Includes:** `module.retail_app_ecs.module.orders_service.aws_iam_role_policy_attachment.cloudwatch_logs`, `module.retail_app_ecs.module.orders_service.aws_iam_role_policy_attachment.ecs_exec`
- **Depends on:** `module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`
- **INFO** (iam-trust-service-workload): Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. On STACKIT the workload runs as a service account (stackit_service_account) and nothing assumes it: it authenticates with a service account key (stackit_service_account_key, key flow) or, on SKE, by Workload Identity Federation (a federated identity provider on the account). What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit).
- **INFO** (iam-managed-customer-policy): This attachment names a customer-managed policy of this estate (an aws_iam_policy), not an AWS-managed one. STACKIT has no managed-policy object to attach: the permissions become role assignments of the service account (stackit_authorization_project_role_assignment: resource_id, role, subject), decided from the policy's document, whose shape is reported on the policy itself (a Deny, a Condition and sts:AssumeRole are UNSUPPORTED there; the service families s3, kms, secrets, logs, ec2 and iam name the STACKIT role or credential). What to decide: the roles of this role's service account from the findings of every policy attached here, and whether one policy shared by several roles becomes one set of role assignments or several.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **INFO** (iam-document-hidden): jsonencode: the permission document of `module.retail_app_ecs.module.orders_service.aws_iam_policy.cloudwatch_logs` is not visible statically: jsonencode, first hidden reference data.aws_region.current.name (a data source, read when a plan runs). `module.retail_app_ecs.module.orders_service.aws_iam_role_policy_attachment.cloudwatch_logs` names it. What it allows or denies cannot be read, so the permission findings of this unit (Deny, Condition, sts:AssumeRole, the service families) do not cover it. What to decide: read the effective policy (aws iam get-role-policy, aws iam get-policy-version), or give the value the document is made of, so the document is visible.
- **Critical semantics left to you to decide or accept (4):** trust, permissions, iam-trust-service-workload, iam-managed-customer-policy
- **Property accounting:** 4 of 4 meaningful properties accounted
- **3 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (3; REVIEW 3): `assume_role_policy`, `module.retail_app_ecs.module.orders_service.aws_iam_role_policy_attachment.cloudwatch_logs.policy_arn`, `module.retail_app_ecs.module.orders_service.aws_iam_role_policy_attachment.ecs_exec.policy_arn` — NOT CARRIED (module.retail_app_ecs.module.orders_service.aws_iam_role.task_role): assume_role_policy, name = (reads a variable; its default is not printed) — stackit_service_account has a name and a project only (pinned provider): no trust policy, path, session duration or permissions boundary.
- **Why those are open, and what closes them:**
  - `trust`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The trust policy document of the role (its principals and conditions) has no STACKIT counterpart: stackit_service_account has name and project_id only (pinned provider schema), and the draft names assume_role_policy as not carried. Closes when: A person decides per principal who may assume the role: a federated identity provider (IRSA), a server attachment or a service account key; a role used only by an AWS service is dropped after a person confirms it.
  - `permissions`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. STACKIT IAM grants roles; the policy documents, conditions and resource patterns of the role are translated by a person. Closes when: A person translates each permission of the attached policies into STACKIT roles on the target resources.
  - `iam-trust-service-workload`: A check of the knowledge base (iam trust service workload) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `iam-managed-customer-policy`: A check of the knowledge base (iam managed customer policy) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). This attachment names a customer-managed policy of this estate (an aws_iam_policy), not an AWS-managed one. What to decide: the roles of this role's service account from the findings of every policy attached here, and whether one policy shared by several roles becomes one set of role assignments or several. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Review:**
  - [ ] List what the attached policies allow (tables, buckets, queues) and grant the same on the STACKIT targets.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); SKE workload identity docs 2026-09-15; IAM checks of 2026-10-06: provider 0.117.0 schema, docs.stackit.cloud access-and-identity 2026-10-06; IAM notes wording (Act-As, S3 bucket policy carrier, Container Registry has no resource): provider 0.119.0 schema and the docs.stackit.cloud pages cited in the checks, checked 2026-10-11; iam-managed-ssm-instance wording: provider 0.119.0 schema (stackit_server agent), docs.stackit.cloud server-agent, run-command and server pages and the AWS AmazonSSMManagedInstanceCore and Systems Manager instance-permission pages, fetched 2026-10-12; role-ec2-no-profile: provider 0.119.0 docs stackit_server_service_account_attach and stackit_service_account, read 2026-11-01; role-ec2-no-profile skips a role an awscc_iam_instance_profile names: the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles), read 2026-11-01; role-instance-profile of an awscc_iam_instance_profile that holds the role exactly (2026-11-01): the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles: a Set of String, one role per EC2 instance) and the awscc provider source of the instance profile resource, instance_profile_resource_gen.go:114 (knowledge-base evidence, not in this folder: the primary identifier is the name), read 2026-11-01; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

#### `module.retail_app_ecs.module.ui_service.aws_iam_role.task_role`

- **Source:** `aws_iam_role` — ../../lib/ecs/service/iam.tf:31
- **Configuration:** conditional — the unit exists and counts in the totals, but part of what configures it is decided only when a plan runs; it is not automation-eligible (gate blocker `CONFIGURATION:conditional-facet`).
  - `module.retail_app_ecs.module.ui_service.aws_iam_role_policy_attachment.cloudwatch_agent` is switched off by default (the default of variable `var.opentelemetry_enabled`; a root variable that a variable file or the command line can override): nothing of it is drafted, and a variable file or `-var` that gives that input another value creates it
- **Module:** `module.retail_app_ecs.module.ui_service` (./service)
- **Candidate target:** STACKIT service account for the workload (`stackit_service_account`, `stackit_service_account_key`, `stackit_authorization_project_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.iam_role/role-workload-execution`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic trust, semantic permissions, semantic tcfp-iam-role-policy-attachment--policy-arn, semantic iam-trust-service-workload and 1 more); a point the scan could not establish
- **Why:** Execution role of an application (Lambda function or ECS task). The application keeps needing these permissions on STACKIT: it gets a service account (or data-service credentials such as database users and object-storage keys) with equivalent grants.
- **Includes:** `module.retail_app_ecs.module.ui_service.aws_iam_role_policy_attachment.cloudwatch_logs`, `module.retail_app_ecs.module.ui_service.aws_iam_role_policy_attachment.ecs_exec`
- **Depends on:** `module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`
- **INFO** (iam-trust-service-workload): Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. On STACKIT the workload runs as a service account (stackit_service_account) and nothing assumes it: it authenticates with a service account key (stackit_service_account_key, key flow) or, on SKE, by Workload Identity Federation (a federated identity provider on the account). What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit).
- **INFO** (iam-managed-customer-policy): This attachment names a customer-managed policy of this estate (an aws_iam_policy), not an AWS-managed one. STACKIT has no managed-policy object to attach: the permissions become role assignments of the service account (stackit_authorization_project_role_assignment: resource_id, role, subject), decided from the policy's document, whose shape is reported on the policy itself (a Deny, a Condition and sts:AssumeRole are UNSUPPORTED there; the service families s3, kms, secrets, logs, ec2 and iam name the STACKIT role or credential). What to decide: the roles of this role's service account from the findings of every policy attached here, and whether one policy shared by several roles becomes one set of role assignments or several.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **INFO** (iam-document-hidden): jsonencode: the permission document of `module.retail_app_ecs.module.ui_service.aws_iam_policy.cloudwatch_logs` is not visible statically: jsonencode, first hidden reference data.aws_region.current.name (a data source, read when a plan runs). `module.retail_app_ecs.module.ui_service.aws_iam_role_policy_attachment.cloudwatch_logs` names it. What it allows or denies cannot be read, so the permission findings of this unit (Deny, Condition, sts:AssumeRole, the service families) do not cover it. What to decide: read the effective policy (aws iam get-role-policy, aws iam get-policy-version), or give the value the document is made of, so the document is visible.
- **Critical semantics left to you to decide or accept (4):** trust, permissions, iam-trust-service-workload, iam-managed-customer-policy
- **Property accounting:** 4 of 4 meaningful properties accounted
- **3 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (3; REVIEW 3): `assume_role_policy`, `module.retail_app_ecs.module.ui_service.aws_iam_role_policy_attachment.cloudwatch_logs.policy_arn`, `module.retail_app_ecs.module.ui_service.aws_iam_role_policy_attachment.ecs_exec.policy_arn` — NOT CARRIED (module.retail_app_ecs.module.ui_service.aws_iam_role.task_role): assume_role_policy, name = (reads a variable; its default is not printed) — stackit_service_account has a name and a project only (pinned provider): no trust policy, path, session duration or permissions boundary.
- **Why those are open, and what closes them:**
  - `trust`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The trust policy document of the role (its principals and conditions) has no STACKIT counterpart: stackit_service_account has name and project_id only (pinned provider schema), and the draft names assume_role_policy as not carried. Closes when: A person decides per principal who may assume the role: a federated identity provider (IRSA), a server attachment or a service account key; a role used only by an AWS service is dropped after a person confirms it.
  - `permissions`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. STACKIT IAM grants roles; the policy documents, conditions and resource patterns of the role are translated by a person. Closes when: A person translates each permission of the attached policies into STACKIT roles on the target resources.
  - `iam-trust-service-workload`: A check of the knowledge base (iam trust service workload) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `iam-managed-customer-policy`: A check of the knowledge base (iam managed customer policy) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). This attachment names a customer-managed policy of this estate (an aws_iam_policy), not an AWS-managed one. What to decide: the roles of this role's service account from the findings of every policy attached here, and whether one policy shared by several roles becomes one set of role assignments or several. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Review:**
  - [ ] List what the attached policies allow (tables, buckets, queues) and grant the same on the STACKIT targets.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); SKE workload identity docs 2026-09-15; IAM checks of 2026-10-06: provider 0.117.0 schema, docs.stackit.cloud access-and-identity 2026-10-06; IAM notes wording (Act-As, S3 bucket policy carrier, Container Registry has no resource): provider 0.119.0 schema and the docs.stackit.cloud pages cited in the checks, checked 2026-10-11; iam-managed-ssm-instance wording: provider 0.119.0 schema (stackit_server agent), docs.stackit.cloud server-agent, run-command and server pages and the AWS AmazonSSMManagedInstanceCore and Systems Manager instance-permission pages, fetched 2026-10-12; role-ec2-no-profile: provider 0.119.0 docs stackit_server_service_account_attach and stackit_service_account, read 2026-11-01; role-ec2-no-profile skips a role an awscc_iam_instance_profile names: the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles), read 2026-11-01; role-instance-profile of an awscc_iam_instance_profile that holds the role exactly (2026-11-01): the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles: a Set of String, one role per EC2 instance) and the awscc provider source of the instance profile resource, instance_profile_resource_gen.go:114 (knowledge-base evidence, not in this folder: the primary identifier is the name), read 2026-11-01; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

#### `module.retail_app_ecs.aws_secretsmanager_secret.catalog_db`

- **Source:** `aws_secretsmanager_secret` — ../../lib/ecs/catalog.tf:65
- **Module:** `module.retail_app_ecs` (../../lib/ecs)
- **Candidate target:** STACKIT Secrets Manager (`stackit_secretsmanager_instance`, `stackit_secretsmanager_user`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.secretsmanager_secret/secret`
- **Feasibility:** CONDITIONAL — blocked by a compliance or security control (encryption, key management, audit logging, retention) (semantic customer-managed-key); identity or access mapping (semantic secret-value, semantic tc-secretsmanager-secret-name); a point the scan could not establish
- **Why:** Secrets move to STACKIT Secrets Manager (a Vault-compatible KV store). Applications switch from the AWS SDK to a Vault client or to injection via the platform (e.g. External Secrets Operator on SKE).
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-API-OPT-IN` (alias `convert:api:secrets-manager-vault:v1:unknown:API_OPT_IN`): Allow calls of the Secrets Manager Vault-compatible API, whose maturity is not established, for this migration (the API may change or vanish)? Accept: the calls of the Secrets Manager Vault-compatible API (WriteSecret) are carried out for module.retail_app_ecs.aws_secretsmanager_secret.catalog_db, module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch, module.retail_app_ecs.aws_secretsmanager_secret.mq, module.retail_app_ecs.aws_secretsmanager_secret.orders_db. Refuse: no call is made, a refusal selects no other path (the draft holds no other carrier of what the calls set), and what they set stays open for module.retail_app_ecs.aws_secretsmanager_secret.catalog_db, module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch, module.retail_app_ecs.aws_secretsmanager_secret.mq, module.retail_app_ecs.aws_secretsmanager_secret.orders_db. · the Secrets Manager Vault-compatible API is of a maturity that is not established (its documentation states no release status and its product documentation does not establish it as generally available): the execution plan executes no call of an API that is not generally available without an explicit opt-in, so the calls of it and the steps of its path for module.retail_app_ecs.aws_secretsmanager_secret.catalog_db, module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch, module.retail_app_ecs.aws_secretsmanager_secret.mq, module.retail_app_ecs.aws_secretsmanager_secret.orders_db wait for this decision; the draft's own blocks do not
- **Includes:** `module.retail_app_ecs.aws_secretsmanager_secret_version.catalog_db`
- **Depends on:** `module.dependencies.module.catalog_rds.aws_rds_cluster.this`, `module.retail_app_ecs.aws_kms_key.cmk`
- **INFO** (secret-cmk): The secret is encrypted with a customer-managed KMS key. STACKIT Secrets Manager can encrypt with a customer-chosen key too, but the AWS key does not move: the instance's kms_key block (stackit_secretsmanager_instance: key_id, key_ring_id, key_version, service_account_email) names a STACKIT KMS key, one key for all secret values of the instance. The draft sets that block only when every source of the shared instance is an AWS secret that references the same drafted key; otherwise it does not set it and names the key NOT CARRIED with the reason. Decide whether to create the key (stackit_kms_keyring, stackit_kms_key) and a service account with at least the Secrets Manager Reader role in the same project and region, put the kms_key block on the instance, and which secrets share an instance when they used different keys (one key per instance, not per secret). Without the block the instance uses STACKIT's default encryption.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (3):** secret-value, customer-managed-key, tc-secretsmanager-secret-name
- **Property accounting:** 3 of 3 meaningful properties accounted
- **3 critical setting(s) left to you** — **not automation-eligible**:
  - encryption (1; REVIEW 1): `kms_key_id` — NOT CARRIED (module.retail_app_ecs.aws_secretsmanager_secret.catalog_db): kms_key_id — the source encrypts with a customer-managed key that the draft does not set on the Secrets Manager instance: the instance also holds module.retail_app_ecs.aws_secretsmanager_secret.mq, which states no customer-managed key (the default key encrypts it), and it would be encrypted with the key too.
  - secret handling (1; REVIEW 1): `module.retail_app_ecs.aws_secretsmanager_secret_version.catalog_db.secret_string` — NOT CARRIED (module.retail_app_ecs.aws_secretsmanager_secret_version.catalog_db): secret_id, secret_string — a setting of module.retail_app_ecs.aws_secretsmanager_secret.catalog_db: the API step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.catalog_db writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
  - workload compatibility (1; REVIEW 1): `name` — NOT CARRIED (module.retail_app_ecs.aws_secretsmanager_secret.catalog_db): name — the API step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.catalog_db writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
- **Why those are open, and what closes them:**
  - `secret-value`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The value moves to STACKIT Secrets Manager (Vault-compatible KV). The draft generates the shared instance, and the plan a WriteSecret step for an aws_secretsmanager_secret or a SecureString aws_ssm_parameter that is not repeated. The step writes the document the person supplies and does not carry this setting (the value is the person's document); for a secret repeated by count or for_each whose instances are not all known, and for a parameter whose type is not the literal SecureString, only the instance is generated. What a person decides, per secret: where the value comes from (the same value fetched from a secure source, or a new one — moving is the moment to rotate) and the Vault path the application will read, then writes it with the Vault provider or CLI — REVIEW. History: added with aws_ssm_parameter on 2026-09-24; REVIEW since 2026-09-27 (was TRANSFORMED); 2026-10-29 the wording names the WriteSecret step of the plan; 2026-10-30 the step is also made for a SecureString parameter. Closes when: A person decides per secret where the value comes from (the same value from a secure source, or a new one) and the Vault path the application reads, then writes it with a Vault KV v2 client.
  - `customer-managed-key`: A check of the knowledge base (secret cmk) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Critical and reading the key since 2026-09-27: the draft names it NOT CARRIED, except where it sets the instance's kms_key (below). The AWS key does not move, AWS's key per secret has no per-secret counterpart, and the draft sets the kms_key block (referencing the drafted STACKIT key) only when every source of the shared instance is an AWS secret that references that one key — otherwise it names the key NOT CARRIED with the reason; either way a person decides (REVIEW, see the customer-managed key check). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `tc-secretsmanager-secret-name`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. aws_secretsmanager_secret.name: Friendly name used to address the secret; losing it breaks lookups by name but does not change who may reach or read the value, its encryption or deletion behaviour (IAM statements that scope by name are assessed on the IAM policy). No semantic of this family has verified it as carried. Held CRITICAL: the workload, its clients or its neighbours rely on it (an address, a name, a protocol or an execution contract). Closes when: A person confirms the secret name or path the application looks up on the target, or accepts the new one.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; docs security/secrets-manager 2026-09-23; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/security/secrets-manager/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/secretsmanager_instance

#### `module.retail_app_ecs.aws_secretsmanager_secret.mq`

- **Source:** `aws_secretsmanager_secret` — ../../lib/ecs/common.tf:11
- **Module:** `module.retail_app_ecs` (../../lib/ecs)
- **Candidate target:** STACKIT Secrets Manager (`stackit_secretsmanager_instance`, `stackit_secretsmanager_user`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.secretsmanager_secret/secret`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic secret-value, semantic tc-secretsmanager-secret-name); a point the scan could not establish
- **Why:** Secrets move to STACKIT Secrets Manager (a Vault-compatible KV store). Applications switch from the AWS SDK to a Vault client or to injection via the platform (e.g. External Secrets Operator on SKE).
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-API-OPT-IN` (alias `convert:api:secrets-manager-vault:v1:unknown:API_OPT_IN`): Allow calls of the Secrets Manager Vault-compatible API, whose maturity is not established, for this migration (the API may change or vanish)? Accept: the calls of the Secrets Manager Vault-compatible API (WriteSecret) are carried out for module.retail_app_ecs.aws_secretsmanager_secret.catalog_db, module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch, module.retail_app_ecs.aws_secretsmanager_secret.mq, module.retail_app_ecs.aws_secretsmanager_secret.orders_db. Refuse: no call is made, a refusal selects no other path (the draft holds no other carrier of what the calls set), and what they set stays open for module.retail_app_ecs.aws_secretsmanager_secret.catalog_db, module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch, module.retail_app_ecs.aws_secretsmanager_secret.mq, module.retail_app_ecs.aws_secretsmanager_secret.orders_db. · the Secrets Manager Vault-compatible API is of a maturity that is not established (its documentation states no release status and its product documentation does not establish it as generally available): the execution plan executes no call of an API that is not generally available without an explicit opt-in, so the calls of it and the steps of its path for module.retail_app_ecs.aws_secretsmanager_secret.catalog_db, module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch, module.retail_app_ecs.aws_secretsmanager_secret.mq, module.retail_app_ecs.aws_secretsmanager_secret.orders_db wait for this decision; the draft's own blocks do not
- **Includes:** `module.retail_app_ecs.aws_secretsmanager_secret_version.mq`
- **Depends on:** `module.dependencies.aws_mq_broker.mq`
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (2):** secret-value, tc-secretsmanager-secret-name
- **Property accounting:** 2 of 2 meaningful properties accounted
- **2 critical setting(s) left to you** — **not automation-eligible**:
  - secret handling (1; REVIEW 1): `module.retail_app_ecs.aws_secretsmanager_secret_version.mq.secret_string` — NOT CARRIED (module.retail_app_ecs.aws_secretsmanager_secret_version.mq): secret_id, secret_string — a setting of module.retail_app_ecs.aws_secretsmanager_secret.mq: the API step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.mq writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
  - workload compatibility (1; REVIEW 1): `name` — NOT CARRIED (module.retail_app_ecs.aws_secretsmanager_secret.mq): name — the API step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.mq writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
- **Why those are open, and what closes them:**
  - `secret-value`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The value moves to STACKIT Secrets Manager (Vault-compatible KV). The draft generates the shared instance, and the plan a WriteSecret step for an aws_secretsmanager_secret or a SecureString aws_ssm_parameter that is not repeated. The step writes the document the person supplies and does not carry this setting (the value is the person's document); for a secret repeated by count or for_each whose instances are not all known, and for a parameter whose type is not the literal SecureString, only the instance is generated. What a person decides, per secret: where the value comes from (the same value fetched from a secure source, or a new one — moving is the moment to rotate) and the Vault path the application will read, then writes it with the Vault provider or CLI — REVIEW. History: added with aws_ssm_parameter on 2026-09-24; REVIEW since 2026-09-27 (was TRANSFORMED); 2026-10-29 the wording names the WriteSecret step of the plan; 2026-10-30 the step is also made for a SecureString parameter. Closes when: A person decides per secret where the value comes from (the same value from a secure source, or a new one) and the Vault path the application reads, then writes it with a Vault KV v2 client.
  - `tc-secretsmanager-secret-name`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. aws_secretsmanager_secret.name: Friendly name used to address the secret; losing it breaks lookups by name but does not change who may reach or read the value, its encryption or deletion behaviour (IAM statements that scope by name are assessed on the IAM policy). No semantic of this family has verified it as carried. Held CRITICAL: the workload, its clients or its neighbours rely on it (an address, a name, a protocol or an execution contract). Closes when: A person confirms the secret name or path the application looks up on the target, or accepts the new one.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; docs security/secrets-manager 2026-09-23; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/security/secrets-manager/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/secretsmanager_instance

#### `module.retail_app_ecs.aws_secretsmanager_secret.orders_db`

- **Source:** `aws_secretsmanager_secret` — ../../lib/ecs/orders.tf:68
- **Module:** `module.retail_app_ecs` (../../lib/ecs)
- **Candidate target:** STACKIT Secrets Manager (`stackit_secretsmanager_instance`, `stackit_secretsmanager_user`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.secretsmanager_secret/secret`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic secret-value, semantic tc-secretsmanager-secret-name); a point the scan could not establish
- **Why:** Secrets move to STACKIT Secrets Manager (a Vault-compatible KV store). Applications switch from the AWS SDK to a Vault client or to injection via the platform (e.g. External Secrets Operator on SKE).
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-API-OPT-IN` (alias `convert:api:secrets-manager-vault:v1:unknown:API_OPT_IN`): Allow calls of the Secrets Manager Vault-compatible API, whose maturity is not established, for this migration (the API may change or vanish)? Accept: the calls of the Secrets Manager Vault-compatible API (WriteSecret) are carried out for module.retail_app_ecs.aws_secretsmanager_secret.catalog_db, module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch, module.retail_app_ecs.aws_secretsmanager_secret.mq, module.retail_app_ecs.aws_secretsmanager_secret.orders_db. Refuse: no call is made, a refusal selects no other path (the draft holds no other carrier of what the calls set), and what they set stays open for module.retail_app_ecs.aws_secretsmanager_secret.catalog_db, module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch, module.retail_app_ecs.aws_secretsmanager_secret.mq, module.retail_app_ecs.aws_secretsmanager_secret.orders_db. · the Secrets Manager Vault-compatible API is of a maturity that is not established (its documentation states no release status and its product documentation does not establish it as generally available): the execution plan executes no call of an API that is not generally available without an explicit opt-in, so the calls of it and the steps of its path for module.retail_app_ecs.aws_secretsmanager_secret.catalog_db, module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch, module.retail_app_ecs.aws_secretsmanager_secret.mq, module.retail_app_ecs.aws_secretsmanager_secret.orders_db wait for this decision; the draft's own blocks do not
- **Includes:** `module.retail_app_ecs.aws_secretsmanager_secret_version.orders_db`
- **Depends on:** `module.dependencies.module.orders_rds.aws_rds_cluster.this`
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (2):** secret-value, tc-secretsmanager-secret-name
- **Property accounting:** 2 of 2 meaningful properties accounted
- **2 critical setting(s) left to you** — **not automation-eligible**:
  - secret handling (1; REVIEW 1): `module.retail_app_ecs.aws_secretsmanager_secret_version.orders_db.secret_string` — NOT CARRIED (module.retail_app_ecs.aws_secretsmanager_secret_version.orders_db): secret_id, secret_string — a setting of module.retail_app_ecs.aws_secretsmanager_secret.orders_db: the API step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
  - workload compatibility (1; REVIEW 1): `name` — NOT CARRIED (module.retail_app_ecs.aws_secretsmanager_secret.orders_db): name — the API step API/secrets-manager-vault/WriteSecret/module.retail_app_ecs.aws_secretsmanager_secret.orders_db writes it into the Secrets Manager instance from a document you supply (the path is its name when the source states it as a literal, and the value is never read from the source); none of its settings is generated as a resource.
- **Why those are open, and what closes them:**
  - `secret-value`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The value moves to STACKIT Secrets Manager (Vault-compatible KV). The draft generates the shared instance, and the plan a WriteSecret step for an aws_secretsmanager_secret or a SecureString aws_ssm_parameter that is not repeated. The step writes the document the person supplies and does not carry this setting (the value is the person's document); for a secret repeated by count or for_each whose instances are not all known, and for a parameter whose type is not the literal SecureString, only the instance is generated. What a person decides, per secret: where the value comes from (the same value fetched from a secure source, or a new one — moving is the moment to rotate) and the Vault path the application will read, then writes it with the Vault provider or CLI — REVIEW. History: added with aws_ssm_parameter on 2026-09-24; REVIEW since 2026-09-27 (was TRANSFORMED); 2026-10-29 the wording names the WriteSecret step of the plan; 2026-10-30 the step is also made for a SecureString parameter. Closes when: A person decides per secret where the value comes from (the same value from a secure source, or a new one) and the Vault path the application reads, then writes it with a Vault KV v2 client.
  - `tc-secretsmanager-secret-name`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. aws_secretsmanager_secret.name: Friendly name used to address the secret; losing it breaks lookups by name but does not change who may reach or read the value, its encryption or deletion behaviour (IAM statements that scope by name are assessed on the IAM policy). No semantic of this family has verified it as carried. Held CRITICAL: the workload, its clients or its neighbours rely on it (an address, a name, a protocol or an execution contract). Closes when: A person confirms the secret name or path the application looks up on the target, or accepts the new one.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; docs security/secrets-manager 2026-09-23; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/security/secrets-manager/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/secretsmanager_instance

#### `module.retail_app_ecs.module.catalog_service.aws_iam_role.task_execution_role`

- **Source:** `aws_iam_role` — ../../lib/ecs/service/iam.tf:14
- **Module:** `module.retail_app_ecs.module.catalog_service` (./service)
- **Candidate target:** STACKIT service account for the workload (`stackit_service_account`, `stackit_service_account_key`, `stackit_authorization_project_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** LOW · rule `aws.iam_role/role-workload-execution`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic trust, semantic permissions, semantic tcfp-iam-role-policy-attachment--policy-arn, semantic iam-trust-service-workload and 2 more); a point the scan could not establish
- **Why:** Execution role of an application (Lambda function or ECS task). The application keeps needing these permissions on STACKIT: it gets a service account (or data-service credentials such as database users and object-storage keys) with equivalent grants.
- **Includes:** `module.retail_app_ecs.module.catalog_service.aws_iam_role_policy_attachment.task_execution_role_additional`, `module.retail_app_ecs.module.catalog_service.aws_iam_role_policy_attachment.task_execution_role_policy`
- **Depends on:** `module.retail_app_ecs.aws_kms_key.cmk`, `module.retail_app_ecs.aws_secretsmanager_secret.catalog_db`, `module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch`
- **INFO** (iam-trust-service-workload): Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. On STACKIT the workload runs as a service account (stackit_service_account) and nothing assumes it: it authenticates with a service account key (stackit_service_account_key, key flow) or, on SKE, by Workload Identity Federation (a federated identity provider on the account). What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit).
- **INFO** (iam-managed-ecs): Managed policy of an ECS role (AWS: task execution pulls images from ECR and writes CloudWatch Logs; the container-instance role registers hosts with ECS). STACKIT has no ECS: image pull is a registry credential (Container Registry roles, Guest is read-only) and log shipping a platform or credential setting (stackit_logs_access_token); no STACKIT role replaces these grants. Container Registry: STACKIT offers this service. A public STACKIT API exists for it. The pinned Terraform provider has no resource for it. StackToIT does not draft automation for it yet; extra implementation is needed. (schema checked 2026-10-11: none of the 115 resource types of the pinned STACKIT provider), so the pull credential is not drafted (project roles: docs.stackit.cloud, updated Jul 2, 2026). What to decide: the registry pull credential and the log destination of the replacing workload.
- **INFO** (iam-inline-kms): A policy of this role grants KMS actions. STACKIT KMS access comes from role assignments on an organisation, folder, project or service account, not on a key ring or key (stackit_kms_key has no policy or grant attribute in the pinned STACKIT provider), so a per-key permission widens to every key of the project. What to decide: which identities may use and which may administer keys, and whether keys that need different access move to their own project.
- **INFO** (iam-inline-secrets): A policy of this role reads or writes secrets or parameters. STACKIT Secrets Manager grants access with role bindings on the instance and on secret groups (stackit_secretsmanager_instance_role_binding_v1, stackit_secretsmanager_secret_group_role_binding_v1; documented roles Secrets Manager Reader and Admin) and with users that carry credentials. What to decide: per secret group, which identity reads and which writes. One more limit exists per instance: a source-address list (stackit_secretsmanager_instance acls, IP addresses or CIDR ranges that may reach the instance), the nearest thing to an aws:SourceIp condition; there is no per-identity or per-secret condition.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret.catalog_db (aws_secretsmanager_secret), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_iam_role does not read aws_secretsmanager_secret, so what the reference becomes is not assessed.
- **WARNING** (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch (aws_secretsmanager_secret), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_iam_role does not read aws_secretsmanager_secret, so what the reference becomes is not assessed.
- **Critical semantics left to you to decide or accept (4):** iam-managed-ecs, iam-trust-service-workload, permissions, trust (**not automation-eligible**: no property the unit sets is read by linked-dependency:aws_secretsmanager_secret)
- **Property accounting:** 4 of 4 meaningful properties accounted
- **3 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (3; REVIEW 3): `assume_role_policy`, `module.retail_app_ecs.module.catalog_service.aws_iam_role_policy_attachment.task_execution_role_additional.policy_arn`, `module.retail_app_ecs.module.catalog_service.aws_iam_role_policy_attachment.task_execution_role_policy.policy_arn` — NOT CARRIED (module.retail_app_ecs.module.catalog_service.aws_iam_role.task_execution_role): assume_role_policy, name = (reads a variable; its default is not printed) — stackit_service_account has a name and a project only (pinned provider): no trust policy, path, session duration or permissions boundary.
- **Why those are open, and what closes them:**
  - `trust`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The trust policy document of the role (its principals and conditions) has no STACKIT counterpart: stackit_service_account has name and project_id only (pinned provider schema), and the draft names assume_role_policy as not carried. Closes when: A person decides per principal who may assume the role: a federated identity provider (IRSA), a server attachment or a service account key; a role used only by an AWS service is dropped after a person confirms it.
  - `permissions`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. STACKIT IAM grants roles; the policy documents, conditions and resource patterns of the role are translated by a person. The unit names 2 resources through this setting whose references the draft does not resolve: module.retail_app_ecs.aws_secretsmanager_secret.catalog_db (aws_secretsmanager_secret), module.retail_app_ecs.aws_secretsmanager_secret.catalog_opensearch (aws_secretsmanager_secret). What each reference becomes is part of this setting. Closes when: A person translates each permission of the attached policies into STACKIT roles on the target resources.
  - `iam-trust-service-workload`: A check of the knowledge base (iam trust service workload) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `iam-managed-ecs`: A check of the knowledge base (iam managed ecs) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Managed policy of an ECS role (AWS: task execution pulls images from ECR and writes CloudWatch Logs; the container-instance role registers hosts with ECS). What to decide: the registry pull credential and the log destination of the replacing workload. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Review:**
  - [ ] List what the attached policies allow (tables, buckets, queues) and grant the same on the STACKIT targets.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); SKE workload identity docs 2026-09-15; IAM checks of 2026-10-06: provider 0.117.0 schema, docs.stackit.cloud access-and-identity 2026-10-06; IAM notes wording (Act-As, S3 bucket policy carrier, Container Registry has no resource): provider 0.119.0 schema and the docs.stackit.cloud pages cited in the checks, checked 2026-10-11; iam-managed-ssm-instance wording: provider 0.119.0 schema (stackit_server agent), docs.stackit.cloud server-agent, run-command and server pages and the AWS AmazonSSMManagedInstanceCore and Systems Manager instance-permission pages, fetched 2026-10-12; role-ec2-no-profile: provider 0.119.0 docs stackit_server_service_account_attach and stackit_service_account, read 2026-11-01; role-ec2-no-profile skips a role an awscc_iam_instance_profile names: the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles), read 2026-11-01; role-instance-profile of an awscc_iam_instance_profile that holds the role exactly (2026-11-01): the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles: a Set of String, one role per EC2 instance) and the awscc provider source of the instance profile resource, instance_profile_resource_gen.go:114 (knowledge-base evidence, not in this folder: the primary identifier is the name), read 2026-11-01; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

#### `module.retail_app_ecs.module.orders_service.aws_iam_role.task_execution_role`

- **Source:** `aws_iam_role` — ../../lib/ecs/service/iam.tf:14
- **Module:** `module.retail_app_ecs.module.orders_service` (./service)
- **Candidate target:** STACKIT service account for the workload (`stackit_service_account`, `stackit_service_account_key`, `stackit_authorization_project_role_assignment`)
- **Target maturity:** EXPERIMENTAL · lifecycle active · region availability not established by a catalogue snapshot
- **Automation cap:** a target resource is experimental (the provider: "likely going to undergo significant changes or be removed in the future"); the unit needs a person's review and is **not automation-eligible** while it is. Target resource: `stackit_authorization_project_role_assignment` (capability `identity.role-assignment`).
- **GA target:** no GA target yet: stackit_authorization_project_role_assignment is experimental (feature iam) in the pinned STACKIT provider (a blocker the provider's own maturity notice raises; the class and the confidence are unchanged).
- **Classification:** RECONFIGURE · **Confidence:** LOW · rule `aws.iam_role/role-workload-execution`
- **Feasibility:** CONDITIONAL — blocked by identity or access mapping (semantic trust, semantic permissions, semantic tcfp-iam-role-policy-attachment--policy-arn, semantic iam-trust-service-workload and 2 more); a point the scan could not establish
- **Why:** Execution role of an application (Lambda function or ECS task). The application keeps needing these permissions on STACKIT: it gets a service account (or data-service credentials such as database users and object-storage keys) with equivalent grants.
- **Includes:** `module.retail_app_ecs.module.orders_service.aws_iam_role_policy_attachment.task_execution_role_additional`, `module.retail_app_ecs.module.orders_service.aws_iam_role_policy_attachment.task_execution_role_policy`
- **Depends on:** `module.retail_app_ecs.aws_kms_key.cmk`, `module.retail_app_ecs.aws_secretsmanager_secret.mq`, `module.retail_app_ecs.aws_secretsmanager_secret.orders_db`
- **INFO** (iam-trust-service-workload): Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. On STACKIT the workload runs as a service account (stackit_service_account) and nothing assumes it: it authenticates with a service account key (stackit_service_account_key, key flow) or, on SKE, by Workload Identity Federation (a federated identity provider on the account). What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit).
- **INFO** (iam-managed-ecs): Managed policy of an ECS role (AWS: task execution pulls images from ECR and writes CloudWatch Logs; the container-instance role registers hosts with ECS). STACKIT has no ECS: image pull is a registry credential (Container Registry roles, Guest is read-only) and log shipping a platform or credential setting (stackit_logs_access_token); no STACKIT role replaces these grants. Container Registry: STACKIT offers this service. A public STACKIT API exists for it. The pinned Terraform provider has no resource for it. StackToIT does not draft automation for it yet; extra implementation is needed. (schema checked 2026-10-11: none of the 115 resource types of the pinned STACKIT provider), so the pull credential is not drafted (project roles: docs.stackit.cloud, updated Jul 2, 2026). What to decide: the registry pull credential and the log destination of the replacing workload.
- **INFO** (iam-inline-kms): A policy of this role grants KMS actions. STACKIT KMS access comes from role assignments on an organisation, folder, project or service account, not on a key ring or key (stackit_kms_key has no policy or grant attribute in the pinned STACKIT provider), so a per-key permission widens to every key of the project. What to decide: which identities may use and which may administer keys, and whether keys that need different access move to their own project.
- **INFO** (iam-inline-secrets): A policy of this role reads or writes secrets or parameters. STACKIT Secrets Manager grants access with role bindings on the instance and on secret groups (stackit_secretsmanager_instance_role_binding_v1, stackit_secretsmanager_secret_group_role_binding_v1; documented roles Secrets Manager Reader and Admin) and with users that carry credentials. What to decide: per secret group, which identity reads and which writes. One more limit exists per instance: a source-address list (stackit_secretsmanager_instance acls, IP addresses or CIDR ranges that may reach the instance), the nearest thing to an aws:SourceIp condition; there is no per-identity or per-secret condition.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret.mq (aws_secretsmanager_secret), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_iam_role does not read aws_secretsmanager_secret, so what the reference becomes is not assessed.
- **WARNING** (linked-dependency-unread): This unit names module.retail_app_ecs.aws_secretsmanager_secret.orders_db (aws_secretsmanager_secret), whose own decision the target does not carry (it is RECONFIGURE, but the converter does not draft this aws_secretsmanager_secret (the generator skips this case, or only records it against a shared instance or a note) and the draft does not create it), and the semantic contract of aws_iam_role does not read aws_secretsmanager_secret, so what the reference becomes is not assessed.
- **Critical semantics left to you to decide or accept (4):** iam-managed-ecs, iam-trust-service-workload, permissions, trust (**not automation-eligible**: no property the unit sets is read by linked-dependency:aws_secretsmanager_secret)
- **Property accounting:** 4 of 4 meaningful properties accounted
- **3 critical setting(s) left to you** — **not automation-eligible**:
  - identity access (3; REVIEW 3): `assume_role_policy`, `module.retail_app_ecs.module.orders_service.aws_iam_role_policy_attachment.task_execution_role_additional.policy_arn`, `module.retail_app_ecs.module.orders_service.aws_iam_role_policy_attachment.task_execution_role_policy.policy_arn` — NOT CARRIED (module.retail_app_ecs.module.orders_service.aws_iam_role.task_execution_role): assume_role_policy, name = (reads a variable; its default is not printed) — stackit_service_account has a name and a project only (pinned provider): no trust policy, path, session duration or permissions boundary.
- **Why those are open, and what closes them:**
  - `trust`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The trust policy document of the role (its principals and conditions) has no STACKIT counterpart: stackit_service_account has name and project_id only (pinned provider schema), and the draft names assume_role_policy as not carried. Closes when: A person decides per principal who may assume the role: a federated identity provider (IRSA), a server attachment or a service account key; a role used only by an AWS service is dropped after a person confirms it.
  - `permissions`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. STACKIT IAM grants roles; the policy documents, conditions and resource patterns of the role are translated by a person. The unit names 2 resources through this setting whose references the draft does not resolve: module.retail_app_ecs.aws_secretsmanager_secret.mq (aws_secretsmanager_secret), module.retail_app_ecs.aws_secretsmanager_secret.orders_db (aws_secretsmanager_secret). What each reference becomes is part of this setting. Closes when: A person translates each permission of the attached policies into STACKIT roles on the target resources.
  - `iam-trust-service-workload`: A check of the knowledge base (iam trust service workload) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Trust policy: lambda.amazonaws.com or ecs-tasks.amazonaws.com assumes this role, so an application workload (a Lambda function or an ECS task) runs as it. What to decide: key or federation, and the roles of the attached policies (see the permission findings of this unit). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `iam-managed-ecs`: A check of the knowledge base (iam managed ecs) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Managed policy of an ECS role (AWS: task execution pulls images from ECR and writes CloudWatch Logs; the container-instance role registers hosts with ECS). What to decide: the registry pull credential and the log destination of the replacing workload. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Review:**
  - [ ] List what the attached policies allow (tables, buckets, queues) and grant the same on the STACKIT targets.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (authorization_*_role_assignment requires experiment iam); SKE workload identity docs 2026-09-15; IAM checks of 2026-10-06: provider 0.117.0 schema, docs.stackit.cloud access-and-identity 2026-10-06; IAM notes wording (Act-As, S3 bucket policy carrier, Container Registry has no resource): provider 0.119.0 schema and the docs.stackit.cloud pages cited in the checks, checked 2026-10-11; iam-managed-ssm-instance wording: provider 0.119.0 schema (stackit_server agent), docs.stackit.cloud server-agent, run-command and server pages and the AWS AmazonSSMManagedInstanceCore and Systems Manager instance-permission pages, fetched 2026-10-12; role-ec2-no-profile: provider 0.119.0 docs stackit_server_service_account_attach and stackit_service_account, read 2026-11-01; role-ec2-no-profile skips a role an awscc_iam_instance_profile names: the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles), read 2026-11-01; role-instance-profile of an awscc_iam_instance_profile that holds the role exactly (2026-11-01): the awscc provider documentation of iam_instance_profile (awscc 1.103.0) (roles: a Set of String, one role per EC2 instance) and the awscc provider source of the instance profile resource, instance_profile_resource_gen.go:114 (knowledge-base evidence, not in this folder: the primary identifier is the name), read 2026-11-01; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/platform/resource-manager/basics/access-control/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/service_account

### Messaging

#### `module.dependencies.aws_mq_broker.mq`

- **Source:** `aws_mq_broker` — ../../lib/dependencies/mq.tf:12
- **Module:** `module.dependencies` (../../lib/dependencies)
- **Candidate target:** STACKIT RabbitMQ (`stackit_rabbitmq_instance`, `stackit_rabbitmq_credential`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.mq_broker/rabbitmq`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (check engine-version-upgrade, semantic engine-version, semantic broker-network, semantic network-exposure and 9 more); a point the scan could not establish
- **Why:** Same broker software: exchanges, queues and bindings are exported from the Amazon MQ definitions and imported into STACKIT RabbitMQ (the eu01 catalogue lists version 4.1, read 2026-10-18; STACKIT's lifecycle page, last updated 2026-03-11, lists 4.0 and no 4.1, so confirm the version the instance accepts before the cutover); clients change host and credentials, and the broker users are not carried (STACKIT generates the credentials). Moving from 3.x to 4.0 drops classic queue mirroring — mirrored queues become quorum queues.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 2 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-SIZE-FROM-SOURCE/module.dependencies.aws_mq_broker.mq` (alias `convert:module.dependencies.aws_mq_broker.mq:dependencies_mq_plan_name:SIZE_FROM_SOURCE`): Confirm the plan the draft derived for module.dependencies.aws_mq_broker.mq from the size the source states: option use-the-size-derived-from-the-source (stackit-rabbitmq-8.16.50-replica, in var.dependencies_mq_plan_name) or option choose-the-size (a plan you set in var.dependencies_mq_plan_name) · the target sizes by a plan of the catalogue, and the source states a size in the terms of its own offer; the draft proposes the smallest plan that covers it, which leaves out what the source does not state (the disk of a plan, the sustained load, the headroom of a pool), so the value is a proposal and the price of the draft moves with it; unit of the memory figure: the plan table gives its RAM as "GB" and does not say whether a GB is 10^9 or 2^30 bytes, so the plan is chosen to hold the source's memory when a GB is 10^9 bytes, which it then also does when a GB is 2^30 bytes (it is never smaller than the source whichever way the table is read)
  - decision `DEC-GEN-CONVERT-EXPOSURE-WIDENED/module.dependencies.aws_mq_broker.mq` (alias `convert:module.dependencies.aws_mq_broker.mq:exposure:EXPOSURE_WIDENED`): Accept a public RabbitMQ endpoint for stackit_rabbitmq_instance.dependencies_mq, limited only by its client list (parameters.sgw_acl), where the source module.dependencies.aws_mq_broker.mq is private, or redesign it: stackit_rabbitmq_instance has no private-network option in the pinned provider (its access is parameters.sgw_acl only) · the source module.dependencies.aws_mq_broker.mq is private (the broker states publicly_accessible = false: it is reached from inside the VPC that hosts its subnets) and the STACKIT RabbitMQ instance has its own endpoint outside the project network, limited only by parameters.sgw_acl; a list the plan does not give is replaced by STACKIT's default ACL, which admits every STACKIT customer's addresses (the draft's variable has the empty list as its default, which the block replaces by the egress addresses of stackit_ske_cluster.retail_app_ecs_cluster (its pods)); the endpoint is wider than the source's and the difference is an accepted change in exposure, not a preserved property
- **Depends on:** `module.dependencies.aws_security_group.mq`, `module.vpc.module.vpc.aws_subnet.private`
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (engine-version-upgrade): Engine version UPGRADE: the source runs RabbitMQ 3.13 (engine_version); STACKIT RabbitMQ in eu01 offers 4.1 (service catalogue of eu01, read 2026-10-18), none of them the source's version. Moving the data upgrades the engine: test the application and the data against the version you choose before the cutover; the draft does not choose it.
- **Critical semantics left to you to decide or accept (8):** engine-version, broker-network, network-exposure, broker-users, tc-user--password, tc-user--username, tcp-deployment-mode, tc-mq-broker-broker-name (**not automation-eligible**: no property the unit sets is read by broker-users)
- **Default(s) the draft carries out:** `DEC-GEN-CONVERT-SIZE-FROM-SOURCE/module.dependencies.aws_mq_broker.mq` (alias `convert:module.dependencies.aws_mq_broker.mq:dependencies_mq_plan_name:SIZE_FROM_SOURCE`), `DEC-GEN-CONVERT-EXPOSURE-WIDENED/module.dependencies.aws_mq_broker.mq` (alias `convert:module.dependencies.aws_mq_broker.mq:exposure:EXPOSURE_WIDENED`) — the draft carries out the default option `use-the-size-derived-from-the-source`, `accept-the-public-endpoint` and the decision stays open; a person confirms it or overrides it in the decisions file (decisions.yaml), and until it is confirmed the unit is **not automation-eligible**.
- **Property accounting:** 12 of 12 meaningful properties accounted
- **8 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (2; REVIEW 2): `publicly_accessible`, `security_groups`
  - identity access (1; REVIEW 1): `user.username` — NOT CARRIED (module.dependencies.aws_mq_broker.mq): user — the broker users are not copied: the draft writes one stackit_rabbitmq_credential for the instance, a user whose username and password STACKIT generates (both computed, pinned provider) — clients get new credentials.
  - availability durability (3; REVIEW 3): `deployment_mode`, `engine_version`, `subnet_ids`
  - secret handling (1; REVIEW 1): `user.password` — NOT CARRIED (module.dependencies.aws_mq_broker.mq): user — the broker users are not copied: the draft writes one stackit_rabbitmq_credential for the instance, a user whose username and password STACKIT generates (both computed, pinned provider) — clients get new credentials.
  - workload compatibility (1; REVIEW 1): `broker_name`
- **Why those are open, and what closes them:**
  - `engine-version`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. stackit_rabbitmq_instance takes a STACKIT RabbitMQ version (the draft asks for it: rabbitmq_version) — which versions STACKIT offers is not in the rule's evidence. Closes when: A person picks the RabbitMQ version for the target instance, since the versions STACKIT offers are not stated for this move.
  - `broker-network`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. stackit_rabbitmq_instance has no subnet or security-group attribute (pinned provider): clients reach the instance at the address STACKIT assigns, restricted by parameters.sgw_acl — a person decides the ranges. Closes when: A person decides which client address ranges may reach the target RabbitMQ instance through its access list, in place of the source subnets and security groups.
  - `network-exposure`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The broker is either reachable from the public internet or only from private networks. Closes when: A person sets which networks may reach the STACKIT RabbitMQ instance with its access list (a list of CIDR networks); the draft sets none.
  - `broker-users`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. Users become stackit_rabbitmq_credential entries with generated passwords; their permissions are set by a person. Closes when: A person sets the permissions of each broker user on the generated RabbitMQ credentials and hands the new passwords to the clients.
  - `tc-user--password`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. aws_mq_broker.user.password: The broker user's login credential; a literal secret. Held CRITICAL: it carries or names a credential; the value is never copied and a person re-creates it on the target. No semantic of this family has verified it as carried. Closes when: A person hands the clients the password of the generated target credential instead of the literal in the source.
  - `tc-user--username`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. aws_mq_broker.user.username: The broker user's login identity. Held CRITICAL: it decides who or what may use, read or change the resource or the data behind it. No semantic of this family has verified it as carried. Closes when: A person confirms the user names the clients log in with; STACKIT generates each RabbitMQ credential's username, so the clients move to the new usernames.
  - and 2 kinds of reason more (engineering/analysis-details.md)
- **Evidence** (validated against terraform-provider-stackit@0.116.0; docs messaging/rabbitmq 2026-09-23; STACKIT catalogue eu01 2026-09-24 and 2026-10-18 (RabbitMQ 4.1; MQTT, STOMP, federation, shovel plugins); J5 2026-10-26: the lifecycle page (Last updated on Mar 11, 2026) lists the versions 4.0 (released April 2025, end of life to be announced), 3.13 (September 2024, end of life September 2025) and 3.10, and no 4.1 row; the provider's acceptance test (v0.119.0) orders version 4.1 — the version the instance accepts is the catalogue's and was not re-read with a login on 2026-10-26; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/messaging/rabbitmq/ · https://docs.stackit.cloud/products/messaging/rabbitmq/reference/lifecycle/ · https://docs.stackit.cloud/products/messaging/rabbitmq/release-notes/ · https://www.rabbitmq.com/docs/definitions · https://www.rabbitmq.com/blog/2021/08/21/4.0-deprecation-announcements · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/rabbitmq_instance · https://github.com/stackitcloud/terraform-provider-stackit/blob/v0.119.0/stackit/internal/services/rabbitmq/rabbitmq_acc_test.go#L26

### Network

#### `module.vpc.module.vpc.aws_eip.nat`

- **Source:** `aws_eip` — .terraform/modules/vpc.vpc/main.tf:1092
- **Module:** `module.vpc.module.vpc` (terraform-aws-modules/vpc/aws 5.21.0)
- **Candidate target:** implicit (belongs to the NAT gateway)
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.eip/eip-for-nat`
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (semantic public-address); a point the scan could not establish
- **Why:** This Elastic IP only exists for a NAT gateway; it goes away together with the NAT gateway.
- **Depends on:** `module.vpc.module.vpc.aws_internet_gateway.this`
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (1):** public-address (**not automation-eligible**: no property the unit sets is read by public-address)
- **Why those are open, and what closes them:**
  - `public-address`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The address changes. An Elastic IP of a NAT gateway is its fixed egress address, an open question on STACKIT (fixed egress ip of the NAT gateway rule). Closes when: A person decides how peers that allow-list the Elastic IP are served: STACKIT egress uses the project's shared address, which differs from the Elastic IP, cannot be set and can change; a STACKIT public IP per server keeps its address.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; terraform-provider-stackit@0.120.0 (re-checked 2026-10-18 against STACKIT provider schema 0.120.0 and the v0.120.0 tag docs: stackit_public_ip schema unchanged, page re-read); found compatible through 0.121.0 by the release check): https://github.com/stackitcloud/terraform-provider-stackit/blob/v0.120.0/docs/resources/public_ip.md

#### `module.vpc.module.vpc.aws_vpc.this`

- **Source:** `aws_vpc` — .terraform/modules/vpc.vpc/main.tf:28
- **Module:** `module.vpc.module.vpc` (terraform-aws-modules/vpc/aws 5.21.0)
- **Candidate target:** STACKIT project networking / Network Area (SNA) (`stackit_network_area`, `stackit_network`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.vpc/vpc`
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, check vpc-main-table-undecided, semantic network-topology-boundary, semantic default-route-table and 19 more); a point the scan could not establish
- **Why:** STACKIT has no VPC container object in its GA model: each subnet becomes a stackit_network in a project, and networks that must talk to each other privately join a Network Area. The newer stackit_vpc resources exist but are experimental (provider experiment "vpc"). With exactly one VPC in the estate the project is that VPC's boundary (STACKIT_STABLE profile) and the draft says so at the top of the draft's network file; with several VPCs, or a VPC count that is not visible statically, which architecture holds them is the architect's decision (the checks on several VPCs and on a VPC count that is not visible).
- **Includes:** `module.vpc.module.vpc.aws_default_network_acl.this`, `module.vpc.module.vpc.aws_default_route_table.default`, `module.vpc.module.vpc.aws_default_security_group.this`
- **WARNING** (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: a resource of the estate (a subnet, route table, security group, network ACL, flow log, peering connection, a Cloud Control twin of those, ...) names a VPC by a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). A unit placed in a subnet that the scan cannot show is one of the estate's (a server, load balancer, function or NAT gateway in a subnet given by a variable, a data source or a literal id) is in the same position: it may stand in another VPC. The draft puts every network, security group and routing table in the one var.project_id and cannot say that they all belong to one VPC. Confirm which VPC each of them is in, and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area. No unit of the VPC topology is automation-eligible until then (gate blocker TOPOLOGY:vpc-unproven).
- **WARNING** (vpc-main-table-undecided): The scan cannot say which route table is the main route table of this VPC: the VPC has count or for_each (or may be absent), an aws_main_route_table_association may name it through a value the scan cannot resolve (a variable, a literal ID, a conditional, a value from a module call), two resources set it (two main associations, or a main association and an aws_default_route_table on one VPC, which the provider documents as conflicting), or the table is a variable or lies outside the configuration. node.vpc_main_table carries the cause. Which table the VPC's subnets follow without an association of their own, and so what their routing and exposure are, is not decided here; the draft attaches no routing table through the main table.
- **INFO** (vpc-default-sg-no-ingress-rules): The adopted default security group states no ingress rule. The AWS provider removes every rule of the default group when it adopts it and creates only the stated ones, so after apply the group allows no inbound traffic at all, not even from the members of the group itself. A new STACKIT security group allows no incoming traffic either, not even between its own members: they reach each other only through a rule whose remote_security_group_id is the group (tested on a STACKIT project on 2026-10-08, IPv4; the concepts page sentence that traffic from the same group is allowed holds for the project's default group, which carries explicit rules for its own members, not for a group you create), so in the ingress direction an empty STACKIT group equals the adopted group. IPv6 between members is not established (no IPv6 network could be created in the probed project). Nothing is drafted for the adopted group: decide which servers relied on the default group and attach them to a STACKIT group that states no ingress rule, not to the project's default group, whose own-member rules would admit its members.
- **WARNING** (vpc-default-sg-no-egress-rules): The adopted default security group states no egress rule. The AWS provider removes every rule of the default group when it adopts it and creates only the stated ones, so after apply the group allows no outbound traffic at all (the provider page calls this denying all egress by omitting the rules). A new STACKIT security group allows all outgoing traffic, so a server that moves onto a STACKIT group is wider than the source unless the allow-all egress rules are deleted after apply.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (6):** network-topology-boundary, dns-settings, default-nacl-rules, default-route-table, default-security-group-omitted-direction, main-table-set (**not automation-eligible**: no property the unit sets is read by default-security-group-omitted-direction, main-table-set, network-topology-boundary)
- **17 critical setting(s) left to you** (implicit unit) — **not automation-eligible**:
  - network exposure (15; REVIEW 15): `module.vpc.module.vpc.aws_default_network_acl.this.egress.action`, `module.vpc.module.vpc.aws_default_network_acl.this.egress.cidr_block`, `module.vpc.module.vpc.aws_default_network_acl.this.egress.from_port`, `module.vpc.module.vpc.aws_default_network_acl.this.egress.ipv6_cidr_block`, `module.vpc.module.vpc.aws_default_network_acl.this.egress.protocol` and 10 more
  - availability durability (2; REVIEW 2): `enable_dns_hostnames`, `enable_dns_support`
- **Why those are open, and what closes them:**
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). STACKIT has no VPC container in its stable model: the project is the boundary of its networks and its virtual router routes between all networks of one project (docs.stackit.cloud core-networking architecture, updated Aug 20, 2026: "Routing between multiple Virtual Networks in the same project"; SNA "extends the networking architecture to enable cross-project connectivity"). Several VPCs, or a count the scan cannot see: the draft puts every network in the one var.project_id and cannot keep them apart — REVIEW, the choice is the architect's. A unit that names a VPC, or is placed in a subnet (subnet_id, subnets, vpc_config.subnet_ids, ...), without one whole reference to the VPC or to a subnet of the estate may stand in a VPC the estate does not create: the architect decides it the same way (REVIEW). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `dns-settings`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. enable_dns_support and enable_dns_hostnames of the VPC decide how names resolve for what runs in it; STACKIT has no VPC object (each subnet becomes a stackit_network). Closes when: A person confirms how names resolve for the servers of the migrated networks.
  - `default-nacl-rules`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The account's default network ACL is adopted by the VPC (aws_default_network_acl); a deny rule, a rule that is not all-protocol, a CIDR other than 0.0.0.0/0 or ::/0, or an explicitly empty rule list narrows or leaves undecided what the AWS default allow-all states. Closes when: A person re-expresses the default network ACL's rules as security group rules, because STACKIT has no stateless subnet ACL; no STACKIT documentation states that a server or network without an attached security group allows all traffic.
  - `default-route-table`: A check of the knowledge base (vpc main table undecided) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The account's default route table is adopted (a facet of the VPC, aws_default_route_table, AWS provider 6.66.0). Routes other than a plain 0.0.0.0/0 to an internet or NAT gateway are REVIEW. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `default-security-group-omitted-direction`: A check of the knowledge base (vpc default sg no ingress rules) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The adopted default security group of the VPC (a facet, aws_default_security_group) does not state an ingress or an egress direction. Nothing is drafted for this facet, so the empty direction is not reproduced: a person decides whether servers that used the default group must stay without outbound traffic (delete the allow-all egress rules of the STACKIT group after apply) or are meant to have it, and puts them in a STACKIT group that states no ingress rule, not in the project's default group. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `main-table-set`: A check of the knowledge base (vpc main table undecided) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The setting names the route table that is the main route table of the VPC, when the configuration sets it or the scan cannot tell. STACKIT has no main route table. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Review:**
  - [ ] Decide the project layout (one project per environment or per application) before mapping networks.
  - [ ] A Network Area can be enabled in several regions (one stackit_network_area_region per region); verify cross-region routing for multi-region AWS designs.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (stackit_vpc* is experimental); terraform-provider-stackit@0.120.0 (re-checked 2026-10-18 against STACKIT provider schema 0.120.0 and the v0.120.0 tag docs: stackit_vpc* still carries the experimental notice; stackit_network attributes unchanged from 0.116.0 (its block description lost the transitional ipv4_nameservers behaviour warning; the attribute description keeps the behaviour); stackit_network_area_region, stackit_security_group, stackit_security_group_rule, stackit_routing_table and stackit_routing_table_route schemas unchanged; no egress-only gateway, network ACL or internet-gateway resource; docs re-read: network, network_area_region, security_group, security_group_rule, routing_table); docs core-networking 2026-09-23; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/network/core-networking/basics/architecture/ · https://docs.stackit.cloud/products/network/core-networking/network-area/basics/concepts/

#### What the 12 aws_security_group units state alike

The lines below are the same for each of the 12 units that follow, with {unit} for the address of the unit and {name} for its name. A unit states under its own heading the lines that are its own.

- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.security_group/sg`
- **WARNING** (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this security group names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). A unit placed in a subnet that the scan cannot show is one of the estate's (a server, load balancer, function or NAT gateway in a subnet given by a variable, a data source or a literal id) is in the same position: it may stand in another VPC. The draft puts every network, security group and routing table in the one var.project_id and cannot say that they all belong to one VPC. Confirm which VPC each of them is in, and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area. No unit of the VPC topology is automation-eligible until then (gate blocker TOPOLOGY:vpc-unproven).
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (stackit_security_group_rule has remote_security_group_id); terraform-provider-stackit@0.120.0 (re-checked 2026-10-18 against STACKIT provider schema 0.120.0 and the v0.120.0 tag docs: stackit_security_group and stackit_security_group_rule schemas unchanged, pages re-read; the rule has direction, protocol, port_range, ip_range, ether_type, icmp_parameters and remote_security_group_id and no action or rule number; the group has no rules attribute; the statement that a rule without protocol, port_range or source allows everything (check sg-rule-not-rendered) is NOT covered by these pages and stays as validated on 0.116.0); found compatible through 0.121.0 by the release check): https://github.com/stackitcloud/terraform-provider-stackit/blob/v0.120.0/docs/resources/security_group.md · https://github.com/stackitcloud/terraform-provider-stackit/blob/v0.120.0/docs/resources/security_group_rule.md · https://docs.stackit.cloud/products/network/core-networking/public-ip-address/how-tos/setup-ipv6-reachability/

#### `module.retail_app_ecs.module.alb.aws_security_group.this`

- Alike lines: see "What the 12 aws_security_group units state alike", above.
- **Source:** `aws_security_group` — .terraform/modules/retail_app_ecs.alb/main.tf:807
- **Module:** `module.retail_app_ecs.module.alb` (terraform-aws-modules/alb/aws 8.7.0)
- **Candidate target:** STACKIT security group (`stackit_security_group`, `stackit_security_group_rule`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic security-group-vpc-membership, semantic network-topology-boundary, check sg-egress-restricted and 2 more); a point the scan could not establish
- **Why:** STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). Rules are re-created one by one; CIDRs of AWS-internal ranges (VPC, prefix lists) must be replaced with STACKIT network prefixes.
- **Behaviour evidence:** behaviour: 2 observed on target, 4 documented, 2 not verified for this variant, 0 contradicted
- **Depends on:** `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (sg-egress-restricted): The source restricts egress (the AWS provider removes AWS's default allow-all egress rule; only the listed egress rules apply). Every new STACKIT security group gets two default egress rules, IPv4 and IPv6, with no ip range (any address), no protocol and no port restriction (the test of 2026-10-07, 2026-10-07: API read-back of a new group, docs concepts page), that stackit_security_group (the pinned STACKIT provider) does not manage — as generated, the draft allows all egress. After apply, delete them (stackit security-group rule list / delete --security-group-id <id>), or egress is wider than in the source.
- **Critical semantics left to you to decide or accept (4):** egress-restriction, network-topology-boundary, security-group-vpc-membership, stateful (**not automation-eligible**: no property the unit sets is read by egress-restriction, network-topology-boundary, stateful)
- **Property accounting:** 1 of 1 meaningful properties accounted
- **1 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (1; UNSUPPORTED 1): `vpc_id` — plan: stackit_security_group.retail_app_ecs_alb_this vpc_id UNSUPPORTED: a STACKIT security group belongs to a project, not to a network: the resource has no network attribute, so the source's VPC membership is not carried (contract aws.security_group/security-group-vpc-membership:UNSUPPORTED)
- **Why those are open, and what closes them:**
  - `security-group-vpc-membership`: A check of the knowledge base (topology vpc unproven) found a setting the target has no counterpart for (a finding of this unit describes it). UNSUPPORTED, by name: a STACKIT security group has no network (VPC) scope. stackit_security_group takes project_id, name, description, labels, stateful and region only (pinned provider), and the IaaS API object SecurityGroup has no network field either (stackit-api-specifications services/iaas/v2); the group is project-wide and can be attached to the network interfaces of every network of the project. Closes when: A person confirms which VPC each network resource of the estate is in and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area; the group is then attached only to the interfaces of the networks that replace its VPC.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this security group included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `stateful`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. STACKIT security groups are stateful by default (tested on a STACKIT project on 2026-09-24: stateful=true). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `egress-restriction`: A check of the knowledge base (sg egress restricted) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The security group restricts its outbound traffic: it has no rule that allows every protocol to 0.0.0.0/0 or ::/0. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.

#### `module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix`

- Alike lines: see "What the 12 aws_security_group units state alike", above.
- **Source:** `aws_security_group` — .terraform/modules/retail_app_ecs.alb_sg/main.tf:37
- **Module:** `module.retail_app_ecs.module.alb_sg` (terraform-aws-modules/security-group/aws 4.17.2)
- **Candidate target:** STACKIT security group (`stackit_security_group`, `stackit_security_group_rule`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic security-group-vpc-membership, semantic network-topology-boundary, check sg-rule-not-rendered and 7 more); a point the scan could not establish
- **Why:** STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). Rules are re-created one by one; CIDRs of AWS-internal ranges (VPC, prefix lists) must be replaced with STACKIT network prefixes.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 0 open decisions, 4 manual actions
  - manual action `DEC-SEC-STACKITSG-ACTION-INCOMPLETE` (alias `awssg:incomplete:module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix:group module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix[0]:rules:module.retail_app_ecs.module.alb_sg.aws_security_group_rule.egress_rules`) (incomplete, before the pilot): Re-create the rules beyond the known set of group module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix[0] (rules, module.retail_app_ecs.module.alb_sg.aws_security_group_rule.egress_rules) — an unknown number of entries of module.retail_app_ecs.module.alb_sg.aws_security_group_rule.egress_rules are not visible statically (group-choice): only the known ones were produced
  - manual action `DEC-SEC-STACKITSG-ACTION-INCOMPLETE` (alias `awssg:incomplete:module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix:group module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix[0]:rules:module.retail_app_ecs.module.alb_sg.aws_security_group_rule.ingress_rules`) (incomplete, before the pilot): Re-create the rules beyond the known set of group module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix[0] (rules, module.retail_app_ecs.module.alb_sg.aws_security_group_rule.ingress_rules) — an unknown number of entries of module.retail_app_ecs.module.alb_sg.aws_security_group_rule.ingress_rules are not visible statically (group-choice): only the known ones were produced
  - manual action `DEC-SEC-STACKITSG-ACTION-UNPLACED` (alias `awssg:unplaced:module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix:module.retail_app_ecs.module.alb_sg.aws_security_group_rule.egress_rules[0]`) (unplaced, before the pilot): Place the source rule module.retail_app_ecs.module.alb_sg.aws_security_group_rule.egress_rules[0] on the security group it belongs to and write it — the rule is attached to module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix but cannot be attributed to one of its groups (group-choice); a rule on the wrong group allows what the source did not allow there, so none was produced
  - manual action `DEC-SEC-STACKITSG-ACTION-UNPLACED` (alias `awssg:unplaced:module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix:module.retail_app_ecs.module.alb_sg.aws_security_group_rule.ingress_rules[0]`) (unplaced, before the pilot): Place the source rule module.retail_app_ecs.module.alb_sg.aws_security_group_rule.ingress_rules[0] on the security group it belongs to and write it — the rule is attached to module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix but cannot be attributed to one of its groups (group-choice); a rule on the wrong group allows what the source did not allow there, so none was produced
- **Behaviour evidence:** behaviour: 2 observed on target, 5 documented, 2 not verified for this variant, 0 contradicted
- **Includes:** `module.retail_app_ecs.module.alb_sg.aws_security_group_rule.egress_rules`, `module.retail_app_ecs.module.alb_sg.aws_security_group_rule.ingress_rules`
- **Depends on:** `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (sg-rule-not-rendered): At least one rule of this group is not in the draft as the source has it. The plan withholds it, holds it as a commented-out rule until a value or a decision is filled in, writes it with a fact that decides what it allows not carried exactly, or cannot name it at all because the source has more rules than are visible statically (a dynamic block over a collection, a count or a rule list that is not known until apply, or a list with a hidden member: the plan's INCOMPLETE action says which set and why, the draft's TODO "rules beyond the known set" names it, and only the known rules are drafted). Typical causes: a protocol, port or source whose value is known only at apply time or comes from a root variable; a source group that is a choice between groups or not a group of the draft; a protocol with no STACKIT counterpart; an ICMP type with every code; an ICMP or ICMPv6 rule whose range is of the other IP family (the API answers HTTP 400, the test of 2026-10-08); a tcp or udp rule with a negative port, a port above 65535, a reversed range, or port 0 only (STACKIT stores no port range for 0 to 0, so the rule would match every port). A tcp or udp range that starts at port 0 and ends below 65535 is written from port 1 (the STACKIT API rejects a range that starts at 0; tested on a STACKIT project on 2026-10-07): port 0 itself is not carried. A stackit_security_group_rule without protocol, port_range or source allows everything (the pinned STACKIT provider), so such a rule is never widened; re-create it with the values it needs (the plan names each one).
- **Critical semantics left to you to decide or accept (7):** network-topology-boundary, rule-ports, security-group-vpc-membership, standalone-rule-empty-sources, standalone-rule-other-sources, standalone-rule-values, stateful (**not automation-eligible**: no property the unit sets is read by network-topology-boundary, stateful)
- **Manual action(s) required before apply:** `DEC-SEC-STACKITSG-ACTION-INCOMPLETE` (alias `awssg:incomplete:module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix:group module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix[0]:rules:module.retail_app_ecs.module.alb_sg.aws_security_group_rule.egress_rules`), `DEC-SEC-STACKITSG-ACTION-INCOMPLETE` (alias `awssg:incomplete:module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix:group module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix[0]:rules:module.retail_app_ecs.module.alb_sg.aws_security_group_rule.ingress_rules`), `DEC-SEC-STACKITSG-ACTION-UNPLACED` (alias `awssg:unplaced:module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix:module.retail_app_ecs.module.alb_sg.aws_security_group_rule.egress_rules[0]`), `DEC-SEC-STACKITSG-ACTION-UNPLACED` (alias `awssg:unplaced:module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix:module.retail_app_ecs.module.alb_sg.aws_security_group_rule.ingress_rules[0]`) — a person does them, and until then the unit is **not automation-eligible**.
- **Property accounting:** 16 of 16 meaningful properties accounted
- **15 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (15; UNSUPPORTED 1 · REVIEW 14): `vpc_id`, `module.retail_app_ecs.module.alb_sg.aws_security_group_rule.egress_rules.cidr_blocks`, `module.retail_app_ecs.module.alb_sg.aws_security_group_rule.egress_rules.from_port`, `module.retail_app_ecs.module.alb_sg.aws_security_group_rule.egress_rules.ipv6_cidr_blocks`, `module.retail_app_ecs.module.alb_sg.aws_security_group_rule.egress_rules.prefix_list_ids` and 10 more — plan: stackit_security_group.retail_app_ecs_alb_sg_this_name_prefix vpc_id UNSUPPORTED: a STACKIT security group belongs to a project, not to a network: the resource has no network attribute, so the source's VPC membership is not carried (contract aws.security_group/security-group-vpc-membership:UNSUPPORTED)
- **Why those are open, and what closes them:**
  - `security-group-vpc-membership`: A check of the knowledge base (topology vpc unproven) found a setting the target has no counterpart for (a finding of this unit describes it). UNSUPPORTED, by name: a STACKIT security group has no network (VPC) scope. stackit_security_group takes project_id, name, description, labels, stateful and region only (pinned provider), and the IaaS API object SecurityGroup has no network field either (stackit-api-specifications services/iaas/v2); the group is project-wide and can be attached to the network interfaces of every network of the project. Closes when: A person confirms which VPC each network resource of the estate is in and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area; the group is then attached only to the interfaces of the networks that replace its VPC.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this security group included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `stateful`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. STACKIT security groups are stateful by default (tested on a STACKIT project on 2026-09-24: stateful=true). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `rule-ports`: A check of the knowledge base (sg rule not rendered) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Each rule becomes a stackit_security_group_rule: protocol → protocol.name/protocol.number, from_port/to_port → port_range.min/max, or icmp_parameters type/code for icmp (pinned provider schema). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `standalone-rule-values`: A check of the knowledge base (sg rule not rendered) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). An aws_security_group_rule becomes a stackit_security_group_rule: type → direction, protocol → protocol, cidr_blocks → ip_range (one rule per range), source_security_group_id → remote_security_group_id. A rule that is not generated is named NOT CARRIED and the group is REVIEW. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `standalone-rule-other-sources`: A check of the knowledge base (sg rule not rendered) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). A standalone rule's own group (self) and IPv6 ranges are written where the draft places the rule (self as remote_security_group_id of the group, an IPv6 range as ip_range with ether_type IPv6), and the draft names the rule NOT CARRIED when the plan withholds it; prefix lists are not generated (as rule other sources for inline rules; prefix lists: the prefix list check), and a person adds the rule if the traffic must pass — REVIEW in every order position. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - and 1 kind of reason more (engineering/analysis-details.md)

#### `module.retail_app_ecs.module.carts_service.aws_security_group.this`

- Alike lines: see "What the 12 aws_security_group units state alike", above.
- **Source:** `aws_security_group` — ../../lib/ecs/service/sg.tf:1
- **Module:** `module.retail_app_ecs.module.carts_service` (./service)
- **Candidate target:** STACKIT security group (`stackit_security_group`, `stackit_security_group_rule`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic security-group-vpc-membership, semantic network-topology-boundary, semantic stateful and 4 more); a point the scan could not establish
- **Why:** STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). Rules are re-created one by one; CIDRs of AWS-internal ranges (VPC, prefix lists) must be replaced with STACKIT network prefixes.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-POD-SEGMENTATION/module.retail_app_ecs.module.carts_service.aws_security_group.this` (alias `convert:module.retail_app_ecs.module.carts_service.aws_security_group.this:security-group:POD_SEGMENTATION`): Decide how the segmentation that the security group module.retail_app_ecs.module.carts_service.aws_security_group.this gave the tasks of module.retail_app_ecs.module.carts_service.aws_ecs_service.this is carried on STACKIT: the tasks become pods of the cluster, and no block of the draft attaches the drafted group stackit_security_group.retail_app_ecs_carts_service_this to anything — option generate-networkpolicy-from-the-group-rules (a Kubernetes NetworkPolicy written from the rules of the group), security-group-on-the-nodes (coarser: the group acts on the interface of a node, so on every pod of it), or accept-no-segmentation (the loss of the restriction is accepted, with who accepted it) · the source restricts the traffic to and from the tasks with this group; a STACKIT security group acts on the network interface of a server and cannot restrict a pod, and the draft attaches the group to nothing, so the tasks would run without the segmentation the source had unless a person decides how it is carried (never equivalent without that decision)
- **Behaviour evidence:** behaviour: 2 observed on target, 6 documented, 6 not verified for this variant, 0 contradicted
- **Depends on:** `module.vpc.module.vpc.aws_vpc.this`
- **Critical semantics left to you to decide or accept (7):** egress-rule-protocol, egress-sources, ingress-sources, network-topology-boundary, rule-ports, security-group-vpc-membership, stateful (**not automation-eligible**: no property the unit sets is read by network-topology-boundary, stateful)
- **Open choice(s) the draft could not make:** `DEC-GEN-CONVERT-POD-SEGMENTATION/module.retail_app_ecs.module.carts_service.aws_security_group.this` (alias `convert:module.retail_app_ecs.module.carts_service.aws_security_group.this:security-group:POD_SEGMENTATION`) — the source does not prove what it means and the draft holds a required variable without a default; a person decides, and until then the unit is **not automation-eligible**.
- **Property accounting:** 10 of 10 meaningful properties accounted
- **9 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (9; REVIEW 8 · UNSUPPORTED 1): `egress.cidr_blocks`, `egress.from_port`, `egress.protocol`, `egress.to_port`, `ingress.cidr_blocks` and 4 more — plan: stackit_security_group.retail_app_ecs_carts_service_this vpc_id UNSUPPORTED: a STACKIT security group belongs to a project, not to a network: the resource has no network attribute, so the source's VPC membership is not carried (contract aws.security_group/security-group-vpc-membership:UNSUPPORTED)
- **Why those are open, and what closes them:**
  - `security-group-vpc-membership`: A check of the knowledge base (topology vpc unproven) found a setting the target has no counterpart for (a finding of this unit describes it). UNSUPPORTED, by name: a STACKIT security group has no network (VPC) scope. stackit_security_group takes project_id, name, description, labels, stateful and region only (pinned provider), and the IaaS API object SecurityGroup has no network field either (stackit-api-specifications services/iaas/v2); the group is project-wide and can be attached to the network interfaces of every network of the project. Closes when: A person confirms which VPC each network resource of the estate is in and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area; the group is then attached only to the interfaces of the networks that replace its VPC.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this security group included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `stateful`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. STACKIT security groups are stateful by default (tested on a STACKIT project on 2026-09-24: stateful=true). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `rule-ports`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. Whether the draft carries this setting is decided by its semantic ledger entry "security group rules", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). Each rule becomes a stackit_security_group_rule: protocol → protocol.name/protocol.number, from_port/to_port → port_range.min/max, or icmp_parameters type/code for icmp (pinned provider schema). Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - `egress-rule-protocol`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. protocol → stackit_security_group_rule.protocol (pinned provider). the egress restriction setting reads the same attribute and is REVIEW exactly when the egress restriction check fires; this semantic is then REVIEW as well, so the two critical readers of egress.protocol never disagree (TRANSFORMED only when neither check fires). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `ingress-sources`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. Whether the draft carries this setting is decided by its semantic ledger entry "security group rules", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). cidr_blocks → stackit_security_group_rule.ip_range (one rule per range), security_groups → remote_security_group_id (pinned provider); REVIEW for the group when a rule is not generated, as rule ports (2026-09-27). Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - and 1 kind of reason more (engineering/analysis-details.md)

#### `module.retail_app_ecs.module.catalog_service.aws_security_group.this`

- Alike lines: see "What the 12 aws_security_group units state alike", above.
- **Source:** `aws_security_group` — ../../lib/ecs/service/sg.tf:1
- **Module:** `module.retail_app_ecs.module.catalog_service` (./service)
- **Candidate target:** STACKIT security group (`stackit_security_group`, `stackit_security_group_rule`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic security-group-vpc-membership, semantic network-topology-boundary, semantic stateful and 4 more); a point the scan could not establish
- **Why:** STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). Rules are re-created one by one; CIDRs of AWS-internal ranges (VPC, prefix lists) must be replaced with STACKIT network prefixes.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-POD-SEGMENTATION/module.retail_app_ecs.module.catalog_service.aws_security_group.this` (alias `convert:module.retail_app_ecs.module.catalog_service.aws_security_group.this:security-group:POD_SEGMENTATION`): Decide how the segmentation that the security group module.retail_app_ecs.module.catalog_service.aws_security_group.this gave the tasks of module.retail_app_ecs.module.catalog_service.aws_ecs_service.this is carried on STACKIT: the tasks become pods of the cluster, and no block of the draft attaches the drafted group stackit_security_group.retail_app_ecs_catalog_service_this to anything — option generate-networkpolicy-from-the-group-rules (a Kubernetes NetworkPolicy written from the rules of the group), security-group-on-the-nodes (coarser: the group acts on the interface of a node, so on every pod of it), or accept-no-segmentation (the loss of the restriction is accepted, with who accepted it) · the source restricts the traffic to and from the tasks with this group; a STACKIT security group acts on the network interface of a server and cannot restrict a pod, and the draft attaches the group to nothing, so the tasks would run without the segmentation the source had unless a person decides how it is carried (never equivalent without that decision)
- **Behaviour evidence:** behaviour: 2 observed on target, 6 documented, 6 not verified for this variant, 0 contradicted
- **Depends on:** `module.vpc.module.vpc.aws_vpc.this`
- **Critical semantics left to you to decide or accept (7):** egress-rule-protocol, egress-sources, ingress-sources, network-topology-boundary, rule-ports, security-group-vpc-membership, stateful (**not automation-eligible**: no property the unit sets is read by network-topology-boundary, stateful)
- **Open choice(s) the draft could not make:** `DEC-GEN-CONVERT-POD-SEGMENTATION/module.retail_app_ecs.module.catalog_service.aws_security_group.this` (alias `convert:module.retail_app_ecs.module.catalog_service.aws_security_group.this:security-group:POD_SEGMENTATION`) — the source does not prove what it means and the draft holds a required variable without a default; a person decides, and until then the unit is **not automation-eligible**.
- **Property accounting:** 10 of 10 meaningful properties accounted
- **9 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (9; REVIEW 8 · UNSUPPORTED 1): `egress.cidr_blocks`, `egress.from_port`, `egress.protocol`, `egress.to_port`, `ingress.cidr_blocks` and 4 more — plan: stackit_security_group.retail_app_ecs_catalog_service_this vpc_id UNSUPPORTED: a STACKIT security group belongs to a project, not to a network: the resource has no network attribute, so the source's VPC membership is not carried (contract aws.security_group/security-group-vpc-membership:UNSUPPORTED)
- **Why those are open, and what closes them:**
  - `security-group-vpc-membership`: A check of the knowledge base (topology vpc unproven) found a setting the target has no counterpart for (a finding of this unit describes it). UNSUPPORTED, by name: a STACKIT security group has no network (VPC) scope. stackit_security_group takes project_id, name, description, labels, stateful and region only (pinned provider), and the IaaS API object SecurityGroup has no network field either (stackit-api-specifications services/iaas/v2); the group is project-wide and can be attached to the network interfaces of every network of the project. Closes when: A person confirms which VPC each network resource of the estate is in and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area; the group is then attached only to the interfaces of the networks that replace its VPC.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this security group included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `stateful`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. STACKIT security groups are stateful by default (tested on a STACKIT project on 2026-09-24: stateful=true). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `rule-ports`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. Whether the draft carries this setting is decided by its semantic ledger entry "security group rules", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). Each rule becomes a stackit_security_group_rule: protocol → protocol.name/protocol.number, from_port/to_port → port_range.min/max, or icmp_parameters type/code for icmp (pinned provider schema). Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - `egress-rule-protocol`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. protocol → stackit_security_group_rule.protocol (pinned provider). the egress restriction setting reads the same attribute and is REVIEW exactly when the egress restriction check fires; this semantic is then REVIEW as well, so the two critical readers of egress.protocol never disagree (TRANSFORMED only when neither check fires). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `ingress-sources`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. Whether the draft carries this setting is decided by its semantic ledger entry "security group rules", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). cidr_blocks → stackit_security_group_rule.ip_range (one rule per range), security_groups → remote_security_group_id (pinned provider); REVIEW for the group when a rule is not generated, as rule ports (2026-09-27). Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - and 1 kind of reason more (engineering/analysis-details.md)

#### `module.retail_app_ecs.module.checkout_service.aws_security_group.this`

- Alike lines: see "What the 12 aws_security_group units state alike", above.
- **Source:** `aws_security_group` — ../../lib/ecs/service/sg.tf:1
- **Module:** `module.retail_app_ecs.module.checkout_service` (./service)
- **Candidate target:** STACKIT security group (`stackit_security_group`, `stackit_security_group_rule`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic security-group-vpc-membership, semantic network-topology-boundary, semantic stateful and 4 more); a point the scan could not establish
- **Why:** STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). Rules are re-created one by one; CIDRs of AWS-internal ranges (VPC, prefix lists) must be replaced with STACKIT network prefixes.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-POD-SEGMENTATION/module.retail_app_ecs.module.checkout_service.aws_security_group.this` (alias `convert:module.retail_app_ecs.module.checkout_service.aws_security_group.this:security-group:POD_SEGMENTATION`): Decide how the segmentation that the security group module.retail_app_ecs.module.checkout_service.aws_security_group.this gave the tasks of module.retail_app_ecs.module.checkout_service.aws_ecs_service.this is carried on STACKIT: the tasks become pods of the cluster, and no block of the draft attaches the drafted group stackit_security_group.retail_app_ecs_checkout_service_this to anything — option generate-networkpolicy-from-the-group-rules (a Kubernetes NetworkPolicy written from the rules of the group), security-group-on-the-nodes (coarser: the group acts on the interface of a node, so on every pod of it), or accept-no-segmentation (the loss of the restriction is accepted, with who accepted it) · the source restricts the traffic to and from the tasks with this group; a STACKIT security group acts on the network interface of a server and cannot restrict a pod, and the draft attaches the group to nothing, so the tasks would run without the segmentation the source had unless a person decides how it is carried (never equivalent without that decision)
- **Behaviour evidence:** behaviour: 2 observed on target, 6 documented, 6 not verified for this variant, 0 contradicted
- **Depends on:** `module.vpc.module.vpc.aws_vpc.this`
- **Critical semantics left to you to decide or accept (7):** egress-rule-protocol, egress-sources, ingress-sources, network-topology-boundary, rule-ports, security-group-vpc-membership, stateful (**not automation-eligible**: no property the unit sets is read by network-topology-boundary, stateful)
- **Open choice(s) the draft could not make:** `DEC-GEN-CONVERT-POD-SEGMENTATION/module.retail_app_ecs.module.checkout_service.aws_security_group.this` (alias `convert:module.retail_app_ecs.module.checkout_service.aws_security_group.this:security-group:POD_SEGMENTATION`) — the source does not prove what it means and the draft holds a required variable without a default; a person decides, and until then the unit is **not automation-eligible**.
- **Property accounting:** 10 of 10 meaningful properties accounted
- **9 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (9; REVIEW 8 · UNSUPPORTED 1): `egress.cidr_blocks`, `egress.from_port`, `egress.protocol`, `egress.to_port`, `ingress.cidr_blocks` and 4 more — plan: stackit_security_group.retail_app_ecs_checkout_service_this vpc_id UNSUPPORTED: a STACKIT security group belongs to a project, not to a network: the resource has no network attribute, so the source's VPC membership is not carried (contract aws.security_group/security-group-vpc-membership:UNSUPPORTED)
- **Why those are open, and what closes them:**
  - `security-group-vpc-membership`: A check of the knowledge base (topology vpc unproven) found a setting the target has no counterpart for (a finding of this unit describes it). UNSUPPORTED, by name: a STACKIT security group has no network (VPC) scope. stackit_security_group takes project_id, name, description, labels, stateful and region only (pinned provider), and the IaaS API object SecurityGroup has no network field either (stackit-api-specifications services/iaas/v2); the group is project-wide and can be attached to the network interfaces of every network of the project. Closes when: A person confirms which VPC each network resource of the estate is in and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area; the group is then attached only to the interfaces of the networks that replace its VPC.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this security group included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `stateful`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. STACKIT security groups are stateful by default (tested on a STACKIT project on 2026-09-24: stateful=true). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `rule-ports`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. Whether the draft carries this setting is decided by its semantic ledger entry "security group rules", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). Each rule becomes a stackit_security_group_rule: protocol → protocol.name/protocol.number, from_port/to_port → port_range.min/max, or icmp_parameters type/code for icmp (pinned provider schema). Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - `egress-rule-protocol`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. protocol → stackit_security_group_rule.protocol (pinned provider). the egress restriction setting reads the same attribute and is REVIEW exactly when the egress restriction check fires; this semantic is then REVIEW as well, so the two critical readers of egress.protocol never disagree (TRANSFORMED only when neither check fires). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `ingress-sources`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. Whether the draft carries this setting is decided by its semantic ledger entry "security group rules", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). cidr_blocks → stackit_security_group_rule.ip_range (one rule per range), security_groups → remote_security_group_id (pinned provider); REVIEW for the group when a rule is not generated, as rule ports (2026-09-27). Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - and 1 kind of reason more (engineering/analysis-details.md)

#### `module.retail_app_ecs.module.orders_service.aws_security_group.this`

- Alike lines: see "What the 12 aws_security_group units state alike", above.
- **Source:** `aws_security_group` — ../../lib/ecs/service/sg.tf:1
- **Module:** `module.retail_app_ecs.module.orders_service` (./service)
- **Candidate target:** STACKIT security group (`stackit_security_group`, `stackit_security_group_rule`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic security-group-vpc-membership, semantic network-topology-boundary, semantic stateful and 4 more); a point the scan could not establish
- **Why:** STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). Rules are re-created one by one; CIDRs of AWS-internal ranges (VPC, prefix lists) must be replaced with STACKIT network prefixes.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-POD-SEGMENTATION/module.retail_app_ecs.module.orders_service.aws_security_group.this` (alias `convert:module.retail_app_ecs.module.orders_service.aws_security_group.this:security-group:POD_SEGMENTATION`): Decide how the segmentation that the security group module.retail_app_ecs.module.orders_service.aws_security_group.this gave the tasks of module.retail_app_ecs.module.orders_service.aws_ecs_service.this is carried on STACKIT: the tasks become pods of the cluster, and no block of the draft attaches the drafted group stackit_security_group.retail_app_ecs_orders_service_this to anything — option generate-networkpolicy-from-the-group-rules (a Kubernetes NetworkPolicy written from the rules of the group), security-group-on-the-nodes (coarser: the group acts on the interface of a node, so on every pod of it), or accept-no-segmentation (the loss of the restriction is accepted, with who accepted it) · the source restricts the traffic to and from the tasks with this group; a STACKIT security group acts on the network interface of a server and cannot restrict a pod, and the draft attaches the group to nothing, so the tasks would run without the segmentation the source had unless a person decides how it is carried (never equivalent without that decision)
- **Behaviour evidence:** behaviour: 2 observed on target, 6 documented, 6 not verified for this variant, 0 contradicted
- **Depends on:** `module.vpc.module.vpc.aws_vpc.this`
- **Critical semantics left to you to decide or accept (7):** egress-rule-protocol, egress-sources, ingress-sources, network-topology-boundary, rule-ports, security-group-vpc-membership, stateful (**not automation-eligible**: no property the unit sets is read by network-topology-boundary, stateful)
- **Open choice(s) the draft could not make:** `DEC-GEN-CONVERT-POD-SEGMENTATION/module.retail_app_ecs.module.orders_service.aws_security_group.this` (alias `convert:module.retail_app_ecs.module.orders_service.aws_security_group.this:security-group:POD_SEGMENTATION`) — the source does not prove what it means and the draft holds a required variable without a default; a person decides, and until then the unit is **not automation-eligible**.
- **Property accounting:** 10 of 10 meaningful properties accounted
- **9 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (9; REVIEW 8 · UNSUPPORTED 1): `egress.cidr_blocks`, `egress.from_port`, `egress.protocol`, `egress.to_port`, `ingress.cidr_blocks` and 4 more — plan: stackit_security_group.retail_app_ecs_orders_service_this vpc_id UNSUPPORTED: a STACKIT security group belongs to a project, not to a network: the resource has no network attribute, so the source's VPC membership is not carried (contract aws.security_group/security-group-vpc-membership:UNSUPPORTED)
- **Why those are open, and what closes them:**
  - `security-group-vpc-membership`: A check of the knowledge base (topology vpc unproven) found a setting the target has no counterpart for (a finding of this unit describes it). UNSUPPORTED, by name: a STACKIT security group has no network (VPC) scope. stackit_security_group takes project_id, name, description, labels, stateful and region only (pinned provider), and the IaaS API object SecurityGroup has no network field either (stackit-api-specifications services/iaas/v2); the group is project-wide and can be attached to the network interfaces of every network of the project. Closes when: A person confirms which VPC each network resource of the estate is in and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area; the group is then attached only to the interfaces of the networks that replace its VPC.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this security group included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `stateful`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. STACKIT security groups are stateful by default (tested on a STACKIT project on 2026-09-24: stateful=true). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `rule-ports`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. Whether the draft carries this setting is decided by its semantic ledger entry "security group rules", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). Each rule becomes a stackit_security_group_rule: protocol → protocol.name/protocol.number, from_port/to_port → port_range.min/max, or icmp_parameters type/code for icmp (pinned provider schema). Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - `egress-rule-protocol`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. protocol → stackit_security_group_rule.protocol (pinned provider). the egress restriction setting reads the same attribute and is REVIEW exactly when the egress restriction check fires; this semantic is then REVIEW as well, so the two critical readers of egress.protocol never disagree (TRANSFORMED only when neither check fires). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `ingress-sources`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. Whether the draft carries this setting is decided by its semantic ledger entry "security group rules", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). cidr_blocks → stackit_security_group_rule.ip_range (one rule per range), security_groups → remote_security_group_id (pinned provider); REVIEW for the group when a rule is not generated, as rule ports (2026-09-27). Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - and 1 kind of reason more (engineering/analysis-details.md)

#### `module.retail_app_ecs.module.ui_service.aws_security_group.this`

- Alike lines: see "What the 12 aws_security_group units state alike", above.
- **Source:** `aws_security_group` — ../../lib/ecs/service/sg.tf:1
- **Module:** `module.retail_app_ecs.module.ui_service` (./service)
- **Candidate target:** STACKIT security group (`stackit_security_group`, `stackit_security_group_rule`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic security-group-vpc-membership, semantic network-topology-boundary, semantic stateful and 4 more); a point the scan could not establish
- **Why:** STACKIT security groups are stateful rule sets like AWS's, including rules that reference another security group (remote_security_group_id). Rules are re-created one by one; CIDRs of AWS-internal ranges (VPC, prefix lists) must be replaced with STACKIT network prefixes.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-POD-SEGMENTATION/module.retail_app_ecs.module.ui_service.aws_security_group.this` (alias `convert:module.retail_app_ecs.module.ui_service.aws_security_group.this:security-group:POD_SEGMENTATION`): Decide how the segmentation that the security group module.retail_app_ecs.module.ui_service.aws_security_group.this gave the tasks of module.retail_app_ecs.module.ui_service.aws_ecs_service.this is carried on STACKIT: the tasks become pods of the cluster, and no block of the draft attaches the drafted group stackit_security_group.retail_app_ecs_ui_service_this to anything — option generate-networkpolicy-from-the-group-rules (a Kubernetes NetworkPolicy written from the rules of the group), security-group-on-the-nodes (coarser: the group acts on the interface of a node, so on every pod of it), or accept-no-segmentation (the loss of the restriction is accepted, with who accepted it) · the source restricts the traffic to and from the tasks with this group; a STACKIT security group acts on the network interface of a server and cannot restrict a pod, and the draft attaches the group to nothing, so the tasks would run without the segmentation the source had unless a person decides how it is carried (never equivalent without that decision)
- **Behaviour evidence:** behaviour: 2 observed on target, 6 documented, 6 not verified for this variant, 0 contradicted
- **Depends on:** `module.vpc.module.vpc.aws_vpc.this`
- **Critical semantics left to you to decide or accept (7):** egress-rule-protocol, egress-sources, ingress-sources, network-topology-boundary, rule-ports, security-group-vpc-membership, stateful (**not automation-eligible**: no property the unit sets is read by network-topology-boundary, stateful)
- **Open choice(s) the draft could not make:** `DEC-GEN-CONVERT-POD-SEGMENTATION/module.retail_app_ecs.module.ui_service.aws_security_group.this` (alias `convert:module.retail_app_ecs.module.ui_service.aws_security_group.this:security-group:POD_SEGMENTATION`) — the source does not prove what it means and the draft holds a required variable without a default; a person decides, and until then the unit is **not automation-eligible**.
- **Property accounting:** 10 of 10 meaningful properties accounted
- **9 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (9; REVIEW 8 · UNSUPPORTED 1): `egress.cidr_blocks`, `egress.from_port`, `egress.protocol`, `egress.to_port`, `ingress.cidr_blocks` and 4 more — plan: stackit_security_group.retail_app_ecs_ui_service_this vpc_id UNSUPPORTED: a STACKIT security group belongs to a project, not to a network: the resource has no network attribute, so the source's VPC membership is not carried (contract aws.security_group/security-group-vpc-membership:UNSUPPORTED)
- **Why those are open, and what closes them:**
  - `security-group-vpc-membership`: A check of the knowledge base (topology vpc unproven) found a setting the target has no counterpart for (a finding of this unit describes it). UNSUPPORTED, by name: a STACKIT security group has no network (VPC) scope. stackit_security_group takes project_id, name, description, labels, stateful and region only (pinned provider), and the IaaS API object SecurityGroup has no network field either (stackit-api-specifications services/iaas/v2); the group is project-wide and can be attached to the network interfaces of every network of the project. Closes when: A person confirms which VPC each network resource of the estate is in and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area; the group is then attached only to the interfaces of the networks that replace its VPC.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this security group included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `stateful`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. STACKIT security groups are stateful by default (tested on a STACKIT project on 2026-09-24: stateful=true). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `rule-ports`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. Whether the draft carries this setting is decided by its semantic ledger entry "security group rules", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). Each rule becomes a stackit_security_group_rule: protocol → protocol.name/protocol.number, from_port/to_port → port_range.min/max, or icmp_parameters type/code for icmp (pinned provider schema). Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - `egress-rule-protocol`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. protocol → stackit_security_group_rule.protocol (pinned provider). the egress restriction setting reads the same attribute and is REVIEW exactly when the egress restriction check fires; this semantic is then REVIEW as well, so the two critical readers of egress.protocol never disagree (TRANSFORMED only when neither check fires). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `ingress-sources`: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. Whether the draft carries this setting is decided by its semantic ledger entry "security group rules", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). cidr_blocks → stackit_security_group_rule.ip_range (one rule per range), security_groups → remote_security_group_id (pinned provider); REVIEW for the group when a rule is not generated, as rule ports (2026-09-27). Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - and 1 kind of reason more (engineering/analysis-details.md)

#### `module.dependencies.aws_security_group.catalog_opensearch_sg`

- Alike lines: see "What the 12 aws_security_group units state alike", above.
- **Source:** `aws_security_group` — ../../lib/dependencies/catalog_opensearch.tf:14
- **Module:** `module.dependencies` (../../lib/dependencies)
- **Candidate target:** not written by this draft (stackit_security_group, stackit_security_group_rule)
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic security-group-vpc-membership, semantic network-topology-boundary, check sg-egress-restricted and 7 more); a point the scan could not establish
- **Why:** This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. The knowledge base maps the unit to STACKIT security group (stackit_security_group, stackit_security_group_rule); this draft writes no block of it, so it creates nothing for the unit on STACKIT.
- **Includes:** `module.dependencies.aws_security_group_rule.allow_https_from_client`
- **Depends on:** `module.retail_app_ecs.module.catalog_service.aws_security_group.this`, `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (sg-egress-restricted): The source restricts egress (the AWS provider removes AWS's default allow-all egress rule; only the listed egress rules apply). Every new STACKIT security group gets two default egress rules, IPv4 and IPv6, with no ip range (any address), no protocol and no port restriction (the test of 2026-10-07, 2026-10-07: API read-back of a new group, docs concepts page), that stackit_security_group (the pinned STACKIT provider) does not manage — as generated, the draft allows all egress. After apply, delete them (stackit security-group rule list / delete --security-group-id <id>), or egress is wider than in the source.
- **WARNING** (sg-rule-not-rendered): At least one rule of this group is not in the draft as the source has it. The plan withholds it, holds it as a commented-out rule until a value or a decision is filled in, writes it with a fact that decides what it allows not carried exactly, or cannot name it at all because the source has more rules than are visible statically (a dynamic block over a collection, a count or a rule list that is not known until apply, or a list with a hidden member: the plan's INCOMPLETE action says which set and why, the draft's TODO "rules beyond the known set" names it, and only the known rules are drafted). Typical causes: a protocol, port or source whose value is known only at apply time or comes from a root variable; a source group that is a choice between groups or not a group of the draft; a protocol with no STACKIT counterpart; an ICMP type with every code; an ICMP or ICMPv6 rule whose range is of the other IP family (the API answers HTTP 400, the test of 2026-10-08); a tcp or udp rule with a negative port, a port above 65535, a reversed range, or port 0 only (STACKIT stores no port range for 0 to 0, so the rule would match every port). A tcp or udp range that starts at port 0 and ends below 65535 is written from port 1 (the STACKIT API rejects a range that starts at 0; tested on a STACKIT project on 2026-10-07): port 0 itself is not carried. A stackit_security_group_rule without protocol, port_range or source allows everything (the pinned STACKIT provider), so such a rule is never widened; re-create it with the values it needs (the plan names each one).
- **Critical semantics left to you to decide or accept (6):** egress-restriction, network-topology-boundary, security-group-vpc-membership, standalone-rule-not-generated, standalone-rule-remote-not-resolved, stateful (**not automation-eligible**: no property the unit sets is read by egress-restriction, network-topology-boundary, standalone-rule-remote-not-resolved, stateful)
- **6 critical setting(s) left to you** (implicit unit) — **not automation-eligible**:
  - network exposure (6; UNSUPPORTED 1 · REVIEW 5): `vpc_id`, `module.dependencies.aws_security_group_rule.allow_https_from_client.from_port`, `module.dependencies.aws_security_group_rule.allow_https_from_client.protocol`, `module.dependencies.aws_security_group_rule.allow_https_from_client.source_security_group_id`, `module.dependencies.aws_security_group_rule.allow_https_from_client.to_port` and 1 more
- **Why those are open, and what closes them:**
  - `security-group-vpc-membership`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: A check of the knowledge base (topology vpc unproven) found a setting the target has no counterpart for (a finding of this unit describes it). UNSUPPORTED, by name: a STACKIT security group has no network (VPC) scope. stackit_security_group takes project_id, name, description, labels, stateful and region only (pinned provider), and the IaaS API object SecurityGroup has no network field either (stackit-api-specifications services/iaas/v2); the group is project-wide and can be attached to the network interfaces of every network of the project. Closes when: A person confirms which VPC each network resource of the estate is in and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area; the group is then attached only to the interfaces of the networks that replace its VPC.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this security group included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `stateful`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. STACKIT security groups are stateful by default (tested on a STACKIT project on 2026-09-24: stateful=true). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `egress-restriction`: A check of the knowledge base (sg egress restricted) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The security group restricts its outbound traffic: it has no rule that allows every protocol to 0.0.0.0/0 or ::/0. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `standalone-rule-not-generated`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. An aws_security_group_rule the draft does not generate (the draft names its settings NOT CARRIED, or the KB cannot decide that it generates it): a prefix list, an ICMP type with every code, ICMPv6 limited by type or code, a protocol with no STACKIT counterpart, a source or protocol or port not visible statically, a source group that is not one whole reference to a security group of the draft, or a repeated or conditionally created group. A person re-creates the rule with the STACKIT range or group it needs (a rule is never widened: a stackit_security_group_rule without source allows every address, pinned provider) - REVIEW, per rule. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `standalone-rule-remote-not-resolved`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The source of a standalone security group rule: the other security group (source_security_group_id) whose members the rule lets in. Closes when: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: A person re-creates the rule with the STACKIT security group or address range it needs; the draft does not widen it (a stackit_security_group_rule without a source allows everything, pinned provider).

#### `module.dependencies.aws_security_group.mq`

- Alike lines: see "What the 12 aws_security_group units state alike", above.
- **Source:** `aws_security_group` — ../../lib/dependencies/mq.tf:33
- **Module:** `module.dependencies` (../../lib/dependencies)
- **Candidate target:** not written by this draft (stackit_security_group, stackit_security_group_rule)
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic security-group-vpc-membership, semantic network-topology-boundary, check sg-egress-restricted and 6 more); a point the scan could not establish
- **Why:** This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. The knowledge base maps the unit to STACKIT security group (stackit_security_group, stackit_security_group_rule); this draft writes no block of it, so it creates nothing for the unit on STACKIT.
- **Includes:** `module.dependencies.aws_security_group_rule.mq`
- **Depends on:** `module.retail_app_ecs.module.orders_service.aws_security_group.this`, `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (sg-egress-restricted): The source restricts egress (the AWS provider removes AWS's default allow-all egress rule; only the listed egress rules apply). Every new STACKIT security group gets two default egress rules, IPv4 and IPv6, with no ip range (any address), no protocol and no port restriction (the test of 2026-10-07, 2026-10-07: API read-back of a new group, docs concepts page), that stackit_security_group (the pinned STACKIT provider) does not manage — as generated, the draft allows all egress. After apply, delete them (stackit security-group rule list / delete --security-group-id <id>), or egress is wider than in the source.
- **WARNING** (sg-rule-not-rendered): At least one rule of this group is not in the draft as the source has it. The plan withholds it, holds it as a commented-out rule until a value or a decision is filled in, writes it with a fact that decides what it allows not carried exactly, or cannot name it at all because the source has more rules than are visible statically (a dynamic block over a collection, a count or a rule list that is not known until apply, or a list with a hidden member: the plan's INCOMPLETE action says which set and why, the draft's TODO "rules beyond the known set" names it, and only the known rules are drafted). Typical causes: a protocol, port or source whose value is known only at apply time or comes from a root variable; a source group that is a choice between groups or not a group of the draft; a protocol with no STACKIT counterpart; an ICMP type with every code; an ICMP or ICMPv6 rule whose range is of the other IP family (the API answers HTTP 400, the test of 2026-10-08); a tcp or udp rule with a negative port, a port above 65535, a reversed range, or port 0 only (STACKIT stores no port range for 0 to 0, so the rule would match every port). A tcp or udp range that starts at port 0 and ends below 65535 is written from port 1 (the STACKIT API rejects a range that starts at 0; tested on a STACKIT project on 2026-10-07): port 0 itself is not carried. A stackit_security_group_rule without protocol, port_range or source allows everything (the pinned STACKIT provider), so such a rule is never widened; re-create it with the values it needs (the plan names each one).
- **Critical semantics left to you to decide or accept (5):** egress-restriction, network-topology-boundary, security-group-vpc-membership, standalone-rule-not-generated, stateful (**not automation-eligible**: no property the unit sets is read by egress-restriction, network-topology-boundary, stateful)
- **6 critical setting(s) left to you** (implicit unit) — **not automation-eligible**:
  - network exposure (6; UNSUPPORTED 1 · REVIEW 5): `vpc_id`, `module.dependencies.aws_security_group_rule.mq.from_port`, `module.dependencies.aws_security_group_rule.mq.protocol`, `module.dependencies.aws_security_group_rule.mq.source_security_group_id`, `module.dependencies.aws_security_group_rule.mq.to_port` and 1 more
- **Why those are open, and what closes them:**
  - `security-group-vpc-membership`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: A check of the knowledge base (topology vpc unproven) found a setting the target has no counterpart for (a finding of this unit describes it). UNSUPPORTED, by name: a STACKIT security group has no network (VPC) scope. stackit_security_group takes project_id, name, description, labels, stateful and region only (pinned provider), and the IaaS API object SecurityGroup has no network field either (stackit-api-specifications services/iaas/v2); the group is project-wide and can be attached to the network interfaces of every network of the project. Closes when: A person confirms which VPC each network resource of the estate is in and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area; the group is then attached only to the interfaces of the networks that replace its VPC.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this security group included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `stateful`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. STACKIT security groups are stateful by default (tested on a STACKIT project on 2026-09-24: stateful=true). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `egress-restriction`: A check of the knowledge base (sg egress restricted) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The security group restricts its outbound traffic: it has no rule that allows every protocol to 0.0.0.0/0 or ::/0. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `standalone-rule-not-generated`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. An aws_security_group_rule the draft does not generate (the draft names its settings NOT CARRIED, or the KB cannot decide that it generates it): a prefix list, an ICMP type with every code, ICMPv6 limited by type or code, a protocol with no STACKIT counterpart, a source or protocol or port not visible statically, a source group that is not one whole reference to a security group of the draft, or a repeated or conditionally created group. A person re-creates the rule with the STACKIT range or group it needs (a rule is never widened: a stackit_security_group_rule without source allows every address, pinned provider) - REVIEW, per rule. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.

#### `module.dependencies.module.catalog_rds.aws_security_group.this`

- Alike lines: see "What the 12 aws_security_group units state alike", above.
- **Source:** `aws_security_group` — .terraform/modules/dependencies.catalog_rds/main.tf:321
- **Module:** `module.dependencies.module.catalog_rds` (terraform-aws-modules/rds-aurora/aws 7.7.1)
- **Candidate target:** not written by this draft (stackit_security_group, stackit_security_group_rule)
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic security-group-vpc-membership, semantic network-topology-boundary, check sg-egress-restricted and 7 more); a point the scan could not establish
- **Why:** This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. The knowledge base maps the unit to STACKIT security group (stackit_security_group, stackit_security_group_rule); this draft writes no block of it, so it creates nothing for the unit on STACKIT.
- **Includes:** `module.dependencies.module.catalog_rds.aws_security_group_rule.default_ingress`
- **Depends on:** `module.retail_app_ecs.module.catalog_service.aws_security_group.this`, `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (sg-egress-restricted): The source restricts egress (the AWS provider removes AWS's default allow-all egress rule; only the listed egress rules apply). Every new STACKIT security group gets two default egress rules, IPv4 and IPv6, with no ip range (any address), no protocol and no port restriction (the test of 2026-10-07, 2026-10-07: API read-back of a new group, docs concepts page), that stackit_security_group (the pinned STACKIT provider) does not manage — as generated, the draft allows all egress. After apply, delete them (stackit security-group rule list / delete --security-group-id <id>), or egress is wider than in the source.
- **WARNING** (sg-rule-not-rendered): At least one rule of this group is not in the draft as the source has it. The plan withholds it, holds it as a commented-out rule until a value or a decision is filled in, writes it with a fact that decides what it allows not carried exactly, or cannot name it at all because the source has more rules than are visible statically (a dynamic block over a collection, a count or a rule list that is not known until apply, or a list with a hidden member: the plan's INCOMPLETE action says which set and why, the draft's TODO "rules beyond the known set" names it, and only the known rules are drafted). Typical causes: a protocol, port or source whose value is known only at apply time or comes from a root variable; a source group that is a choice between groups or not a group of the draft; a protocol with no STACKIT counterpart; an ICMP type with every code; an ICMP or ICMPv6 rule whose range is of the other IP family (the API answers HTTP 400, the test of 2026-10-08); a tcp or udp rule with a negative port, a port above 65535, a reversed range, or port 0 only (STACKIT stores no port range for 0 to 0, so the rule would match every port). A tcp or udp range that starts at port 0 and ends below 65535 is written from port 1 (the STACKIT API rejects a range that starts at 0; tested on a STACKIT project on 2026-10-07): port 0 itself is not carried. A stackit_security_group_rule without protocol, port_range or source allows everything (the pinned STACKIT provider), so such a rule is never widened; re-create it with the values it needs (the plan names each one).
- **Critical semantics left to you to decide or accept (6):** egress-restriction, network-topology-boundary, rule-ports, security-group-vpc-membership, standalone-rule-values, stateful (**not automation-eligible**: no property the unit sets is read by egress-restriction, network-topology-boundary, stateful)
- **6 critical setting(s) left to you** (implicit unit) — **not automation-eligible**:
  - network exposure (6; UNSUPPORTED 1 · REVIEW 5): `vpc_id`, `module.dependencies.module.catalog_rds.aws_security_group_rule.default_ingress.from_port`, `module.dependencies.module.catalog_rds.aws_security_group_rule.default_ingress.protocol`, `module.dependencies.module.catalog_rds.aws_security_group_rule.default_ingress.source_security_group_id`, `module.dependencies.module.catalog_rds.aws_security_group_rule.default_ingress.to_port` and 1 more
- **Why those are open, and what closes them:**
  - `security-group-vpc-membership`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: A check of the knowledge base (topology vpc unproven) found a setting the target has no counterpart for (a finding of this unit describes it). UNSUPPORTED, by name: a STACKIT security group has no network (VPC) scope. stackit_security_group takes project_id, name, description, labels, stateful and region only (pinned provider), and the IaaS API object SecurityGroup has no network field either (stackit-api-specifications services/iaas/v2); the group is project-wide and can be attached to the network interfaces of every network of the project. Closes when: A person confirms which VPC each network resource of the estate is in and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area; the group is then attached only to the interfaces of the networks that replace its VPC.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this security group included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `stateful`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. STACKIT security groups are stateful by default (tested on a STACKIT project on 2026-09-24: stateful=true). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `egress-restriction`: A check of the knowledge base (sg egress restricted) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The security group restricts its outbound traffic: it has no rule that allows every protocol to 0.0.0.0/0 or ::/0. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `rule-ports`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: A check of the knowledge base (sg rule not rendered) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Each rule becomes a stackit_security_group_rule: protocol → protocol.name/protocol.number, from_port/to_port → port_range.min/max, or icmp_parameters type/code for icmp (pinned provider schema). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `standalone-rule-values`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: A check of the knowledge base (sg rule not rendered) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). An aws_security_group_rule becomes a stackit_security_group_rule: type → direction, protocol → protocol, cidr_blocks → ip_range (one rule per range), source_security_group_id → remote_security_group_id. A rule that is not generated is named NOT CARRIED and the group is REVIEW. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.

#### `module.dependencies.module.checkout_elasticache_redis.module.aws_security_group.aws_security_group.cbd`

- Alike lines: see "What the 12 aws_security_group units state alike", above.
- **Source:** `aws_security_group` — .terraform/modules/dependencies.checkout_elasticache_redis.aws_security_group/main.tf:81
- **Module:** `module.dependencies.module.checkout_elasticache_redis.module.aws_security_group` (cloudposse/security-group/aws 1.0.1)
- **Candidate target:** not written by this draft (stackit_security_group, stackit_security_group_rule)
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic security-group-vpc-membership, semantic network-topology-boundary, check sg-rule-not-rendered and 7 more); a point the scan could not establish
- **Why:** This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. The knowledge base maps the unit to STACKIT security group (stackit_security_group, stackit_security_group_rule); this draft writes no block of it, so it creates nothing for the unit on STACKIT.
- **Includes:** `module.dependencies.module.checkout_elasticache_redis.module.aws_security_group.aws_security_group_rule.keyed`
- **Depends on:** `module.retail_app_ecs.module.checkout_service.aws_security_group.this`, `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (sg-rule-not-rendered): At least one rule of this group is not in the draft as the source has it. The plan withholds it, holds it as a commented-out rule until a value or a decision is filled in, writes it with a fact that decides what it allows not carried exactly, or cannot name it at all because the source has more rules than are visible statically (a dynamic block over a collection, a count or a rule list that is not known until apply, or a list with a hidden member: the plan's INCOMPLETE action says which set and why, the draft's TODO "rules beyond the known set" names it, and only the known rules are drafted). Typical causes: a protocol, port or source whose value is known only at apply time or comes from a root variable; a source group that is a choice between groups or not a group of the draft; a protocol with no STACKIT counterpart; an ICMP type with every code; an ICMP or ICMPv6 rule whose range is of the other IP family (the API answers HTTP 400, the test of 2026-10-08); a tcp or udp rule with a negative port, a port above 65535, a reversed range, or port 0 only (STACKIT stores no port range for 0 to 0, so the rule would match every port). A tcp or udp range that starts at port 0 and ends below 65535 is written from port 1 (the STACKIT API rejects a range that starts at 0; tested on a STACKIT project on 2026-10-07): port 0 itself is not carried. A stackit_security_group_rule without protocol, port_range or source allows everything (the pinned STACKIT provider), so such a rule is never widened; re-create it with the values it needs (the plan names each one).
- **Critical semantics left to you to decide or accept (7):** network-topology-boundary, rule-ports, security-group-vpc-membership, standalone-rule-empty-sources, standalone-rule-other-sources, standalone-rule-values, stateful (**not automation-eligible**: no property the unit sets is read by network-topology-boundary, stateful)
- **9 critical setting(s) left to you** (implicit unit) — **not automation-eligible**:
  - network exposure (9; UNSUPPORTED 1 · REVIEW 8): `vpc_id`, `module.dependencies.module.checkout_elasticache_redis.module.aws_security_group.aws_security_group_rule.keyed.cidr_blocks`, `module.dependencies.module.checkout_elasticache_redis.module.aws_security_group.aws_security_group_rule.keyed.from_port`, `module.dependencies.module.checkout_elasticache_redis.module.aws_security_group.aws_security_group_rule.keyed.ipv6_cidr_blocks`, `module.dependencies.module.checkout_elasticache_redis.module.aws_security_group.aws_security_group_rule.keyed.prefix_list_ids` and 4 more
- **Why those are open, and what closes them:**
  - `security-group-vpc-membership`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: A check of the knowledge base (topology vpc unproven) found a setting the target has no counterpart for (a finding of this unit describes it). UNSUPPORTED, by name: a STACKIT security group has no network (VPC) scope. stackit_security_group takes project_id, name, description, labels, stateful and region only (pinned provider), and the IaaS API object SecurityGroup has no network field either (stackit-api-specifications services/iaas/v2); the group is project-wide and can be attached to the network interfaces of every network of the project. Closes when: A person confirms which VPC each network resource of the estate is in and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area; the group is then attached only to the interfaces of the networks that replace its VPC.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this security group included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `stateful`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. STACKIT security groups are stateful by default (tested on a STACKIT project on 2026-09-24: stateful=true). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `rule-ports`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: A check of the knowledge base (sg rule not rendered) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Each rule becomes a stackit_security_group_rule: protocol → protocol.name/protocol.number, from_port/to_port → port_range.min/max, or icmp_parameters type/code for icmp (pinned provider schema). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `standalone-rule-values`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: A check of the knowledge base (sg rule not rendered) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). An aws_security_group_rule becomes a stackit_security_group_rule: type → direction, protocol → protocol, cidr_blocks → ip_range (one rule per range), source_security_group_id → remote_security_group_id. A rule that is not generated is named NOT CARRIED and the group is REVIEW. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `standalone-rule-other-sources`: A check of the knowledge base (sg rule not rendered) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). A standalone rule's own group (self) and IPv6 ranges are written where the draft places the rule (self as remote_security_group_id of the group, an IPv6 range as ip_range with ether_type IPv6), and the draft names the rule NOT CARRIED when the plan withholds it; prefix lists are not generated (as rule other sources for inline rules; prefix lists: the prefix list check), and a person adds the rule if the traffic must pass — REVIEW in every order position. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - and 1 kind of reason more (engineering/analysis-details.md)

#### `module.dependencies.module.orders_rds.aws_security_group.this`

- Alike lines: see "What the 12 aws_security_group units state alike", above.
- **Source:** `aws_security_group` — .terraform/modules/dependencies.orders_rds/main.tf:321
- **Module:** `module.dependencies.module.orders_rds` (terraform-aws-modules/rds-aurora/aws 7.7.1)
- **Candidate target:** not written by this draft (stackit_security_group, stackit_security_group_rule)
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic security-group-vpc-membership, semantic network-topology-boundary, check sg-egress-restricted and 7 more); a point the scan could not establish
- **Why:** This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. The knowledge base maps the unit to STACKIT security group (stackit_security_group, stackit_security_group_rule); this draft writes no block of it, so it creates nothing for the unit on STACKIT.
- **Includes:** `module.dependencies.module.orders_rds.aws_security_group_rule.default_ingress`
- **Depends on:** `module.retail_app_ecs.module.orders_service.aws_security_group.this`, `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (sg-egress-restricted): The source restricts egress (the AWS provider removes AWS's default allow-all egress rule; only the listed egress rules apply). Every new STACKIT security group gets two default egress rules, IPv4 and IPv6, with no ip range (any address), no protocol and no port restriction (the test of 2026-10-07, 2026-10-07: API read-back of a new group, docs concepts page), that stackit_security_group (the pinned STACKIT provider) does not manage — as generated, the draft allows all egress. After apply, delete them (stackit security-group rule list / delete --security-group-id <id>), or egress is wider than in the source.
- **WARNING** (sg-rule-not-rendered): At least one rule of this group is not in the draft as the source has it. The plan withholds it, holds it as a commented-out rule until a value or a decision is filled in, writes it with a fact that decides what it allows not carried exactly, or cannot name it at all because the source has more rules than are visible statically (a dynamic block over a collection, a count or a rule list that is not known until apply, or a list with a hidden member: the plan's INCOMPLETE action says which set and why, the draft's TODO "rules beyond the known set" names it, and only the known rules are drafted). Typical causes: a protocol, port or source whose value is known only at apply time or comes from a root variable; a source group that is a choice between groups or not a group of the draft; a protocol with no STACKIT counterpart; an ICMP type with every code; an ICMP or ICMPv6 rule whose range is of the other IP family (the API answers HTTP 400, the test of 2026-10-08); a tcp or udp rule with a negative port, a port above 65535, a reversed range, or port 0 only (STACKIT stores no port range for 0 to 0, so the rule would match every port). A tcp or udp range that starts at port 0 and ends below 65535 is written from port 1 (the STACKIT API rejects a range that starts at 0; tested on a STACKIT project on 2026-10-07): port 0 itself is not carried. A stackit_security_group_rule without protocol, port_range or source allows everything (the pinned STACKIT provider), so such a rule is never widened; re-create it with the values it needs (the plan names each one).
- **Critical semantics left to you to decide or accept (6):** egress-restriction, network-topology-boundary, rule-ports, security-group-vpc-membership, standalone-rule-values, stateful (**not automation-eligible**: no property the unit sets is read by egress-restriction, network-topology-boundary, stateful)
- **6 critical setting(s) left to you** (implicit unit) — **not automation-eligible**:
  - network exposure (6; UNSUPPORTED 1 · REVIEW 5): `vpc_id`, `module.dependencies.module.orders_rds.aws_security_group_rule.default_ingress.from_port`, `module.dependencies.module.orders_rds.aws_security_group_rule.default_ingress.protocol`, `module.dependencies.module.orders_rds.aws_security_group_rule.default_ingress.source_security_group_id`, `module.dependencies.module.orders_rds.aws_security_group_rule.default_ingress.to_port` and 1 more
- **Why those are open, and what closes them:**
  - `security-group-vpc-membership`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: A check of the knowledge base (topology vpc unproven) found a setting the target has no counterpart for (a finding of this unit describes it). UNSUPPORTED, by name: a STACKIT security group has no network (VPC) scope. stackit_security_group takes project_id, name, description, labels, stateful and region only (pinned provider), and the IaaS API object SecurityGroup has no network field either (stackit-api-specifications services/iaas/v2); the group is project-wide and can be attached to the network interfaces of every network of the project. Closes when: A person confirms which VPC each network resource of the estate is in and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area; the group is then attached only to the interfaces of the networks that replace its VPC.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this security group included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `stateful`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: UNENFORCED: the security group is attached to no block of the target (it is written in the draft and listed by no resource, or, where the access lists of its members carry it, not written), so its rules ("security group rules") restrict nothing on the target until an attachment is designed; this setting is not carried as an enforced control. STACKIT security groups are stateful by default (tested on a STACKIT project on 2026-09-24: stateful=true). Closes when: A person designs how the target enforces what the group allowed (attaches the group, or its replacement, to the target resources that take its place), or accepts the difference.
  - `egress-restriction`: A check of the knowledge base (sg egress restricted) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The security group restricts its outbound traffic: it has no rule that allows every protocol to 0.0.0.0/0 or ::/0. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `rule-ports`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: A check of the knowledge base (sg rule not rendered) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Each rule becomes a stackit_security_group_rule: protocol → protocol.name/protocol.number, from_port/to_port → port_range.min/max, or icmp_parameters type/code for icmp (pinned provider schema). Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `standalone-rule-values`: This draft writes no stackit_security_group, stackit_security_group_rule for this unit: every unit that names the group is a managed data service of STACKIT, which has no security group and takes its clients from an access list of its own, so the group is listed by no resource and what it admitted reaches those access lists as addresses only. What follows states the knowledge base's candidate target, not a block of this draft: A check of the knowledge base (sg rule not rendered) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). An aws_security_group_rule becomes a stackit_security_group_rule: type → direction, protocol → protocol, cidr_blocks → ip_range (one rule per range), source_security_group_id → remote_security_group_id. A rule that is not generated is named NOT CARRIED and the group is REVIEW. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.

#### `module.vpc.module.vpc.aws_nat_gateway.this`

- **Source:** `aws_nat_gateway` — .terraform/modules/vpc.vpc/main.tf:1111
- **Module:** `module.vpc.module.vpc` (terraform-aws-modules/vpc/aws 5.21.0)
- **Candidate target:** implicit outbound (STACKIT network)
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.nat_gateway/nat`
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic network-topology-boundary, semantic fixed-egress-ip, semantic nat-placement); a point the scan could not establish
- **Why:** STACKIT has no discrete NAT gateway resource. Outbound traffic from private workloads leaves through the network's default routing (observed on the target, the test of 2026-10-10, in a project outside a Network Area), by the network's publicIp - one address shared by every routed network of the project.
- **Depends on:** `module.vpc.module.vpc.aws_eip.nat`, `module.vpc.module.vpc.aws_internet_gateway.this`, `module.vpc.module.vpc.aws_subnet.public`
- **WARNING** (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: a resource of the estate (a subnet, route table, security group, network ACL, flow log, peering connection, a Cloud Control twin of those, ...) names a VPC by a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). A unit placed in a subnet that the scan cannot show is one of the estate's (a server, load balancer, function or NAT gateway in a subnet given by a variable, a data source or a literal id) is in the same position: it may stand in another VPC. The draft puts every network, security group and routing table in the one var.project_id and cannot say that they all belong to one VPC. Confirm which VPC each of them is in, and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area. No unit of the VPC topology is automation-eligible until then (gate blocker TOPOLOGY:vpc-unproven).
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (3):** network-topology-boundary, fixed-egress-ip, nat-placement (**not automation-eligible**: no property the unit sets is read by network-topology-boundary)
- **2 critical setting(s) left to you** (implicit unit) — **not automation-eligible**:
  - network exposure (2; REVIEW 2): `allocation_id`, `subnet_id`
- **Why those are open, and what closes them:**
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this NAT gateway included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `fixed-egress-ip`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. A stable egress IP on STACKIT is an open question (no source in this repository answers it; the per-network SNAT address is computed and cannot be chosen or kept). Closes when: A person decides how peers that allow-list the Elastic IP are served: a routed STACKIT network leaves by the project's shared egress address, which cannot be set and can change, so the allow-list follows it or each server gets a STACKIT public IP.
  - `nat-placement`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. A zonal NAT gateway (subnet_id) is placed in one AZ; a regional one lists its per-AZ egress in availability_zone_address(es).availability_zone. STACKIT has no NAT gateway resource, and its documentation does not state whether the implicit outbound path is zone-scoped: REVIEW. Closes when: A person decides whether the egress path must stay in one zone or per zone, because the STACKIT documentation does not state whether the implicit outbound path is scoped to a zone.
- **Review:**
  - [ ] If partners allowlist the fixed egress IP of the NAT gateway, that address is lost (observed, tested on a STACKIT project on 2026-10-10: the network's publicIp is shared by every routed network of the project, changed twice when every network of the project was deleted, and cannot be set - a PATCH answers 202 and is ignored). A STACKIT public IP per server keeps its address (the test of 2026-10-10); otherwise the allow-list has to follow the changing address.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (no NAT-gateway resource); terraform-provider-stackit@0.120.0 (re-checked 2026-10-18 against STACKIT provider schema 0.120.0 and the v0.120.0 tag docs: no such resource in the 0.120.0 schema (115 resources; since 0.116.0 only stackit_volume_automation was added)); found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/network/core-networking/basics/architecture/

#### `module.retail_app_ecs.module.alb.aws_lb.this`

- **Source:** `aws_lb` — .terraform/modules/retail_app_ecs.alb/main.tf:5
- **Module:** `module.retail_app_ecs.module.alb` (terraform-aws-modules/alb/aws 8.7.0)
- **Candidate target:** STACKIT Application Load Balancer (`stackit_application_load_balancer`, `stackit_alb_certificate`)
- **Target maturity:** GA · lifecycle active · offered in eu01, eu02 (live catalogue snapshot)
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.lb/alb`
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (semantic lb-connection-timeouts, semantic network-exposure, semantic frontend-http2, semantic client-restriction and 8 more); a point the scan could not establish
- **Why:** An application load balancer maps to the STACKIT Application Load Balancer (HTTP/HTTPS listeners, target pools with health checks, optional WAF). Listener rules, certificates and targets are re-created; target pools point at STACKIT server or node IPs.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 2 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-AMBIGUOUS-INSTANCE-SELECTION` (alias `convert:module.retail_app_ecs.module.alb.aws_lb.this:network_id:AMBIGUOUS_INSTANCE_SELECTION`): Decide which instance of stackit_network.vpc_vpc_public the networks of stackit_application_load_balancer.retail_app_ecs_alb_this means: set var.retail_app_ecs_alb_this_network_id_target to its index · the reference reaches stackit_network.vpc_vpc_public, a repeated resource (count or for_each), and nothing in the source proves which instance it means; no instance is assumed and the variable has no default
  - decision `DEC-GEN-CONVERT-INGRESS-EXPOSURE-PATH` (alias `convert:module.retail_app_ecs.module.alb.aws_lb.this:target_pools:INGRESS_EXPOSURE_PATH`): Decide how the clients of module.retail_app_ecs.module.alb.aws_lb.this reach the workloads of module.retail_app_ecs.module.ui_service.aws_ecs_service.this on SKE (aws.ingress.exposure-path): option nodeport-alb-target-pool (the drafted path: a NodePort Service of each workload and the target pool on its node port at the private IPs of the cluster's nodes, an input), ingress-controller-behind-alb (an Ingress controller on the cluster, reached by the load balancer on the controller's node port, routes to the ClusterIP Services), or stackit-alb-ingress-controller (the SKE Application Load Balancer extension provisions the load balancer from an Ingress of the IngressClass stackit-alb over NodePort Services; the drafted stackit_application_load_balancer.retail_app_ecs_alb_this is not applied) · a STACKIT target pool reaches its targets by private IP and the SKE cluster exports no node address to Terraform, so a Kubernetes workload is reachable from the load balancer only through a node port at the IPs of the nodes, which change as the node pool scales and is updated, or through an Ingress controller; the source registered the tasks of the service by their own IPs (awsvpc)
- **Includes:** `module.retail_app_ecs.module.alb.aws_lb_listener.frontend_http_tcp`
- **Depends on:** `module.retail_app_ecs.module.alb.aws_security_group.this`, `module.retail_app_ecs.module.alb_sg.aws_security_group.this_name_prefix`, `module.vpc.module.vpc.aws_subnet.public`, `module.vpc.module.vpc.aws_vpc.this`
- **INFO** (alb-http2-frontend): The source accepts HTTP/2 client connections (enable_http2). The STACKIT ALB's HTTPS listener does not negotiate HTTP/2 (tested in a STACKIT sandbox on 2026-09-24 and 2026-09-30); ordinary HTTP clients fall back to HTTP/1.1, clients that require HTTP/2 do not work.
- **INFO** (lb-security-groups): Security groups restrict clients of the load balancer; on STACKIT this becomes options.access_control.allowed_source_ranges (ALB) or options.acl (NLB). — a variable's default, not a fact
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (8):** client-restriction, lb-connection-timeouts, lb-routing-and-addressing, lb-subnets, network-exposure, request-handling, request-header-options, tc-lb-name (**not automation-eligible**: no property the unit sets is read by client-restriction)
- **Open choice(s) the draft could not make:** `DEC-GEN-CONVERT-AMBIGUOUS-INSTANCE-SELECTION` (alias `convert:module.retail_app_ecs.module.alb.aws_lb.this:network_id:AMBIGUOUS_INSTANCE_SELECTION`), `DEC-GEN-CONVERT-INGRESS-EXPOSURE-PATH` (alias `convert:module.retail_app_ecs.module.alb.aws_lb.this:target_pools:INGRESS_EXPOSURE_PATH`) — the source does not prove what it means and the draft holds a required variable without a default; a person decides, and until then the unit is **not automation-eligible**.
- **Property accounting:** 21 of 21 meaningful properties accounted
- **11 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (6; REVIEW 6): `desync_mitigation_mode`, `enable_waf_fail_open`, `internal`, `security_groups`, `subnets` and 1 more — NOT CARRIED (module.retail_app_ecs.module.alb.aws_lb.this): enable_http2 = true, desync_mitigation_mode = defensive, xff_header_processing_mode = append, enable_xff_client_port = true — no attribute for it on the STACKIT load balancers (pinned provider).
  - availability durability (1; REVIEW 1): `idle_timeout` — NOT CARRIED (module.retail_app_ecs.module.alb.aws_lb.this): idle_timeout = 60 — the STACKIT Application Load Balancer has no idle timeout; Network Load Balancer listeners take tcp.idle_timeout — not generated (pinned provider).
  - workload compatibility (4; REVIEW 4): `enable_tls_version_and_cipher_suite_headers`, `enable_xff_client_port`, `name`, `preserve_host_header` — NOT CARRIED (module.retail_app_ecs.module.alb.aws_lb.this): enable_http2 = true, desync_mitigation_mode = defensive, xff_header_processing_mode = append, enable_xff_client_port = true — no attribute for it on the STACKIT load balancers (pinned provider).
- **Why those are open, and what closes them:**
  - `lb-connection-timeouts`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. aws_lb.idle_timeout and client_keep_alive (aws 6.66.0): how long the load balancer lets a client connection idle and how long it keeps it open. The STACKIT application load balancer has no such attribute and the draft does not carry them - REVIEW: a person decides whether the applications behind the load balancer (long polling, streaming, WebSockets, slow requests) cope with the STACKIT default. aws_alb, the alias type, is not read here. Closes when: A person confirms the value against the target, or the knowledge base gains a rule that decides this setting.
  - `network-exposure`: Whether the draft carries this setting is decided by its semantic ledger entry "network exposure", and that entry does not state it as carried (it reads review or unsupported, is missing, or rests on a variable's default). internal not visible statically (a variable): the source states no exposure and the draft carries nothing for it; a person decides whether the STACKIT load balancer is private_network_only (REVIEW). Closes when: The ledger entry reads preserved or transformed with a value that is a fact of the source, or a person accepts the difference.
  - `client-restriction`: A check of the knowledge base (lb security groups) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Who may reach the load balancer, read from the ingress rules of the security groups that filter its clients. A group reference, a prefix list, an IPv6 range or a variable is not carried: the plan lists the clients the target would block and adds the client-access manual step for the Security Architect. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded. A person confirms the carried ranges against the source rules, or decides the open client-access step, and the regenerated draft carries the result.
  - `request-handling`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The setting states how the load balancer treats HTTP requests that may carry a request-smuggling (desync) risk, and how it rewrites the X-Forwarded-For header before the target sees it. Closes when: A person confirms that the application does not depend on either behaviour: the STACKIT application load balancer has neither setting and its documentation does not state the behaviour (pinned provider), also for the AWS default values.
  - `request-header-options`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The setting states which extra headers the load balancer adds to the request the target receives (TLS version and cipher suite, the client port in X-Forwarded-For) and whether it keeps the original Host header. Closes when: A person decides, for each setting, what the STACKIT load balancer or the application does instead, because the STACKIT application load balancer has no setting that adds, rewrites or renames a request header towards its targets (pinned provider).
  - `lb-routing-and-addressing`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The setting states how the load balancer answers DNS for clients (Availability Zone affinity), whether it still forwards to targets when AWS WAF cannot be reached (fail open), zonal shift, customer-owned address pools and IPv6 source NAT prefixes. Closes when: A person decides whether the STACKIT load balancer needs an equivalent for each of them, because the STACKIT application and network load balancers have no setting for any of them (pinned provider).
  - and 2 kinds of reason more (engineering/analysis-details.md)
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (stackit_application_load_balancer listeners: http/https/waf_config_name; no OIDC/Cognito/JWT action; rules: cookie_persistence, headers exact_match, host (wildcard), path exact_match/prefix, query_parameters exact_match, target_pool, web_socket; no redirect action, no regex condition matching, no deletion protection, cross-zone, header or IPv6 attribute) 2026-09-29; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/network/load-balancing-and-content-delivery/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/application_load_balancer · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/loadbalancer

#### `module.vpc.module.vpc.aws_internet_gateway.this`

- **Source:** `aws_internet_gateway` — .terraform/modules/vpc.vpc/main.tf:1051 · instances: 0–1 instances (decided by `module.vpc.data.aws_availability_zones.available`); POSSIBLE_SOURCE_ERROR: `slice(…, 3)` fails in Terraform and OpenTofu when the list has fewer than 3 elements (the source proves none), so the count is not exact
- **Standing:** conditional — whether it exists is decided only when a plan runs; the class below is the one it would get, it is not counted in the totals and not automation-eligible (gate blocker `TOPOLOGY:unknown`).
- **Module:** `module.vpc.module.vpc` (terraform-aws-modules/vpc/aws 5.21.0)
- **Candidate target:** implicit (STACKIT network default gateway)
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.internet_gateway/igw`
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, semantic network-topology-boundary); a point the scan could not establish
- **Why:** There is no internet-gateway object on STACKIT; a routed network with a gateway reaches the internet and inbound access is given per resource with public IPs and security groups. The IGW disappears from the target configuration. That a network reaches the internet with no route was observed and is documented for a project outside a Network Area; for a draft that may put its project in one it is open.
- **Depends on:** `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: a resource of the estate (a subnet, route table, security group, network ACL, flow log, peering connection, a Cloud Control twin of those, ...) names a VPC by a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). A unit placed in a subnet that the scan cannot show is one of the estate's (a server, load balancer, function or NAT gateway in a subnet given by a variable, a data source or a literal id) is in the same position: it may stand in another VPC. The draft puts every network, security group and routing table in the one var.project_id and cannot say that they all belong to one VPC. Confirm which VPC each of them is in, and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area. No unit of the VPC topology is automation-eligible until then (gate blocker TOPOLOGY:vpc-unproven).
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (1):** network-topology-boundary (**not automation-eligible**: no property the unit sets is read by network-topology-boundary)
  - not read instance by instance (unknown_count: the number of instances is not known statically): `network-topology-boundary`
- **Why those are open, and what closes them:**
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this gateway included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (no internet-gateway resource); terraform-provider-stackit@0.120.0 (re-checked 2026-10-18 against STACKIT provider schema 0.120.0 and the v0.120.0 tag docs: no such resource in the 0.120.0 schema (115 resources; since 0.116.0 only stackit_volume_automation was added)); found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/network/core-networking/basics/architecture/

#### `module.vpc.module.vpc.aws_route_table.private`

- **Source:** `aws_route_table` — .terraform/modules/vpc.vpc/main.tf:296 · instances: 0–1 instances (decided by `module.vpc.data.aws_availability_zones.available`); POSSIBLE_SOURCE_ERROR: `slice(…, 3)` fails in Terraform and OpenTofu when the list has fewer than 3 elements (the source proves none), so the count is not exact
- **Standing:** conditional — whether it exists is decided only when a plan runs; the class below is the one it would get, it is not counted in the totals and not automation-eligible (gate blocker `TOPOLOGY:unknown`).
- **Configuration:** conditional — whether the unit exists is decided when a plan runs, and so is part of what configures it; the facets below are open too.
  - the configuration of `module.vpc.module.vpc.aws_route_table_association.private` is decided by `module.vpc.data.aws_availability_zones.available` (a data source, read when a plan runs)
- **Module:** `module.vpc.module.vpc` (terraform-aws-modules/vpc/aws 5.21.0)
- **Candidate target:** implicit (STACKIT network default routing)
- **Classification:** RECONFIGURE · **Confidence:** LOW · rule `aws.route_table/rt-default-only-nat`
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-route-table-not-drafted, check topology-vpc-unproven, check rt-private-subnet-association, semantic subnet-association-target and 8 more); a point the scan could not establish
- **Why:** A route of the table sends traffic to a NAT gateway (the others, if any, to an internet gateway), and the draft's project is outside a Network Area. Observed on the target (tested on a STACKIT project in eu01 on 2026-10-10, a project outside a Network Area): a routed STACKIT network gives servers with and without a public IP the same outbound reachability with no route and no routing table, nothing initiated from the internet reaches a server behind the network address, and egress is restricted by the egress rules of security groups. The table is therefore not drafted: STACKIT's default routing replaces it. What a NAT gateway has beyond an internet route is NOT CARRIED and stays an open review: the gateway's fixed egress address is LOST (observed: the address a routed network leaves by is its project's publicIp, one address for every routed network of the project, not fixed - it changed after every network of the project was deleted, twice - and not settable, a PATCH answers 202 and is ignored), so a third party's allow-list on the NAT gateway's address does not survive and needs a STACKIT public IP per server (the only address the probe saw stay fixed); the restriction of egress to the gateway is carried only by security-group egress rules, which the draft does not tie to this table; the absence of an inbound path is observed. LOW: the loss is for a person to decide, as the plan decision NAT_FIXED_EGRESS_ADDRESS_LOST. The egress itself is not widened where the gateway is a public one: the subnets of this table reached the internet through it in the source, so the plan decision EXPOSURE_WIDENED_EGRESS (a subnet whose source had no route to the internet; a subnet behind a private NAT gateway is one, a private gateway gives no internet access) is not what this table raises; what changes is the address. STACKIT documents the way out as source NAT of the network (Virtual Network concepts, last updated Mar 11, 2026). Which NAT gateway the route names does not change this: a table that picks its NAT gateway by an index (one gateway per availability zone) or by a conditional between NAT gateways is decided as a table with one plain reference, because every gateway it can name is lost the same way and STACKIT has no NAT gateway to pick. A Gateway endpoint of S3 or DynamoDB that names the table adds a route that is NOT CARRIED (Object Storage is reached over the network's default path); it does not change the case, a check on the gateway endpoint names it. The destinations are read by the check of the route destinations. (1 conditional relation could not be resolved statically because module.vpc.module.vpc.aws_route_table_association.private's count/for_each is not known statically (it may not exist); the mapping decides the same either way; affected: this unit and `module.vpc.module.vpc.aws_route_table_association.private`.)
- **Includes:** `module.vpc.module.vpc.aws_route.private_nat_gateway`, `module.vpc.module.vpc.aws_route_table_association.private`
- **Depends on:** `module.vpc.module.vpc.aws_nat_gateway.this`, `module.vpc.module.vpc.aws_subnet.private`, `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (topology-route-table-not-drafted): This route table is created with count or for_each. What the draft makes of it follows the decision of this unit. A table that STACKIT's default routing replaces (the cases of a table with only internet or NAT routes in a project outside a Network Area) is not drafted at all, whatever its count: no routing table is made and none is to be attached, and this warning only records that the table is repeated. A table the decision keeps as a routing table of its own (rt-custom) is made only where the source names, instance by instance, which route and which subnet belongs to which instance (a table created with count whose routes and associations name the table by their own count.index): one routing table for each instance, with the routes the draft carries in each, attached to no network, and none at all when the draft carries none of the routes. Where the source does not name them, the draft makes none (which instance a route belongs to is not decided). For a table the decision keeps, nothing in the draft states which VPC the table belonged to (the routing table the draft writes, stackit_routing_table, belongs to a Network Area; the experimental stackit_vpc_routing_table of the pinned provider takes a vpc_id, but the draft writes none): the table, its routes and the subnets it is associated with are re-created or attached by hand once the VPC architecture is decided.
- **WARNING** (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this route table names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). A unit placed in a subnet that the scan cannot show is one of the estate's (a server, load balancer, function or NAT gateway in a subnet given by a variable, a data source or a literal id) is in the same position: it may stand in another VPC. The draft puts every network, security group and routing table in the one var.project_id and cannot say that they all belong to one VPC. Confirm which VPC each of them is in, and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area. No unit of the VPC topology is automation-eligible until then (gate blocker TOPOLOGY:vpc-unproven).
- **WARNING** (rt-private-subnet-association): A subnet uses a route table whose default route goes through a NAT gateway — a private subnet in AWS. STACKIT networks have no public/private split: a server there is reachable as soon as it gets a public IP, only its security group restricts it. Keep the converted servers without a public IP (or restrict them) where privacy is needed.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (8):** routes, route-destinations, route-targets, nat-fixed-egress-address, egress-restriction, subnet-association-target, tcr-route-table-vpc-id, network-topology-boundary (**not automation-eligible**: no property the unit sets is read by egress-restriction, nat-fixed-egress-address, network-topology-boundary)
  - not read instance by instance (unknown_count: the number of instances is not known statically): `routes`, `route-destinations`, `route-targets`, `nat-fixed-egress-address`, `egress-restriction`, `subnet-association-target`, `tcr-route-table-vpc-id`, `network-topology-boundary`
- **4 critical setting(s) left to you** (implicit unit) — **not automation-eligible**:
  - network exposure (4; REVIEW 4): `vpc_id`, `module.vpc.module.vpc.aws_route.private_nat_gateway.destination_cidr_block`, `module.vpc.module.vpc.aws_route.private_nat_gateway.nat_gateway_id`, `module.vpc.module.vpc.aws_route_table_association.private.subnet_id`
- **Why those are open, and what closes them:**
  - `routes`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. Custom routes map to stackit_routing_table_route, an experimental resource (experiment routing-tables); next hops that name AWS gateways are chosen anew. Closes when: A person creates the routes on the STACKIT routing table (stackit_routing_table_route, experimental) and chooses the next hops anew, because they name AWS gateways.
  - `route-destinations`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. Destinations are read by value: every route of a default-only table sends 0.0.0.0/0 to an internet or NAT gateway — STACKIT's default network routing, observed equivalent for a draft outside a Network Area (the test of 2026-10-10) and REVIEW all the same. Closes when: A person confirms every route destination that is not the default route to an internet or NAT gateway (a CIDR, a prefix list, any IPv6 route): the draft carries none, and a specific destination needs a stackit_routing_table_route, which takes IPv4 CIDR destinations only.
  - `route-targets`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The next hop of each route of the table: a route whose target is anything but an internet or NAT gateway, or that names none, makes the table a custom routing table. Closes when: A person decides the next hop of each route on STACKIT: an internet gateway becomes the next hop internet, an appliance (a network interface or an instance) a next hop of type ipv4. A NAT gateway, a transit gateway or a VPC peering has no STACKIT counterpart, so the connectivity design is the person's.
  - `nat-fixed-egress-address`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. NOT CARRIED, an observed loss (the test of 2026-10-10): the NAT gateway's fixed egress address. Closes when: A person accepts the project's shared egress address, which can change and cannot be set, or gives each server a STACKIT public IP when a third party allow-lists the old address.
  - `egress-restriction`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The restriction of egress to the NAT gateway (the only way out of a private subnet) is carried on STACKIT by the egress rules of the security groups, not by a route (the test of 2026-10-10: with egress rules for one /32 only that destination was reachable, with none nothing left). Whether the source restricts egress that way, and whether the draft carries those rules for the servers of this table's subnets, is not something this contract can read, so it is REVIEW and never PRESERVED: a person confirms that the servers of the private subnets keep a restricting egress rule set. Closes when: A person confirms that the servers of the private subnets keep a restricting egress rule set in their security groups, because on STACKIT the restriction of egress is carried by egress rules, not by a route.
  - `subnet-association-target`: A check of the knowledge base (rt private subnet association) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The setting states which subnet uses this route table, for the associations the draft does not attach. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded. A person decides which networks of the Network Area take the routing table and sets routing_table_id on them: STACKIT attaches a routing table to a whole network (stackit_network.routing_table_id), there is no per-subnet association, and routing tables apply only to routed Layer 3 networks in a Network Area.
  - and 2 kinds of reason more (engineering/analysis-details.md)
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (stackit_routing_table requires experiment routing-tables; stackit_network no_ipv4_gateway; stackit_routing_table_route destination cidrv4 only); terraform-provider-stackit@0.120.0 (re-checked 2026-10-18 against STACKIT provider schema 0.120.0 and the v0.120.0 tag docs: stackit_routing_table still part of the experimental feature routing-tables, stackit_routing_table_route destination (Only `cidrv4` is supported during experimental stage), stackit_network no_ipv4_gateway (the network does not have a gateway when true); schemas of the two routing resources unchanged, pages routing_table and routing_table_route re-read); terraform-provider-aws@6.66.0 route_table docs 2026-09-28; rt-route-set-route-server / rt-route-set-unmodelled-source (2026-10-08): terraform-provider-aws@6.66.0 vpc_route_server_propagation, vpc_route_server, fsx_ontap_file_system and fsx_openzfs_file_system docs (local provider-docs mirror), terraform-provider-stackit@0.118.0 schema (stackit_routing_table.dynamic_routes); rt-route-set-route-list-unread / rt-route-set-gated-propagation / rt-route-set-maybe-member (2026-10-08): terraform-provider-aws@6.66.0 route_table docs lines 120-123, vpn_gateway_route_propagation docs lines 11 and 31-32, route docs line 53, route_table_association docs line 37 (local provider-docs mirror), Terraform dynamic blocks and count documentation; rt-route-set-maybe-member narrowed to route-adding resources and rt-association-table-undecided added (KB-ROUTE-SET-3, 2026-10-08): route_table_association docs line 37, main_route_table_association docs line 31 (local provider-docs mirror), EC2 API AssociateRouteTable (docs.aws.amazon.com/AWSEC2/latest/APIReference/API_AssociateRouteTable.html read 2026-10-08: associates a subnet, internet gateway or virtual private gateway with a route table; no route parameter); rt-default-only, rt-default-only-nat, rt-default-only-area (2026-10-10): the test of 2026-10-10 (a STACKIT project in eu01, outside a Network Area), the area's default routing table unobserved (403); rt-default-only-open worded for an internet gateway created only when a plan runs (L2, 2026-10-27; wording only: the class and the case are unchanged; the cause is the reference not being exact, the knowledge-base input node.ref_exact, a target whose presence is not known is not pinned); rt-default-only-open narrowed (N2-2, 2026-10-27): a NAT gateway picked by an index is the NAT case, a plainly stated Gateway endpoint of S3 or DynamoDB does not hold the table (docs.stackit.cloud Virtual Network concepts, Last updated Mar 11, 2026, mirror virtual-network/basics/concepts.txt:144; the STACKIT professional-services example of Velero backups on SKE addresses Object Storage as https://object.storage.<region>.onstackit.cloud; terraform-provider-stackit@0.120.0 STACKIT provider schema 0.120.0: 115 resources, none a private endpoint, PrivateLink or VPC endpoint, no such attribute on any; stackit_objectstorage_bucket exposes url_path_style and url_virtual_hosted_style; terraform-provider-aws@6.66.0 vpc_endpoint docs line 184 route_table_ids "Applicable for endpoints of type Gateway", line 193 vpc_endpoint_type defaults to Gateway); rt-local-only-closed and rt-default-only-open for a Gateway endpoint whose service name a plan decides (2026-10-31): AWS PrivateLink concepts (docs.aws.amazon.com/vpc/latest/privatelink/concepts.html, read 2026-10-31: the endpoint type Gateway "creates a gateway endpoint to send traffic to Amazon S3 or DynamoDB") and Gateway endpoints page (docs.aws.amazon.com/vpc/latest/privatelink/gateway-endpoints.html, the same day: "Gateway VPC endpoints provide reliable connectivity to Amazon S3 and DynamoDB"; the added route has the service's prefix list as destination and the endpoint as target), terraform-provider-aws@6.66.0 vpc_endpoint docs (route_table_ids "Applicable for endpoints of type Gateway", vpc_endpoint_type defaults to Gateway), the rest of the evidence of rt-default-only-open N2-2; rt-local-only-closed (2026-10-27): docs.stackit.cloud Virtual Network concepts (Last updated Mar 11, 2026, mirror virtual-network/basics/concepts.txt:144: "Every subnet is routed to the public internet"), network-area FAQ (mirror network-area/faq.txt:146-147: disabling the internet access of a project is not supported), routing-tables page (public preview), terraform-provider-aws@6.66.0 route_table docs line 152 (the VPC-CIDR local route is created implicitly); the AWS VPC User Guide pages are cited by URL, they are not in the local mirror; rt-local-only worded for what makes it a review and what closes it (L4, 2026-10-27; wording only: the class, the confidence and the case are unchanged): terraform-provider-aws@6.66.0 main_route_table_association docs (the AWS provider documentation of main_route_table_association: the resource sets the main route table of a VPC, vpc_id and route_table_id arguments), the case rt-local-only-closed above and its evidence (Virtual Network concepts, network-area FAQ: no network setting is documented as a control of outbound access, so the earlier text offering the gateway setting as one is removed); rt-default-only-open narrowed (#320, 2026-10-28): an internet gateway created only when a plan runs that the route names by a literal key is the internet case (OpenTofu v1.13.1, local probe tested on a STACKIT project on 2026-10-28 a plan that creates the route without the named instance fails, Invalid index, exit 1; terraform-provider-aws@6.66.0 route docs line 61, local provider-docs mirror: one target argument must be supplied); read 2026-10-28: the Routing tables page (last updated 2026-04-14: one default routing table per Network Area, created automatically, not deletable, followed by every routed network unless another is assigned; the feature is a public preview) and the Network Area FAQ (2025-12-12: the internet access of a project cannot be disabled); the IaaS v2 API specification (stackit-api-specifications checkout of 2026-10-13): the routing-table endpoints (iaas.network-area.rt.list, rt.get, rt.route.list) are scoped to the organisation (resource-type organization) while the project endpoints (iaas.project.get) return the area ID of a project and no routing table; STACKIT provider schema 0.120.0: the data sources stackit_routing_table, stackit_routing_tables and stackit_routing_table_routes require organization_id and network_area_id (stackit_routing_table also routing_table_id), stackit_network exposes routing_table_id; the role that carries the routing-table actions is not named on the roles page and the next hop of 0.0.0.0/0 in the default table is not documented anywhere read, so the question stays open; found compatible through 0.121.0 by the release check): https://github.com/stackitcloud/terraform-provider-stackit/blob/v0.120.0/docs/resources/routing_table.md · https://github.com/stackitcloud/terraform-provider-stackit/blob/v0.120.0/docs/resources/routing_table_route.md · tested on a STACKIT project on 2026-10-10 · https://registry.terraform.io/providers/hashicorp/aws/6.66.0/docs/resources/route_table · https://raw.githubusercontent.com/hashicorp/terraform-provider-aws/v6.66.0/website/docs/r/route_table.html.markdown · https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-route.html · https://registry.terraform.io/providers/hashicorp/aws/6.66.0/docs/resources/route_table_association · https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-gatewayroutetableassociation.html · https://docs.aws.amazon.com/vpc/latest/userguide/subnet-route-tables.html · https://docs.stackit.cloud/products/network/core-networking/network-area/basics/routing-tables/ · https://docs.stackit.cloud/products/network/core-networking/virtual-network/basics/concepts/ · https://github.com/stackitcloud/stackit-api-specifications/blob/main/services/iaas/v2/iaas.json · https://github.com/stackitcloud/terraform-provider-stackit/blob/v0.120.0/docs/data-sources/routing_table.md

#### `module.vpc.module.vpc.aws_route_table.public`

- **Source:** `aws_route_table` — .terraform/modules/vpc.vpc/main.tf:164 · instances: 0–1 instances (decided by `module.vpc.data.aws_availability_zones.available`); POSSIBLE_SOURCE_ERROR: `slice(…, 3)` fails in Terraform and OpenTofu when the list has fewer than 3 elements (the source proves none), so the count is not exact
- **Standing:** conditional — whether it exists is decided only when a plan runs; the class below is the one it would get, it is not counted in the totals and not automation-eligible (gate blocker `TOPOLOGY:unknown`).
- **Configuration:** conditional — whether the unit exists is decided when a plan runs, and so is part of what configures it; the facets below are open too.
  - the configuration of `module.vpc.module.vpc.aws_route.public_internet_gateway` is decided by `module.vpc.data.aws_availability_zones.available` (a data source, read when a plan runs)
  - the configuration of `module.vpc.module.vpc.aws_route_table_association.public` is decided by `module.vpc.data.aws_availability_zones.available` (a data source, read when a plan runs)
- **Module:** `module.vpc.module.vpc` (terraform-aws-modules/vpc/aws 5.21.0)
- **Candidate target:** implicit (STACKIT network default routing)
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.route_table/rt-default-only`
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-route-table-not-drafted, check topology-vpc-unproven, semantic tcr-route-table-vpc-id, semantic network-topology-boundary and 3 more); a point the scan could not establish
- **Why:** Every route of the table sends traffic to an internet gateway (a reference to an aws_internet_gateway, or an ID that is not a virtual private gateway's) and the draft's project is outside a Network Area. Observed on the target (tested on a STACKIT project in eu01 on 2026-10-10, a project outside a Network Area): a routed STACKIT network gives servers with and without a public IP the same outbound reachability with no route and no routing table configured (HTTPS, ICMP, DNS and TCP 443 in 62 of 62 rounds over 30 minutes per server; a non-routed network reaches nothing), nothing initiated from the internet reaches a server behind the network address (tcp 22, 80, 8080 timed out in 137 of 137 samples with an admitting security group), egress is restricted by the egress rules of security groups, and routed networks reach each other with no table. The table is therefore not drafted: STACKIT's default routing replaces it. Equivalent for a server that has a public IP. NOT equivalent for a server WITHOUT one: in the source an internet gateway serves only an instance with a public IPv4 or Elastic IP address ("the instances in the public subnet must have public IP addresses or Elastic IP addresses to enable communication with the internet over the internet gateway", AWS internet gateway documentation), so such an instance has no internet path; on STACKIT the same server leaves through the SNAT address of its network (observed in the STACKIT sandbox on two rounds; "VM without one: the SNAT address of its network, shared by every VM in that network without its own public IP", stackitcloud/professional-service examples/vpn-full-tunnel-central-egress README). The draft therefore GIVES egress to servers the source did not give it; the table does not carry that, and it is decided on the subnet (the finding that the egress of the subnet is not proven, and the plan decision EXPOSURE_WIDENED_EGRESS of the subnet, private egress ipv4), not here. What the STACKIT documentation says of the same behaviour (Virtual Network concepts, last updated Mar 11, 2026, read 2026-10-27): "Every subnet is routed to the public internet. Technically this is done by source NAT (SNAT) in combination with masquerading", it "supports outbound internet access but does not allow traffic initiated from the public internet to reach your resources", and the routing "can be controlled using Routing tables" only for projects that are part of a Network Area. So outside an area the equivalence rests on the documentation and on the test of 2026-10-10, which agree. Not HIGH: the test was one project, one region, one day, no probe in a Network Area (a draft that writes a Network Area is the case of a table in a Network Area), and the servers without a public IP are not equivalent (above). The destinations are read by the check of the route destinations: only 0.0.0.0/0 is default routing, any other destination (IPv6 included) is REVIEW. A Gateway endpoint of S3 or DynamoDB that names the table adds a route that is NOT CARRIED and does not change the case. (2 conditional relations could not be resolved statically because module.vpc.module.vpc.aws_route.public_internet_gateway's count/for_each is not known statically (it may not exist); module.vpc.module.vpc.aws_route_table_association.public's count/for_each is not known statically (it may not exist); the mapping decides the same either way; affected: this unit and `module.vpc.module.vpc.aws_route.public_internet_gateway`, `module.vpc.module.vpc.aws_route_table_association.public`.)
- **Includes:** `module.vpc.module.vpc.aws_route.public_internet_gateway`, `module.vpc.module.vpc.aws_route_table_association.public`
- **Depends on:** `module.vpc.module.vpc.aws_internet_gateway.this`, `module.vpc.module.vpc.aws_subnet.public`, `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (topology-route-table-not-drafted): This route table is created with count or for_each. What the draft makes of it follows the decision of this unit. A table that STACKIT's default routing replaces (the cases of a table with only internet or NAT routes in a project outside a Network Area) is not drafted at all, whatever its count: no routing table is made and none is to be attached, and this warning only records that the table is repeated. A table the decision keeps as a routing table of its own (rt-custom) is made only where the source names, instance by instance, which route and which subnet belongs to which instance (a table created with count whose routes and associations name the table by their own count.index): one routing table for each instance, with the routes the draft carries in each, attached to no network, and none at all when the draft carries none of the routes. Where the source does not name them, the draft makes none (which instance a route belongs to is not decided). For a table the decision keeps, nothing in the draft states which VPC the table belonged to (the routing table the draft writes, stackit_routing_table, belongs to a Network Area; the experimental stackit_vpc_routing_table of the pinned provider takes a vpc_id, but the draft writes none): the table, its routes and the subnets it is associated with are re-created or attached by hand once the VPC architecture is decided.
- **WARNING** (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this route table names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). A unit placed in a subnet that the scan cannot show is one of the estate's (a server, load balancer, function or NAT gateway in a subnet given by a variable, a data source or a literal id) is in the same position: it may stand in another VPC. The draft puts every network, security group and routing table in the one var.project_id and cannot say that they all belong to one VPC. Confirm which VPC each of them is in, and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area. No unit of the VPC topology is automation-eligible until then (gate blocker TOPOLOGY:vpc-unproven).
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (5):** routes, route-destinations, route-targets, tcr-route-table-vpc-id, network-topology-boundary (**not automation-eligible**: no property the unit sets is read by network-topology-boundary)
  - not read instance by instance (unknown_count: the number of instances is not known statically): `routes`, `route-destinations`, `route-targets`, `tcr-route-table-vpc-id`, `network-topology-boundary`
- **4 critical setting(s) left to you** (implicit unit) — **not automation-eligible**:
  - network exposure (4; REVIEW 3 · open 1): `vpc_id`, `module.vpc.module.vpc.aws_route.public_internet_gateway.destination_cidr_block`, `module.vpc.module.vpc.aws_route.public_internet_gateway.gateway_id`, `module.vpc.module.vpc.aws_route_table_association.public.subnet_id`
- **Why those are open, and what closes them:**
  - `routes`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. Custom routes map to stackit_routing_table_route, an experimental resource (experiment routing-tables); next hops that name AWS gateways are chosen anew. Closes when: A person creates the routes on the STACKIT routing table (stackit_routing_table_route, experimental) and chooses the next hops anew, because they name AWS gateways.
  - `route-destinations`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. Destinations are read by value: every route of a default-only table sends 0.0.0.0/0 to an internet or NAT gateway — STACKIT's default network routing, observed equivalent for a draft outside a Network Area (the test of 2026-10-10) and REVIEW all the same. Closes when: A person confirms every route destination that is not the default route to an internet or NAT gateway (a CIDR, a prefix list, any IPv6 route): the draft carries none, and a specific destination needs a stackit_routing_table_route, which takes IPv4 CIDR destinations only.
  - `route-targets`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The next hop of each route of the table: a route whose target is anything but an internet or NAT gateway, or that names none, makes the table a custom routing table. Closes when: A person decides the next hop of each route on STACKIT: an internet gateway becomes the next hop internet, an appliance (a network interface or an instance) a next hop of type ipv4. A NAT gateway, a transit gateway or a VPC peering has no STACKIT counterpart, so the connectivity design is the person's.
  - `tcr-route-table-vpc-id`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). aws_route_table.vpc_id: The VPC whose subnets this route table's rules apply to; a route table's entries only make sense, and only affect reachability, within this one VPC, so losing or mismapping it silently changes which network the routing rules govern. A custom table is REVIEW whatever the estate: the draft's stackit_routing_table is organisation and Network Area scoped (organization_id, network_area_id, pinned provider), not a resource of the project that is the VPC's boundary (the experimental stackit_vpc_routing_table, pinned provider: project_id, vpc_id, is a VPC-scoped table that the draft does not write and that nothing establishes as the counterpart of an AWS route table), so which networks the table governs is decided by the Network Area the person puts the project in and the routing_table_id each network is given. A table the draft does not make (count or for_each) and one left to the architect are REVIEW. Several VPCs, a VPC count that is not visible, or a vpc_id (this table's or another unit's) that is a literal, a variable, a data source or an expression the scan cannot reduce to the estate's VPC: which routing domain the table belongs to is the architect's decision — REVIEW. Held CRITICAL: it decides which networks, clients or endpoints reach the resource or what it reaches. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded. A person decides which STACKIT networks the routing table governs: the draft's custom table is organisation and Network Area scoped, so the Network Area the project joins and the routing table each network is given decide it.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this route table included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
- **Evidence** (validated against terraform-provider-stackit@0.116.0 (stackit_routing_table requires experiment routing-tables; stackit_network no_ipv4_gateway; stackit_routing_table_route destination cidrv4 only); terraform-provider-stackit@0.120.0 (re-checked 2026-10-18 against STACKIT provider schema 0.120.0 and the v0.120.0 tag docs: stackit_routing_table still part of the experimental feature routing-tables, stackit_routing_table_route destination (Only `cidrv4` is supported during experimental stage), stackit_network no_ipv4_gateway (the network does not have a gateway when true); schemas of the two routing resources unchanged, pages routing_table and routing_table_route re-read); terraform-provider-aws@6.66.0 route_table docs 2026-09-28; rt-route-set-route-server / rt-route-set-unmodelled-source (2026-10-08): terraform-provider-aws@6.66.0 vpc_route_server_propagation, vpc_route_server, fsx_ontap_file_system and fsx_openzfs_file_system docs (local provider-docs mirror), terraform-provider-stackit@0.118.0 schema (stackit_routing_table.dynamic_routes); rt-route-set-route-list-unread / rt-route-set-gated-propagation / rt-route-set-maybe-member (2026-10-08): terraform-provider-aws@6.66.0 route_table docs lines 120-123, vpn_gateway_route_propagation docs lines 11 and 31-32, route docs line 53, route_table_association docs line 37 (local provider-docs mirror), Terraform dynamic blocks and count documentation; rt-route-set-maybe-member narrowed to route-adding resources and rt-association-table-undecided added (KB-ROUTE-SET-3, 2026-10-08): route_table_association docs line 37, main_route_table_association docs line 31 (local provider-docs mirror), EC2 API AssociateRouteTable (docs.aws.amazon.com/AWSEC2/latest/APIReference/API_AssociateRouteTable.html read 2026-10-08: associates a subnet, internet gateway or virtual private gateway with a route table; no route parameter); rt-default-only, rt-default-only-nat, rt-default-only-area (2026-10-10): the test of 2026-10-10 (a STACKIT project in eu01, outside a Network Area), the area's default routing table unobserved (403); rt-default-only-open worded for an internet gateway created only when a plan runs (L2, 2026-10-27; wording only: the class and the case are unchanged; the cause is the reference not being exact, the knowledge-base input node.ref_exact, a target whose presence is not known is not pinned); rt-default-only-open narrowed (N2-2, 2026-10-27): a NAT gateway picked by an index is the NAT case, a plainly stated Gateway endpoint of S3 or DynamoDB does not hold the table (docs.stackit.cloud Virtual Network concepts, Last updated Mar 11, 2026, mirror virtual-network/basics/concepts.txt:144; the STACKIT professional-services example of Velero backups on SKE addresses Object Storage as https://object.storage.<region>.onstackit.cloud; terraform-provider-stackit@0.120.0 STACKIT provider schema 0.120.0: 115 resources, none a private endpoint, PrivateLink or VPC endpoint, no such attribute on any; stackit_objectstorage_bucket exposes url_path_style and url_virtual_hosted_style; terraform-provider-aws@6.66.0 vpc_endpoint docs line 184 route_table_ids "Applicable for endpoints of type Gateway", line 193 vpc_endpoint_type defaults to Gateway); rt-local-only-closed and rt-default-only-open for a Gateway endpoint whose service name a plan decides (2026-10-31): AWS PrivateLink concepts (docs.aws.amazon.com/vpc/latest/privatelink/concepts.html, read 2026-10-31: the endpoint type Gateway "creates a gateway endpoint to send traffic to Amazon S3 or DynamoDB") and Gateway endpoints page (docs.aws.amazon.com/vpc/latest/privatelink/gateway-endpoints.html, the same day: "Gateway VPC endpoints provide reliable connectivity to Amazon S3 and DynamoDB"; the added route has the service's prefix list as destination and the endpoint as target), terraform-provider-aws@6.66.0 vpc_endpoint docs (route_table_ids "Applicable for endpoints of type Gateway", vpc_endpoint_type defaults to Gateway), the rest of the evidence of rt-default-only-open N2-2; rt-local-only-closed (2026-10-27): docs.stackit.cloud Virtual Network concepts (Last updated Mar 11, 2026, mirror virtual-network/basics/concepts.txt:144: "Every subnet is routed to the public internet"), network-area FAQ (mirror network-area/faq.txt:146-147: disabling the internet access of a project is not supported), routing-tables page (public preview), terraform-provider-aws@6.66.0 route_table docs line 152 (the VPC-CIDR local route is created implicitly); the AWS VPC User Guide pages are cited by URL, they are not in the local mirror; rt-local-only worded for what makes it a review and what closes it (L4, 2026-10-27; wording only: the class, the confidence and the case are unchanged): terraform-provider-aws@6.66.0 main_route_table_association docs (the AWS provider documentation of main_route_table_association: the resource sets the main route table of a VPC, vpc_id and route_table_id arguments), the case rt-local-only-closed above and its evidence (Virtual Network concepts, network-area FAQ: no network setting is documented as a control of outbound access, so the earlier text offering the gateway setting as one is removed); rt-default-only-open narrowed (#320, 2026-10-28): an internet gateway created only when a plan runs that the route names by a literal key is the internet case (OpenTofu v1.13.1, local probe tested on a STACKIT project on 2026-10-28 a plan that creates the route without the named instance fails, Invalid index, exit 1; terraform-provider-aws@6.66.0 route docs line 61, local provider-docs mirror: one target argument must be supplied); read 2026-10-28: the Routing tables page (last updated 2026-04-14: one default routing table per Network Area, created automatically, not deletable, followed by every routed network unless another is assigned; the feature is a public preview) and the Network Area FAQ (2025-12-12: the internet access of a project cannot be disabled); the IaaS v2 API specification (stackit-api-specifications checkout of 2026-10-13): the routing-table endpoints (iaas.network-area.rt.list, rt.get, rt.route.list) are scoped to the organisation (resource-type organization) while the project endpoints (iaas.project.get) return the area ID of a project and no routing table; STACKIT provider schema 0.120.0: the data sources stackit_routing_table, stackit_routing_tables and stackit_routing_table_routes require organization_id and network_area_id (stackit_routing_table also routing_table_id), stackit_network exposes routing_table_id; the role that carries the routing-table actions is not named on the roles page and the next hop of 0.0.0.0/0 in the default table is not documented anywhere read, so the question stays open; found compatible through 0.121.0 by the release check): https://github.com/stackitcloud/terraform-provider-stackit/blob/v0.120.0/docs/resources/routing_table.md · https://github.com/stackitcloud/terraform-provider-stackit/blob/v0.120.0/docs/resources/routing_table_route.md · tested on a STACKIT project on 2026-10-10 · https://registry.terraform.io/providers/hashicorp/aws/6.66.0/docs/resources/route_table · https://raw.githubusercontent.com/hashicorp/terraform-provider-aws/v6.66.0/website/docs/r/route_table.html.markdown · https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-route.html · https://registry.terraform.io/providers/hashicorp/aws/6.66.0/docs/resources/route_table_association · https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-gatewayroutetableassociation.html · https://docs.aws.amazon.com/vpc/latest/userguide/subnet-route-tables.html · https://docs.stackit.cloud/products/network/core-networking/network-area/basics/routing-tables/ · https://docs.stackit.cloud/products/network/core-networking/virtual-network/basics/concepts/ · https://github.com/stackitcloud/stackit-api-specifications/blob/main/services/iaas/v2/iaas.json · https://github.com/stackitcloud/terraform-provider-stackit/blob/v0.120.0/docs/data-sources/routing_table.md · https://docs.stackit.cloud/products/network/core-networking/basics/architecture/ · https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html · https://github.com/stackitcloud/professional-service/blob/main/examples/vpn-full-tunnel-central-egress/README.md

#### `module.vpc.module.vpc.aws_subnet.private`

- **Source:** `aws_subnet` — .terraform/modules/vpc.vpc/main.tf:267 · instances: 0–3 instances (decided by `module.vpc.data.aws_availability_zones.available`); POSSIBLE_SOURCE_ERROR: `slice(…, 3)` fails in Terraform and OpenTofu when the list has fewer than 3 elements (the source proves none), so the count is not exact
- **Standing:** conditional — whether it exists is decided only when a plan runs; the class below is the one it would get, it is not counted in the totals and not automation-eligible (gate blocker `TOPOLOGY:unknown`).
- **Module:** `module.vpc.module.vpc` (terraform-aws-modules/vpc/aws 5.21.0)
- **Candidate target:** STACKIT network (`stackit_network`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.subnet/subnet`
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, check subnet-egress-ipv4-unproven, semantic subnet-vpc-membership, semantic network-topology-boundary and 3 more); a point the scan could not establish
- **Why:** A subnet becomes a stackit_network with the same IPv4 prefix. Public vs private is not a subnet property on STACKIT: servers get public IPs explicitly, and a network can be created without a default gateway.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 0 manual actions
  - decision `DEC-GEN-CONVERT-WORKLOAD-PLACEMENT` (alias `convert:module.vpc.module.vpc.aws_subnet.private:network:WORKLOAD_PLACEMENT`): Decide where the source consumers of module.vpc.module.vpc.aws_subnet.private are placed on STACKIT: the source places module.dependencies.aws_mq_broker.mq, module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this, module.dependencies.module.catalog_rds.aws_rds_cluster.this, module.dependencies.module.checkout_elasticache_redis.aws_elasticache_replication_group.default, module.dependencies.module.orders_rds.aws_rds_cluster.this, module.retail_app_ecs.module.carts_service.aws_ecs_service.this, module.retail_app_ecs.module.catalog_service.aws_ecs_service.this, module.retail_app_ecs.module.checkout_service.aws_ecs_service.this, module.retail_app_ecs.module.orders_service.aws_ecs_service.this and module.retail_app_ecs.module.ui_service.aws_ecs_service.this in it, and the draft places none of them in stackit_network.vpc_vpc_private (the target networks the draft generates for the subnets of the same VPC: stackit_network.vpc_vpc_private and stackit_network.vpc_vpc_public); the drafted Kubernetes cluster stackit_ske_cluster.retail_app_ecs_cluster of these consumers sets no network.id — option one-network-for-the-cluster-and-services (the cluster and the servers in one network, the managed services reached by access lists naming its range), keep-the-networks-and-place-by-tier, redesign-the-network-placement, or accept-the-consumers-outside-the-network (the network as drafted, holding none of them) · the source splits these workloads over subnets, and STACKIT places them differently: an SKE cluster is deployed into one network (network.id) and its node pools state no network, a managed database, cache or broker takes an access list and no network id; no one-to-one placement of the consumers in stackit_network.vpc_vpc_private follows from the source, so the network's step waits for the decision
- **Depends on:** `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this subnet names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). A unit placed in a subnet that the scan cannot show is one of the estate's (a server, load balancer, function or NAT gateway in a subnet given by a variable, a data source or a literal id) is in the same position: it may stand in another VPC. The draft puts every network, security group and routing table in the one var.project_id and cannot say that they all belong to one VPC. Confirm which VPC each of them is in, and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area. No unit of the VPC topology is automation-eligible until then (gate blocker TOPOLOGY:vpc-unproven).
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (subnet-egress-ipv4-unproven): PRIVATE_EGRESS_EQUIVALENCE_UNPROVEN (IPv4, not proven). The scan cannot say whether this subnet can start an IPv4 connection to the internet: which route table it follows, or what that table's default route goes to, is not proven; or the route table sends 0.0.0.0/0 to an internet gateway but the scan shows no public IPv4 address for what is launched in the subnet - no server in it that has one (a public address asked for or given by the subnet at launch, or an Elastic IP), a server in it that has none, a server whose address or whose subnet is not visible or not resolved, a server with an address in only some of the instances of a repeated subnet, or a workload the reader does not read (a function, a container service, a cluster): "The instances in the public subnet must have public IP addresses or Elastic IP addresses to enable communication with the internet over the internet gateway" (AWS VPC User Guide, Internet gateways, read 2026-10-12). The cause is named below. The stackit_network the draft makes of it (an aws_default_subnet gets none: adopting the account's default subnet is a decision) keeps STACKIT's default gateway, which reaches the internet through source NAT ("Every subnet is routed to the public internet. Technically this is done by source NAT (SNAT) in combination with masquerading.", docs.stackit.cloud Virtual Network concepts, read 2026-10-11), so where the source has no route to the internet the two are not equivalent. The draft sets neither routed nor no_ipv4_gateway (see the subnet's egress finding: what either does to outbound access is not documented). Closing evidence: the route table the subnet follows and its default route - name the association by an exact reference to the table and to the subnet, with a count that is known - and, for a route to an internet gateway, the public IPv4 address of every server in the subnet named by an exact reference (its own switch, an Elastic IP or the subnet's setting at launch) - or an architect's statement of what the source subnet reaches. A subnet that is not proven to reach the internet is never read as one that does. Here: IPv4 egress reading UNKNOWN (table-not-proven (selects-collapsed)); no route table of the configuration is proven for the subnet.
- **Critical semantics left to you to decide or accept (5):** subnet-vpc-membership, network-topology-boundary, private-egress-ipv4, prefix, availability-zone (**not automation-eligible**: no property the unit sets is read by network-topology-boundary, private-egress-ipv4)
  - not read instance by instance (unknown_count: the number of instances is not known statically): `subnet-vpc-membership`, `network-topology-boundary`, `private-egress-ipv4`, `prefix`, `availability-zone`
- **Open choice(s) the draft could not make:** `DEC-GEN-CONVERT-WORKLOAD-PLACEMENT` (alias `convert:module.vpc.module.vpc.aws_subnet.private:network:WORKLOAD_PLACEMENT`) — the source does not prove what it means and the draft holds a required variable without a default; a person decides, and until then the unit is **not automation-eligible**.
- **Property accounting:** 9 of 9 meaningful properties accounted
- **4 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (2; REVIEW 2): `cidr_block`, `vpc_id` — NOT CARRIED (module.vpc.module.vpc.aws_subnet.private): vpc_id — the source VPC is not generated: the network is created in the project (stackit_network also takes a vpc_id of the experimental STACKIT VPC feature, pinned provider — not used by this draft).
  - availability durability (2; REVIEW 2): `availability_zone`, `availability_zone_id` — NOT CARRIED (module.vpc.module.vpc.aws_subnet.private): availability_zone, availability_zone_id — stackit_network has no availability zone (pinned provider): the network serves the region; servers and volumes choose their zone.
- **Why those are open, and what closes them:**
  - `subnet-vpc-membership`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The VPC the subnet belongs to: the draft creates every network in one project, so the source VPC's boundary is kept only when the estate has one VPC and every resource that names a VPC provably names it; the draft states the estate's topology and what the architect decides about it once, at the top of its network file. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this subnet included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `private-egress-ipv4`: A check of the knowledge base (subnet egress ipv4 unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The source and the target are not equivalent for outbound access, and the draft closes nothing: REVIEW. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `prefix`: The value is not visible statically (a case of the mapping rule for this kind of unit), so nothing is credited for it. stackit_network.ipv4_prefix. TRANSFORMED for a CIDR the scan has seen. The draft carries the prefix as stackit_network.ipv4_prefix taken from a variable without a default (pinned provider: "The IPv4 prefix of the network (CIDR)") and says in the variable's description that the source CIDR is not visible; decide the CIDR each STACKIT network gets (the source CIDRs are reused unless the address plan changes) and enter it before plan. Closes when: A literal value or a resolved reference in the source closes it, or a person confirms the value.
  - `availability-zone`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The availability zone of the subnet. STACKIT networks are regional (stackit_network has no zone field, pinned provider); the zone is chosen per server and volume, and AWS zone names do not map to STACKIT zones. Closes when: A person decides, per source zone, which STACKIT zone (eu01-1, eu01-2 or eu01-3) takes the servers and volumes that sat in it, so that the source's spread and its failure domains are kept.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; terraform-provider-stackit@0.120.0 (re-checked 2026-10-18 against STACKIT provider schema 0.120.0 and the v0.120.0 tag docs: stackit_network re-read, stackit_network attributes unchanged from 0.116.0 (its block description lost the transitional ipv4_nameservers behaviour warning; the attribute description keeps the behaviour); no destroy-protection, DNS64, hostname or per-server record attribute in stackit_network or stackit_server (both unchanged); stackit_public_ip and stackit_dns_record_set unchanged); found compatible through 0.121.0 by the release check): https://github.com/stackitcloud/terraform-provider-stackit/blob/v0.120.0/docs/resources/network.md

#### `module.vpc.module.vpc.aws_subnet.public`

- **Source:** `aws_subnet` — .terraform/modules/vpc.vpc/main.tf:131 · instances: 0–3 instances (decided by `module.vpc.data.aws_availability_zones.available`); POSSIBLE_SOURCE_ERROR: `slice(…, 3)` fails in Terraform and OpenTofu when the list has fewer than 3 elements (the source proves none), so the count is not exact
- **Standing:** conditional — whether it exists is decided only when a plan runs; the class below is the one it would get, it is not counted in the totals and not automation-eligible (gate blocker `TOPOLOGY:unknown`).
- **Module:** `module.vpc.module.vpc` (terraform-aws-modules/vpc/aws 5.21.0)
- **Candidate target:** STACKIT network (`stackit_network`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.subnet/subnet`
- **Feasibility:** CONDITIONAL — blocked by network reachability, restrictions or public exposure (check topology-vpc-unproven, check subnet-route-table-undecided, check subnet-egress-ipv4-unproven, semantic subnet-vpc-membership and 5 more); a point the scan could not establish
- **Why:** A subnet becomes a stackit_network with the same IPv4 prefix. Public vs private is not a subnet property on STACKIT: servers get public IPs explicitly, and a network can be created without a default gateway.
- **Depends on:** `module.vpc.module.vpc.aws_vpc.this`
- **WARNING** (topology-vpc-unproven): The project can be taken as one VPC's boundary only if every resource that names a VPC provably names the estate's one, and this estate does not show it: the VPC this subnet names, or the VPC another resource of the estate names (a network ACL, a flow log, a peering connection, a Cloud Control subnet, ...), is a literal id, a variable, a data source, an attribute of a VPC other than its id (its arn, its owner id, ...) or an expression the scan cannot reduce to one reference to the VPC the estate creates (or the estate creates no VPC of its own). A unit placed in a subnet that the scan cannot show is one of the estate's (a server, load balancer, function or NAT gateway in a subnet given by a variable, a data source or a literal id) is in the same position: it may stand in another VPC. The draft puts every network, security group and routing table in the one var.project_id and cannot say that they all belong to one VPC. Confirm which VPC each of them is in, and whether the networks of another VPC belong in this project or in a project of their own joined through a Network Area. No unit of the VPC topology is automation-eligible until then (gate blocker TOPOLOGY:vpc-unproven).
- **WARNING** (subnet-route-table-undecided): The scan cannot say which route table this subnet follows: a route table association may name it through a value the scan cannot resolve (a variable, a literal ID, a conditional, a value from a module call), an association names only some of its instances or repeats by a count or for_each that is not the subnet's own (aws_subnet.x[0].id for a counted subnet, fewer association instances than subnet instances), an association may create no instance (a count or for_each that a variable decides, count = var.on ? 1 : 0, whatever the variable's default: the subnet then follows the main route table), the VPC of the subnet or its main route table is not decided (count or for_each, two resources that set the main table, a main association and an aws_default_route_table on one VPC, a table or VPC outside the configuration). node.subnet_routing carries the cause. Which table the subnet follows, and so what its routing and exposure are, is not decided here; the draft attaches no routing table to its network.
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **WARNING** (subnet-egress-ipv4-unproven): PRIVATE_EGRESS_EQUIVALENCE_UNPROVEN (IPv4, not proven). The scan cannot say whether this subnet can start an IPv4 connection to the internet: which route table it follows, or what that table's default route goes to, is not proven; or the route table sends 0.0.0.0/0 to an internet gateway but the scan shows no public IPv4 address for what is launched in the subnet - no server in it that has one (a public address asked for or given by the subnet at launch, or an Elastic IP), a server in it that has none, a server whose address or whose subnet is not visible or not resolved, a server with an address in only some of the instances of a repeated subnet, or a workload the reader does not read (a function, a container service, a cluster): "The instances in the public subnet must have public IP addresses or Elastic IP addresses to enable communication with the internet over the internet gateway" (AWS VPC User Guide, Internet gateways, read 2026-10-12). The cause is named below. The stackit_network the draft makes of it (an aws_default_subnet gets none: adopting the account's default subnet is a decision) keeps STACKIT's default gateway, which reaches the internet through source NAT ("Every subnet is routed to the public internet. Technically this is done by source NAT (SNAT) in combination with masquerading.", docs.stackit.cloud Virtual Network concepts, read 2026-10-11), so where the source has no route to the internet the two are not equivalent. The draft sets neither routed nor no_ipv4_gateway (see the subnet's egress finding: what either does to outbound access is not documented). Closing evidence: the route table the subnet follows and its default route - name the association by an exact reference to the table and to the subnet, with a count that is known - and, for a route to an internet gateway, the public IPv4 address of every server in the subnet named by an exact reference (its own switch, an Elastic IP or the subnet's setting at launch) - or an architect's statement of what the source subnet reaches. A subnet that is not proven to reach the internet is never read as one that does. Here: IPv4 egress reading UNKNOWN (the route table association module.vpc.module.vpc.aws_route_table_association.public names the subnet module.vpc.module.vpc.aws_subnet.public but the scan cannot show that it names every instance of it (a value that is not exactly one reference to it, an index that picks some instances, a count or for_each that is not the subnet's own), so which table it follows is not decided here); no route table of the configuration is proven for the subnet.
- **Critical semantics left to you to decide or accept (6):** subnet-vpc-membership, network-topology-boundary, effective-route-table, private-egress-ipv4, prefix, availability-zone (**not automation-eligible**: no property the unit sets is read by effective-route-table, network-topology-boundary, private-egress-ipv4)
  - not read instance by instance (unknown_count: the number of instances is not known statically): `subnet-vpc-membership`, `network-topology-boundary`, `effective-route-table`, `private-egress-ipv4`, `prefix`, `availability-zone`
- **Property accounting:** 10 of 10 meaningful properties accounted
- **4 critical setting(s) left to you** — **not automation-eligible**:
  - network exposure (2; REVIEW 2): `cidr_block`, `vpc_id` — NOT CARRIED (module.vpc.module.vpc.aws_subnet.public): vpc_id — the source VPC is not generated: the network is created in the project (stackit_network also takes a vpc_id of the experimental STACKIT VPC feature, pinned provider — not used by this draft).
  - availability durability (2; REVIEW 2): `availability_zone`, `availability_zone_id` — NOT CARRIED (module.vpc.module.vpc.aws_subnet.public): availability_zone, availability_zone_id — stackit_network has no availability zone (pinned provider): the network serves the region; servers and volumes choose their zone.
- **Why those are open, and what closes them:**
  - `subnet-vpc-membership`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The VPC the subnet belongs to: the draft creates every network in one project, so the source VPC's boundary is kept only when the estate has one VPC and every resource that names a VPC provably names it; the draft states the estate's topology and what the architect decides about it once, at the top of its network file. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `network-topology-boundary`: A check of the knowledge base (topology vpc unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). Several VPCs, a VPC count that is not visible, or a unit of the estate that names a VPC, or is placed in a subnet, the scan cannot prove is the estate's, leave the architecture to the architect for every unit of the topology, this subnet included: STACKIT has no VPC container in its stable model, the project is the boundary of its networks, so the draft cannot keep several VPCs apart in one project. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `effective-route-table`: A check of the knowledge base (subnet route table undecided) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The subnet follows the VPC's main route table when no association names a route table. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded. A person decides which routes the subnet's network gets: the draft attaches no routing table to the network, and a STACKIT network gets a default gateway unless it is told not to, so what the subnet reaches can differ from AWS.
  - `private-egress-ipv4`: A check of the knowledge base (subnet egress ipv4 unproven) fired on this unit and leaves the setting to a person: the target does not settle it by itself (a finding of this unit describes it). The source and the target are not equivalent for outbound access, and the draft closes nothing: REVIEW. Closes when: A person decides it as that finding asks, and the finding's closing evidence or decision is recorded.
  - `prefix`: The value is not visible statically (a case of the mapping rule for this kind of unit), so nothing is credited for it. stackit_network.ipv4_prefix. TRANSFORMED for a CIDR the scan has seen. The draft carries the prefix as stackit_network.ipv4_prefix taken from a variable without a default (pinned provider: "The IPv4 prefix of the network (CIDR)") and says in the variable's description that the source CIDR is not visible; decide the CIDR each STACKIT network gets (the source CIDRs are reused unless the address plan changes) and enter it before plan. Closes when: A literal value or a resolved reference in the source closes it, or a person confirms the value.
  - `availability-zone`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. The availability zone of the subnet. STACKIT networks are regional (stackit_network has no zone field, pinned provider); the zone is chosen per server and volume, and AWS zone names do not map to STACKIT zones. Closes when: A person decides, per source zone, which STACKIT zone (eu01-1, eu01-2 or eu01-3) takes the servers and volumes that sat in it, so that the source's spread and its failure domains are kept.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; terraform-provider-stackit@0.120.0 (re-checked 2026-10-18 against STACKIT provider schema 0.120.0 and the v0.120.0 tag docs: stackit_network re-read, stackit_network attributes unchanged from 0.116.0 (its block description lost the transitional ipv4_nameservers behaviour warning; the attribute description keeps the behaviour); no destroy-protection, DNS64, hostname or per-server record attribute in stackit_network or stackit_server (both unchanged); stackit_public_ip and stackit_dns_record_set unchanged); found compatible through 0.121.0 by the release check): https://github.com/stackitcloud/terraform-provider-stackit/blob/v0.120.0/docs/resources/network.md

### Observability

#### `module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`

- **Source:** `aws_cloudwatch_log_group` — ../../lib/ecs/cluster.tf:10
- **Module:** `module.retail_app_ecs` (../../lib/ecs)
- **Candidate target:** STACKIT Logs (`stackit_logs_instance`, `stackit_logs_access_token`)
- **Target maturity:** GA · lifecycle active · region availability not established by a catalogue snapshot
- **Classification:** RECONFIGURE · **Confidence:** MEDIUM · rule `aws.cloudwatch_log_group/log-group`
- **Feasibility:** CONDITIONAL — blocked by a feature the draft does not carry yet (semantic tc-name); a point the scan could not establish
- **Why:** Log groups become label sets in a STACKIT Logs instance (a label-based Grafana Loki store written over OTLP or the Loki API, retention in days for the whole instance). STACKIT has no log group or stream object: a group's name survives only as a label the shipper sends. Agents switch from the CloudWatch agent to a documented shipper (Grafana Alloy, OpenTelemetry Collector, Vector or Fluent Bit); log groups that keep their logs for the same number of days share one instance.
- **Deployment prerequisites:** passed StackToIT's own draft checks; tofu validate: PASSED; NOT deployment-ready: 1 open decisions, 3 manual actions
  - decision `DEC-OPS-STACKITLOGS-RETENTION-OVER-180-DAYS` (alias `stackitlogs:module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks:retention_over_180_days`): Decide whether the logs of module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks older than 180 days are kept in an archive outside the Logs instance · the source keeps its logs for ever and a STACKIT Logs instance keeps at most 180 days, so the instance drafted for it (stackit_logs_instance.logs_retention_180d) holds only the last 180 days; logs older than that exist only if a person configures an archive beside it. Choose the archive if the workload needs them; reject it if the requirement is that more than 180 days stay inside STACKIT Logs with no external archive, which STACKIT Logs alone cannot meet
  - manual action `DEC-OPS-STACKITLOGS-ACTION-ARCHIVE-FLOW` (alias `stackitlogs:archive:module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`) (archive flow, before the cutover): Configure a cold-storage log flow for module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks: send a copy of its logs, in parallel to the Logs instance stackit_logs_instance.logs_retention_180d, to a long-term store (for example a separate Object Storage bucket) that keeps them for the retention beyond 180 days — the source keeps its logs for ever and a STACKIT Logs instance keeps at most 180 days (retention beyond 180 days is not supported by the managed service): the first 180 days are kept in the Logs instance, and the longer retention is an archive outside it, which STACKIT recommends as a cold-storage approach (a stream of the log data to a low-cost long-term store in parallel to Logs). The plan creates no archive store, configures no stream and sets no retention of the archive. The step exists only when the decision about the logs beyond 180 days chooses the archive; where the requirement is more than 180 days inside STACKIT Logs with no external archive, the archive is rejected and the migration cannot meet that requirement with STACKIT Logs alone
  - manual action `DEC-OPS-STACKITLOGS-ACTION-LABEL-CONVENTION` (alias `stackitlogs:label-convention:module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`) (label convention, before the cutover): Choose a static label and send the name of module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks (and of its streams) from its log producers as the value of that label — STACKIT Logs has no log group or stream object that can hold a name, only labels the shipper sends (no-log-group-or-stream-object); the plan chooses no label key and reconfigures no producer
  - manual action `DEC-OPS-STACKITLOGS-ACTION-TARGET-PRECONDITION` (alias `stackitlogs:token:stackit_logs_instance.logs_retention_180d`) (target precondition, before the cutover): Before any log source writes to stackit_logs_instance.logs_retention_180d: create a write access token for the instance (stackit_logs_access_token with the permission write), set the access control list of the instance, and point the shipper at the instance's ingest_url (Loki API) or ingest_otlp_url (OpenTelemetry) — the plan generates no access token: the token is a credential written to the state, its lifetime (unset, it never expires) and its permissions are choices the source does not state, and one token belongs to one instance; what an instance with no ACL entry allows is not established, so the plan sets no ACL and states no default
- **WARNING** (source-provider-unpinned): No lock file entry pins aws (>= 3.0, >= 3.29, >= 4.18, >= 4.30, >= 4.59, >= 5.64, >= 5.79, ~> 5.0): the version the plan would use is not proven, so the knowledge base (checked against 5.100.0) is not taken as proof of it (stated once for the whole estate, with the units it covers and the rest of the words)
- **Critical semantics left to you to decide or accept (1):** tc-name
- **Open plan decision(s):** `DEC-OPS-STACKITLOGS-RETENTION-OVER-180-DAYS` (alias `stackitlogs:module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks:retention_over_180_days`) — a person decides, and until then the unit is **not automation-eligible**.
- **Manual action(s) required before apply:** `DEC-OPS-STACKITLOGS-ACTION-ARCHIVE-FLOW` (alias `stackitlogs:archive:module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`), `DEC-OPS-STACKITLOGS-ACTION-LABEL-CONVENTION` (alias `stackitlogs:label-convention:module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`), `DEC-OPS-STACKITLOGS-ACTION-TARGET-PRECONDITION` (alias `stackitlogs:token:stackit_logs_instance.logs_retention_180d`) — a person does them, and until then the unit is **not automation-eligible**.
- **Property accounting:** 1 of 1 meaningful properties accounted
- **1 critical setting(s) left to you** — **not automation-eligible**:
  - workload compatibility (1; REVIEW 1): `name` — plan: stackit_logs_instance.logs_retention_180d name of module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks MANUAL_ACTION (`DEC-OPS-STACKITLOGS-ACTION-LABEL-CONVENTION` (alias `stackitlogs:label-convention:module.retail_app_ecs.aws_cloudwatch_log_group.ecs_tasks`)) (contract aws.cloudwatch_log_group/tc-name:REVIEW)
- **Why those are open, and what closes them:**
  - `tc-name`: The mapping rule for this kind of unit recognises the unit but only passes this setting to a person; it does not decide its value. aws_cloudwatch_log_group.name is the address a log producer writes to (awslogs-group, PutLogEvents logGroupName). The name is therefore not carried by anything the draft generates, and no producer is rewired: a person decides the label convention and reconfigures each producer - REVIEW (the plan holds it as a label convention manual action). Held CRITICAL: the workload, its clients or its neighbours rely on it (an address, a name, a protocol or an execution contract). Closes when: A person decides the label convention under which the log group name survives in STACKIT Logs and reconfigures each producer to send it; the draft configures no shipper.
- **Evidence** (validated against terraform-provider-stackit@0.116.0; found compatible through 0.121.0 by the release check): https://docs.stackit.cloud/products/logging-and-monitoring/observability/ · https://registry.terraform.io/providers/stackitcloud/stackit/0.116.0/docs/resources/logs_instance · https://docs.stackit.cloud/products/logging-and-monitoring/logs/ · https://docs.stackit.cloud/products/logging-and-monitoring/logs/basics/core-features-and-use-cases-of-logs/ · https://docs.stackit.cloud/products/logging-and-monitoring/logs/faq/ · https://github.com/stackitcloud/stackit-api-specifications/blob/main/services/logs/v1/logs.json

## Support resources — critical settings left to a person

The draft creates nothing for these resources; the units that use them are drafted without them. Every critical setting they state is listed so that it is decided on the target, not lost.

| Support resource | Type | Critical settings |
|---|---|---|
| `module.dependencies.aws_iam_policy.carts_dynamo` | aws_iam_policy | `module.dependencies.aws_iam_policy.carts_dynamo.path` (CRITICAL/OPEN:not-applicable), `module.dependencies.aws_iam_policy.carts_dynamo.policy` (CRITICAL/CLOSED:REVIEW) |
| `module.dependencies.module.catalog_rds.aws_db_subnet_group.this` | aws_db_subnet_group | `module.dependencies.module.catalog_rds.aws_db_subnet_group.this.subnet_ids` (CRITICAL/CLOSED:REVIEW) |
| `module.dependencies.module.checkout_elasticache_redis.aws_elasticache_subnet_group.default` | aws_elasticache_subnet_group | `module.dependencies.module.checkout_elasticache_redis.aws_elasticache_subnet_group.default.subnet_ids` (CRITICAL/CLOSED:REVIEW) |
| `module.dependencies.module.orders_rds.aws_db_subnet_group.this` | aws_db_subnet_group | `module.dependencies.module.orders_rds.aws_db_subnet_group.this.subnet_ids` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.aws_iam_policy.catalog_policy` | aws_iam_policy | `module.retail_app_ecs.aws_iam_policy.catalog_policy.path` (CRITICAL/OPEN:not-applicable), `module.retail_app_ecs.aws_iam_policy.catalog_policy.policy` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.aws_iam_policy.orders_policy` | aws_iam_policy | `module.retail_app_ecs.aws_iam_policy.orders_policy.path` (CRITICAL/OPEN:not-applicable), `module.retail_app_ecs.aws_iam_policy.orders_policy.policy` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.aws_service_discovery_private_dns_namespace.this` | aws_service_discovery_private_dns_namespace | `module.retail_app_ecs.aws_service_discovery_private_dns_namespace.this.name` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.aws_service_discovery_private_dns_namespace.this.vpc` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.module.alb.aws_lb_target_group.main` | aws_lb_target_group | `module.retail_app_ecs.module.alb.aws_lb_target_group.main.deregistration_delay` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.module.alb.aws_lb_target_group.main.health_check.enabled` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.module.alb.aws_lb_target_group.main.health_check.healthy_threshold` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.module.alb.aws_lb_target_group.main.health_check.interval` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.module.alb.aws_lb_target_group.main.health_check.path` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.module.alb.aws_lb_target_group.main.health_check.port` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.module.alb.aws_lb_target_group.main.health_check.protocol` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.module.alb.aws_lb_target_group.main.health_check.timeout` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.module.alb.aws_lb_target_group.main.health_check.unhealthy_threshold` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.module.alb.aws_lb_target_group.main.port` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.module.alb.aws_lb_target_group.main.protocol` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.module.alb.aws_lb_target_group.main.proxy_protocol_v2` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.module.alb.aws_lb_target_group.main.target_type` (CRITICAL/CLOSED:REVIEW), `module.retail_app_ecs.module.alb.aws_lb_target_group.main.vpc_id` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.module.carts_service.aws_iam_policy.cloudwatch_logs` | aws_iam_policy | `module.retail_app_ecs.module.carts_service.aws_iam_policy.cloudwatch_logs.policy` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.module.carts_service.aws_iam_policy.ecs_exec` | aws_iam_policy | `module.retail_app_ecs.module.carts_service.aws_iam_policy.ecs_exec.path` (CRITICAL/OPEN:not-applicable), `module.retail_app_ecs.module.carts_service.aws_iam_policy.ecs_exec.policy` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.module.catalog_service.aws_iam_policy.cloudwatch_logs` | aws_iam_policy | `module.retail_app_ecs.module.catalog_service.aws_iam_policy.cloudwatch_logs.policy` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.module.catalog_service.aws_iam_policy.ecs_exec` | aws_iam_policy | `module.retail_app_ecs.module.catalog_service.aws_iam_policy.ecs_exec.path` (CRITICAL/OPEN:not-applicable), `module.retail_app_ecs.module.catalog_service.aws_iam_policy.ecs_exec.policy` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.module.checkout_service.aws_iam_policy.cloudwatch_logs` | aws_iam_policy | `module.retail_app_ecs.module.checkout_service.aws_iam_policy.cloudwatch_logs.policy` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.module.checkout_service.aws_iam_policy.ecs_exec` | aws_iam_policy | `module.retail_app_ecs.module.checkout_service.aws_iam_policy.ecs_exec.path` (CRITICAL/OPEN:not-applicable), `module.retail_app_ecs.module.checkout_service.aws_iam_policy.ecs_exec.policy` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.module.orders_service.aws_iam_policy.cloudwatch_logs` | aws_iam_policy | `module.retail_app_ecs.module.orders_service.aws_iam_policy.cloudwatch_logs.policy` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.module.orders_service.aws_iam_policy.ecs_exec` | aws_iam_policy | `module.retail_app_ecs.module.orders_service.aws_iam_policy.ecs_exec.path` (CRITICAL/OPEN:not-applicable), `module.retail_app_ecs.module.orders_service.aws_iam_policy.ecs_exec.policy` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.module.ui_service.aws_iam_policy.cloudwatch_logs` | aws_iam_policy | `module.retail_app_ecs.module.ui_service.aws_iam_policy.cloudwatch_logs.policy` (CRITICAL/CLOSED:REVIEW) |
| `module.retail_app_ecs.module.ui_service.aws_iam_policy.ecs_exec` | aws_iam_policy | `module.retail_app_ecs.module.ui_service.aws_iam_policy.ecs_exec.path` (CRITICAL/OPEN:not-applicable), `module.retail_app_ecs.module.ui_service.aws_iam_policy.ecs_exec.policy` (CRITICAL/CLOSED:REVIEW) |

## Disabled by configuration

These resources exist in code but produce no instances with the current variable values (count/for_each = 0). They are not counted above.

- `module.dependencies.module.catalog_opensearch.aws_cloudwatch_log_group.this` (.terraform/modules/dependencies.catalog_opensearch/main.tf:405) — switched off by for_each = 0
- `module.dependencies.module.catalog_opensearch.aws_cloudwatch_log_resource_policy.this` (.terraform/modules/dependencies.catalog_opensearch/main.tf:450) — switched off by count = 0
- `module.dependencies.module.catalog_opensearch.aws_security_group.this` (.terraform/modules/dependencies.catalog_opensearch/main.tf:472) — switched off by count = 0
- `module.dependencies.module.catalog_rds.aws_cloudwatch_log_group.this` (.terraform/modules/dependencies.catalog_rds/main.tf:445) — switched off by for_each = 0
- `module.dependencies.module.catalog_rds.aws_iam_role.rds_enhanced_monitoring` (.terraform/modules/dependencies.catalog_rds/main.tf:255) — switched off by count = 0
- `module.dependencies.module.checkout_elasticache_redis.aws_cloudwatch_metric_alarm.cache_cpu` (.terraform/modules/dependencies.checkout_elasticache_redis/main.tf:169) — switched off by count = 0
- `module.dependencies.module.checkout_elasticache_redis.aws_cloudwatch_metric_alarm.cache_memory` (.terraform/modules/dependencies.checkout_elasticache_redis/main.tf:193) — switched off by count = 0
- `module.dependencies.module.checkout_elasticache_redis.module.aws_security_group.aws_security_group.default` (.terraform/modules/dependencies.checkout_elasticache_redis.aws_security_group/main.tf:24) — switched off by count = 0
- `module.dependencies.module.checkout_elasticache_redis.module.dns.aws_route53_record.default` (.terraform/modules/dependencies.checkout_elasticache_redis.dns/main.tf:1) — switched off by count = 0
- `module.dependencies.module.dynamodb_carts.aws_dynamodb_table.autoscaled` (.terraform/modules/dependencies.dynamodb_carts/main.tf:88) — switched off by count = 0
- `module.dependencies.module.dynamodb_carts.aws_dynamodb_table.autoscaled_gsi_ignore` (.terraform/modules/dependencies.dynamodb_carts/main.tf:179) — switched off by count = 0
- `module.dependencies.module.orders_rds.aws_cloudwatch_log_group.this` (.terraform/modules/dependencies.orders_rds/main.tf:445) — switched off by for_each = 0
- `module.dependencies.module.orders_rds.aws_iam_role.rds_enhanced_monitoring` (.terraform/modules/dependencies.orders_rds/main.tf:255) — switched off by count = 0
- `module.retail_app_ecs.module.alb.aws_lambda_permission.lb` (.terraform/modules/retail_app_ecs.alb/main.tf:155) — switched off by for_each = 0
- `module.retail_app_ecs.module.alb.aws_wafv2_web_acl_association.this` (.terraform/modules/retail_app_ecs.alb/main.tf:845) — switched off by count = 0
- `module.retail_app_ecs.module.alb_sg.aws_security_group.this` (.terraform/modules/retail_app_ecs.alb_sg/main.tf:13) — switched off by count = 0
- `module.vpc.module.vpc.aws_cloudwatch_log_group.flow_log` (.terraform/modules/vpc.vpc/vpc-flow-logs.tf:65) — switched off by count = 0
- `module.vpc.module.vpc.aws_default_vpc.this` (.terraform/modules/vpc.vpc/main.tf:1252) — switched off by count = 0
- `module.vpc.module.vpc.aws_flow_log.this` (.terraform/modules/vpc.vpc/vpc-flow-logs.tf:36) — switched off by count = 0
- `module.vpc.module.vpc.aws_iam_role.vpc_flow_log_cloudwatch` (.terraform/modules/vpc.vpc/vpc-flow-logs.tf:77) — switched off by count = 0
- `module.vpc.module.vpc.aws_network_acl.database` (.terraform/modules/vpc.vpc/main.tf:513) — switched off by count = 0
- `module.vpc.module.vpc.aws_network_acl.elasticache` (.terraform/modules/vpc.vpc/main.tf:780) — switched off by count = 0
- `module.vpc.module.vpc.aws_network_acl.intra` (.terraform/modules/vpc.vpc/main.tf:898) — switched off by count = 0
- `module.vpc.module.vpc.aws_network_acl.outpost` (.terraform/modules/vpc.vpc/main.tf:1000) — switched off by count = 0
- `module.vpc.module.vpc.aws_network_acl.private` (.terraform/modules/vpc.vpc/main.tf:331) — switched off by count = 0
- `module.vpc.module.vpc.aws_network_acl.public` (.terraform/modules/vpc.vpc/main.tf:212) — switched off by count = 0
- `module.vpc.module.vpc.aws_network_acl.redshift` (.terraform/modules/vpc.vpc/main.tf:650) — switched off by count = 0
- `module.vpc.module.vpc.aws_route_table.database` (.terraform/modules/vpc.vpc/main.tf:430) — switched off by count = 0
- `module.vpc.module.vpc.aws_route_table.elasticache` (.terraform/modules/vpc.vpc/main.tf:747) — switched off by count = 0
- `module.vpc.module.vpc.aws_route_table.intra` (.terraform/modules/vpc.vpc/main.tf:866) — switched off by count = 0
- `module.vpc.module.vpc.aws_route_table.redshift` (.terraform/modules/vpc.vpc/main.tf:610) — switched off by count = 0
- `module.vpc.module.vpc.aws_subnet.database` (.terraform/modules/vpc.vpc/main.tf:387) — switched off by count = 0
- `module.vpc.module.vpc.aws_subnet.elasticache` (.terraform/modules/vpc.vpc/main.tf:706) — switched off by count = 0
- `module.vpc.module.vpc.aws_subnet.intra` (.terraform/modules/vpc.vpc/main.tf:835) — switched off by count = 0
- `module.vpc.module.vpc.aws_subnet.outpost` (.terraform/modules/vpc.vpc/main.tf:953) — switched off by count = 0
- `module.vpc.module.vpc.aws_subnet.redshift` (.terraform/modules/vpc.vpc/main.tf:569) — switched off by count = 0
- `module.vpc.module.vpc.aws_vpc_block_public_access_exclusion.this` (.terraform/modules/vpc.vpc/main.tf:68) — switched off by for_each = 0
- `module.vpc.module.vpc.aws_vpc_block_public_access_options.this` (.terraform/modules/vpc.vpc/main.tf:62) — switched off by count = 0
- `module.vpc.module.vpc.aws_vpc_dhcp_options.this` (.terraform/modules/vpc.vpc/main.tf:99) — switched off by count = 0
- `module.vpc.module.vpc.aws_vpn_gateway.this` (.terraform/modules/vpc.vpc/main.tf:1188) — switched off by count = 0
- `module.vpc.module.vpc.aws_vpn_gateway_attachment.this` (.terraform/modules/vpc.vpc/main.tf:1202) — switched off by count = 0
- `module.retail_app_ecs.module.carts_service.aws_iam_role_policy_attachment.task_execution_role_additional` (../../lib/ecs/service/iam.tf:25) — switched off by count = 0, a part of `module.retail_app_ecs.module.carts_service.aws_iam_role.task_execution_role`
- `module.retail_app_ecs.module.checkout_service.aws_iam_role_policy_attachment.task_execution_role_additional` (../../lib/ecs/service/iam.tf:25) — switched off by count = 0, a part of `module.retail_app_ecs.module.checkout_service.aws_iam_role.task_execution_role`
- `module.retail_app_ecs.module.ui_service.aws_iam_role_policy_attachment.task_execution_role_additional` (../../lib/ecs/service/iam.tf:25) — switched off by count = 0, a part of `module.retail_app_ecs.module.ui_service.aws_iam_role.task_execution_role`
- `module.vpc.module.vpc.aws_egress_only_internet_gateway.this` (.terraform/modules/vpc.vpc/main.tf:1063) — switched off by count = 0, a part of `module.vpc.module.vpc.aws_vpc.this`
- `module.vpc.module.vpc.aws_vpc_ipv4_cidr_block_association.this` (.terraform/modules/vpc.vpc/main.tf:53) — switched off by count = 0, a part of `module.vpc.module.vpc.aws_vpc.this`
- `module.retail_app_ecs.module.alb.aws_security_group_rule.this` (.terraform/modules/retail_app_ecs.alb/main.tf:826) — switched off by for_each = 0, a part of `module.retail_app_ecs.module.alb.aws_security_group.this`
- `module.retail_app_ecs.module.catalog_service.aws_iam_role_policy_attachment.task_role_additional` (../../lib/ecs/service/iam.tf:110) — switched off by count = 0, a part of `module.retail_app_ecs.module.catalog_service.aws_iam_role.task_role`
- `module.retail_app_ecs.module.orders_service.aws_iam_role_policy_attachment.task_role_additional` (../../lib/ecs/service/iam.tf:110) — switched off by count = 0, a part of `module.retail_app_ecs.module.orders_service.aws_iam_role.task_role`
- `module.retail_app_ecs.module.ui_service.aws_iam_role_policy_attachment.task_role_additional` (../../lib/ecs/service/iam.tf:110) — switched off by count = 0, a part of `module.retail_app_ecs.module.ui_service.aws_iam_role.task_role`
- `module.dependencies.module.catalog_rds.aws_security_group_rule.cidr_ingress` (.terraform/modules/dependencies.catalog_rds/main.tf:351) — switched off by count = 0, a part of `module.dependencies.module.catalog_rds.aws_security_group.this`
- `module.dependencies.module.catalog_rds.aws_security_group_rule.egress` (.terraform/modules/dependencies.catalog_rds/main.tf:364) — switched off by for_each = 0, a part of `module.dependencies.module.catalog_rds.aws_security_group.this`
- `module.dependencies.module.orders_rds.aws_security_group_rule.cidr_ingress` (.terraform/modules/dependencies.orders_rds/main.tf:351) — switched off by count = 0, a part of `module.dependencies.module.orders_rds.aws_security_group.this`
- `module.dependencies.module.orders_rds.aws_security_group_rule.egress` (.terraform/modules/dependencies.orders_rds/main.tf:364) — switched off by for_each = 0, a part of `module.dependencies.module.orders_rds.aws_security_group.this`
- `module.retail_app_ecs.module.alb.aws_lb_listener.frontend_https` (.terraform/modules/retail_app_ecs.alb/main.tf:696) — switched off by count = 0, a part of `module.retail_app_ecs.module.alb.aws_lb.this`
- `module.retail_app_ecs.module.alb.aws_lb_listener_certificate.https_listener` (.terraform/modules/retail_app_ecs.alb/main.tf:791) — switched off by count = 0, a part of `module.retail_app_ecs.module.alb.aws_lb.this`
- `module.retail_app_ecs.module.alb.aws_lb_listener_rule.http_tcp_listener_rule` (.terraform/modules/retail_app_ecs.alb/main.tf:427) — switched off by count = 0, a part of `module.retail_app_ecs.module.alb.aws_lb.this`
- `module.retail_app_ecs.module.alb.aws_lb_listener_rule.https_listener_rule` (.terraform/modules/retail_app_ecs.alb/main.tf:180) — switched off by count = 0, a part of `module.retail_app_ecs.module.alb.aws_lb.this`
- `module.dependencies.module.catalog_opensearch.aws_opensearch_domain_saml_options.this` (.terraform/modules/dependencies.catalog_opensearch/main.tf:330) — switched off by count = 0, a part of `module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this`
- `module.dependencies.module.catalog_opensearch.aws_opensearch_outbound_connection.this` (.terraform/modules/dependencies.catalog_opensearch/main.tf:363) — switched off by for_each = 0, a part of `module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this`
- `module.dependencies.module.catalog_opensearch.aws_opensearch_package_association.this` (.terraform/modules/dependencies.catalog_opensearch/main.tf:239) — switched off by for_each = 0, a part of `module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this`
- `module.dependencies.module.catalog_opensearch.aws_opensearch_vpc_endpoint.this` (.terraform/modules/dependencies.catalog_opensearch/main.tf:250) — switched off by for_each = 0, a part of `module.dependencies.module.catalog_opensearch.aws_opensearch_domain.this`
- `module.dependencies.module.catalog_rds.aws_appautoscaling_policy.this` (.terraform/modules/dependencies.catalog_rds/main.tf:293) — switched off by count = 0, a part of `module.dependencies.module.catalog_rds.aws_rds_cluster.this`
- `module.dependencies.module.catalog_rds.aws_appautoscaling_target.this` (.terraform/modules/dependencies.catalog_rds/main.tf:283) — switched off by count = 0, a part of `module.dependencies.module.catalog_rds.aws_rds_cluster.this`
- `module.dependencies.module.catalog_rds.aws_rds_cluster_endpoint.this` (.terraform/modules/dependencies.catalog_rds/main.tf:213) — switched off by for_each = 0, a part of `module.dependencies.module.catalog_rds.aws_rds_cluster.this`
- `module.dependencies.module.catalog_rds.aws_rds_cluster_role_association.this` (.terraform/modules/dependencies.catalog_rds/main.tf:232) — switched off by for_each = 0, a part of `module.dependencies.module.catalog_rds.aws_rds_cluster.this`
- `module.dependencies.module.orders_rds.aws_appautoscaling_policy.this` (.terraform/modules/dependencies.orders_rds/main.tf:293) — switched off by count = 0, a part of `module.dependencies.module.orders_rds.aws_rds_cluster.this`
- `module.dependencies.module.orders_rds.aws_appautoscaling_target.this` (.terraform/modules/dependencies.orders_rds/main.tf:283) — switched off by count = 0, a part of `module.dependencies.module.orders_rds.aws_rds_cluster.this`
- `module.dependencies.module.orders_rds.aws_rds_cluster_endpoint.this` (.terraform/modules/dependencies.orders_rds/main.tf:213) — switched off by for_each = 0, a part of `module.dependencies.module.orders_rds.aws_rds_cluster.this`
- `module.dependencies.module.orders_rds.aws_rds_cluster_role_association.this` (.terraform/modules/dependencies.orders_rds/main.tf:232) — switched off by for_each = 0, a part of `module.dependencies.module.orders_rds.aws_rds_cluster.this`
- `module.vpc.module.vpc.aws_route.private_dns64_nat_gateway` (.terraform/modules/vpc.vpc/main.tf:1149) — switched off by count = 0, a part of `module.vpc.module.vpc.aws_route_table.private`
- `module.vpc.module.vpc.aws_route.private_ipv6_egress` (.terraform/modules/vpc.vpc/main.tf:1075) — switched off by count = 0, a part of `module.vpc.module.vpc.aws_route_table.private`
- `module.vpc.module.vpc.aws_route_table_association.outpost` (.terraform/modules/vpc.vpc/main.tf:982) — switched off by count = 0, a part of `module.vpc.module.vpc.aws_route_table.private`
- `module.vpc.module.vpc.aws_vpn_gateway_route_propagation.private` (.terraform/modules/vpc.vpc/main.tf:1222) — switched off by count = 0, a part of `module.vpc.module.vpc.aws_route_table.private`
- `module.vpc.module.vpc.aws_route.public_internet_gateway_ipv6` (.terraform/modules/vpc.vpc/main.tf:200) — switched off by count = 0, a part of `module.vpc.module.vpc.aws_route_table.public`
- `module.vpc.module.vpc.aws_vpn_gateway_route_propagation.public` (.terraform/modules/vpc.vpc/main.tf:1209) — switched off by count = 0, a part of `module.vpc.module.vpc.aws_route_table.public`

## Scan diagnostics

What the scanner could not see or decide — read before trusting the numbers.

- **info** unconsumed-lookup: module.dependencies.module.catalog_opensearch.data.aws_caller_identity.current (data source aws_caller_identity) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (.terraform/modules/dependencies.catalog_opensearch/main.tf:7)
- **info** unconsumed-lookup: module.dependencies.module.catalog_opensearch.data.aws_iam_session_context.current (data source aws_iam_session_context) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (.terraform/modules/dependencies.catalog_opensearch/main.tf:10)
- **info** unconsumed-lookup: module.dependencies.module.catalog_opensearch.data.aws_partition.current (data source aws_partition) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (.terraform/modules/dependencies.catalog_opensearch/main.tf:4)
- **info** unconsumed-lookup: module.dependencies.module.catalog_opensearch.data.aws_region.current (data source aws_region) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (.terraform/modules/dependencies.catalog_opensearch/main.tf:1)
- **info** unconsumed-lookup: module.dependencies.module.catalog_rds.data.aws_iam_policy_document.monitoring_rds_assume_role (data source aws_iam_policy_document) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (.terraform/modules/dependencies.catalog_rds/main.tf:244)
- **info** unconsumed-lookup: module.dependencies.module.catalog_rds.data.aws_partition.current (data source aws_partition) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (.terraform/modules/dependencies.catalog_rds/main.tf:1)
- **info** unconsumed-lookup: module.dependencies.module.orders_rds.data.aws_iam_policy_document.monitoring_rds_assume_role (data source aws_iam_policy_document) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (.terraform/modules/dependencies.orders_rds/main.tf:244)
- **info** unconsumed-lookup: module.dependencies.module.orders_rds.data.aws_partition.current (data source aws_partition) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (.terraform/modules/dependencies.orders_rds/main.tf:1)
- **info** unconsumed-lookup: module.retail_app_ecs.data.aws_caller_identity.current (data source aws_caller_identity) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (../../lib/ecs/eventbridge.tf:1)
- **info** unconsumed-lookup: module.retail_app_ecs.data.aws_region.current (data source aws_region) is read by no enabled resource, provider block, output or check block of this scan, so no unit takes anything from it. (../../lib/ecs/eventbridge.tf:2)

---

*StackToIT does not deploy, modify the source environment or STACKIT, migrate data or perform cutover. Classifications come from the knowledge-base rules cited under each unit.*
