DEV Community

Nurul Ramadhona for AWS Community Builders

Posted on • Updated on

Create and Manage AWS IAM Policy Using Ansible

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

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

Inline policy is policy that you attach directly to an identity. It's 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 IAM Inline Policy, we use community.aws.iam_policy module.
For 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 access key. Here are the updated task:

    - 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=daffa)

TASK [create user's key] *******************************************************
changed: [localhost] => (item={'name': 'daffa'})
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': 'daffa', '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 setup the new user as secondary IAM user first by running aws configure --profile daffa on the localhost. The access key and secret access key are stored on the file named key_list.txt)

$ aws iam list-users --profile daffa | grep UserName
            "UserName": "aira",
            "UserName": "beny",
            "UserName": "daffa",
            "UserName": "nurul",
            "UserName": "rahman",
            "UserName": "rama",

$ aws iam list-roles --profile daffa | 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 daffa

An error occurred (AccessDenied) when calling the ListGroups operation: User: arn:aws:iam::0123456789:user/daffa 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 daffa 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 create 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 the existing one, should be 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 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': 'rahman'})

TASK [create a user and attach a managed policy] *******************************
changed: [localhost] => (item={'name': 'beny', '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 beny and to group developer, also add user rahman into the group. So, the user beny and all developer group's members have same policy that's IAMGetUser_Only.
Check if the policy works:

$ aws iam get-user --user-name nurul --profile beny | grep UserName
        "UserName": "nurul",

$ aws iam get-user --user-name nurul --profile rahman | grep UserName
        "UserName": "nurul",

$ aws iam list-users --profile beny

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

$ aws iam list-users --profile rahman

An error occurred (AccessDenied) when calling the ListUsers operation: User: arn:aws:iam::0123456789:user/rahman 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 do get operation but not for list.

So, we already reached to the end of 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 for it. Let's move to the last part of this series!

References:
https://docs.ansible.com/ansible/latest/collections/community/aws/iam_policy_module.html
https://docs.ansible.com/ansible/latest/collections/community/aws/iam_managed_policy_module.html

Top comments (0)