AWS permissions for provisioning

adj cluster provision runs an OpenTofu apply in your AWS account (VPC + EKS + FSx for OpenZFS + the IAM roles/IRSA the cluster needs). This page is the policy to grant the principal that runs it.

Print the same document locally — no login, no cluster, works offline:

$ adj cluster iam-policy

The policy

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Networking",
      "Effect": "Allow",
      "Action": [
        "ec2:CreateVpc",
        "ec2:DeleteVpc",
        "ec2:DescribeVpcs",
        "ec2:CreateSubnet",
        "ec2:CreateRouteTable",
        "ec2:CreateInternetGateway",
        "ec2:CreateNatGateway",
        "ec2:AllocateAddress",
        "ec2:CreateSecurityGroup",
        "ec2:AuthorizeSecurityGroupIngress",
        "ec2:RunInstances",
        "ec2:CreateTags"
      ],
      "Resource": "*"
    },
    {
      "Sid": "EKS",
      "Effect": "Allow",
      "Action": [
        "eks:CreateCluster",
        "eks:DescribeCluster",
        "eks:DeleteCluster",
        "eks:CreateNodegroup",
        "eks:DescribeNodegroup",
        "eks:TagResource"
      ],
      "Resource": "*"
    },
    {
      "Sid": "FSxOpenZFS",
      "Effect": "Allow",
      "Action": [
        "fsx:CreateFileSystem",
        "fsx:DescribeFileSystems",
        "fsx:DeleteFileSystem",
        "fsx:CreateVolume",
        "fsx:DeleteVolume",
        "fsx:TagResource"
      ],
      "Resource": "*"
    },
    {
      "Sid": "IAM",
      "Effect": "Allow",
      "Action": [
        "iam:CreateRole",
        "iam:AttachRolePolicy",
        "iam:PassRole",
        "iam:CreatePolicy",
        "iam:CreateOpenIDConnectProvider",
        "iam:TagRole"
      ],
      "Resource": "*"
    }
  ]
}

This is the representative action set the provisioning preflight simulates (with iam:SimulatePrincipalPolicy) before touching any resource. It is representative, not exhaustive — the module also exercises further read/describe/tag calls within these same services during an apply, so the practical grant is "administrative access to EC2, EKS, FSx, and IAM role management". Resource is "*" because the resources the module creates do not exist (and have no ARNs) until apply time.

What the preflight checks

Before rotating the join token or creating anything, adj cluster provision:

  1. Resolves credentials (--aws-profile, or ambient AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY) and calls sts get-caller-identity.
  2. Probes IAM capability with one read-only call. Provisioning must create IAM roles, so credentials that cannot call IAM at all are rejected immediately (see below) instead of failing ten minutes into the apply with VPC/NAT/FSx already billing.
  3. Simulates the action set above against your principal and hard-fails with the exact missing actions if any are denied. If the simulation itself cannot run (the principal lacks iam:SimulatePrincipalPolicy, or is not simulatable), provisioning proceeds with a warning — only a known gap blocks.

STS session tokens do not work

Credentials from aws sts get-session-token cannot call any IAM API (without MFA) — an AWS limitation, not a policy problem. They pass the identity check, but provisioning creates IAM roles, so the apply would fail at the first role with:

InvalidClientTokenId: The security token included in the request is invalid

The preflight now detects exactly this and refuses up front. Use one of: