Ansible ssh public keys copying - ssh

I want to create new user and then copy SSH key to this users dir (I've got this key before executing role). After that I'd like to disable password login.
Here's what I've got for now:
My tasks/main.yml
- name: Add users
user: name={{ item }}
groups=users,wheel
update_password=on_create
password=$6$QoFz/cLhsroToP$4...
with_items:"{{ list }}"
- name: Copy SSH keys
authorized_key: user={{ item }} key={{ item }}.pub state=present
with_items: "{{ list }}"
My vars/main.yml file:
list:
- 'user1'
- 'user2'
- 'user3'
And here's my question - where are my keys stored? Is that form of copying correct?
I've got an error:
failed: [127.0.0.1] => (item=user1) => {"failed": true, "item": "user1"}
msg: invalid key specified: user1.pub

The second task will fail as authorized_key expects the key parameter to be a string ( authorized_key docs ). You can still use the list parameter to get the content of the key file, but you will have to use a lookup.
So this is what the second task might look like:
- name: "Copy SSH Keys"
authorized_key: user={{ item }} key={{ lookup('file', item) }} state=present
To answer your question "Where would the file be stored, that's entirely up to you. By default ( If you don't specify a path ) the module will look into all the files/ directories available. So if it's a role it will look into:
/roles/your_role/files
/files
./files
Lookups docs

Thanks for answer, i could'nt comment your post, beacuse my answer would be too long.
I can finally see keys from ansible side, but the task still fails. Here's the output:
failed: [127.0.0.1] => (item=user1) => {"failed": true, "item": "user1"}
msg: this module requires key=value arguments (['user=user1', 'key=ssh-rsa', 'AAAAB3NzaC1yc2EAAAADAQABAAA...', 'user#domain', 'state=present'])
Am I doing something wrong?
FOUND THE ANSWER!
Quoting the key inputs solves the problem, so the function in my case should look like this:
- name: "Copy SSH Keys"
authorized_key: user="{{ item }}" key="{{ lookup('file', item) }}" state=present
Hope it will help someone in the future. Thanks a lot for help!

Related

Unable to set default value for set_fact in Ansible

Lets consider the user passes a Number parameter to my ansible-playbook as
ansible-playbook /app/test.yml
-e "Number=22235_ReDep_292001105550"
I want set_fact "Number_New" to be the string before the first underscore "_" i.e 22235 and "Status" to be everything after the first underscore "_" i.e
Expectation:
Number_New should be "22235"
Status should be "ReDep_292001105550"
Second scenario; the user may pass -e "Number=22235". This this case i want the set_fact "Number_New" should be same as the "Number=22235" passed while the Status should be "%" modulus symbol.
Expectation:
Number_New should be "22235"
Status should be "%"
Below is my playbook attempt which works fine when parameter passed is "Number=22235_ReDep_292001105550" but fails when -e "Number=22235"
tasks:
- name: Populate number and status from user input
set_fact:
Number_New: "{{ Number.split('_')[0] | default(Number) }}"
Status: "{{ Number.split('_')[1] }}_{{ Number.split('_')[2] | default('%') }}"
Error when it fails:
fatal: [localhost]: FAILED! => {
"msg": "The task includes an option with an undefined variable. The error was: list object has no element 1\n\nThe error appears to be in '/app/test.yml': line 32, column 6, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: Populate number and status from user input\n ^ here\n"
}
The task below does the job
- set_fact:
Number_New: "{{ nsplit.0 }}"
Status: "{{ nsplit.1|default('%') }}"
vars:
nsplit: "{{ Number.split('_', 1) }}"

How to use wildcard for ansible output

I am trying to use wildcard for my ansible variable but it seems like i cant manage to use it.
I have tried something from here but still the same.
the ansible output
"reboot_required": false,
"updates": {
"0720a128-90b1-4b21-a8cf-3c5c86239435": {
"kb": [
"2267602"
],
"installed": false,
"id": "0720a128-90b1-4b21-a8cf-3c5c86239435",
"categories": [
"Definition Updates",
"Windows Defender"
],
"title": "Definition Update for Windows Defender Antivirus - KB2267602 (Definition 1.297.412.0)"
},
"60bbf4af-afd3-45fe-aad2-6d72beddeba2": {
"kb": [
"4509475"
],
"installed": false,
"id": "60bbf4af-afd3-45fe-aad2-6d72beddeba2",
"categories": [
"Updates",
"Windows Server 2016"
],
"title": "2019-06 Cumulative Update for Windows Server 2016 for x64-based Systems (KB4509475)"
I am trying to get the title, or id
- name: debug
debug:
msg: "{{ item.updates.*.id }}"
with_items:
- "{{ result }}"
appreciate the help
Given the ansible output above is stored in the variable result the tasks below
- set_fact:
id_list: "{{ result.updates|
json_query('*.id')
}}"
- debug:
var: id_list
give the list of id (similar titles)
id_list:
- 0720a128-90b1-4b21-a8cf-3c5c86239435
- 60bbf4af-afd3-45fe-aad2-6d72beddeba2
And the tasks below
- set_fact:
my_list: "{{ result.updates|
json_query('*.{ id: id, title: title }')
}}"
- debug:
var: my_list
give the list of the id, title hashes
my_list:
- id: 0720a128-90b1-4b21-a8cf-3c5c86239435
title: Definition Update for Windows Defender Antivirus - KB2267602 (Definition 1.297.412.0)
- id: 60bbf4af-afd3-45fe-aad2-6d72beddeba2
title: 2019-06 Cumulative Update for Windows Server 2016 for x64-based Systems (KB4509475)
The wildcard he's using in the example that you linked is apart of the json_query filter. He's piping to the json_query filter and then using the wildcard as part of that syntax.
results | json_query('[].block_device_mapping.*.snapshot_id')
You're not using json_query in your example and therefore, this syntax is not available and won't work.
Try piping your results to json_query and then including the path that you want to get to. If {{ results }} is already created you can leave off the with_items and go with something like:
{{ results | json_query('updates.*.id') }}
I'm guessing here at the exact syntax but you definitely have to start with json_query.
To figure out the exact syntax you want, start small piping to json_query and then grabbing the top most element(updates, in your case), adding pieces to the filter until you've narrowed it down to the information you want. I've linked to a pathfinder below that helps.
Reference:
json_query filter documentation
json_query documentation
jsonpath finder to help you figure stuff out easier.
edit: The syntax in the first part of the answer from Vladimir looks way sexier than what I'm guessing at. Try his syntax to get to what works, use my answer to understand what's wrong. Then mark him as the correct answer.
Try below. I have not tested it though.
- name: debug
debug:
msg: "{{ item|first }}:{{ item[item|first].title }}"
with_items:
- "{{ result.updates }}"

