0

I am trying to create new IAM users with Console and CLI access via Ansible. Because of the limitation of access_key_state, I cannot retrieve the Secret Access Key.

So instead, I am creating the API access and secret access keys via command using the AWS CLI.

# Creates the API Access and Secret keys
- name: create access key for {{ item }}
  command: aws iam create-access-key --user-name {{ item }}
  register: user_keys
  with_items:
    - "testuser"
    - "testuser2"

However, every time that I run my playbook, it will try to create the keys. So I have to limit it to only run that task when there is no key already created for that specific user.

I've been trying to achieve that by doing:

- name: list access key for {{ item }}
  command: aws iam list-access-keys --user-name {{ item }}
  register: list_user_keys
  with_items:
    - "testuser1"
    - "testuser2"

# Creates the API Access and Secret keys
- name: create access key for {{ item }}
  command: aws iam create-access-key --user-name {{ item }}
  register: user_keys
  with_items:
    - "testuser1"
    - "testuser2"
  when: list_user_keys.stdout = ""

Error:

TASK [create access key for {{ item }}] ****************************************
fatal: [localhost]: FAILED! => {"msg": "The conditional check 'list_user_keys.stdout = \"\"' failed. The error was: template error while templating string: expected token 'end of statement block', got '='. String: {% if list_user_keys.stdout = \"\" %} True {% else %} False {% endif %}\n\nThe error appears to be in '/tasks/create-user.yml': line 39, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n# Creates the API Access and Secret keys\n- name: create access key for {{ item }}\n  ^ here\nWe could be wrong, but this one looks like it might be an issue with\nmissing quotes. Always quote template expression brackets when they\nstart a value. For instance:\n\n    with_items:\n      - {{ foo }}\n\nShould be written as:\n\n    with_items:\n      - \"{{ foo }}\"\n"}

aws iam list-access-keys --user-name 'testuser1' output:

{
    "AccessKeyMetadata": []
}

What am I missing here?

Edit 1: Adding the {{ list_user_keys.results }} output (Thanks @larsks):

