DEV Community

Nurul Ramadhona for AWS Community Builders

Posted on • Updated on

Create and Manage AWS IAM Policy Using Ansible

Since Part 2, I've mentioned policies such as what's the best practice to attach policy and more. Now, we will discuss Identity-based policy which consists of 2 categories: Managed policy and Inline policy.

The managed policy is divided into 2 categories: AWS-managed policy and customer-managed policy. AWS-managed policy is a policy that AWS already provided and a customer-managed policy is the custom policy created by the customer itself based on what they need and it will be created as the new policy as well as the name.

Inline policy is a policy that you attach directly to an identity. It's a 1:1 trust relationship. When you delete the user, the inline policy will go along with it. This is not the best practice but here I'll just show you that we can do it with ansible.

For the IAM Inline Policy, we use community.aws.iam_policy module. For the IAM Managed Policy, we use community.aws.iam_managed_policy module.

Inline Policy

Create JSON file:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:ListUsers",
                "iam:ListRoles"
            ],
            "Resource": "*"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Task:

    - name: create inline policy
      community.aws.iam_policy:
        iam_type: user
        iam_name: "{{ item.user }}"
        policy_name: "{{ item.policy }}"
        state: present
        policy_json: "{{ item.template }}"
      loop: 
        - { user: "{{ user6 }}", policy: IAMListUsers_Roles, template: "{{ lookup('template', 'inline_policy.json.j2') }}" }
      tags:
        - iam_policy_new_inline
Enter fullscreen mode Exit fullscreen mode

Before we run the playbook, we need an IAM user to be used. I'll create one more along with the access key. Here are the updated tasks:

    - name: create user
      community.aws.iam_user:
        name: "{{ item }}"
        state: present
      loop: 
#        - "{{ user1 }}"
#        - "{{ user2 }}"
#        - "{{ user3 }}"
#        - "{{ user4 }}"
        - "{{ user6 }}"
      tags:
        - iam_user_new ### create user + pass + key
        - iam_user_only ### create user only
        - iam_user_key ### create user + key
        - iam_user_pass ### create user + pass

    - name: create user's key
      community.aws.iam_access_key:
        user_name: "{{ item }}"
        state: present
      loop: 
#        - { name: "{{ user1 }}" }
#        - { name: "{{ user2 }}" }
#        - { name: "{{ user3 }}" }
#        - { name: "{{ user4 }}" }
#        - { name: "{{ user5 }}" }
        - { name: "{{ user6 }}" }
      tags:
        - iam_user_new
        - iam_user_key
        - iam_user_key_only
Enter fullscreen mode Exit fullscreen mode
$ ansible-playbook -i host.yml iam.yml -t iam_user_key

PLAY [iam] *********************************************************************

TASK [create user] *************************************************************
changed: [localhost] => (item=name6)