Ansible variable list span

When adding a variable list in Ansible how would one achieve a span of similar values? For instance "000-100" - in an Ansible hosts file this can be done by listing like so, "hostname-[a:v].com". Would this process be the similar in a variable list?
My use case is to provision many VM's within oVirt in a single go without having to make a line by line list.
---
- name: Create VM based on template
hosts: ovirt-engine
become: yes
become_method: sudo
vars:
- temp: '{{temp_fedora25}}'
- iname:
- db-aa
- db-ab
- db-ac
tasks:
- name: Giving Birth to lil Baby VM's
ovirt:
user: '{{ovirt_usr}}'
password: '{{ovirt_pass}}'
url: '{{engine_url}}'
instance_name: "{{item}}"
instance_nic: ovirtmgmt
resource_type: template
image: '{{temp}}'
zone: superblade-a
disk_alloc: preallocated
with_items: "{{iname}}"
You can use sequence lookup:
- name: numeric
debug:
msg: "{{ item }}"
with_sequence: start=1 count=10 format=server-%0d
- name: characters from small 'a'
debug:
msg: "{{ item }}"
with_sequence: start=0x61 count=10 format=server-%c
- name: save for future use
set_fact:
my_seq: "{{ lookup('sequence','start={} count={} format={}{}'.format(beg,cnt,pref,fmt),wantlist=True) }}"
vars:
beg: 1
cnt: 10
pref: host-
fmt: '%0d'
You can skip set_fact and define my_seq in vars section, but if you use my_seq much, list generation will be done internally every time. With set_fact list is generated once.
With respect to the correct answer from Konstantin, I'm adding the full solution as per my case....
My goal is to be able to reuse the sequenced values as registered variables in order to pass the instance name to host name. This works so far but Im sure it can be streamlined by nesting variables perhaps?
---
- name: Create VM based on template
hosts: ovirt-engine
become: yes
become_method: sudo
vars:
- temp: '{{temp_fedora25}}'
- host_pre: db
- host_seq: a%c
- host_cnt: 3
- host_srt: 0x61
tasks:
- name: Giving Birth to lil Baby VM's
ovirt:
user: '{{ovirt_usr}}'
password: '{{ovirt_pass}}'
url: '{{engine_url}}'
instance_name: "{{item}}"
instance_nic: ovirtmgmt
resource_type: template
image: '{{temp}}'
zone: superblade-a
disk_alloc: preallocated
with_sequence: start="{{host_srt}}" count="{{host_cnt}}" format="{{host_pre}}-{{host_seq}}"

