ansible - copy key to authorized keys file - ansible

I have created a user using ansible and now would like to copy the .ssh/id_rsa.pub file to the authorized_keys file.
I checked the authorized_keys module but that is used to copy the keys from the host machine to the guest.
Wondering what would the right approach.
- name: Adding user - {{ user }}
user: name={{ user }}
group={{ group }}
shell=/bin/bash
password=${password}
groups=sudo
append=yes
generate_ssh_key=yes
ssh_key_bits=2048
ssh_key_file=.ssh/id_rsa

The generated key is returned by the user module, so you can register the result and then use the key in a subsequent authorized_key task. That is, if I have a playbook like this:
- hosts: localhost
tasks:
- name: add user
user:
name: testuser
shell: /bin/bash
password: secret
append: yes
generate_ssh_key: yes
ssh_key_bits: 2048
register: newuser
- debug:
var: newuser
I will see as output something like:
TASK [debug] *******************************************************************
ok: [localhost] => {
"newuser": {
"append": true,
"changed": true,
"comment": "",
"group": 21946,
"home": "/home/testuser",
"move_home": false,
"name": "testuser",
"password": "NOT_LOGGING_PASSWORD",
"shell": "/bin/bash",
"ssh_fingerprint": "2048 SHA256:Tn6UOl/WYToJCaW3QUnLMWgEfthILIsoCP+534qWzfw ansible-generated on lkellogg-pc0dzzve (RSA)",
"ssh_key_file": "/home/testuser/.ssh/id_rsa",
"ssh_public_key": "ssh-rsa ... ansible-generated on examplehost",
"state": "present",
"uid": 21940
}
}
So you can add a task like this:
- authorized_key:
user: root
state: present
key: "{{ newuser.ssh_public_key }}"

Related

How do I work with Ansible list of dicts?

I'm so confused with this. If I have a file containing:
users:
- name: jconnor
first: john
last: connor
uid: 3003
- name: sconnor
first: sarah
last: connor
uid: 3001
How do I get the details of each user? With this simple playbook:
- name: create users
hosts: localhost
gather_facts: false
tasks:
- name: Include vars
include_vars:
file: user_list.yml
name: users
- name: debug
debug:
msg: "{{ item }}"
with_dict: "{{ users }}"
I get the following which I can't use:
ok: [localhost] => (item={'value': [{u'last': u'connor', u'uid': 3003, u'name': u'jconnor', u'first': u'john'}, {u'last': u'connor', u'uid': 3001, u'name': u'sconnor', u'first': u'sarah'}], 'key': u'users'}) => {
"msg": {
"key": "users",
"value": [
{
"first": "john",
"last": "connor",
"name": "jconnor",
"uid": 3003
},
{
"first": "sarah",
"last": "connor",
"name": "sconnor",
"uid": 3001
}
]
}
}
I want to create user accounts with this but I simply don't understand how to use this structure.
Note that this is part of a larger structure and I can't change it.
Thanks
Since the users variable is a list of dicts, you should loop with loop or with_items. Then we can access the key of each dict with item.key. E.g.: item.name, item.uid, etc.
Note that you are importing the variables from the file with the name users. So this variable now contains the users hash of that file. If you skip name: users in include_var, then you can directly access the users dict while looping.
tasks:
- include_vars:
file: user_list.yml
name: users
- debug:
msg: "Username is {{ item.name }}, full name is {{ item.first }} {{ item.last }}, userid is {{ item.uid }}"
with_items: "{{ users.users }}"
This outputs message (showing 1 item):
ok: [localhost] => (item={u'last': u'connor', u'uid': 3003, u'name': u'jconnor', u'first': u'john'}) => {
"msg": "Username is jconnor, full name is john connor, userid is 3003"
}

Undefined variable when passing dictionary to a submodule-role

