# Landing zone requirements — gcp-candidates/terraform-dynamic-python-webapp/infra

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

Run `6f8f72b2-1c34-4cfc-8483-344c41245364` · source digest `sha256:19bfed642d5789ccada81b91d5c36e33175dcafd66dc46b1644ffa105d020000`

What the STACKIT organization and project have to provide before the first apply, read from the blocks of the draft, the target plans (target-plan.json), the execution plan (execution-plan.json) and the assessment. A line that says unknown is not a gap of this document: it is a value the run does not state.

## 1. Organization

- A STACKIT organization that the people who carry out the migration belong to, with a project in it that holds everything the draft creates. The plans state no organization name or id; none is assumed.
- The variable that gives the draft its project: unknown. No plan of this run declares one; the variables of the draft are in terraform/.

## 2. Project

- The project exists

Values a person supplies before the apply:

- `containers_machine_type`: STACKIT machine type of the node pool hosting the migrated container workloads (size from their CPU/memory requests). See https://docs.stackit.cloud/products/compute-engine/server/basics/machine-types/
- `containers_nodes_max`: Maximum nodes of the node pool hosting the migrated container workloads
- `containers_nodes_min`: Minimum nodes of the node pool hosting the migrated container workloads
- `media_bucket_name`: DNS-conform bucket name replacing google_storage_bucket.media
- `postgres_allowed_cidrs`: CIDRs allowed to reach google_sql_database_instance.postgres. The source used private IP or no authorized networks; list the STACKIT network prefixes of the clients
- `postgres_storage_size`: PostgreSQL Flex storage size in GB for google_sql_database_instance.postgres: the source states no disk_size — set the size STACKIT should provision. (the full description is in terraform/variables.tf)
- `postgresflex_storage_class`: PostgreSQL Flex storage performance class
- `project_id`: STACKIT project ID the migrated resources are created in
- `rabbitmq_allowed_cidrs`: CIDRs allowed to reach the one STACKIT RabbitMQ instance that hosts all migrated queues and topics (parameters.sgw_acl). (the full description is in terraform/variables.tf)
- `rabbitmq_plan_name`: STACKIT RabbitMQ plan (see the RabbitMQ service plans)
- `rabbitmq_version`: STACKIT RabbitMQ version

## 3. Network area and region

- Region: `var.region`, default `eu01` in the draft; no input of the run overrides it. Check that the services below are available in it.
- Network area: the draft writes none.
- Networks: the draft writes none.

## 4. Address ranges

Every network prefix and route destination the plans and the draft state. A prefix that is still open is marked to decide, with the variable or the decision that settles it. A prefix the draft takes from a variable is not written out: the row says where the draft states it and which variable carries it.

The draft writes no network, network area or route, so it states no prefix.

## 5. Routing

No plan holds a routing table or a route, and no plan states a routing precondition.

## 6. DNS

No plan writes a DNS zone or a record.

## 7. Identity

- Service account `stackit_service_account.automation`: no plan states its name
- Service account `stackit_service_account.client`: no plan states its name
- Service account `stackit_service_account.init`: no plan states its name
- Service account `stackit_service_account.server`: no plan states its name
- A person decides or does: Decide how google_cloud_run_v2_job.migrate gets its application identity on STACKIT (a service account of its own, workload federation): the draft does not write it (needed before the pilot)
- A person decides or does: Decide how google_cloud_run_v2_service.server gets its application identity on STACKIT (a service account of its own, workload federation): the draft does not write it (needed before the pilot)
- A person decides or does: Decide who may use the STACKIT service account written for google_service_account.automation, what it may do and which workloads run as it: the draft attaches it to nothing (needed before the pilot)
- A person decides or does: Decide who may use the STACKIT service account written for google_service_account.server, what it may do and which workloads run as it: the draft attaches it to nothing (needed before the pilot)

## 8. Service enablement

Each service below has a block in the draft and has to be usable in the project and in the region of section 3. StackToIT does not read which services the project has.

| Service | Resource types | Blocks in the draft | Source units mapped | Note |
|---|---|---|---|---|
| Identity and access | `stackit_service_account` | 4 | 3 | — |
| Kubernetes Engine (SKE) | `stackit_ske_cluster` | 1 | 2 | — |
| Object Storage | `stackit_objectstorage_bucket` | 1 | 1 | — |
| PostgreSQL Flex | `stackit_postgresflex_instance` | 1 | 1 | — |
| RabbitMQ | `stackit_rabbitmq_instance` | 1 | 1 | — |
| Secrets Manager | `stackit_secretsmanager_instance`, `stackit_secretsmanager_user` | 2 | 2 | — |

