Updraft ExtensionsPreview
AWS Identity and Access ManagementSecurity Stable

AWS::IAM::Role

Creates an IAM role — a set of permissions that principals assume rather than hold, and the join between “who is asking” and “what they may do”.

Required properties 1 of 9
Ref returns Role nameacme-payments-task-role
Fn::GetAtt 2 attributes
Replacement risk 2 2 properties force replacement

Minimal template

Every required property, nothing else
Resources:
  TaskRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action: sts:AssumeRole
A role with a trust policy and no permission policies is valid and useful: it can be assumed, and it can do nothing. Start here and add permissions as they are needed, rather than starting from a managed policy and trimming.

Overview #

A role is a set of permissions with no credentials attached. Principals do not have a role; they assume it, receiving temporary credentials that expire. That indirection is the whole point: it is what makes it possible to grant an EC2 instance, a Lambda function, or an engineer at another company access to something without ever creating a long-lived key.

Two documents govern every role, and confusing them is the most common source of “why is this denied”:

  • AssumeRolePolicyDocument — the trust policy. Answers who may become this role. Contains a Principal.
  • Policies and ManagedPolicyArns — the permission policies. Answer what the role may then do. Contain no Principal, because the principal is the role.

An AccessDenied on sts:AssumeRole is a trust policy problem. An AccessDenied on anything else is a permission policy problem. The two are never fixed in the same place.

How a request is actually evaluated #

Worth internalising, because it explains almost every surprising denial.

Evaluation order for a request made by an assumed role. Any explicit Deny at any stage ends the evaluation immediately; an Allow must survive every stage that applies.

The consequence: a role whose policy plainly allows an action can still be denied by a service control policy, a permissions boundary, or a resource policy, and none of those appear in the role’s own definition. When a denial makes no sense, work outwards from the role rather than staring at it.

A role you would actually deploy #

Resources:
  PaymentsTaskRole:
    Type: AWS::IAM::Role
    Properties:
      Description: Runtime role for the payments API tasks.

      # Who may become this role. Conditions scope it to *our* tasks,
      # not to every ECS task in the account.
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action: sts:AssumeRole
            Condition:
              ArnLike:
                aws:SourceArn: !Sub 'arn:${AWS::Partition}:ecs:${AWS::Region}:${AWS::AccountId}:*'
              StringEquals:
                aws:SourceAccount: !Ref AWS::AccountId

      # What it may then do. Inline, because it is meaningless elsewhere.
      Policies:
        - PolicyName: read-payments-config
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action: ssm:GetParametersByPath
                Resource: !Sub 'arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/acme/payments/production'
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                Resource: !Sub '${AssetBucket.Arn}/receipts/*'

      PermissionsBoundary: !Ref DeveloperBoundary

      Tags:
        - Key: System
          Value: payments

Referencing a role #

!Ref PaymentsTaskRole → acme-payments-task-rolethe name, without the path

!GetAtt PaymentsTaskRole.Arn → arn:aws:iam::123456789012:role/service-roles/acme-payments-task-role

Use the ARN anywhere the value crosses a boundary — another account’s trust policy, an sts:AssumeRole call, a PassRole condition. The bare name is only safe inside the same account and only for roles at the default path.

Properties

Expand a row for the full reference; nested types open in place