ok: [localhost] => {
    "msg": [
        {
            "ansible_loop_var": "item",
            "changed": true,
            "cmd": [
                "aws",
                "iam",
                "list-access-keys",
                "--user-name",
                "testuser1"
            ],
            "delta": "0:00:01.213801",
            "end": "2020-05-08 12:58:36.338219",
            "failed": false,
            "invocation": {
                "module_args": {
                    "_raw_params": "aws iam list-access-keys --user-name testuser1",
                    "_uses_shell": false,
                    "argv": null,
                    "chdir": null,
                    "creates": null,
                    "executable": null,
                    "removes": null,
                    "stdin": null,
                    "stdin_add_newline": true,
                    "strip_empty_ends": true,
                    "warn": true
                }
            },
            "item": "testuser1",
            "rc": 0,
            "start": "2020-05-08 12:58:35.124418",
            "stderr": "",
            "stderr_lines": [],
            "stdout": "{\n    \"AccessKeyMetadata\": []\n}",
            "stdout_lines": [
                "{",
                "    \"AccessKeyMetadata\": []",
                "}"
            ]
        },

So it looks like that somehow I need to get to the stdout_lines.AccessKeyMetadata output.

Edit 2: Adding the output of the response from @miwa

ok: [localhost] => {
    "res0": {
        "AccessKeyMetadata": [
            {
                "AccessKeyId": "AK___O3",
                "CreateDate": "2020-05-06T22:07:42Z",
                "Status": "Active",
                "UserName": "testuser1"
            },
            {
                "AccessKeyId": "AK___GB",
                "CreateDate": "2020-05-06T22:16:11Z",
                "Status": "Active",
                "UserName": "testuser1"
            }
        ]
    }
}

Edit 3: Still troubleshooting with @miwa

TASK [Optionally store results for further usage] ******************************
fatal: [localhost]: FAILED! => {"msg": "The conditional check 'list_user_keys.results[6].stdout != \"\"' failed. The error was: error while evaluating conditional (list_user_keys.results[6].stdout != \"\"): list object has no element 6\n\nThe error appears to be in 'tasks/create-user.yml': line 39, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Optionally store results for further usage\n  ^ here\n"}

Also, note that the Debug shows me the following for testuser2 who doesn't have any Key created: "stdout": "{\n \"AccessKeyMetadata\": []\n}",

So you see that stdout isn't empty, therefore list_user_keys.results[1].stdout != "" won't work?

Manuela
  • 49
  • 6
  • Your `list_user_keys` variable doesn't have the structure you think it does. Read [the documentation about using `register` in a loop](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#registering-variables-with-a-loop). – larsks May 08 '20 at 00:46
  • thanks! I've edited my question. I'm doing some tests to see how I can get to that result. If you have any examples, please feel free to share. – Manuela May 08 '20 at 01:06

2 Answers2

0

It took me some time but was able to get where I wanted. Thanks @miwa for all the help! Also this and this helped.

My playbook looks like this now:

---
# List access keys for existing users
- name: list access key for {{ item }}
  command: aws iam list-access-keys --user-name {{ item }}
  register: list_user_keys
  with_items:
    - "testuser1"
    - "testuser2"

# Store keys for further usage
- name: Store testuser1 key for further usage
  set_fact:
    key0user0: "{{ list_user_keys.results[0].stdout | from_json }}"
  when:
   - list_user_keys.results[0].stdout != ""

- name: Store testuser2 key for further usage
  set_fact:
    key1user1: "{{ list_user_keys.results[1].stdout | from_json }}"
  when:
   - list_user_keys.results[1].stdout != ""

# Create the API Access and Secret keys if needed
- name: create access key for "testuser1"
  command: aws iam create-access-key --user-name "testuser1"
  register: user0_key
  when:
   - key0user0.AccessKeyMetadata | length == 0

- name: create access key for "testuser2"
  command: aws iam create-access-key --user-name "testuser2"
  register: user1_key
  when:
    - key1user1.AccessKeyMetadata | length == 0

# Display nearly created access and secret keys - if applicable
- name: Access and Secret keys for testuser1
  debug:
    msg: "{{ user0_key.stdout_lines }}"
  when:
   - key0user0.AccessKeyMetadata | length == 0

# Display nearly created access and secret keys - if applicable
- name: Access and Secret keys for testuser2
  debug:
    msg: "{{ user1_key.stdout_lines }}"
  when:
   - key1user1.AccessKeyMetadata | length == 0

With that, my playbook will only create the Access and Secret access keys if the user has none created already.

Please, feel free to comment below if you think there is a better way to achieve this, as I do not have much experience with Ansible.

Update: For further reference.

Manuela
  • 49
  • 6
-1

This is an ongoing debugging answer that will be further improved.

The following tasks should get the access keys and if there are none of them, create the new ones. Its dumb and straightforward because I dont have access to the AWS CLI at the moment to check everything on my machine.

- name: list access key for {{ item }}
  command: aws iam list-access-keys --user-name {{ item }}
  register: list_user_keys
  with_items:
    - "testuser1"
    - "testuser2"

- name: Store user1 key for further usage
  set_fact:
    key0: "{{ list_user_keys.results[0].stdout | from_json }}"
  when:
   - list_user_keys.results[0].stdout != ""

- name: Store user2 key for further usage
  set_fact:
    key1: "{{ list_user_keys.results[1].stdout | from_json }}"
  when:
   - list_user_keys.results[1].stdout != ""

# Create the API Access and Secret keys if needed
- name: create access key for "testuser1"
  command: aws iam create-access-key --user-name "testuser1"
  register: user1_key
  when:
   - list_user_keys.results[0].stdout == ""

- name: create access key for "testuser2"
  command: aws iam create-access-key --user-name "testuser2"
  register: user2_key
  when:
   - list_user_keys.results[1].stdout == ""
miwa
  • 407
  • 6
  • 13
  • I use the oficial module. But the module does not retrieve the secret access key, only the access key. – Manuela May 08 '20 at 00:56
  • So have you tried to use == instead of = in your comparison like this `when: list_user_keys.stdout == ""` ? – miwa May 08 '20 at 00:59
  • Oh, you use loop, I missed that, sorry. You cannot refer to stdout if register a var in loop, use results array instead. P.S. Whoops, I'm too slow :) – miwa May 08 '20 at 01:10
  • thanks for the updated response! I've tried your approach but now I'm getting: `Conditional result was False. Skipped`. – Manuela May 08 '20 at 02:41
  • At least we got rid of the error which is a good sign for me :) I have updated my answer, please let me know is that what you need. – miwa May 08 '20 at 02:55
  • yup.. I've updated my question with the output of your suggestions. Thanks! – Manuela May 08 '20 at 03:03
  • Well, I'm afraid now I don't understand whats your problem? Looks like you are able to create an access key, also to check if its created, and to skip its creation if needed. Do you need some help to combine everything together or there's something else I missed? – miwa May 08 '20 at 03:17
  • yeah i just need to combine it all together.. I am trying here.. but quite new to Ansible – Manuela May 08 '20 at 03:22
  • No problem, updating my answer. Just give me a couple of minutes. – miwa May 08 '20 at 03:22
  • Thanks. Sorry got some errors. I've updated my questions with more details. (BTW - i can't move these comments to a chat 'cause don't have enough reputation) – Manuela May 08 '20 at 03:48
  • No problem, comments are also good enough :) I can see in your error `list_user_keys.results[6].stdout` while there's no `results[6]` in my listing. Anyway, looks like you are right, there's no results[1] as well and we should refer to the first element only. Updating my answer accordingly. – miwa May 08 '20 at 03:52
  • hmm sorry but you're forgetting there are more then one user. So, user A might have a key created already, but user B not.. so we only want to run the task `create access key for {{ item }}` for User B. Your task skipped all of them, even the one that didn't have the key created – Manuela May 08 '20 at 04:03
  • Whoops, you're absolutely right. Updated the answer. It should be done in a more elegant way but unfortunately I cannot debug it on my machine at the moment. Can you please test it works as expected for you now? – miwa May 08 '20 at 04:30
  • thanks for your help! it is skipping for all users again, even the ones that don't have the key created. I'm trying to troubleshoot.... – Manuela May 09 '20 at 00:08