GOOGLE CLOUD IAM → STACKIT
GCP IAM and service account migration to STACKIT
A Google service account becomes a STACKIT service account, and that is the easy part. The role bindings, custom roles, keys and GKE workload identity around it are where the work sits: StackToIT writes the account and puts each of the others on a review list for a person, because Google roles and STACKIT roles do not line up one to one.
A service account, its key and its role, assessed
A small identity estate written for this page and assessed by StackToIT on 4 November 2026 (eight resources). Left: the CI deployer account, its key and its project binding. Right: the only block of that group the engine writes as Terraform; the review comments above it in the file are left out here. The input blocks are not adjacent in main.tf, so each has its own pane, verbatim.
resource "google_service_account" "deployer" {
account_id = "ci-deployer"
display_name = "CI deployer"
}resource "google_service_account_key" "deployer" {
service_account_id = google_service_account.deployer.name
}resource "google_project_iam_member" "deployer_editor" {
project = "shop-platform-prod"
role = "roles/editor"
member = "serviceAccount:${google_service_account.deployer.email}"
}resource "stackit_service_account" "deployer" {
project_id = var.project_id
name = "ci-deployer"
}The name is kept, the address is not
The account name comes from account_id. The e-mail address changes, because STACKIT generates it, so every reference to the old iam.gserviceaccount.com address needs an update. Google's address format is name, project id and iam.gserviceaccount.com; look for it in application configuration, bucket policies and CI variables.
The display name has no home
stackit_service_account takes a name and a project id and nothing else, so the display name is listed as not carried. Keep the description in your own inventory.
Eight resources, two units
Only the two service accounts are units. The key is attached to the deployer unit as a facet. The three project bindings, the custom role and the workload identity binding are recorded as support resources that no unit reads, and the draft writes nothing for them.
What the run leaves to a person
From the same run: an excerpt of the deployer unit in assessment.json, with the values exactly as the run wrote them. Two critical settings stay open: the role bindings and the long-lived key.
{
"id": "google_service_account.deployer",
"facets": [
"google_service_account_key.deployer"
],
"result": {
"class": "RECONFIGURE",
"confidence": "MEDIUM",
"target": {
"resources": [
"stackit_service_account",
"stackit_authorization_project_role_assignment"
]
},
"findings": [
{
"severity": "info",
"message": "Long-lived JSON keys are issued; they become STACKIT service account keys — or disappear where workload identity replaces them."
}
],
"semantics": {
"critical_open": [
"long-lived-keys",
"role-bindings"
]
}
}
}Role bindings: a person re-maps them
The target of each account lists stackit_authorization_project_role_assignment, which the provider marks as part of an opt-in iam feature that may still change. The run does not translate roles/editor, roles/viewer or the custom role into STACKIT roles; it opens a review record per account.
Keys: decide whether they survive
A long-lived JSON key is flagged. STACKIT service accounts can have keys too, and STACKIT's own page says to treat one like a password for the application; Google itself advises against keys wherever a more secure alternative exists. Decide per caller whether it still needs one.
The binding targets are read as unknown
In this run the engine reads a member written as serviceAccount: plus the account's generated address as an unknown value, and so it cannot show who a binding names. Check the binding list by hand against your real policy export.
How the Google constructs map
| Google Cloud construct | In the STACKIT run | What you do |
|---|---|---|
| Service account | stackit_service_account, class RECONFIGURE | Create it; update every reference to its e-mail address |
| Project IAM binding (member) | Support resource, no draft block | Re-map the role to a STACKIT role and assign it to the account in the project |
| Basic role (Owner, Editor, Viewer) | Support resource, role left to review | Replace with the narrowest STACKIT role that covers the work |
| Custom role | Support resource, permissions listed for review | Rebuild as the combination of STACKIT roles that fits |
| Service account key | Facet of the account, long-lived-keys under review | Replace with workload identity federation, or issue a STACKIT key |
| GKE workload identity binding | Support resource, no draft block | Federate the cluster's OIDC issuer, or issue explicit credentials |
| Group as member | Appears in the graph as a plain string | Rebuild the group or its members in your STACKIT identity setup |
Rows two to seven come from the support list in terraform/README.md and engineering/review.csv. Google's own guidance is to avoid basic roles in production and that a custom role is limited to the project or organisation it was created in.
The migration in order
Inventory principals and grants
Export every service account, key, binding and custom role of the projects you migrate. The Terraform in the estate shows what you manage as code; bindings made in the console or by other tools are not in it, and the run cannot see them.
Classify each account
Split accounts into application runtime identities, CI identities and Google-managed service agents. The last group usually has no STACKIT counterpart to create; confirm that per account.
Create the accounts
Apply the stackit_service_account blocks. STACKIT service accounts have no access by default; permissions come from roles assigned in the project, so nothing works until step four.
Assign roles deliberately
For each binding, pick the STACKIT role with the least privilege that does the job. The provider resource takes resource_id, role and a lowercase subject; available roles are read from the authorization API.
Replace keys with federation
A STACKIT service account can trust an external OIDC issuer: the issuer URL must be HTTPS without a trailing slash, an aud assertion is required, and only equality assertions are supported. The Terraform provider itself can authenticate this way in CI, which removes the need for a stored key.
Retarget workloads and clean up
Point applications at the new credentials, watch for denied calls, and delete the Google accounts and keys only after a quiet period. Deleting a STACKIT service account is permanent, so keep an export.
Decisions the architect owns
The role model
Whether to mirror Google's grants or to restart from the STACKIT roles. Mirroring carries over old over-grants such as roles/editor.
Where workloads authenticate from
Pods that used Google's cluster identity (the binding names a Kubernetes service account in a project pool) have no equivalent on STACKIT until you federate their issuer or give them a key.
Who may create keys
A key is a password for the account. Decide who may issue one and where it is stored before the first one exists.
Project boundaries
The run places every resource in the one project given by var.project_id, and says that a source spread over several projects is collapsed into it. Decide how many projects you want, because role assignments are made per project.
Questions security teams ask
Does StackToIT translate Google roles into STACKIT roles?
No. It maps the service account and leaves the role bindings to a person, because the permissions of a Google role and a STACKIT role are not the same set. The run records an open review item for it.
What happens to GKE Workload Identity bindings?
They are listed as support resources and nothing is drafted. Google's model grants a role to a Kubernetes identity through a project pool; on STACKIT you federate the cluster's OIDC issuer with a service account or issue explicit credentials.
Are service account keys carried over?
No. The run flags them for a decision. Where an application can use federation instead, that avoids a stored secret altogether; where it cannot, STACKIT can issue a key.
Is the role assignment resource stable?
The provider documents stackit_authorization_project_role_assignment as part of an opt-in feature it says may change significantly. Plan for that when you put it into a pipeline.
Sources
- Google Cloud: Service accounts overview
- Google Cloud: Best practices for managing service account keys
- Google Cloud: IAM roles overview
- Google Cloud: Workload Identity Federation for GKE
- STACKIT: Service accounts
- STACKIT: Manage service account federations
- STACKIT Terraform provider v0.121.0: stackit_authorization_project_role_assignment
- STACKIT Terraform provider v0.121.0: authentication and experiments
Your next move: STACKIT.
Tell us about your estate. We show you what StackToIT delivers for it: target architecture, Terraform artifacts and a structured migration plan.