version: "0.2"
title: Create An IAM Role and Policy
description: This wizard will create a new IAM role for you
plan:
  ask_role_name:
    shortname: Intro
    description: Provide role name and description
    values:
      role_name:
        type: prompt
        description: Role name
      role_description:
        type: prompt
        description: Role description
  decide_role_type:
    shortname: Trusted Entity
    description: Select the trusted entity for the role
    values:
      # This will prompt the user using the 'description' value.
      # The value the user enters is saved under the global variable
      # 'name'.
      role_type:
        type: prompt
        description: Select type of trusted entity
        choices:
          # There's also Web Identity and SAML but we're skipping that.
          - display: AWS Service
            actual_value: aws_service
          - display: This AWS Account
            actual_value: this_aws_account
          - display: Another AWS Account
            actual_value: aws_account
      service_name:
        type: prompt
        description: Choose the service that will use this role
        condition:
          variable: role_type
          equals: aws_service
        choices:
          - display: Amazon EC2
            actual_value: ec2
          - display: AWS Lambda
            actual_value: lambda
          - display: AWS CodeBuild
            actual_value: codebuild
          - display: Amazon EventBridge
            actual_value: events
      account_id:
        type: prompt
        description: Enter the Account ID that can use this role
        condition:
          variable: role_type
          equals: aws_account
      this_account_id:
        # We need a separate condition here because
        # the key for the value is associated with a single set of steps
        # to populate this value.  Ideally we could have an "output_var"
        # that lets us populate other vars so could have a single "account_id"
        # that could be populated by any number of different values.
        type: apicall
        condition:
          variable: role_type
          equals: this_aws_account
        operation: sts.GetCallerIdentity
        params: {}
        query: Account
      trust_policy:
        type: template
        value: |
          {{
            "Version": "2008-10-17",
            "Statement": [
                {{
                    "Action": "sts:AssumeRole",
                    "Principal": {{
                        {% if {role_type} == aws_service %}
                        "Service": "{service_name}.amazonaws.com"
                        {% endif %}
                        {% if {role_type} == aws_account %}
                        "AWS": "arn:aws:iam::{account_id}:root"
                        {% endif %}
                        {% if {role_type} == this_aws_account %}
                        "AWS": "arn:aws:iam::{this_account_id}:root"
                        {% endif %}
                    }},
                    "Effect": "Allow",
                    "Sid": ""
                }}
            ]
          }}
  ask_role_permissions:
    shortname: Permissions
    description: Attach permissions policies
    # The console by default asks you to pick an existing policy
    # to attach to.  We'll just go with that behavior for now.
    values:
      version_id:
        type: apicall
        operation: iam.GetPolicy
        params:
          PolicyArn: "{policy_arn}"
        query: "Policy.DefaultVersionId"
        cache: true
      policy_document:
        type: apicall
        operation: iam.GetPolicyVersion
        params:
          PolicyArn: "{policy_arn}"
          VersionId: "{version_id}"
        query: "PolicyVersion.Document"
        cache: true
      existing_policies:
        type: apicall
        operation: iam.ListPolicies
        params:
          Scope: All
        query: "sort_by(Policies[?IsAttachable==`true`&&Path!=`/aws-service-role/`].{display: PolicyName, actual_value: Arn}, &display)"
        cache: true
        paginate: true
      policy_arn:
        type: prompt
        description: Choose a policy to attach
        choices: existing_policies
        details:
          value: policy_document
          output: json
          description: "Policy Document"
  ask_profile_config:
    shortname: CLI config
    description: Determine CLI configuration
    values:
      wants_config_profile:
        type: prompt
        description: Do you want to create a new CLI profile with this role?
        choices:
          - display: Yes
            actual_value: yes
          - display: No
            actual_value: no
      new_profile_name:
        type: prompt
        description: Enter the name of the new profile
        condition:
          variable: wants_config_profile
          equals: yes
      existing_profiles:
        type: sharedconfig
        operation: ListProfiles
      source_type:
        type: prompt
        description: Select the credential source
        condition:
          variable: wants_config_profile
          equals: yes
        choices:
          - display: Source Profile
            actual_value: wants_source_profile
          - display: Environment Variables
            actual_value: wants_env_source
          - display: EC2 Instance Metadata
            actual_value: wants_imds_source
          - display: ECS Container Task Role
            actual_value: wants_ecs_source
      source_profile:
        type: prompt
        description: Name of the source profile
        choices: existing_profiles
        condition:
          variable: source_type
          equals: wants_source_profile
  preview:
    shortname: Preview
    description: Preview results
    values:
      cli_config_cmd:
        type: template
        value: |
          {% if {source_type} == wants_source_profile %}
          aws configure set source_profile {source_profile} --profile {new_profile_name}
          {% endif %}
          {% if {source_type} == wants_env_source %}
          aws configure set credential_source Environment --profile {new_profile_name}
          {% endif %}
          {% if {source_type} == wants_imds_source %}
          aws configure set credential_source Ec2InstanceMetadata --profile {new_profile_name}
          {% endif %}
          {% if {source_type} == wants_ecs_source %}
          aws configure set credential_source EcsContainer --profile {new_profile_name}
          {% endif %}
      preview_cli_command_value:
        type: template
        value: |
          aws iam create-role \
            --role-name "{role_name}" \
            --description '{role_description}' \
            --assume-role-policy-document \
            '{{"Version": "2008-10-17","Statement":
             [{{"Action": "sts:AssumeRole","Principal":
             {% if {role_type} == aws_service %}
             {{"Service": "{service_name}.amazonaws.com"}}{% endif %}
             {% if {role_type} == aws_account %}
             {{"AWS": "arn:aws:iam::{account_id}:root"}}{% endif %}
             {% if {role_type} == this_aws_account %}
             {{"AWS": "arn:aws:iam::{this_account_id}:root"}}{% endif %}
          ,"Effect": "Allow","Sid": ""}}]}}'

          aws iam attach-role-policy \
            --role-name "{role_name}" \
            --policy-arn '{policy_arn}'

          {% if {wants_config_profile} == yes %}
          {cli_config_cmd}

          role_arn=$(aws iam get-role --role-name "{role_name}" \
            --query Role.Arn --output text)

          aws configure set role_arn "$role_arn" --profile {new_profile_name}
          {% endif %}
      preview_cfn_template_value:
        type: template
        value: |
          Resources:
            {role_name}:
              Type: "AWS::IAM::Role"
              Properties:
                RoleName: {role_name}
                {% if '{role_description}' != '' %}
                Description: {role_description}
                {% endif %}
                AssumeRolePolicyDocument:
                  Version: 2012-10-17
                  Statement:
                    - Effect: Allow
                      Principal:
                      {% if {role_type} == aws_service %}
                        Service:
                          - {service_name}.amazonaws.com
                      {% endif %}
                      {% if {role_type} == aws_account %}
                        AWS:
                          - arn:aws:iam::{account_id}:root
                      {% endif %}
                      {% if {role_type} == this_aws_account %}
                        AWS:
                          - arn:aws:iam::{this_account_id}:root
                      {% endif %}
                      Action:
                        - 'sts:AssumeRole'
                      Sid: ''
                ManagedPolicyArns:
                  - {policy_arn}
      preview_value:
        type: template
        value: |
          {%if {preview_type} == preview_cli_command %}
          {preview_cli_command_value}
          {% endif %}
          {%if {preview_type} == preview_cfn_template %}
          {preview_cfn_template_value}
          {% endif %}
      preview_type:
        type: prompt
        description: Select an preview format
        choices:
          - display: None
            actual_value: preview_none
          - display: AWS CLI command
            actual_value: preview_cli_command
          - display: AWS CloudFormation template
            actual_value: preview_cfn_template
        details:
          value: preview_value
          visible: True
          description: "Preview"
  __DONE__:
execute:
  default:
    - type: apicall
      operation: iam.CreateRole
      params:
        RoleName: "{role_name}"
        AssumeRolePolicyDocument: "{trust_policy}"
        Description: "{role_description}"
      output_var: created_role_arn
      query: Role.Arn
    - type: apicall
      operation: iam.AttachRolePolicy
      params:
        RoleName: "{role_name}"
        PolicyArn: "{policy_arn}"
  write_config_file:
    - type: sharedconfig
      operation: SetValues
      condition:
        variable: wants_config_profile
        equals: yes
      profile: "{new_profile_name}"
      params:
        source_profile: "{source_profile}"
        # This role_arn comes from the `output_var` in the previous
        # executor step.
        role_arn: "{created_role_arn}"
__OUTPUT__:
  value: |
    Wizard successfully created role with following properties:
      Role name: {role_name}
      Role ARN: {created_role_arn}

    {% if {preview_type} == preview_cli_command %}
    Steps to create role is equivalent to running the following sample AWS CLI commands:

    {preview_cli_command_value}
    {% endif %}
    {% if {preview_type} == preview_cfn_template %}
    Steps to create role is equivalent to deploying the following sample AWS CloudFormation template:

    {preview_cfn_template_value}
    {% endif %}
