Repository: ansible/ansible

Issue:
iam_role should have a parameter to suppress creation of instance profiles
##### ISSUE TYPE
 - Feature Idea

##### COMPONENT NAME
iam_role

##### ANSIBLE VERSION
```
ansible 2.3.1.0
  config file =
  configured module search path = Default w/o overrides
  python version = 2.7.13 (default, Mar 13 2017, 20:56:15) [GCC 5.4.0]
```

##### CONFIGURATION
Nothing spectacular

##### OS / ENVIRONMENT
Not relevant

##### SUMMARY
When creating custom roles in AWS using the iam_role module, it is not always desirable to create an instance profile and role association. It would be good if the iam_role gains an additional option to suppress the creation of instance profile.

##### STEPS TO REPRODUCE

The standard iam_role example will create a role and instance profile in AWS.

```yaml
- iam_role:
    name: MyTestRole
    assume_role_policy_document: "{{ lookup('file','policy.json') }}"
    state: present
    managed_policy:
      - arn:aws:iam::aws:policy/PowerUserAccess
```
Creation of instance profiles could be suppressed with an additional task parameter `create_instance_profile`:

```yaml
- iam_role:
    name: MyTestRole
    create_instance_profile: no
    assume_role_policy_document: "{{ lookup('file','policy.json') }}"
    state: present
    managed_policy:
      - arn:aws:iam::aws:policy/PowerUserAccess
```

##### EXPECTED RESULTS

`aws iam list-instance-profiles-for-role --role-name MyTestRole`

```json
{
    "InstanceProfiles": []
}
```

##### ACTUAL RESULTS

`aws iam list-instance-profiles-for-role --role-name MyTestRole`

```json
{
  "InstanceProfiles": [
    {
      "InstanceProfileId": "AIIIIIIIPPPPPPPPPPPP2",
      "InstanceProfileName": "MyTestRole",
      "CreateDate": "2017-06-22T16:47:00Z",
      "Path": "/",
      "Arn": "arn:aws:iam::xxxxxxxxxxxx:instance-profile/MyTestRole",
      "Roles": [
        {
          "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
              {
                "Action": "sts:AssumeRoleWithSAML",
                "Effect": "Allow",
                "Condition": {
                  "StringEquals": {
                    "SAML:aud": "https://signin.aws.amazon.com/saml"
                  }
                },
                "Principal": {
                  "Federated": "arn:aws:iam::xxxxxxxxxxxx:saml-provider/ADFS"
                }
              }
            ]
          },
          "RoleId": "ARREDDFGGGGHHHHJJJK34",
          "CreateDate": "2017-06-03T11:56:47Z",
          "RoleName": "MyTestRole",
          "Path": "/",
          "Arn": "arn:aws:iam::xxxxxxxxxxxx:role/MyTestRole"
        }
      ]
    }
  ]
}
```

iam_role should have a parameter to suppress creation of instance profiles
##### ISSUE TYPE
 - Feature Idea

##### COMPONENT NAME
iam_role

##### ANSIBLE VERSION
```
ansible 2.3.1.0
  config file =
  configured module search path = Default w/o overrides
  python version = 2.7.13 (default, Mar 13 2017, 20:56:15) [GCC 5.4.0]
```

##### CONFIGURATION
Nothing spectacular

##### OS / ENVIRONMENT
Not relevant

##### SUMMARY
When creating custom roles in AWS using the iam_role module, it is not always desirable to create an instance profile and role association. It would be good if the iam_role gains an additional option to suppress the creation of instance profile.

##### STEPS TO REPRODUCE

The standard iam_role example will create a role and instance profile in AWS.

```yaml
- iam_role:
    name: MyTestRole
    assume_role_policy_document: "{{ lookup('file','policy.json') }}"
    state: present
    managed_policy:
      - arn:aws:iam::aws:policy/PowerUserAccess
```
Creation of instance profiles could be suppressed with an additional task parameter `create_instance_profile`:

```yaml
- iam_role:
    name: MyTestRole
    create_instance_profile: no
    assume_role_policy_document: "{{ lookup('file','policy.json') }}"
    state: present
    managed_policy:
      - arn:aws:iam::aws:policy/PowerUserAccess
```

##### EXPECTED RESULTS

`aws iam list-instance-profiles-for-role --role-name MyTestRole`

```json
{
    "InstanceProfiles": []
}
```

##### ACTUAL RESULTS

