Ansible, get variable from vault before gathering facts - ansible

I used to store ansible_ssh_pass in host_vars, enctypted with ansible-vault, but now i want to move it to hashicorp-vault. I wrote a simple role to get this variable from hashicorp-vault and set it as ansible_ssh_pass, so i can connect to host via it. But unless i do it i can't gather facts, so the only way is to set gather_facts: no and run
- name: Gathering facts
setup:
at the end of my role. But now i need to change my playbooks and some roles for this. Is there a better way to run role before gathering facts or force Ansible to get variable from hashicorp-vault?

It sounds like you should be using the hashi_vault lookup plugin.
For example, you could set in your inventory something like this:
all:
vars:
ansible_ssh_pass: "{{ lookup('hashi_vault', 'secret=secret/ssh_password:value' }}
hosts:
host1:
host2:
...
This would require you to have VAULT_ADDR and VAULT_TOKEN set appropriately in your environment.
NB: I don't have a Vault instance to play with, but I do something very similar using the aws_secret lookup.

Related

Use a variable for remote_user in ansible

I want to parameterize (use a variable) for remote_user in ansible.
This is the first part from the playbook:
- hosts: xxx
remote_user: "centos"
become: true
I will replace it with
- hosts: wazuh
remote_user: "{{ new_user }}"
become: true
But what is a good place to store the value of this variable? It seems group_vars/all mostly contain variables which are more app/env specific than ansible specific. Or should I put it in inventories/hosts as a var? What is the recommended location to store it?
You should actually store it in your inventory as ansible_user either for the all group (for all host), a specific group or a specific host. You can keep a remote_user in your play which will be used in case the ansible_user is not defined for some hosts in your inventory. If you remove it, you local user on the controller will be the default, unless you use the -u flag on the command line.
You can find a good explanation of the difference between ansible_user and remote_user and how the overide works in the documentation on variable precedence
Using a var as you wrote it in your above example can actually work. But since it must be expanded before the play actually starts and any action is taken on any host, the only place you can "store" it is in an extra_var on the command line.
To be a little more practical, here is what I suggest from your above example:
inventories/dev/hosts.yml
---
wazuh:
hosts:
host_a.wazuh.tld:
host.b.wazuh.tld:
inventories/dev/group_vars/wazuh.yml
---
# Vars for the wazuh group
ansible_user: centos
plabook.yml
---
- hosts: wazuh
tasks:
- name: Proove we connected with the given user
cmd: whoami
register: whoami_result
- name: Show actual result
debug:
var: whoami_result.stdout
Launching the playbook:
ansible-playbook -i inventories/dev playbook.yml

How to combine multiple vars files per host?

I have a playbook running against multiple servers. All servers require a sudo password to be specified, which is specific to each user running the playbook. When running the playbook, I can't use --ask-become-pass, because the sudo passwords on the servers differ. This is the same situation as in another question about multiple sudo passwords.
A working solution is to specify ansible_become_pass in host_vars:
# host_vars/prod01.yml
ansible_become_pass: secret_prod01_password
domain: prod01.example.com
# host_vars/prod02.yml
ansible_become_pass: secret_prod02_password
domain: prod02.example.com
Besides ansible_become_pass, there are other variables defined per host. These variables should be committed to the git repository. However, as ansible_become_pass is specific to each user running the playbook, I'd like to have a separate file (ideally, vaulted) which specifies the password per host.
I imagine the following:
# host_vars/prod01.yml: shared in git
domain: prod01.example.com
# host_vars/prod01_secret.yml: in .gitignore
ansible_become_pass: secret_prod01_password
I imagine both files to be combined by Ansible when running the playbook. Is this possible in Ansible? If so, how?
You should be able to use the include_vars task with the inventory_hostname or ansible_hostname variable. For example:
- name: Include host specific variables
include_vars: "{{ ansible_hostname }}.yml"
- name: Include host specific secret variables
include_vars: "{{ ansible_hostname }}_secret.yml"
An even better solution would be to address the problem of users having unique passwords on different hosts.
You could create a new group in the inventory file, maybe sudo-hosts. Put all your sudo host in this group. Then create a file under the directory group_vars with the name of this goup. In this file put the secret yaml-structured text.
sudo_hosts:
host1:
password: xyz
othersecret_stuff: abc
host2:
...
then use ansbile-vault to encrypt this file with ONE password. Call the playbook with option --ask-vault-pass
and you can use your secrets with
"{{ sudo_host['ansible_host'].password }}"

Execute on host conditionally, Ansible [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I'm attempting to create a conditional in my playbook that switches based on an ENV defined in a Dockerfile. The playbook is copied in by the Dockerfile, and Ansible runs it against localhost to do some configuration. However, these playbooks are also used to configure an ordinary server.
Here's my question: Is is possible to use a conditional when defining hosts?
- hosts: actual_server
roles:
- some_roles
when:
- DOCKER_CONTAINER is not defined
- hosts: docker_container
roles:
- almost_same_roles
when:
- DOCKER_CONTAINER is true
I've hunted through the Ansible docs, and found several examples where multiple hosts are targeted in a single playbook, but I an unsure if my syntax for the conditional is wrong, or if what I want to accomplish simply cannot be done. Am I limited to defining conditionals only on a role-by-role basis?
I'd be glad to edit this question, to make it more clear, since it has been closed for being "unclear"... but I'm not sure how much MORE clear I could be, than stating exactly what I'm asking in the above. Glad for more specific feedback if anyone is willing to give it.
It honestly feels like this behavior should be pushed lower into the tasks as opposed to the role level. Roles describe how to accomplish a specific state through a list of tasks, and the tasks themselves perform the steps in order to accomplish that specific state.
With that said, it makes sense to have the logic in the task to determine whether or not it will execute. This means that your role some_roles would look like this (warning: untested).
# In tasks/playbook.yml
- hosts: actual_server
roles:
- some_roles
vars:
environment_type: Server
- hosts: docker_container
roles:
- some_roles
vars:
environment_type: Docker
# In vars/main.yml file
environment_type: Server
# In tasks/main.yml
- name: Download a tarball
get_url:
url: "https://example.com/some_package.tar.gz"
dest: /tmp
mode: 0750
when: environment_type == 'Docker'
If you want to run one ansible script for the different environment.
Here is your answer, you can go with inventory file for each environment generated by docker(if needed).
ansible-playbook playbook.yml -i development.ini
ansible-playbook playbook.yml -i testing.ini
ansible-playbook playbook.yml -i staging.ini
development.ini
[actual_server]
192.168.0.100 # some IP address
[docker_container]
127.0.0.1
testing.ini
[actual_server]
192.168.0.101 # some IP address
[docker_container]
127.0.0.1
https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html
https://symfonycasts.com/screencast/ansible/hosts-inventory
Not the ideal answer, but you can use a when condition on each role:
- hosts: actual_server
roles:
- role: role1
when: DOCKER_CONTAINER is not defined
- role: role2
when: DOCKER_CONTAINER is not defined
...
- hosts: docker_container
roles:
- role: role3
when: DOCKER_CONTAINER is true
- role: role4
when: DOCKER_CONTAINER is true
...

Ansible: How to declare global variable within playbook?

How can I declare global variable within Ansible playbook. I have searched in google and found the below solution, but its not working as expected.
- hosts: all
vars:
prod-servers:
- x.x.x.x
- x.x.x.x
- hosts: "{{prod-servers}}"
tasks:
- name: ping
action: ping
When I'm trying the above code, it says variable prod-servers is undefined.
You cannot define a variable accessible on a playbook level (global variable) from within a play.
Variable Scopes
Ansible has 3 main scopes:
Global: this is set by config, environment variables and the command line
Play: each play and contained structures, vars entries (vars; vars_files; vars_prompt), role defaults and vars.
Host: variables directly associated to a host, like inventory, include_vars, facts or registered task outputs
Anything you declare inside a play can thus only be either a play variable, or a (host) fact.
To define a variable, which you can use in the hosts declaration:
run ansible-playbook with --extra-vars option and pass the value in the argument;
or to achieve the same functionality (decide which hosts to run a play on, from within a preceding play):
define an in-memory inventory and run the subsequent play against that inventory.
what you seem to want is an inventory (http://docs.ansible.com/ansible/latest/intro_inventory.html), it looks like you have an static list of IP's that may be prod servers (or dev, or whatever), therefore you can create an static inventory.
In your second play you want to use the list of IP's as hosts to run the tasks, that's not what Ansible expects. After the "hosts" keyword in a play declaration, Ansible expects a group name from the inventory.
If, on the opossite, your prod servers change from time to time, you may need to create a dynamic inventory. You can have a look at examples in https://github.com/ansible/ansible/tree/devel/contrib/inventory (for instance, there are examples of dynamic inventory based on EC2 from Amazon or vsphere)
regards
well, this can be done using
set_fact.
I don't know the best practice for this but this works for me
Here's my playbook example
- hosts: all
gather_facts: false
tasks:
- set_fact: host='hostname'
- hosts: host-name1
gather_facts: false
tasks:
- name: CheckHostName
shell: "{{ host }}"
register: output
- debug: msg="{{ output }}"
- hosts: host-name2
gather_facts: false
tasks:
- name: CheckHostName
shell: "{{ host }}"
register: output
- debug: msg="{{ output }}"

How do I share ansible variables across hosts using vars_prompt

In ansible, I do some code on a remote machine, and then I want to use the result from the vars_prompt again on a different host. I've searched around, and the docs make it sound like i should use {{ hostvars.local_server_name_in_vagrant_group.local_username }}, using my example below to set the context. However, it says that the index from the dictionary doesn't exist when referencing hostvars. Instead, as shown below, I simply do a vars_prompt twice. Gross! Any tips?
BTW, there's also discussion on whether or not using vars_prompt is a great idea. I have confirmed that for my usage, indeed, I do want to use vars_prompt. Thanks!
- hosts: vagrant
vars_prompt:
local_username: "enter your desired local username"
... remote task activity using local_username...
- hosts: localhost
connection: local
vars_prompt:
local_username: "enter your desired local username, again (please)
... host task activity, also using local_username ...
As I said in the comment to the question :
You can use set_facts to register your variable as a fact of the current host and access it from a different one. I do not think standard variables are stored after the role/tasks.
Here is an example :
- name: First
connection: local
hosts: host1
tasks:
- name: register real root user to localhost facts
set_fact: fact_for_host1="1"
- name: Second
connection: local
hosts: host2
tasks:
- debug: msg="{{ hostvars['host1']['fact_for_host1'] }}"
Note that the connection: local is present only for local tests purpose.

Resources