AWSTemplateFormatVersion: "2010-09-09"
Description: >-
  Ankra provisioning cross-account role for creating and managing EKS clusters
  in your account. Grants EKS cluster and node-group lifecycle access, IAM role
  management scoped to the ankra-eks-* roles Ankra creates, and read-only
  EC2/pricing/cost access (a superset of the read-only cost role, so one
  credential covers both). Review the permissions before deploying. Ankra
  assumes the role via STS with a per-organisation external ID; no long-lived
  credentials leave your account.

Parameters:
  ExternalId:
    Type: String
    Description: Per-organisation external ID provided by Ankra during setup. Do not change.
    AllowedPattern: "^ankra-[A-Za-z0-9_-]+$"
  AnkraPrincipalArn:
    Type: String
    Description: The Ankra AWS principal allowed to assume this role.
  RoleName:
    Type: String
    Default: AnkraProvisioning
    Description: Name of the IAM role to create.
  PermissionsBoundaryArn:
    Type: String
    Default: ""
    Description: Optional IAM permissions boundary ARN applied to this role.

Conditions:
  HasPermissionsBoundary: !Not [!Equals [!Ref PermissionsBoundaryArn, ""]]

Resources:
  AnkraProvisioningRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Ref RoleName
      Description: Write access for Ankra to provision and manage EKS clusters.
      MaxSessionDuration: 3600
      PermissionsBoundary: !If [HasPermissionsBoundary, !Ref PermissionsBoundaryArn, !Ref "AWS::NoValue"]
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: !Ref AnkraPrincipalArn
            Action: "sts:AssumeRole"
            Condition:
              StringEquals:
                "sts:ExternalId": !Ref ExternalId
      Policies:
        - PolicyName: AnkraEksProvisioning
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              # Create, describe, scale, upgrade, and delete EKS clusters and
              # managed node groups.
              - Sid: EksLifecycle
                Effect: Allow
                Action:
                  - "eks:*"
                Resource: "*"
              # Read-only EC2 lookups: default-VPC subnet discovery, regions,
              # instance types, and spot price history. Ankra never creates or
              # modifies EC2 resources; node groups are EKS-managed.
              - Sid: Ec2Read
                Effect: Allow
                Action:
                  - "ec2:Describe*"
                Resource: "*"
              # Read-only pricing, cost, and identity access so this
              # credential also covers cost estimation and inventory
              # (superset of the AnkraCloudCostReadOnly role).
              - Sid: PricingAndCostRead
                Effect: Allow
                Action:
                  - "pricing:GetProducts"
                  - "pricing:DescribeServices"
                  - "ce:GetCostAndUsage"
                  - "ce:GetCostForecast"
                  - "sts:GetCallerIdentity"
                Resource: "*"
              # Lifecycle of the two IAM roles Ankra creates per cluster:
              # ankra-eks-cluster-<name> and ankra-eks-node-<name>.
              - Sid: IamForEksRoles
                Effect: Allow
                Action:
                  - "iam:CreateRole"
                  - "iam:DeleteRole"
                  - "iam:AttachRolePolicy"
                  - "iam:DetachRolePolicy"
                  - "iam:PutRolePolicy"
                  - "iam:DeleteRolePolicy"
                  - "iam:GetRole"
                  - "iam:GetRolePolicy"
                  - "iam:ListRolePolicies"
                  - "iam:ListAttachedRolePolicies"
                  - "iam:TagRole"
                Resource:
                  - "arn:aws:iam::*:role/ankra-eks-*"
              # EKS auto-creates its service-linked roles on first use in an
              # account (control plane, node groups, and the autoscaling
              # groups behind managed node groups).
              - Sid: IamServiceLinkedRoles
                Effect: Allow
                Action:
                  - "iam:CreateServiceLinkedRole"
                Resource:
                  - "arn:aws:iam::*:role/aws-service-role/*"
                Condition:
                  StringEquals:
                    "iam:AWSServiceName":
                      - "eks.amazonaws.com"
                      - "eks-nodegroup.amazonaws.com"
                      - "autoscaling.amazonaws.com"
              # EKS validates the service-linked roles with the caller's own
              # iam:GetRole before CreateNodegroup proceeds; without this the
              # API rejects node groups with "Failed to validate if SLR:
              # AWSServiceRoleForAmazonEKSNodegroup already exists due to
              # missing permissions for 'iam:GetRole'". Kept as a separate
              # read-only statement: the iam:AWSServiceName condition above
              # only evaluates for CreateServiceLinkedRole and would deny a
              # conditioned iam:GetRole outright.
              - Sid: IamServiceLinkedRolesRead
                Effect: Allow
                Action:
                  - "iam:GetRole"
                Resource:
                  - "arn:aws:iam::*:role/aws-service-role/eks.amazonaws.com/*"
                  - "arn:aws:iam::*:role/aws-service-role/eks-nodegroup.amazonaws.com/*"
                  - "arn:aws:iam::*:role/aws-service-role/autoscaling.amazonaws.com/*"
              # Pass the ankra-eks-* roles to the EKS control plane and to
              # EC2 instances in managed node groups.
              - Sid: IamPassRole
                Effect: Allow
                Action:
                  - "iam:PassRole"
                Resource:
                  - "arn:aws:iam::*:role/ankra-eks-*"
                Condition:
                  StringEquals:
                    "iam:PassedToService":
                      - "eks.amazonaws.com"
                      - "ec2.amazonaws.com"

Outputs:
  RoleArn:
    Description: Paste this Role ARN back into Ankra to allow cluster provisioning.
    Value: !GetAtt AnkraProvisioningRole.Arn
  ExternalId:
    Description: The external ID this role is bound to.
    Value: !Ref ExternalId
