IDENTITY · AWS, AZURE, GOOGLE CLOUD → STACKIT

Cloud IAM and identity migration to STACKIT

Policies do not migrate; identities do. On STACKIT a machine identity from AWS, Azure or Google Cloud becomes a service account, a person signs in through your organisation's identity provider, and what the identity may do becomes a role assignment that you choose, because StackToIT does not translate cloud actions into STACKIT roles. Three small runs of 4 November 2026 show what the drafts write, what they leave to you and why the access keys are the part to plan first.

How each source identity maps

One row per identity kind, taken from three runs: an 11-resource AWS estate, and a 4-resource estate each for Azure and Google Cloud.

Source identitySTACKIT target the draft writesWhat stays with you
AWS IAM user with an access key and no console loginA service account, a service account key and project role assignmentsThe roles, the lifetime of the key and the hand-over of the new key to every caller of the old one
AWS IAM role of an EC2 instance, with its instance profileA service account attached to the server, with role assignmentsThe roles, and the permission to act as the account when the server is attached
AWS IAM groupAn identity provider group; the roles are assigned to its membersWho the members are and which roles they get
Azure user-assigned managed identityA service account only; its role assignments are left to a personMapping of resource groups to projects, every consumer's code, the roles
Google service account with bucket and project bindingsA service account; the bindings are reviewed by a personThe roles, and the code of workloads that used the metadata server

In the AWS run, 11 resources became 5 units: the policy, the attachments, the membership, the instance profile and the access key are folded into the user, role, group and instance they belong to. Azure and Google Cloud drafts write the principal and leave the grants as open settings. Only the AWS draft wrote role assignment resources.

An instance role becomes an attached service account

Left: an EC2 role and its instance profile as the AWS source declares them. Right: three blocks of the STACKIT draft in identity.tf, with the comment lines above each block left out.

Example inputmain.tf
resource "aws_iam_role" "app" {
  name = "reports-app"
  assume_role_policy = jsonencode({
    Version   = "2012-10-17"
    Statement = [{ Effect = "Allow", Action = "sts:AssumeRole", Principal = { Service = "ec2.amazonaws.com" } }]
  })
}

resource "aws_iam_instance_profile" "app" {
  name = "reports-app"
  role = aws_iam_role.app.name
}
STACKIT Terraform by StackToITterraform/identity.tf
resource "stackit_service_account" "app" {
  project_id = var.project_id
  name       = "app"
}

resource "stackit_authorization_project_role_assignment" "app" {
  for_each    = toset(var.app_project_roles)
  resource_id = var.project_id
  role        = each.value
  subject     = stackit_service_account.app.email
}

resource "stackit_server_service_account_attach" "app" {
  project_id            = var.project_id
  region                = var.region
  server_id             = stackit_server.app.server_id
  service_account_email = stackit_service_account.app.email
}
  • The roles are a variable

    The role assignment reads var.app_project_roles. The variable's description lists what the source policy allows, s3:GetObject and s3:PutObject, and leaves the choice of STACKIT roles to you.

  • The grant is wider than the policy

    The AWS policy named one bucket. A project role assignment applies to the whole project, and the draft says so: use per-resource bindings where the STACKIT service offers them.

  • The instance profile has no object

    The draft notes that STACKIT has no instance profile: the server acts as the attached service account directly, and the trust policy, session duration and permissions boundary of the role are not carried.

  • Two traps in the attach step

    Attaching needs the right to act as the account. The draft records that an attachment answered 403 about half a second after the account was created and 201 about seven seconds later, so retry before you suspect permissions.

An access key becomes a service account key

Left: the CI user with its access key. Right: the service account, its key and the first role assignment from the same draft; comments above each block are left out.

Example inputmain.tf
resource "aws_iam_user" "ci" {
  name = "ci-deploy"
}

resource "aws_iam_access_key" "ci" {
  user = aws_iam_user.ci.name
}
STACKIT Terraform by StackToITterraform/identity.tf
resource "stackit_service_account" "ci" {
  project_id = var.project_id
  name       = "ci"
}

resource "stackit_service_account_key" "ci" {
  project_id            = var.project_id
  service_account_email = stackit_service_account.ci.email
  ttl_days              = var.ci_key_ttl_days
}

