Ansible. Reconnecting the playbook connection - ansible

The server is being created. Initially there is user root, his password and ssh on 22 port (default).
There is a written playbook, for example, for a react application.
When you start playbook'a, everything is deployed for it, but before deploying, you need to configure the server to a minimum. Those. create a new sudo user, change the ssh port and copy the ssh key to the server. I think this is probably needed for any server.
After this setting, yaml appears in the host_vars directory with the variables for this server (ansible_user, ansible_sudo_pass, etc.)
For example, there are 2 roles: initial-server, deploy-react-app.
And the playbook itself (main.yml) for a specific application:
- name: Deploy
hosts: prod
roles:
- role: initial-server
- role: deploy-react-app
How to make it so that when you run ansible-playbook main.yml, the initial-server role is executed from the root user with his password, and the deploy-react-app role from the newly created one user and connection was by ssh key and not by password (root)? Or is it, in principle, not the correct approach?

Note: using dashes (-) in role names is deprecated. I fixed that in my below example
Basically:
- name: initialize server
hosts: prod
remote_user: root
roles:
- role: initial_server
- name: deploy application
hosts: prod
# That one will prevent to gather facts twice but is not mandatory
gather_facts: false
remote_user: reactappuser
roles:
- role: deploy_react_app
You could also set the ansible_user for each role vars in a single play:
- name: init and deploy
hosts: prod
roles:
- role: initial_server
vars:
ansible_user: root
- role: deploy_react_app
vars:
ansible_user: reactappuser
There are other possibilities (using an include_role task). This really depends on your precise requirement.

Related

How in a single playbook become root as well as application user

I have a requirement to setup an application and for that I need to install Nginx as root and then run another Java application as a different application user.
The condition for this is, I have a privileged user "priv_suer" which has sudo and I'm running the playbook as this user as I need to install and configure Nginx. But my application user is different from this user "app_user" which is unprivileged application only user.
The issue I'm facing is, this app_user needs password to become app_user. So in my case I need two passwords one is to become root and another one to become app_user.
I referred Understanding privilege escalation: become and only option I could find was "ansible_become_password".
Can anyone help me with this?
I think that privilege escalation can help. My solution is:
Declare different groups for servers running your Java applications and servers you want to install Nginx. In your case, the two groups can share the same servers.
Here below I give an example of inventory.yml file:
all:
children:
app:
hosts:
127.0.0.1:
vars:
ansible_become_pass: app_user#123
ansible_python_interpreter: /usr/bin/python3
ansible_user: app_user
nginx:
hosts:
127.0.0.1:
vars:
ansible_become_pass: root#123
ansible_python_interpreter: /usr/bin/python3
ansible_user: root
An example of playbook is as follow:
- hosts: app
tasks:
- name: Install Java app
become: yes
- hosts: nginx
tasks:
- name: Install NGINX
become: yes
Finally, run your ansible playbook with an inventory provided using -i option:
ansible-playbook -i etc/ansible/inventory.yml etc/ansible/playbook.yml

ansible: run role as a different user

I have two roles that run in a playbook, one that creates a user and the other which runs through a series of tasks that I want to run as the newly created user on the server.
The playbook is written as follows:
- hosts: centos
connection: ssh
gather_facts: false
become: true
roles:
- ../roles/user_setup
- ../roles/tasks
Let's say the user created from the user_setup role is called user1: I basically want the role named tasks to run as user1. What would be the best way to do this? Thanks.
This question almost provides you a solution. You can use something like:
- hosts: centos
connection: ssh
gather_facts: false
roles:
- role: ../roles/user_setup
become: true
- role: ../roles/tasks
become: true
become_user: user1
If you want to connect directly as user1 (rather than escalating to it), you can replace the latest role call with:
- role: ../roles/tasks
become: false
remote_user: user1

How to skip role when host is unreachable?

I have disable_root role, which creates admin user and disables root user from connecting to server via ssh.
When I rerun playbook with this role for second time I get unreachable error (which is ok, as I just disabled it).
I'd like to skip this role in such case and continue with other roles (which would run as a admin user). How can I do this?
This is my playbook (disbale_root uses ansible_user: root var)
- hosts: webservers
roles:
- disable_root
- common
- nginx
One playbook shall connect to the remote host as root, if necessary, or as admin if this user has already been created. This can be done with remote_user (see Ansible remote_user vs ansible_user
).
Let's create the playbook to disable root and enable admin
> cat play-disable-root.yml
- hosts: webservers
remote_user: 'root'
tasks:
- include_role:
name: disable_root
when: play_disable_root|default(false)
In the first play import this playbook if admin can't connect to the remote host
- hosts: webservers
remote_user: 'admin'
tasks:
- delegate_to: localhost
command: ping -c1 "{{ inventory_hostname }}"
register: result
ignore_errors: true
- set_fact:
play_disable_root: true
when: result.rc != 0
- import_playbook: play-disable-root.yml
in the second play proceed with remaining roles
- hosts: webservers
remote_user: 'admin'
roles:
- common
- nginx
Both first and second play may be put into one playbook.
(code not tested)
Updates:
it's not possible to conditionally import playbooks