Paste sensitive data the ansible way

Let's suppose i have some applications inside a repository. Sensitive data, like database username+password, are not stored inside the repository but are in a separate encrypted password database. Within the source code are only place-holders like this: %%mysqlpassword%%.
I want to create an ansible-playbook to checkout the code and replace the user-credentials.
I have two ideas to do so:
with a template or
with the replace module.
Is there a best practise way to accomplish this task?
---
- hosts: test
vars_prompt:
- name: "mysqlpassword"
prompt: "Enter mysql password for app"
private: yes
tasks:
- name: copy code from repo
subversion: repo=https://repo.url.local/app dest=/srv/www/app
- name: Replacement of sensitive data by templating
template: src=mysqlconnect.php.j2 dest=/srv/www/app/inc/mysqlconnect.php
- name: Replacement of sensitive data by replacement function
replace: dest=/srv/www/app/inc/mysqlconnect.php regexp='%%mysqlpassword%%' replace='{{ mysqlpassword }}'
The best answer to your question is use ansible-vault.
1- use mysqlpassword as variable {{ mysqlpassword }} inside your template mysqlconnect.php.j2
2- create separate file like my_very_secure.yml(whatever name you want) with all the values of your secure username and password:
---
mysqlpassword: very-secure-password-value
anothervariable: another-secure-value
After that you can encrypt this file with ansible-vault:
ansible-vault encrypt my_very_secure.yml
Then you can store this file into source control server because it's encrypted or leave it on the ansible master server, but once you are ready to run the playbook just include the --ask-vault-pass option like this and path to your secure file:
ansible-playbook -i yourhostfile yourplaybook.yml -e#/path-to-your-file/my_very_secure.yml --ask-vault-pass
Hope this will help you.

Remove quotes from Ansible variable output

I'm using this task to add a line to a file:
lineinfile: "dest={{ ansible_env.HOME }}/{{ deploy_dir }}/config/deploy/{{ stage_name }}.rb
insertbefore='# role-based syntax'
line='server "'{{ ip_addr }}'", user: "'{{ user_name }}'", roles: %w{'{{ role }}'}'"
Which adds this line:
server '172.16.8.11', user: 'vagrant', roles: %w{'api'}
But I don't want the quotes around api. Instead I want this output:
server '172.16.8.11', user: 'vagrant', roles: %w{api}
Actually the quotes do not come from the variable, but are right there in your string:
%w{'{{ role }}'}
Now the solution is little bit tricky though. Because you can not simply remove the quotes like that:
%w{{{ role }}}
This would result into a parse error, since {{ starts an expression...
The solution is to write the outer parentheses, which are meant to be in the string, as an expression themselves.
So to output { you would instead write {{'{'}} and instead of } you would write {{'}'}}. Does that make sense? You're instructing the template engine (Jinja2) to output the parentheses to avoid the parsing error:
%w{{'{'}}{{ role }}{{'}'}}
But since role is an expression already, you just also can group it together into one single expression:
%w{{ '{'+role+'}' }}
Your whole task would then read like this:
- lineinfile:
dest: "{{ ansible_env.HOME }}/{{ deploy_dir }}/config/deploy/{{ stage_name }}.rb"
insertbefore: "# role-based syntax"
line: "server '{{ ip_addr }}', user: '{{ user_name }}', roles: %w{{ '{'+role+'}' }}"
This also is converted into proper YAML syntax because this quoted k=v format is just really hard to read. :)