1

Ansible version 2.7.9

I'm writing an ansible playbook to deploy an piece of software to a linux environment. SSH access to these systems is protected by a CPM (Cyberark), used as an ssh key manager.

I've got most of the logic figured out, save for one piece. The playbook needs to loop through hosts in an inventory group, lookup the ssh private key in Cyberark for each host and then use each key to ssh into each host in the inventory group to install the software. I'm struggling with how to make that work in ansible.

I've read through the add_host and cyberarkpassword documentation, as well about 4 hours worth of searching stackoverflow and blogs, and couldn't find a single example even close to what I'm trying to do.

As far as how I think it should work:

  • Using the cyberarkpassword lookup module, loop through hosts in inventory group specified by {{ env }}. Value for this will be passed in through --extra-args.
  • Retrieve the ssh private key for each host.
  • Register the output from the lookup, and copy to disk, again looping through each host, and naming the file with {{ inventory_hostname }}.pem
  • Finally, to consume it in the next play, set a variable ansible_ssh_common_args: "-o StrictHostKeyChecking=no -i {{ deploy_temp_dir}}/keys/{{ inventory_hostname }}.pem"

But I can't figure out how to put the loop-lookup-write to disk piece together.

Sample inventory file

[local]
localhost

[local:vars]
ansible_connection=local

[corp:children]
corp-onprem-dev
corp-onprem-stage
corp-onprem-prod
corp-cloud-dev
corp-cloud-stage
corp-cloud-dev

[corp-onprem-dev]
host1
host2
host3

[corp-onprem-stage]
host1
host2
host3
[corp-onprem-prod]
host1
host2
host3
[corp-cloud-dev]

[corp-cloud-stage]

[corp-cloud-prod]

deploy.yml -- this code does not work, just my attempt at figuring it out.

- name: retrieve ssh keys for hosts in the specified group, and write them to disk
  hosts: local
  gather_facts: no
  tasks:
    - name: lookup ssh private key for each host
      debug: msg={{ lookup("cyberarkpassword", cyquery)}}
      vars:
        cyquery:
          appid: 'myapp'
          query: 'Safe=mysafe;Folder=Root;Object={{ env[0] }}'
          output: 'Password'
      loop: groups['{{ env }}']
      register: sshkeys
    - name: Copy ssh key to disk
      copy:
        content: "{{ sshkeys }}"
        dest: "{{ deploy_temp_dir }}/keys/{{ env[0] }}.pem"
        mode: 0600
      loop: {{ env }}
0

register a debug task to try and get output is messy. I consider debug an output only, not an input.

Rather, remove the debug task. In the copy task, loop over your hosts and do the cyberarkpassword lookup on the loop variable "item". I assume that "env" contains the Ansible host group in question.

- name: Copy ssh key to disk
  copy:
    content: "{{  lookup("cyberarkpassword", cyquery) }}"
    dest: "{{ deploy_temp_dir }}/keys/{{ item }}.pem"
    mode: 0600
  vars:
    cyquery:
      appid: 'myapp'
      query: 'Safe=mysafe;Folder=Root;Object={{ item }}'
      output: 'Password'
  loop: groups['{{ env }}']

Ideally your ssh_config is configured to use the correct key, such as with an IdentityFile directive in a Host or Match block.

Use ssh-add to add the keys to your agent.

  • That worked! I didn't think you could use a lookup inside the content block of the copy module.. guess I need to read more about how lookup plugins work, will do. In case you or anyone else is interested, will post the final code. – Austin H Jun 15 '19 at 20:21
  • You can use Jinja and thus lookups for almost any value in Ansible playbooks, variables, and templates. The other trick is knowing that item is the default loop_var. – John Mahowald Jun 15 '19 at 22:37
0

Thanks to John Mahowald for this one. Performing the cyberarkpassword lookup inside the copy module's content field, looping through each host and copying to disk worked like a charm. Had a tweak a few other things, seen below.

Final (working) code (with certain details omitted):


- name: retrieve ssh keys for hosts in the specified group, and write them to disk
  hosts: local
  gather_facts: no
  vars_files:
    - vars.yml
  tasks:
    - name: Lookup ssh key for each host and copy to disk
      copy:
        content: "{{  lookup('cyberarkpassword', cyquery)[0]['password']}}"
        dest: "{{ deploy_temp_dir }}/keys/{{ item }}.pem"
        mode: 0600
      vars:
        cyquery:
          appid: 'myapp'
          query: 'Safe=mysafe;Folder=Root;Object={{ item }}'
          output: 'Password'
      with_items: "{{ groups[env] }}"

Knowing you can use python vars inside the dict specified for with_items tied it all together.

When executing this, I run ansible-playbook -i site.ini deploy.yml --extra-vars="env=corp-onprem-dev". Works beautifully now!

PLAY [prep execution environment] *********************************************************************************************************************************************************************************************************

TASK [create temp dir] ********************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [create dir for keys] ****************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [download agent binaries] ************************************************************************************************************************************************************************************************************
ok: [localhost]

PLAY [retrieve ssh keys for hosts in the specified group, and write them to disk] *********************************************************************************************************************************************************

TASK [Lookup ssh key for each host and copy to disk] **************************************************************************************************************************************************************************************
ok: [localhost] => (item=host1)
ok: [localhost] => (item=host2)
ok: [localhost] => (item=host3)

PLAY RECAP ********************************************************************************************************************************************************************************************************************************
localhost                  : ok=4    changed=0    unreachable=0    failed=0   

Thank you so much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.