Run a playbook on hosts with a specific parameter

In my host file I have:
[web]
192.168.1.1:8682 master="yes"
192.168.1.1:8682 master="no"
and in my playbook I would like to run roles only on the server with master=yes like:
---
- name: Switch MySQL master
hosts: web[master=yes]
remote_user: andy
become: yes
roles:
- replication_setup_switch_server
...
Is it possible to do that with Ansible ?
In Ansible you can create ad-hoc groups based on facts using group_by module.
Add a new play before Switch MySQL master and create a new group in it. I called the new play Create groups by role in the example below. You could maybe rename the variable master to role to make the playbook more intuitive. So, the inventory and the playbook would become:
---
[web]
192.168.1.1:8682 role="master"
192.168.1.1:8682 role="slave"
---
- name: Create groups by role
hosts: web
tasks:
- name: Group by web role
group_by:
key: "web_{{ role }}"
- name: Switch MySQL master
hosts: web_master
remote_user: andy
become: yes
roles:
- replication_setup_switch_server

Ansible ec2 only provision required servers

I've got a basic Ansible playbook like so:
---
- name: Provision ec2 servers
hosts: 127.0.0.1
connection: local
roles:
- aws
- name: Configure {{ application_name }} servers
hosts: webservers
sudo: yes
sudo_user: root
remote_user: ubuntu
vars:
- setup_git_repo: no
- update_apt_cache: yes
vars_files:
- env_vars/common.yml
- env_vars/remote.yml
roles:
- common
- db
- memcached
- web
with the following inventory:
[localhost]
127.0.0.1 ansible_python_interpreter=/usr/local/bin/python
The Provision ec2 servers task does what you'd expect. It creates an ec2 instance; it also creates a host group [webservers] and adds the created instance IP to it.
The Configure {{ application_name }} servers step then configures that server, installing everything I need.
So far so good, this all does exactly what I want and everything seems to work.
Here's where I'm stuck. I want to be able to fire up an ec2 instance for different roles. Ideally I'd create a dbserver, a webserver and maybe a memcached server. I'd like to be able to deploy any part(s) of this infrastructure in isolation, e.g. create and provision just the db servers
The only ways I can think of to make this work... well, they don't work.
I tried simply declaring the host groups without hosts in the inventory:
[webservers]
[dbservers]
[memcachedservers]
but that's a syntax error.
I would be okay with explicitly provisioning each server and declaring the host group it is for, like so:
- name: Provision webservers
hosts: webservers
connection: local
roles:
- aws
- name: Provision dbservers
hosts: dbservers
connection: local
roles:
- aws
- name: Provision memcachedservers
hosts: memcachedservers
connection: local
roles:
- aws
but those groups don't exist until after the respective step is complete, so I don't think that will work either.
I've seen lots about dynamic inventories, but I haven't been able to understand how that would help me. I've also looked through countless examples of ansible ec2 provisioning projects, they are all invariably either provisioning pre-existing ec2 instances, or just create a single instance and install everything on it.
In the end I realised it made much more sense to just separate the different parts of the stack into separate playbooks, with a full-stack playbook that called each of them.
My remote hosts file stayed largely the same as above. An example of one of the playbooks for a specific part of the stack is:
---
- name: Provision ec2 apiservers
hosts: apiservers #important bit
connection: local #important bit
vars:
- host_group: apiservers
- security_group: blah
roles:
- aws
- name: Configure {{ application_name }} apiservers
hosts: apiservers:!127.0.0.1 #important bit
sudo: yes
sudo_user: root
remote_user: ubuntu
vars_files:
- env_vars/common.yml
- env_vars/remote.yml
vars:
- setup_git_repo: no
- update_apt_cache: yes
roles:
- common
- db
- memcached
- web
This means that the first step of each layer's play adds a new host to the apiservers group, with the second step (Configure ... apiservers) then being able to exclude the localhost without getting a no hosts matching error.
The wrapping playbook is dead simple, just:
---
- name: Deploy all the {{ application_name }} things!
hosts: all
- include: webservers.yml
- include: apiservers.yml
I'm very much a beginner w/regards to ansible, so please do take this for what it is, some guy's attempt to find something that works. There may be better options and this could violate best practice all over the place.
ec2_module supports an "exact_count" property, not just a "count" property.
It will create (or terminate!) instances that match specified tags ("instance_tags")

Resources