9 top-level properties

  • AssumeRolePolicyDocument JSONThe trust policy — who is allowed to assume this role. Required No interruption — updates in place
    The single most important property on the resource, and the one people confuse with the permission policies. This document answers who may become this role; Policies and ManagedPolicyArns answer what the role may then do.
    Type
    JSON
    Required
    Yes
    Update behaviour
    No interruption
  • RoleName StringThe role's name. Generated from the stack and logical ID when omitted. Replacement — CloudFormation creates a new resource and deletes the old one Create-only
    Naming a role explicitly makes it referenceable from outside the stack and readable in CloudTrail. It also makes the stack non-repeatable within an account, and requires CAPABILITY_NAMED_IAM on every operation.
    Type
    String
    Required
    No
    Update behaviour
    Replacement
    Pattern
    ^[\w+=,.@-]+$ Letters, digits, and `_ + = , . @ -`. No spaces, no slashes — a slash belongs in `Path`.
    Length
    1 – 64

    Example values

    • acme-payments-task-role
  • Description StringFree-text description of the role's purpose. No interruption — updates in place
    Worth filling in. It is displayed in the assume-role picker in the console and in Access Analyzer findings, which are exactly the moments when somebody is trying to work out what a role is for.
    Type
    String
    Required
    No
    Update behaviour
    No interruption
    Length
    0 – 1000
  • ManagedPolicyArns Array of StringARNs of managed policies to attach. No interruption — updates in place
    The quota of 20 attached managed policies per role is a hard limit and not adjustable in the way most IAM quotas are. Large permission sets belong in customer-managed policies with several statements, not in many small attached policies.
    Type
    Array of String
    Required
    No
    Update behaviour
    No interruption
    Items
    0 – 20

    Example values

    • ["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]
  • MaxSessionDuration IntegerLongest session, in seconds, that AssumeRole may issue for this role. No interruption — updates in place
    This is a ceiling, not a duration. The caller still asks for a duration and gets the smaller of the two.
    Type
    Integer
    Required
    No
    Update behaviour
    No interruption
    Default
    3600
    Range
    3600 – 43200

    Example values

    • 3600
  • Path StringA namespace for the role, used for organisation and for wildcard policies. Replacement — CloudFormation creates a new resource and deletes the old one Create-only
    Paths are the closest thing IAM has to folders. Their practical value is in permission boundaries and delegation policies, where arn:aws:iam::*:role/service-roles/payments/* scopes an administrator to one team’s roles.
    Type
    String
    Required
    No
    Update behaviour
    Replacement
    Default
    /
    Pattern
    ^(/|/[\x21-\x7E]+/)$ Must begin and end with a forward slash.
    Length
    0 – 512

    Example values

    • /service-roles/payments/
  • PermissionsBoundary StringARN of a managed policy that caps what this role can ever be granted. No interruption — updates in place
    A boundary grants nothing. Effective permissions are the intersection of the boundary and the role’s policies, so a boundary can only ever subtract.
    Type
    String
    Required
    No
    Update behaviour
    No interruption

    Example values

    • arn:aws:iam::123456789012:policy/acme-developer-boundary
  • Policies Array of InlinePolicyInline policies embedded in the role, deleted with it. No interruption — updates in place
    Inline policies cannot be shared or reused, which is exactly why they are often the right choice: a policy that only makes sense for one role should not be attachable to another, and it should disappear when the role does.
    Type
    Array of InlinePolicy
    Required
    No
    Update behaviour
    No interruption

    InlinePolicy properties

    • PolicyName StringName of the inline policy, unique within the role. Required No interruption — updates in place

      Name of the inline policy, unique within the role.

      Type
      String
      Required
      Yes
      Update behaviour
      No interruption
      Length
      1 – 128

      Example values

      • read-payments-config
    • PolicyDocument JSONThe permission policy document. Required No interruption — updates in place

      The permission policy document.

      Type
      JSON
      Required
      Yes
      Update behaviour
      No interruption
  • Tags Array of TagKey/value tags on the role. No interruption — updates in place

    Key/value tags on the role.

    Type
    Array of Tag
    Required
    No
    Update behaviour
    No interruption
    Items
    0 – 50

    Tag properties

    • Key StringTag key. Required No interruption — updates in place

      Tag key.

      Type
      String
      Required
      Yes
      Update behaviour
      No interruption
      Length
      1 – 128
    • Value StringTag value. Required No interruption — updates in place

      Tag value.

      Type
      String
      Required
      Yes
      Update behaviour
      No interruption
      Length
      0 – 256
updates in place some interruption replacement create-only read-only write-only

Return values

What other resources can read from this one
Ref
Returns the role name without its path. For anything that needs an ARN, use Fn::GetAtt Arn — reconstructing the ARN from this value silently drops the path.

!Ref MyResource → acme-payments-task-role

Fn::GetAtt attributes

AttributeTypeDescriptionExample value
ArnStringThe role’s ARN, including its path. This is what sts:AssumeRole takes and what other trust policies should reference.arn:aws:iam::123456789012:role/service-roles/acme-payments-task-role
RoleIdStringThe role’s unique ID. Stable for the life of the role and regenerated on replacement — which is what makes a deleted-and-recreated role fail policies that pinned the old ID.AROA1EXAMPLEID234567

Required permissions

For the principal running the stack operation

create

  • iam:CreateRole
  • iam:PutRolePolicy
  • iam:AttachRolePolicy
  • iam:TagRole
  • iam:GetRole

read

  • iam:GetRole
  • iam:ListRolePolicies
  • iam:GetRolePolicy
  • iam:ListAttachedRolePolicies
  • iam:ListRoleTags

update

  • iam:UpdateRole
  • iam:UpdateAssumeRolePolicy
  • iam:PutRolePolicy
  • iam:DeleteRolePolicy
  • iam:AttachRolePolicy
  • iam:DetachRolePolicy
  • iam:TagRole
  • iam:UntagRole
  • iam:PutRolePermissionsBoundary

delete

  • iam:DeleteRole
  • iam:DeleteRolePolicy
  • iam:DetachRolePolicy

list

  • iam:ListRoles
{
  "Statement": [
    {
      "Action": [
        "iam:AttachRolePolicy",
        "iam:CreateRole",
        "iam:DeleteRole",
        "iam:DeleteRolePolicy",
        "iam:DetachRolePolicy",
        "iam:GetRole",
        "iam:GetRolePolicy",
        "iam:ListAttachedRolePolicies",
        "iam:ListRolePolicies",
        "iam:ListRoles",
        "iam:ListRoleTags",
        "iam:PutRolePermissionsBoundary",
        "iam:PutRolePolicy",
        "iam:TagRole",
        "iam:UntagRole",
        "iam:UpdateAssumeRolePolicy",
        "iam:UpdateRole"
      ],
      "Effect": "Allow",
      "Resource": "*",
      "Sid": "ManageResource"
    }
  ],
  "Version": "2012-10-17"
}