`aws iam list-instance-profiles-for-role --role-name MyTestRole`

```json
{
  "InstanceProfiles": [
    {
      "InstanceProfileId": "AIIIIIIIPPPPPPPPPPPP2",
      "InstanceProfileName": "MyTestRole",
      "CreateDate": "2017-06-22T16:47:00Z",
      "Path": "/",
      "Arn": "arn:aws:iam::xxxxxxxxxxxx:instance-profile/MyTestRole",
      "Roles": [
        {
          "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
              {
                "Action": "sts:AssumeRoleWithSAML",
                "Effect": "Allow",
                "Condition": {
                  "StringEquals": {
                    "SAML:aud": "https://signin.aws.amazon.com/saml"
                  }
                },
                "Principal": {
                  "Federated": "arn:aws:iam::xxxxxxxxxxxx:saml-provider/ADFS"
                }
              }
            ]
          },
          "RoleId": "ARREDDFGGGGHHHHJJJK34",
          "CreateDate": "2017-06-03T11:56:47Z",
          "RoleName": "MyTestRole",
          "Path": "/",
          "Arn": "arn:aws:iam::xxxxxxxxxxxx:role/MyTestRole"
        }
      ]
    }
  ]
}
```



Discussion:
cc @wimnat
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
cc @wimnat
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/cloud/amazon/iam_role.py b/lib/ansible/modules/cloud/amazon/iam_role.py
--- a/lib/ansible/modules/cloud/amazon/iam_role.py
+++ b/lib/ansible/modules/cloud/amazon/iam_role.py
@@ -57,6 +57,12 @@
       - Create or remove the IAM role
     required: true
     choices: [ 'present', 'absent' ]
+  create_instance_profile:
+    description:
+      - Creates an IAM instance profile along with the role
+    type: bool
+    default: true
+    version_added: 2.5
 requirements: [ botocore, boto3 ]
 extends_documentation_fragment:
   - aws
@@ -217,6 +223,7 @@ def create_or_update_role(connection, module):
     if module.params.get('description') is not None:
         params['Description'] = module.params.get('description')
     managed_policies = module.params.get('managed_policy')
+    create_instance_profile = module.params.get('create_instance_profile')
     if managed_policies:
         managed_policies = convert_friendly_names_to_arns(connection, module, managed_policies)
     changed = False
@@ -275,22 +282,23 @@ def create_or_update_role(connection, module):
                 changed = True
 
     # Instance profile
-    try:
-        instance_profiles = connection.list_instance_profiles_for_role(RoleName=params['RoleName'])['InstanceProfiles']
-    except ClientError as e:
-        module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
-    if not any(p['InstanceProfileName'] == params['RoleName'] for p in instance_profiles):
-        # Make sure an instance profile is attached
+    if create_instance_profile:
         try:
-            connection.create_instance_profile(InstanceProfileName=params['RoleName'], Path=params['Path'])
-            changed = True
+            instance_profiles = connection.list_instance_profiles_for_role(RoleName=params['RoleName'])['InstanceProfiles']
         except ClientError as e:
-            # If the profile already exists, no problem, move on
-            if e.response['Error']['Code'] == 'EntityAlreadyExists':
-                pass
-            else:
-                module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
-        connection.add_role_to_instance_profile(InstanceProfileName=params['RoleName'], RoleName=params['RoleName'])
+            module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
+        if not any(p['InstanceProfileName'] == params['RoleName'] for p in instance_profiles):
+            # Make sure an instance profile is attached
+            try:
+                connection.create_instance_profile(InstanceProfileName=params['RoleName'], Path=params['Path'])
+                changed = True
+            except ClientError as e:
+                # If the profile already exists, no problem, move on
+                if e.response['Error']['Code'] == 'EntityAlreadyExists':
+                    pass
+                else:
+                    module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
+            connection.add_role_to_instance_profile(InstanceProfileName=params['RoleName'], RoleName=params['RoleName'])
 
     # Get the role again
     role = get_role(connection, module, params['RoleName'])
@@ -369,7 +377,8 @@ def main():
             assume_role_policy_document=dict(type='json'),
             managed_policy=dict(type='list', aliases=['managed_policies']),
             state=dict(choices=['present', 'absent'], required=True),
-            description=dict(required=False, type='str')
+            description=dict(required=False, type='str'),
+            create_instance_profile=dict(type='bool', default=True)
         )
     )
 


Test patch: