I want to create a user and set a password for him.
First password line and second one in user module doesnt work. Tried to pass it via hash variable, but no luck :)
If I run
and place value into the password line - it works just fine, still i'd like to use my password variable. Can you kindly show the way how i can send its value into this command?
"password | password_hash('sha512', 'mysecretsalt') }}"
.
---
- name: create ssh keys and distribute ssh public key for user
hosts: clients
become: yes
vars:
uname : Jim
create_user : False
password : imuser
tasks:
- name: creating password
set_fact:
hash : "{{ 'password' | password_hash('sha512', 'mysecretsalt') }}"
- debug:
msg : "hashed password is {{ hash }}"
- name: create user if necessary
user:
name: "{{ uname }}"
state: present
password : "password | password_hash('sha512', 'mysecretsalt') }}"
# password : "{{ hash }}"
# password: $6$mysecretsalt$ZfUPIwkf1o9u8P04aJuQCgMfSZoIAeCoZpkbNKKn7LtiI.nQl8UWRIhO.rStaZzM8u0Bja3/9bzgOjagM5whY.
shell : /bin/bash
when: create_user == "True"
- name: get etc/passwd
shell: cat /etc/passwd
register: passwd
- block:
- debug:
var: passwd.stdout
- debug:
var: uname
when: inventory_hostname == "ansible_client1"
- name: create ssh key for user
user:
name: "{{ uname }}"
generate_ssh_key : yes
ssh_key_file : '{{ uname }}_id_rsa'
when: '"uname" in passwd.stdout'
register: create_key
- debug:
var: create_key
And the second question is:
Somehow task "create ssh key for user" is being skipped on ansible_client1 each run after i have deleted the user with userdel and his homedir with rm -rf since it looked weird at first runs of playbook. It works perfectly on 2nd host.
If i check /etc/passwd - user exist for both servers:
[admin#ansible_client1 ~]$ cat /etc/passwd | grep Jim
Jim:x:1004:1005::/home/Jim:/bin/bash
[admin#ansible_client2 Jim]$ cat /etc/passwd | grep Jim
Jim:x:1007:1008::/home/Jim:/bin/bash
User is being created each time on ansible_client1 and homedir is there, still task is being skipped and it looks like uname cannot be found in passwd.stdout somehow.
So... what's might be going on here i wonder
in the second task you have "password | password_hash('sha512', 'mysecretsalt') }}" it must be "{{ password | password_hash('sha512', 'mysecretsalt') }}" to use use te var password or "{{ 'password' | password_hash('sha512', 'mysecretsalt') }}" to use the word password as password.
Related
I'm trying write role to install MySql 8, and get problem with this:
- name: Extract root password from logs into {{ mysql_root_old_password }} variable
ansible.builtin.slurp:
src: "{{ mysql_logfile_path }}"
register: mysql_root_old_password
#when: "'mysql' in ansible_facts.packages"
- name: Extract root password from logs into {{ mysql_root_old_password }} variable
set_fact:
mysql_root_old_password: "{{ mysql_root_old_password.content | b64decode | regex_findall('generated for root#localhost: (.*)$', 'multiline=true') }}"
#when: "'mysqld' in ansible_facts.packages"
- name: Get Server template
ansible.builtin.template:
src: "{{ item.name }}.j2"
dest: "{{ item.path }}"
loop:
- { name: "my.cnf", path: "/root/.my.cnf" }
notify:
- Restart mysqld
on the .my.cnf I get password with quotes and brackets:
[client]
user=root
password=['th6k(gZeJSt4']
How to trim that?
What I try:
- name: trim password
set_fact:
mysql_root_old_password2: "{{ mysql_root_old_password | regex_findall('[a-zA-Z0-9,()!##$%^&*]{12}')}}"
Thanks.
The result of regex_findall is a list because there might be more matches. Take the last item
- set_fact:
mysql_root_old_password: "{{ mysql_root_old_password.content|
b64decode|
regex_findall('generated for root#localhost: (.*)$', 'multiline=true')|
last }}"
From your description
on the .my.cnf I get password with quotes and brackets ... How to trim that
I understand that you like to read a INI file like my.cnf.ini
[client]
user=root
password=['A1234567890B']
where the value of the key password looks like a list with one element in YAML and the structure doesn't change, but you are interested in the value without leading and trailing square brackets and single quotes only.
To do so there are several possibilities.
Via Ansible Lookup plugins
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Extract root password from INI file
debug:
msg: "{{ lookup('ini', 'password section=client file=my.cnf.ini') }}"
register: result
- name: Show result with type
debug:
msg:
- "{{ result.msg }}"
- "result.msg is of type {{ result.msg | type_debug }}"
- "Show password only {{ result.msg[0] }}" # the first list element
Such approach will work on the Control Node.
Like all templating, lookups execute and are evaluated on the Ansible control machine.
Further Q&A
How to read a line from a file into an Ansible variable
What is the difference between .ini and .conf?
Further Documentation
ini lookup – read data from an INI file
Via Ansible shell module, sed and cut.
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Extract root password from INI file
shell:
cmd: echo $(sed -n 's/^password=//p' my.cnf.ini | cut -d "'" -f 2)
register: result
- name: Show result
debug:
msg: "{{ result.stdout }}"
Please take note regarding "I get password with quotes and brackets ... ['<pass>'] ... How to trim that?" that from perspective of the SQL service, .cnf file, [' and '] are actually part of the password!
- name: Server template
template:
src: "my.cnf.ini"
dest: "/root/.my.cnf"
If that is correct they will be necessary for proper function of the service.
I have a remote user without sudo and servers with forbidden ssh for root.
So I try to use next approach for privilege escalation:
- block:
- name: Get hardware password
shell: |
slcli --format json hardware detail --passwords {{ hostname }}
register: json_answer
delegate_to: localhost
- name: set hardwareInfo variable
set_fact:
hardwareInfo: "{{ json_answer.stdout|from_json }}"
- name: set password variable
set_fact:
ansible_become_pass: "{{ hardwareInfo | to_json | from_json | json_query(password_query) }}"
vars:
password_query: "users[?username==`root`].password"
no_log: true
- name: Install repository deb
shell: |
dpkg -i {{ deb_repo_url }}
become: yes
become_method: su
become_user: root
But I get error:
{ "msg": "Incorrect su password", "_ansible_no_log": false }
I checked out ansible_become_pass variable and it has correct password.
Found that my variable was in wrong format (array instead of string).
{
"changed": false,
"ansible_facts": {
"ansible_become_pass": [
"my_password"
]
},
"_ansible_no_log": false
}
Changed set_fact to this and now it's works
- name: set password variable
set_fact:
ansible_become_pass: "{{ hardwareInfo | to_json | from_json | json_query(password_query) | join('') }}"
I am writing a playbook to create a user if it does not exist. If it exist then it ask again for a new username. It must ask again for new user input. But var_promt runs only one time. How can I do that?
- name: An example prompting playbook
hosts: all
vars_prompt:
- name: username
prompt: "Enter a username"
tasks:
- name: Print out your input
debug:
msg: "You provided the {{ username }} for the prompt"
- name: User Exist
command: grep {{ username }} /etc/passwd
ignore_errors: yes
register: user_exist
- name: User Existance output
debug: var=user_exist.stdout
- name: User creation
user: name={{ username }}
when: user_exist.stdout is not match(".*:.*:.*:.*::.*:")
- name: Display Message
debug:
msg: "User {{ username }} already exists"
when: user_exist.stdout is match(".*:.*:.*:.*::.*:")
- name: User check
command: id {{ username }}
ignore_errors: yes
register: ID
- name: UserID of Username
debug: var=ID.stdout
name: An example prompting playbook
hosts: localhost
vars_files:
/root/users.yml
tasks:
name: Create deploy user
user:
name: "{{ item.name }}"
shell: "{{ item.shell }}"
password: "{{ lookup('password', '/tmp/{{ item.name }}.txt chars=ascii_letters') | password_hash('sha512') }}"
createhome: yes
groups: "{{ item.groups }}"
update_password: on_create
with_items: "{{ users }}"
I am trying to check if inventory_hostname is in a list into an imported variable.
vars/users.yml file:
---
users:
- username: user1
comment: "User 1"
group: admin
password: "sha password"
keys:
active:
- "ssh-rsa etc"
admin: yes
- username: user2
comment: "User 2"
group: users
groups: deployer
keys:
active:
- "ssh-rsa etc"
hosts:
user:
- host1
- host2
deployer:
- host3
I want to execute a task only if inventory_hostname is into any of hosts lists (user, deployer, others ...).
I tried this:
- name: Create users
user:
name: "{{ item.username }}"
comment: "{{ item.comment | default('User {{item.username}}') }}"
password: "{{ item.password | default('!') }}"
state: "{{ item.state | default('present') }}"
shell: "{{ item.shell | default('/bin/bash') }}"
group: "{{ item.group | default('users') }}"
with_items: '{{ users }}'
when: item.username is defined and ((item.admin is defined and item.admin == True) or (item.hosts is defined and item.hosts.user is defined and inventory_hostname in item.hosts.user)
It works for user1 (which have admin enabled) but not for user2 (if this play is executed on host1 which is included into user2's hosts.user list).
Well .. I tried your code snippet and it works well for both users. Only thing which can make it fail is that hostnames in item.host.user are not matching the inventory_hostname. You can try to debug the inventory_hostname before this task to see what are the inventory hostnames read by ansible and whether you have specified them correctly in item.host.user list.
- debug: var=inventory_hostname
I want to be able to change the userid within a playbook and then get the home directory on a host for that userid. How would I do this?
I know I can change the userid with 'become:' and 'become_user:', but that works at the task level. I can get the home directory with the '{{ lookup('env', 'HOME) }}' variable, but that seems to work at the playbook level. This was my latest attempt:
---
- hosts: all
vars:
user_id: "{{ userid }}"
tasks:
- set_fact:
home_dir: "{{ lookup('env', 'HOME') }}"
become: yes
become_user: "{{ user_id }}"
- debug:
msg: "Variable values: user_id: {{ user_id }} home_dir: {{ home_dir }}"
My command looked like this:
$ ansible-playbook myplaybook.yaml --limit MYHOSTS --extra-vars "userid=myid"
This was the response:
ok: [host-01] => {
"msg": "Variable values: user_id: myid home_dir: /root"
}
ok: [host-02] => {
"msg": "Variable values: user_id: myid home_dir: /root"
}
ok: [host-03] => {
"msg": "Variable values: user_id: myid home_dir: /root"
}
Is there a way I can change the userid to "myid" and get the playbook to know that the home directory is "/home/myid"?
Thanks!
When you use become and become_user, you're actually telling Ansible to change the current user, from what it initially logged-in with.
As per Ansible Docs:
These Directives (become, become_user, etc.) can be set from play to task level, but are overridden by connection variables as they can be host specific.
You must also note that by using the above syntax, you are actually activating a privilege escalation method, to become a non-privileged user. This is rather risky with quite a few limitation. Please read here: Becoming an Unprivileged User.
I hope the following play, will give you clearer picture:
---
- hosts: all
gather_facts: no
remote_user: "{{ userid }}"
tasks:
- name: first_task
register: first_task
shell: "whoami"
- name: become-root
register: become-root
shell: "whoami"
become: yes
become_user: root
- name: final_task
register: final_task
shell: "whoami"
You should run the above, by executing this command:
# ansible-playbook playbook.yaml -i /path/to/inventory/hosts -e "userid=myid"
It will return:
first_task --> myid
become-root --> root
final_task --> myid
Note: You can also override remote_user, separately for each task.
But if you still require to do it your own way, you can try this one:
---
- hosts: all
vars:
user_id: "{{ userid }}"
tasks:
- set_fact:
home_dir: "{{ lookup('env', 'HOME') }}"
become: true
- debug:
msg: "Variable values: user_id: {{ userid }} home_dir: {{ home_dir }}"
when: userid is defined
Run with this command:
# ansible-playbook myplaybook.yaml -i path/to/inventory/hosts --limit MYHOSTS --become-user=myid --extra-vars "userid=myid"
And finally, if none of these did what you were after, try getting the home directory, by using the command module and then retrieve its output by first registering it, and then using {{ registered_name.stdout_lines }}:
- name: user_home
register: user_home
action: command eval echo "~{{ userid }}"
- debug:
msg: "Home path is {{ user_home.stdout_lines }}
Using this last workaround, you don't even need to change user as it prints out the home directory for user userid.
# ansible-playbook myplaybook.yaml -i path/to/inventory/hosts --limit MYHOSTS -e "userid=myid"
Hope it helped; but this very question was asked before. You might be able to find more details here: How to switch a user per task or set of tasks?.