Not created by this draft: the assessment maps source units to these resource types and no block of the draft writes one, so this draft creates nothing in them and nothing has to be enabled for it.

| Service | Resource types | Source units mapped |
|---|---|---|
| Identity and access | `stackit_authorization_folder_role_assignment`, `stackit_authorization_organization_role_assignment`, `stackit_authorization_project_role_assignment`, `stackit_authorization_service_account_role_assignment` | 3 |
| Object Storage | `stackit_objectstorage_credential`, `stackit_objectstorage_credentials_group` | 1 |
| PostgreSQL Flex | `stackit_postgresflex_database`, `stackit_postgresflex_user` | 1 |
| RabbitMQ | `stackit_rabbitmq_credential` | 1 |

## 9. Quotas

What the draft creates, counted by type. A block with count or for_each creates one object for each element, so the objects can be more than the blocks: where the draft states the number it is given, else the line says the multiplicity is not expanded. A block the draft writes only as a comment creates nothing and is not counted. StackToIT states no quota and reads none from the project.

- Check the project quota for 1 `stackit_objectstorage_bucket` block
- Check the project quota for 1 `stackit_postgresflex_instance` block
- Check the project quota for 1 `stackit_rabbitmq_instance` block
- Check the project quota for 1 `stackit_secretsmanager_instance` block
- Check the project quota for 1 `stackit_secretsmanager_user` block
- Check the project quota for 4 `stackit_service_account` blocks
- Check the project quota for 1 `stackit_ske_cluster` block

Source units are mapped to these types and no block of the draft creates one, so they are not counted above. Check their quota when the units are drafted.

| Type | Source units mapped |
|---|---|
| `stackit_authorization_folder_role_assignment` | 3 |
| `stackit_authorization_organization_role_assignment` | 3 |
| `stackit_authorization_project_role_assignment` | 3 |
| `stackit_authorization_service_account_role_assignment` | 3 |
| `stackit_objectstorage_credential` | 1 |
| `stackit_objectstorage_credentials_group` | 1 |
| `stackit_postgresflex_database` | 1 |
| `stackit_postgresflex_user` | 1 |
| `stackit_rabbitmq_credential` | 1 |

## 10. Required API access

The draft and the steps of the plan call the STACKIT APIs of the services in section 8, in the region of section 3, from the machine that runs them. That machine needs network access to those APIs.

- Terraform provider `stackit`, version `0.121.0`.
- STACKIT API step `API/secrets-manager-vault/WriteSecret/google_secret_manager_secret.django_admin_password`: secrets-manager-vault, WriteSecret. Authorisation: the username and password of a Secrets Manager user of the instance with write access (the stackit_secretsmanager_user the draft creates, write_enabled = true), which the script exchanges for a token (login) and sends as X-Vault-Token.
- STACKIT API step `API/secrets-manager-vault/WriteSecret/google_secret_manager_secret.django_settings`: secrets-manager-vault, WriteSecret. Authorisation: the username and password of a Secrets Manager user of the instance with write access (the stackit_secretsmanager_user the draft creates, write_enabled = true), which the script exchanges for a token (login) and sends as X-Vault-Token.

## 11. Required Terraform permissions

Terraform acts on the project as one STACKIT identity whose credentials are given to the provider outside the draft; the draft holds none. The identity needs, for each service the plans use:

- Identity and access: the role that may create Identity and access resources in the project
- Kubernetes Engine (SKE): the role that may create Kubernetes Engine (SKE) resources in the project
- Object Storage: the role that may create Object Storage resources in the project
- PostgreSQL Flex: the role that may create PostgreSQL Flex resources in the project
- RabbitMQ: the role that may create RabbitMQ resources in the project
- Secrets Manager: the role that may create Secrets Manager resources in the project

StackToIT names no role: which role grants this is the project's to look up.

## 12. External dependencies