TASK [create user's key] *******************************************************
changed: [localhost] => (item={'name': 'name6'})
Enter fullscreen mode Exit fullscreen mode

Then, now we're ready to run the playbook:

$ ansible-playbook -i host.yml iam.yml -t iam_policy_new_inline

PLAY [iam] *********************************************************************

TASK [create inline policy] ****************************************************
changed: [localhost] => (item={'user': 'name6', 'policy': 'IAMListUsers_Roles', 'template': {'Version': '2012-10-17', 'Statement': [{'Effect': 'Allow', 'Action': ['iam:ListUsers', 'iam:ListRoles'], 'Resource': '*'}]}})
Enter fullscreen mode Exit fullscreen mode

Check if the policy works! (Please set up the new user as a secondary IAM user first by running aws configure --profile name6 on the localhost. The access key and secret access key are stored in the file named key_list.txt)

$ aws iam list-users --profile name6 | grep UserName
            "UserName": "name5",
            "UserName": "name3",
            "UserName": "name6",
            "UserName": "name1",
            "UserName": "name4",
            "UserName": "name2",

$ aws iam list-roles --profile name6 | grep RoleName
            "RoleName": "aws-ec2-spot-fleet-tagging-role",
            "RoleName": "AWSServiceRoleForAmazonElasticFileSystem",
            "RoleName": "AWSServiceRoleForSupport",
            "RoleName": "AWSServiceRoleForTrustedAdvisor",
            "RoleName": "EC2DemoRole",
            "RoleName": "IAM",
            "RoleName": "IAM_Policy",

$ aws iam list-groups --profile name6

An error occurred (AccessDenied) when calling the ListGroups operation: User: arn:aws:iam::0123456789:user/name6 is not authorized to perform: iam:ListGroups on resource: arn:aws:iam::0123456789:group/
Enter fullscreen mode Exit fullscreen mode

As we can see, user name6 is only allowed to list users and roles as mentioned in the inline policy document.

Managed Policy

Create JSON file:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "iam:GetUser",
            "Resource": "*"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Task:

    - name: create managed policy
      community.aws.iam_managed_policy:
        policy_name: "{{ item.name }}"
        policy: "{{ item.policy }}"
        state: present
      loop: 
        - { name: IAMGetUser_Only, policy: "{{ lookup('template', 'managed_policy.json.j2') }}" }
      tags:
        - iam_policy_new_managed
Enter fullscreen mode Exit fullscreen mode

Run the playbook:

$ ansible-playbook -i host.yml iam.yml -t iam_policy_new_managed

PLAY [iam] *********************************************************************

TASK [create managed policy] ***************************************************
changed: [localhost] => (item={'name': 'IAMGetUser_Only', 'policy': {'Version': '2012-10-17', 'Statement': [{'Effect': 'Allow', 'Action': 'iam:GetUser', 'Resource': '*'}]}})
Enter fullscreen mode Exit fullscreen mode

The task above only creates a managed policy. To attach it to an IAM group and user, I'll use the same task as before. I just need to add new value and comment on the existing one, should look like this:

    - name: create group and add existing users as members
      community.aws.iam_group:
        name: "{{ item.name }}"
        state: present
        users: "{{ item.members }}"
      loop: 
#        - { name: "{{ group1 }}", members: ["{{ user1 }}","{{ user2 }}"] }
        - { name: "{{ group1 }}", members: "{{ user4 }}" }
      tags:
        - iam_group_new_members

    - name: create a user and attach a managed policy
      community.aws.iam_user:
        name: "{{ item.name }}"
        managed_policies: "{{ item.policy }}"
        state: present
      loop: 
#        - { name: "{{ user5 }}", policy: arn:aws:iam::aws:policy/IAMFullAccess }
        - { name: "{{ user3 }}", policy: arn:aws:iam::0123456789:policy/IAMGetUser_Only } 
      tags:
        - iam_user_new_policy

    - name: create group + attach managed policy
      community.aws.iam_group:
        name: "{{ item.name }}"
        managed_policies: "{{ item.policy }}"
        state: present
      loop: 
#        - { name: "{{ group2 }}", policy: arn:aws:iam::aws:policy/IAMReadOnlyAccess }
        - { name: "{{ group1 }}", policy: arn:aws:iam::0123456789:policy/IAMGetUser_Only }
      tags:
        - iam_group_new_policy
Enter fullscreen mode Exit fullscreen mode

Then, I'll run the existing playbook with multiple tags.

$ ansible-playbook -i host.yml iam.yml -t "iam_user_new_policy, iam_group_new_policy, iam_group_new_members"

PLAY [iam] *********************************************************************

TASK [create group and add existing users as members] **************************
changed: [localhost] => (item={'name': 'developer', 'members': 'name4'})

TASK [create a user and attach a managed policy] *******************************
changed: [localhost] => (item={'name': 'name3', 'policy': 'arn:aws:iam::0123456789:policy/IAMGetUser_Only'})

TASK [create group + attach managed policy] ************************************
changed: [localhost] => (item={'name': 'developer', 'policy': 'arn:aws:iam::0123456789:policy/IAMGetUser_Only'})
Enter fullscreen mode Exit fullscreen mode

The tasks above attach policy directly to user name3 and to group developer, also add user name4 into the group. So, the user name3 and all developer group members have the same policy that is IAMGetUser_Only. Check if the policy works:

$ aws iam get-user --user-name name1 --profile name3 | grep UserName
        "UserName": "name1",

$ aws iam get-user --user-name name1 --profile name4 | grep UserName
        "UserName": "name1",

$ aws iam list-users --profile name3

An error occurred (AccessDenied) when calling the ListUsers operation: User: arn:aws:iam::0123456789:user/name3 is not authorized to perform: iam:ListUsers on resource: arn:aws:iam::0123456789:user/

$ aws iam list-users --profile name4

An error occurred (AccessDenied) when calling the ListUsers operation: User: arn:aws:iam::0123456789:user/name4 is not authorized to perform: iam:ListUsers on resource: arn:aws:iam::0123456789:user/
Enter fullscreen mode Exit fullscreen mode

As we can see, the users can get operation but not for the list.

So, we already reached the end of the IAM section. In the next part, we will delete all the things we just created from Part 2 till Part 5. It's optional but in case you need it, I'll show you. Let's move to the last part of this series!

References:

Top comments (0)