I'm having a really weird problem on my ansible role. I send two dictionaries to a submodule like that:
import_role:
name: .submodules/monitoring-plugins
vars:
monitoring_plugins:
check_content:
command: "files/icinga/commands/check_content"
dest: "{{ icinga_server_plugin_directory }}"
group: "root"
owner: "root"
mode: "0755"
package: "curl"
src: "files/plugins/server/check_content"
check_http_response_time:
command: "files/icinga/commands/check_http_response_time"
dest: "{{ icinga_server_plugin_directory }}"
group: "root"
owner: "root"
mode: "0775"
src: "files/plugins/server/check_http_response_time"
check_https_response_time:
command: "files/icinga/commands/check_https_response_time"
dest: "{{ icinga_server_plugin_directory }}"
group: "root"
owner: "root"
mode: "0775"
src: "files/plugins/server/check_https_response_time"
check_port:
command: "files/icinga/commands/check_port"
dest: "{{ icinga_server_plugin_directory }}"
group: "root"
owner: "root"
mode: "0775"
src: "files/plugins/server/check_port"
check_ssl_cert:
command: "files/icinga/commands/check_ssl_cert"
dest: "{{ icinga_server_plugin_directory }}"
group: "root"
owner: "root"
mode: "0775"
src: "files/plugins/server/check_ssl_cert"
custom_services:
content:
service-preamble: 'apply Service "content"'
configuration: |
{{ common_service_header }}
assign where host.vars.ansible.system == "Linux"
definition:
"{{ lookup('template', 'config/services/content.conf') }}"
http_response_time:
service-preamble: 'apply Service "http_response_time"'
configuration: |
{{ common_service_header }}
assign where host.vars.ansible.system == "Linux"
definition:
"{{ lookup('template', 'config/services/http_response_time.conf') }}"
https_response_time:
service-preamble: 'apply Service "https-response-time"'
configuration: |
{{ common_service_header }}
assign where host.vars.ansible.system == "Linux"
definition:
"{{ lookup('template', 'config/services/https_response_time.conf') }}"
http_port:
service-preamble: 'apply Service "http-port"'
configuration: |
{{ common_service_header }}
assign where host.vars.ansible.system == "Linux"
definition:
"{{ lookup('template', 'config/services/http_port.conf') }}"
https_port:
service-preamble: 'apply Service "https-port"'
configuration: |
{{ common_service_header }}
assign where host.vars.ansible.system == "Linux"
definition:
"{{ lookup('template', 'config/services/https_port.conf') }}"
ssl_cert:
service-preamble: 'apply Service "ssl-cert"'
configuration: |
{{ common_service_header }}
assign where host.vars.ansible.system == "Linux"
definition:
"{{ lookup('template', 'config/services/ssl_cert.conf') }}"
on the submodule I created two debug tasks:
- debug:
var: monitoring_plugins
- debug:
var: custom_services
output:
ok: [server.test] => {
"monitoring_plugins": {
"check_content": {
"command": "files/icinga/commands/check_content",
"dest": "/usr/lib/nagios/plugins",
"group": "root",
"mode": "0755",
"owner": "root",
"package": "curl",
"src": "files/plugins/server/check_content"
},
"check_http_response_time": {
"command": "files/icinga/commands/check_http_response_time",
"dest": "/usr/lib/nagios/plugins",
"group": "root",
"mode": "0775",
"owner": "root",
"src": "files/plugins/server/check_http_response_time"
},
"check_https_response_time": {
"command": "files/icinga/commands/check_https_response_time",
"dest": "/usr/lib/nagios/plugins",
"group": "root",
"mode": "0775",
"owner": "root",
"src": "files/plugins/server/check_https_response_time"
},
"check_port": {
"command": "files/icinga/commands/check_port",
"dest": "/usr/lib/nagios/plugins",
"group": "root",
"mode": "0775",
"owner": "root",
"src": "files/plugins/server/check_port"
},
"check_ssl_cert": {
"command": "files/icinga/commands/check_ssl_cert",
"dest": "/usr/lib/nagios/plugins",
"group": "root",
"mode": "0775",
"owner": "root",
"src": "files/plugins/server/check_ssl_cert"
}
}
}
TASK [.submodules/monitoring-plugins : debug] ************************************
ok: [server.test] => {
"custom_services": "VARIABLE IS NOT DEFINED!"
}
Does anybody have any idea what could possibly go wrong? I sent both of them from the very same task but yet one of them looks just fine and the other don't. I even tried to remove the submodule and add it again but it still doesn't work. Any other suggestions would be very appreciated!
The background
A var containing other vars expansion being undefined cannot be interpreted and is undefined.
$ ansible localhost -e undef="{{ i_dont_exist }}" -m debug -a var=undef
localhost | SUCCESS => {
"undef": "VARIABLE IS NOT DEFINED!"
}
To see what is going wrong, you need to actually expand the var at debug time
$ ansible localhost -e undef="{{ i_dont_exist }}" -m debug -a msg="{{ undef }}"
localhost | FAILED! => {
"msg": "The task includes an option with an undefined variable. The error was: 'i_dont_exist' is undefined"
}
Your specific case
The root cause is that common_service_header is undefined. Since it is used inside your variable definition for the role include, ansible tries to interpret it, fails, and the var stays undefined.
You will actually see the same result for monitoring_plugins if you undefine icinga_server_plugin_directory.
To have some more info on what actually happens, the "trick" is to force ansible to interpret the variable in your debug. There are two possible ways to do this:
- name: Use a simple jinja2 expansion
debug:
msg: "{{ custom_services }}"
- name: Use a the 'vars' lookup
debug:
msg: "{{ lookup('vars', 'custom_services') }}"
Which then gives a more meaningful info (reformated for legibility....):
TASK [.submodules/monitoring-plugins : debug] *****************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an
undefined variable. The error was: 'common_service_header' is undefined\n\n
The error appears to be in
'/some/path/.submodules/monitoring-plugins/tasks/main.yml': line 4, column 3,
but may\nbe elsewhere in the file depending on the exact syntax problem.\n\n
The offending line appears to be:\n\n
msg: \"{{ lookup('vars', 'monitoring_plugins') }}\"\n- debug:\n ^ here\n"}

Creating IAM users with Ansible - getting the CLI credentials

I am create usernames with the iam module, and I am using the access_key_state: create option.
However, I want my playbook to output the Access Key and the Secret Access Key for each user.
playbook.yml:
---
- name: "Starting the tasks: Creates IAM Policy, group, Role and User"
hosts: localhost
connection: local
gather_facts: False
vars_files:
- vars/aws-credentials.yml
tasks:
- include: tasks/create-user.yml
tags: user
- include: tasks/create-group.yml
tags: group
tasks/create-user.yml:
---
# Create the IAM users with Console and API access
- name: Create new IAM users with API keys and console access
iam:
iam_type: user
name: "{{ item }}"
state: present
password: "{{ lookup('password', 'passwordfile chars=ascii_letters') }}"
access_key_state: create
update_password: on_create
no_log: true
register: newusers
loop:
- johna
- mariab
- carlosc
- name: test
debug:
msg: "{{ credentials.results }}"
The debug message "{{ credentials.results }}" gives me the Access Key, but not the Secret Access Key:
{
"ansible_loop_var": "item",
"changed": true,
"created_keys": [],
"failed": false,
"groups": null,
"invocation": {
"module_args": {
"access_key_ids": null,
"access_key_state": "create",
"aws_access_key": null,
"aws_secret_key": null,
"debug_botocore_endpoint_logs": false,
"ec2_url": null,
"groups": null,
"iam_type": "user",
"key_count": 1,
"name": "carol.v",
"new_name": null,
"new_path": null,
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"path": "/",
"profile": null,
"region": null,
"security_token": null,
"state": "present",
"trust_policy": null,
"trust_policy_filepath": null,
"update_password": "always",
"validate_certs": true
}
},
"item": "carlosc",
"keys": {
"AK_________FV": "Active"
},
"user_meta": {
"access_keys": [
{
"access_key_id": "AK_________FV",
"status": "Active"
}
]
},
"user_name": "carlosc"
}
How to get the Secret Access Key for each user?
Update 09 May 2020: For further reference.
Bad news; it appears they are purposefully throwing the secret_access_key in the trash: https://github.com/ansible/ansible/blob/v2.9.7/lib/ansible/modules/cloud/amazon/iam.py#L238-L241
It appears the only way around that is to set key_count: 0 in your iam: and then use awscli or a custom ansible module to make that same iam.create_access_key call and preserve the result
- name: create access key for {{ item }}
command: aws iam create-access-key --user-name {{ item }}
environment:
AWS_REGION: '{{ the_region_goes_here }}'
AWS_ACCESS_KEY_ID: '{{ whatever_you_called_your_access_key }}'
AWS_SECRET_ACCESS_KEY: '{{ your_aws_secret_access_key_name_here }}'
register: user_keys
with_items:
- johna
- mariab
- carlosc
Feel free to file an issue, although you'll likely have to file it against the new amazon.aws collection since that iam.py is no longer present in the devel branch
You can use community.aws.iam:
- name: Create IAM User with API keys
community.aws.iam:
iam_type: user
name: some_dummy_user
state: present
access_key_state: create
register: new_user
- debug:
var: new_user
You'll be able to get your access and secret keys at:
new_user.user_meta.access_keys[0].access_key_id
new_user.user_meta.access_keys[0].secret_access_key
I have mine getting loaded into Secrets Manager and will eventually have them rotated with a lambda function.

how to access ansible newly created dictionary