- Not migrated: the critical setting `force-destroy` of `google_storage_bucket.media` — A check of the knowledge base (gcs force destroy) found a setting the target has no counterpart for (a finding of this unit describes it). stackit_objectstorage_bucket (pinned provider) "cannot be destroyed if the bucket contains objects" (schema description): force_destroy = false — a destroy that stops at a non-empty bucket — is what STACKIT does, PRESERVED; true has no counterpart, UNSUPPORTED (check gcs-force-destroy); reason: the target has no counterpart that carries this setting of the source (`TARGET_SETTING_UNSUPPORTED`); missing on STACKIT: counterpart that carries the setting `force-destroy` of google_storage_bucket (the knowledge base marks it UNSUPPORTED)
- Not migrated: google_firebase_project.default (google_firebase_project) — Nothing on STACKIT holds the registration of an app or the enabling of Firebase on a project. It stays with Google for as long as any Firebase service (push messaging, for example) is used, and a person decides, app by app, which backend replaces the Firebase services the app calls. Adding Firebase to a project cannot be undone; reason: no STACKIT service or resource carries this source resource (`TARGET_RESOURCE_UNSUPPORTED`); missing on STACKIT: enabling of Firebase on a project; direction: List the Firebase services each app uses (authentication, database, storage, messaging, remote config); each needs its own replacement; The signing keys and store listings stay with Google Play and the Apple App Store; only the backend the app talks to moves
- Before the pilot, pin remote modules to an immutable Git ref or a registry version: a module source that can move can change the estate this migration was planned for between two runs. Unpinned module sources found:
  - `module.project_services` from `terraform-google-modules/project-factory/google//modules/project_services`

## 13. Customer decisions

The decisions a step of the plan waits for. Each one is answered by the customer; the roadmap shows the steps behind it.

