PS Product SecurityKnowledge Base

AWS IAM Snippet Pack

Intro: IAM programs become maintainable when repeated patterns are turned into reviewed snippets instead of re-invented in every project. This page is a dense pack of reusable examples for federation, role trust, boundaries, ABAC, and analysis.

What this page includes

  • practical JSON and Terraform snippets for common IAM controls
  • command examples for validation and access analysis
  • commentary on when each pattern is useful and what it protects

Working assumptions

  • prefer federation and short-lived credentials over long-lived keys
  • trust policies deserve the same review depth as permission policies

1. Trust policy for GitLab OIDC to assume a deployment role

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012:oidc-provider/gitlab.example.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "gitlab.example.com:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "gitlab.example.com:sub": "project_path:platform/product-api:ref_type:branch:ref:main"
        }
      }
    }
  ]
}

Why it helps:

  • ties deployment rights to a specific CI identity pattern;
  • avoids distributing static AWS access keys into the pipeline;
  • keeps the trust boundary readable and reviewable.

2. Permission policy for one deployment role

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "EcrPushPull",
      "Effect": "Allow",
      "Action": [
        "ecr:GetAuthorizationToken",
        "ecr:BatchCheckLayerAvailability",
        "ecr:CompleteLayerUpload",
        "ecr:InitiateLayerUpload",
        "ecr:PutImage",
        "ecr:UploadLayerPart"
      ],
      "Resource": "*"
    },
    {
      "Sid": "EksReadOnlyDescribe",
      "Effect": "Allow",
      "Action": [
        "eks:DescribeCluster"
      ],
      "Resource": "arn:aws:eks:us-east-1:123456789012:cluster/prod-platform"
    }
  ]
}

3. Permissions boundary for team-created roles

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": [
        "iam:*",
        "organizations:*",
        "account:*"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "logs:*",
        "cloudwatch:*",
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "*"
    }
  ]
}

Use a permissions boundary when product teams are allowed to create roles but must remain inside a maximum permission envelope.

4. ABAC with principal tags and resource tags

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::team-data-*/*",
      "Condition": {
        "StringEquals": {
          "aws:PrincipalTag/team": "${aws:ResourceTag/team}"
        }
      }
    }
  ]
}

Use this when you want the same policy logic to scale across many teams or services.

5. STS assume-role with session tags

aws sts assume-role   --role-arn arn:aws:iam::123456789012:role/app-deployer   --role-session-name product-api-main   --tags team=payments env=prod   --transitive-tag-keys team env

Session tags are useful when you want access decisions or CloudTrail records to carry workload or team context.

6. IAM Access Analyzer commands

# Create an account analyzer.
aws accessanalyzer create-analyzer   --analyzer-name org-security   --type ACCOUNT

# List current findings.
aws accessanalyzer list-findings   --analyzer-name org-security

Use this to detect unintended external or cross-account access and to validate policy changes before they become normal.

7. IRSA trust policy for EKS workloads

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E:sub": "system:serviceaccount:payments:api"
        }
      }
    }
  ]
}

Kubernetes service account annotation:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: api
  namespace: payments
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/payments-api-irsa

8. Terraform for an IAM role with boundary

resource "aws_iam_role" "app_deployer" {
  name                 = "app-deployer"
  permissions_boundary = aws_iam_policy.team_boundary.arn
  assume_role_policy   = data.aws_iam_policy_document.gitlab_oidc_trust.json

  tags = {
    owner = "product-security-kb"
    env   = "prod"
  }
}

resource "aws_iam_role_policy_attachment" "deploy_attach" {
  role       = aws_iam_role.app_deployer.name
  policy_arn = aws_iam_policy.app_deployer.arn
}

9. Detect broad policies during review

# Search for wildcard actions before merge.
jq -r '.. | objects | select(.Action? == "*" or (.Action? | type == "array" and index("*") != null))' policy.json

10. Quick design checklist

  • Does the trust policy restrict who can assume the role?
  • Do you prefer federation or workload identity over static keys?
  • Is a permissions boundary needed for delegated role creation?
  • Can principal or session tags simplify authorization logic?
  • Are external and cross-account paths reviewed with Access Analyzer?

Author attribution: Ivan Piskunov, 2026 - Educational and defensive-engineering use.