resource "stackit_authorization_project_role_assignment" "ci" {
  count       = length([stackit_service_account.ci.email]) * length(var.ci_project_roles)
  resource_id = var.project_id
  role        = var.ci_project_roles[count.index % length(var.ci_project_roles)]
  subject     = [stackit_service_account.ci.email][floor(count.index / length(var.ci_project_roles))]
}
  • The key has a lifetime

    ttl_days reads var.ci_key_ttl_days. The variable's description notes that the AWS access keys do not expire and that a STACKIT key without ttl_days stays valid until deleted.

  • The secret never travels

    The credential is the sensitive json output of the key, created by STACKIT. The AWS secret is never read or carried, and the new key reaches callers through a manual hand-over step.

  • The old key stays until the GO

    The rollback of the hand-over is to switch the callers back to the AWS key, which stays active until the retirement of the user after the GO decision.

  • Federation is a question, not a result

    The identity transition file marks this user's static credential as observed and workload identity federation as evidence required. The run never claims that federation can replace the key.

Azure: the identity moves, the role assignment waits for a person

Left: a user-assigned managed identity and its blob role assignment. Right: the only block the draft writes for it.

Example inputmain.tf
resource "azurerm_user_assigned_identity" "app" {
  name                = "id-reports-app"
  resource_group_name = azurerm_resource_group.app.name
  location            = azurerm_resource_group.app.location
}

resource "azurerm_role_assignment" "app_blob" {
  scope                = azurerm_storage_account.reports.id
  role_definition_name = "Storage Blob Data Contributor"
  principal_id         = azurerm_user_assigned_identity.app.principal_id
}
STACKIT Terraform by StackToITterraform/identity.tf
resource "stackit_service_account" "app" {
  project_id = var.project_id
  name       = "app"
}
  • Three open settings

    The plan asks a person about the resource group scope, the credential-less code and the role assignments. Each Azure role is re-mapped by hand.

  • Code changes in every consumer

    Code that used a managed identity usually holds no credentials at all. On STACKIT it needs service account credentials or workload identity, so every consumer changes, not only the infrastructure.

  • Where the Google Cloud draft lands

    The service account maps the same way, and its e-mail address changes: references to the old address must be updated. The project-level binding is reviewed by a person.

The steps, in order

General practice, tied to the files of a run.

  1. Read the identity transition

    assurance/identity-transition.md lists each workload, its static credentials and whether the attachment to a server is exact. It also lists what it does not assess: privilege delta, break-glass access and human identity.

  2. Separate people from workloads

    People sign in through the organisation's identity provider, and groups are recreated there. The draft lists the members in a variable and assigns roles per user, service account or client, not per group.

  3. Choose the roles

    For each variable such as app_project_roles, list the roles STACKIT offers on the project and choose the narrowest set that covers what the old policy allowed.

  4. Create accounts, then attach

    Apply the service accounts and grant the applying principal the permission to act as them. Attach to servers afterwards, and retry once if the first answer is 403.

  5. Hand over keys or switch to federation

    Give every caller of an old access key its new credential, or set up a federated identity provider that trusts the caller's OIDC issuer. STACKIT documents that the issuer URL must match the exact iss value of the tokens.

  6. Retire the source identities last

    The plan places the retirement of users and roles after the GO decision, so the rollback of a hand-over stays a switch back to the old key.

Decisions the architect owns

  • Roles per service account

    The drafts never derive a STACKIT role from a cloud action. A person chooses, and the scope of the grant is a project unless a service offers finer bindings.

  • Key or federation

    A service account key is a credential, and STACKIT warns that a leaked private key exposes everything the account can access. Federation yields short-lived tokens without static keys but needs an OIDC issuer.

  • Project layout

    STACKIT has no resource group. Where Azure inherited roles through a group, you decide how the boundaries map to projects, folders and roles.

  • Token flow

    STACKIT documents 16 December 2025 as the deprecation date of service account access tokens and offers a guide for moving from the token flow to the key flow. Build new automation on keys or federation.

Questions security teams ask

Can my IAM policies be imported into STACKIT?

No. The drafts write role assignments with the roles as a variable, because an AWS action does not map one to one to a STACKIT role. The source policy appears in the variable's description, and a person translates it.

Does an EC2 instance profile have an equivalent on STACKIT?

The server acts as an attached service account. The draft notes that a metadata token path answered with a token in its tests of 8 and 9 October 2026, while an EC2-style credentials path answered HTTP 500, so code that reads credentials from an instance metadata endpoint changes.

Can I apply the role assignments as written?

They are written with an opt-in feature of the STACKIT Terraform provider that the draft enables in its provider block and the provider documents as likely to change. Review them, and set the roles, before you apply.

What happens to the AWS access key?

It keeps working until you retire it. The plan puts the retirement after the GO decision, so you can switch callers back until then.

Sources

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.