| Decision | Question | Why it matters | Google Cloud resource | Needed | Blocks |
|---|---|---|---|---|---|
| `DEC-GEN-CONVERT-API-OPT-IN/google_pubsub_topic.faux` | Allow calls of the beta pubsub API v1beta for this migration (the API may change or vanish)? Accept: the pubsub API v1beta path is carried out for google_pubsub_topic.faux: its calls become executable. the RabbitMQ instance the draft writes stays in the draft this run wrote, so its step is held (REGENERATE_REQUIRED) until a draft is generated without it (answer target.messaging.path with pubsub in the inputs file and run again); an instance shared with a queue or topic that has no call of the pubsub API v1beta path stays taken. Refuse: the RabbitMQ instance the draft writes is carried out and the calls and steps of the pubsub API v1beta path are not taken. | the pubsub API v1beta is beta: 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 google_pubsub_topic.faux wait for this decision; the draft's own blocks do not | — | before the pilot; answer with one of its options: "Allow the calls of the API for this migration" | 1 step of the plan |
| `DEC-GEN-CONVERT-API-OPT-IN/google_secret_manager_secret.django_admin_password` | 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 google_secret_manager_secret.django_admin_password, google_secret_manager_secret.django_settings. 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 google_secret_manager_secret.django_admin_password, google_secret_manager_secret.django_settings. | 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 google_secret_manager_secret.django_admin_password, google_secret_manager_secret.django_settings wait for this decision; the draft's own blocks do not | — | before the pilot; answer with one of its options: "Allow the calls of the API for this migration" | 4 steps of the plan |
| `DEC-GEN-CONVERT-DATA-MOVEMENT` | Choose how the data of google_sql_database_instance.postgres moves from google_sql_database_instance to PostgreSQL Flex (stackit_postgresflex_instance.postgres): 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 | google_sql_database_instance.postgres | before the pilot; answer with one of its options: "Export the data from the source and import it with the clients of the target engine" or "Replicate the data with the replication of the source engine until the cutover" or "Copy the objects of the bucket with rclone, from the source bucket to the STACKIT bucket" or "Copy the objects of the bucket with the AWS CLI, through a staging directory" or "Move the data with a migration tool or a replication of the owner's own" | 13 steps of the plan |
| `DEC-GEN-CONVERT-PROPOSED-ALTERNATIVE/google_cloudbuild_trigger.activategcb` | Decide whether the proposed STACKIT alternative replaces google_cloudbuild_trigger.activategcb: read the module proposals/proposal_activategcb, accept the difference and set its values, or design it another way | the target has no equal of this Cloud Build trigger: starts a build on a source event, a Pub/Sub message, a webhook or by hand, with its steps, substitutions, artifacts, secrets and optional approval: Nothing is converted. The same delivery is a workflow of STACKIT Git Pipelines (written for GitHub Actions; STACKIT-managed or custom runners; secrets from Secrets Manager or the repository; a manual-approval action) or the customer's own CI/CD. Trigger conditions, steps, secrets (created again, never copied), the service account (replaced by the credentials the workflow uses against STACKIT), the log destination and the approval are written again by a person. To decide: Which pipelines are still needed, where they run (STACKIT Git Pipelines or the customer's own CI/CD), how each trigger, step, secret and approval is written again, and who owns the workflow files. | google_cloudbuild_trigger.activategcb | before the pilot; answer with one of its options: "Use the proposed module, with the stated difference" or "Design it another way and leave the module off" | 1 step of the plan |
| `DEC-GEN-CONVERT-PROPOSED-ALTERNATIVE/google_cloudbuild_trigger.init` | Decide whether the proposed STACKIT alternative replaces google_cloudbuild_trigger.init: read the module proposals/proposal_init, accept the difference and set its values, or design it another way | the target has no equal of this Cloud Build trigger: starts a build on a source event, a Pub/Sub message, a webhook or by hand, with its steps, substitutions, artifacts, secrets and optional approval: Nothing is converted. The same delivery is a workflow of STACKIT Git Pipelines (written for GitHub Actions; STACKIT-managed or custom runners; secrets from Secrets Manager or the repository; a manual-approval action) or the customer's own CI/CD. Trigger conditions, steps, secrets (created again, never copied), the service account (replaced by the credentials the workflow uses against STACKIT), the log destination and the approval are written again by a person. To decide: Which pipelines are still needed, where they run (STACKIT Git Pipelines or the customer's own CI/CD), how each trigger, step, secret and approval is written again, and who owns the workflow files. | google_cloudbuild_trigger.init | before the pilot; answer with one of its options: "Use the proposed module, with the stated difference" or "Design it another way and leave the module off" | 1 step of the plan |
| `DEC-GEN-CONVERT-PROPOSED-ALTERNATIVE/google_cloudbuild_trigger.placeholder` | Decide whether the proposed STACKIT alternative replaces google_cloudbuild_trigger.placeholder: read the module proposals/proposal_placeholder, accept the difference and set its values, or design it another way | the target has no equal of this Cloud Build trigger: starts a build on a source event, a Pub/Sub message, a webhook or by hand, with its steps, substitutions, artifacts, secrets and optional approval: Nothing is converted. The same delivery is a workflow of STACKIT Git Pipelines (written for GitHub Actions; STACKIT-managed or custom runners; secrets from Secrets Manager or the repository; a manual-approval action) or the customer's own CI/CD. Trigger conditions, steps, secrets (created again, never copied), the service account (replaced by the credentials the workflow uses against STACKIT), the log destination and the approval are written again by a person. To decide: Which pipelines are still needed, where they run (STACKIT Git Pipelines or the customer's own CI/CD), how each trigger, step, secret and approval is written again, and who owns the workflow files. | google_cloudbuild_trigger.placeholder | before the pilot; answer with one of its options: "Use the proposed module, with the stated difference" or "Design it another way and leave the module off" | 1 step of the plan |
| `DEC-GEN-CONVERT-PROPOSED-ALTERNATIVE/google_firebase_hosting_site.client` | Decide whether the proposed STACKIT alternative replaces google_firebase_hosting_site.client: read the module proposals/proposal_client, accept the difference and set its values, or design it another way | the target has no equal of this static web hosting site: Static files are published into an Object Storage bucket by a pipeline, and a CDN distribution (a beta resource) with the bucket as origin serves them on a custom domain; the redirects of the site become redirect rules of the distribution. Custom response headers, rewrites to Cloud Run services or Cloud Functions, preview channels and the release history have no counterpart and are restated in the pipeline or in the application. To decide: Which bucket is the origin, which domain the distribution serves, and how rewrites and previews are replaced. The CDN resources are beta. | google_firebase_hosting_site.client | before the pilot; answer with one of its options: "Use the proposed module, with the stated difference" or "Design it another way and leave the module off" | 1 step of the plan |
| `DEC-GEN-CONVERT-SOURCE-PROJECT-MAPPING` | State where the units of each source project of the estate go | The source places its units in the project example-project, and in a project the scan cannot read for some units, and the source project is carried nowhere. A person maps the source projects by answering target.project.source_project for each: var.project_id, or the project of the unit's network (network-project). The answer records that mapping and changes nothing in the draft, which keeps its own project resolver. | — | before the pilot; answer with one of its options: "The units of the source project go to the project the variable project_id names" or "The units of the source project go to the project of their network" | 1 step of the plan |
| `DEC-GEN-CONVERT-SOURCE-REGION-MAPPING` | Map each source location of the estate to a STACKIT region | The source places its units in a location the scan cannot read (the value comes from an input a plan can change, or the source does not state it). No mapping between Google and STACKIT regions is evidenced, so the region the draft builds in is not shown to hold the residency of a source location: a person states it once for the estate, by answering target.region.source_location for each location. | — | before the pilot; answer with one of its options: "Map every source location of the estate to the one STACKIT region the draft builds in" or "Choose the STACKIT region of each source location" | 1 step of the plan |