I am following the example here http://docs.ansible.com/ansible/iam_policy_module.html to try to create a new AWS IAM user and then use this new user's username to attach an IAM policy to it.
The example:
task:
- name: Create Two Groups, Mario and Luigi
iam:
iam_type: group
name: "{{ item }}"
state: present
with_items:
- Mario
- Luigi
register: new_groups
- name: Apply READ-ONLY policy to new groups that have been recently created
iam_policy:
iam_type: group
iam_name: "{{ item.created_group.group_name }}"
policy_name: "READ-ONLY"
policy_document: readonlypolicy.json
state: present
with_items: "{{ new_groups.results }}"
I have adapted that to work with one user:
- hosts: 127.0.0.1
gather_facts: no
connection: local
tasks:
- name: Create user lamda_ecr_delete
iam:
iam_type: user
name: "{{ item }}"
state: present
with_items:
- lambda_ecr_delete
register: new_user
- name: Apply ecr delete policy to newly created user
iam_policy:
iam_type: user
iam_name: "{{ item.created_user.user_name }}"
policy_name: "lambda_ecr_delete"
policy_document: assets/aws-policies/lambda_ecr_delete.json
state: present
with_items: "{{ new_user.results }}"
But when I try to retrieve the username in the dictionary, item.created_user does not exist.
When I use debug to see the content of {{ new_user.results }} I can identify that it's a python list that contains a dict so I can probably access it with [0] and then call invocation.module_args.name which is a valid key.
This is the output for debug: msg="{{ new_user.results }}" when run with --check:
ok: [127.0.0.1] => {
"changed": false,
"msg": [
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": false,
"invocation": {
"module_args": {
"iam_type": "user",
"name": "lambda_ecr_delete",
"state": "present"
}
},
"item": "lambda_ecr_delete",
"msg": "remote module (iam) does not support check mode",
"skipped": true
}
]
}
But that seems hackish. Is there a shortcut to access those module_args directly? Something as shown in the example with a .created_user?
Use item.user_meta.created_user.user_name instead.
You could note that created_user is nested into user_meta if you inspect debug output of new_user.results. Looks like:
"user_meta": {
"access_keys": null,
"created_user": {
"arn": "arn:aws:iam::<yourid>:user/test-ansible",
"create_date": "2017-04-03T16:31:53.530Z",
"path": "/",
"user_id": "EXAMPLEKAJHFEXAMPLE",
"user_name": "test-ansible"
},
"password": null
}
But be warned that on the second run iam module returns different output:
"user_name": "test-ansible"
instead of user_meta dictionary.

Adding new sudo user using ansible - "password": "NOT_LOGGING_PASSWORD" message

I'm using Vagrant (Virtual Box provider) to setup a local Virtual Machine. I'm also using ansible and more specific ansible_local (Vagrant plugin) to deploy some tools into the VM.
Initially I'm trying to create a new user following the ansible documentation.
---
- name: Master Node
hosts: 127.0.0.1
connection: local
user: root
vars_files:
- vars/vars.yml
vars:
username: nikolas
tasks:
- name: Adding user
user: name={{username}} shell=/bin/bash groups=root append=yes password={{pass}}
sudo: yes
- name: Placing RSA key
authorized_key: user={{username}} key="{{ lookup('file', 'id_rsa.pub') }}"
sudo: yes
When I run the playbook, I get this message:
PLAY [Master Node] ************************************************************
GATHERING FACTS ***************************************************************
ok: [127.0.0.1]
TASK: [Adding user] **************************************************
changed: [127.0.0.1] => {"changed": true, "comment": "", "createhome": >true, "group": 1001, "groups": "root", "home": "/home/nikolas", "name": >"nikolas", "password": "NOT_LOGGING_PASSWORD", "shell": "/bin/bash", >"state": "present", "system": false, "uid": 1001}
TASK: [Placing RSA key] *******************************************************
changed: [127.0.0.1] => {"changed": true, "key": "ssh-rsa >AAAAB3N....public_rsa_key", "key_options": null, >"keyfile": "/home/desmotes/.ssh/authorized_keys", "manage_dir": true, >"path": null, "state": "present", "unique": false, "user": "nikolas"}
PLAY RECAP ********************************************************************
127.0.0.1 : ok=4 changed=2 unreachable=0 >failed=0
"password": "NOT_LOGGING_PASSWORD"
As a result, when i am trying to logged in as nikolas in the VM to get authentication error.
Do you know where is my mistake ?
Thank you
I think you need to modified your user creation task like this:
- name: Adding user
user: name={{username}} shell=/bin/bash groups=root append=yes password={{ pass | password_hash('sha512') }}
sudo: yes
Hope that help you.

Resources