I'm working to setup UFW rules via Ansible. I'm able to get it installed, start it and deny everything. I then attempt to allow connections from http, https, and ssh. All attempts to add the allow for those items are met with errors that look like:
failed: [lempy1] (item={u'service': u'http'}) => {"failed": true, "item": {"service": "http"}, "msg": "ERROR: Could not find a profile matching 'http'\n"}
failed: [lempy1] (item={u'service': u'https'}) => {"failed": true, "item": {"service": "https"}, "msg": "ERROR: Could not find a profile matching 'https'\n"}
failed: [lempy1] (item={u'service': u'ssh'}) => {"failed": true, "item": {"service": "ssh"}, "msg": "ERROR: Could not find a profile matching 'ssh'\n"}
The entire role looks like this:
tasks/main.yml
---
- name: Install ufw
apt: name=ufw state=present
tags:
- security
- name: Allow webservery things
ufw:
rule: allow
name: '{{item.service}}'
with_items:
- service: http
- service: https
- service: ssh
tags:
- security
- name: Start ufw
ufw: state=enabled policy=deny
tags:
- security
Any idea why I wouldn't be able to allow these services? I am able to add the services properly when ssh'ing into the server and running sudo ufw allow http, etc.
As mentioned in the ufw module docs, the name (or app) parameter uses applications that are registered in /etc/ufw/applications.d which have an INI format and look something like this:
[CUPS]
title=Common UNIX Printing System server
description=CUPS is a printing system with support for IPP, samba, lpd, and other protocols.
ports=631
Normally you can use ufw allow application-profile to allow an application defined either in /etc/ufw/applications.d or /etc/services to open up iptables for things that aren't necessarily defined in /etc/ufw/applications.d.
Unfortunately, Ansible's ufw module instead builds the ufw command in this format instead:
/usr/sbin/ufw allow from any to any app 'application-profile'
Which only uses the /etc/ufw/applications.d list and won't read /etc/services.
In your case you could simply specify the ports as these are well known, potentially using a named variable to further explain your Ansible code:
- name: Allow webservery things
ufw:
rule: allow
port: '{{ item }}'
with_items:
- '{{ http_port }}'
- '{{ https_port }}'
- '{{ ssh_port }}'
tags:
- security
And then define the variables somewhere (such as your role defaults):
http_port: 80
https_port: 443
ssh_port: 22
As an aside, you might want to notice that I simplified your list of dictionaries with a single key into a simpler straight list which tidies up your task a bit.
Alternatively you could easily template the application profiles using Ansible's template module.
Related
I am new to Ansible, I am only using a central machine and a host node on Ubuntu server, for which I have to deploy a firewall; I was able to make the SSH connections and the execution of the playbook. What I need to know is how to verify that the port I described in the playbook was blocked or opened, either on the controller machine and on the host node. Thanks
According your question
How to verify that the port I described in the playbook was blocked or opened, either on the controller machine and on the host node?
you may are looking for an approach like
- name: "Test connection to NFS_SERVER: {{ NFS_SERVER }}"
wait_for:
host: "{{ NFS_SERVER }}"
port: "{{ item }}"
state: drained
delay: 0
timeout: 3
active_connection_states: SYN_RECV
with_items:
- 111
- 2049
and have also a look into How to use Ansible module wait_for together with loop?
Documentation
Ansible wait_for Examples
You may also interested in Manage firewall with UFW and have a look into
Ansible ufw Examples
I'm trying to convert a playbook which deploys vSphere VMs. The current version
of the playbook gets individual IP addresses and source template information
from vars/main.yml in the role (I'm using the best practice directory layout.)
vms:
- name: demo-server-0
ip_address: 1.1.1.1
- name: demo-server-1
ip_address: 1.1.1.2
Template, and other information is stored elsewhere in the vars.yml file but
it makes more sense to use the standard inventory, so I created these entries
in the inventory file:
test_and_demo:
hosts:
demo-server-0:
ip-address: 1.1.1.1
demo-server-1:
ip-address: 1.1.1.2
vars:
vc_template: xdr-template-1
The play is pretty much unchanged, apart from this key change:
FROM:
with_items: '{{ vms }}'
TO:
with_items: "{{ query('inventory_hostnames', 'test_and_demo') }}"
But this throws the following error:
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ModuleNotFoundError: No module named 'pyVim'
failed: [localhost] (item=demo-deployer) => {"ansible_loop_var": "item", "changed": false, "item": "demo-deployer", "msg": "Failed to import the required Python library (PyVmomi) on lubuntu's Python /usr/bin/python3. Please read the module documentation and install it in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter"}
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ModuleNotFoundError: No module named 'pyVim'
I don't believe this is a platform issue, as reverting back to with_items: '{{ vms }}'
works just fine (vars\main.yml still exists and duplicates data).
I'm probably using query incorrectly but can anyone give me a hint what I'm
doing wrong?
Accessing sub-values
If I can get the VMs to deploy using with_items: + query I'd then need to
access the variables of the host and group for the various items I need to
specify, can someone advise me here, too.
Many thanks.
Although I was convinced the problem was in the way I was doing the query, it was in the root Play which I hadn't noticed. By adding become: yes I think it was switching to the root user which didn't have the module installed.
Once it was removed, the problem was resolved.
- hosts: localhost
roles:
- deploy_demo_servers
become: yes
I need to run some tasks only if ufw is enabled on the Ubuntu server.
Pseudocode looks like:
- name: detect if ufw is enabled
magical_module: ???
register: ufw_is_enabled
- name: my task
when: ufw_is_enabled
I see only this nonelegant solution:
exec remotely ufs status
parse the output:
root#test:~# ufw status
Status: inactive
Maybe there is some file when ufw is enabled? In this case, it will be possible to use stat module. Any other solutions?
Something along the lines of:
- name: check whether ufw status is active
shell: ufw status
changed_when: false
register: ufw_check
- debug:
msg: "{{ ufw_check }}"
- name: do something if ufw is enabled
shell: echo
when: "'inactive' not in ufw_check.stdout"
Make sure to use become: true, since root privileges are required to successfully execute the command.
To manage systems with the UFW module, see this Ansible module
What you can do, for example is, disable UFW on systems on which you want it disabled:
- name: Disable UFW on hosts
ufw:
state: disabled # unloads firewall and disables firewall on boot.
My Situation is my database server is not opened with default ssh port 22, so I am trying to execute a query over port 3838.Below is the code -
tasks:
- name: passive | Get MasterDB IP
mysql_replication: mode=getslave
register: slaveInfo
- name: Active | Get Variable Details
mysql_variables: variable=hostname ansible_ssh_port=3838
delegate_to: "{{ slaveInfo.Master_Host }}"
register: activeDbHostname
Ansible version is :- 1.7.2
TASK: [Active | Get Variable Details] *****************************************
<192.168.0.110> ESTABLISH CONNECTION FOR USER: root on PORT 22 TO 192.168.0.110
fatal: [example1.com -> 192.168.0.110] => {'msg': 'FAILED: [Errno 101] Network is unreachable', 'failed': True}
FATAL: all hosts have already failed -- aborting
It connecting over default port 22 rather connecting on 3838 port. Please share your thoughts, If I am going wrong somewhere ...
You can specify the value for ansible_ssh_port in a number of places. But you will likely want to use a dynamic inventory script.
eg. From hosts file:
[db-slave]
10.0.0.20 ansible_ssh_port=3838
eg. as a variable in host_vars:
---
# host_vars/10.0.0.20/default.yml
ansible_ssh_port: 3838
eg. in a dynamic inventory! you may use a combo of group_vars and tagging the instances:
---
# group_vars/db-slaves/default.yml
ansible_ssh_port: 3838
use gce.py, ec2.py or some other dynamic inventory script and group your intances in the hosts file:
[tag_db-slaves]
; this is automatically filled by ec2.py or gce.py
[db-slaves:children]
tag_db-slaves
Of course this will mean you need to tag the instances when you fire them up. You can find several dynamic inventory scripts in the ansible repository.
If your mysqld is running on a docker instance in the same host, I would recommend you create a custom dynamic inventory with some form of service discovery, such as using consul, etcd, zookeeper, or some custom solution using a key-value store such as redis. You can find an introduction to dynamic inventories in the ansible documentation.
During deployment needed setup ufw firewall rule: enable access for hosts group servers from inventory. Target host is anazon ec2 instance, but it maybe placed at other provider.
I tried:
- name: Ufw rules
ufw: rule=allow from_ip={{ hostvars[item]['ansible_eth0']['ipv4']['address'] }}
with_items: groups['servers']
notify:
- Restart ufw
file hosts:
..
[servers]
server1.site.com
server2.site.com
server3.site.com
..
But host server1.site.com, actually have host_vars:
"ansible_eth0": {
"active": true,
"device": "eth0",
"ipv4": {
"address": "10.x.x.x",
...
Ip address 10.x.x.x, as I understand, is internal amazon network ip address.
If execute ping server1.site.com from outside ec2, I get:
64 bytes from server1.site.com (46.x.x.x): icmp_seq=1 ttl=56 time=49.5 ms
...
Executing ansible server1.site.com -m setup -i hosts | grep 46.x.x.x found nothing.
How to known external ip address of host from inventory group using ansible?
Or how setup ufw firewall using host names from inventory?
I think your best bet is to use the lookup plugin written by #dsedivec (https://github.com/dsedivec/ansible-plugins).
Create a lookup_plugins/ directory at the top directory of your playbook.
Put dns.py in it
curl https://raw.githubusercontent.com/dsedivec/ansible-plugins/master/lookup_plugins/dns.py > lookup_plugins/dns.py
And use it like so :
- name: Ufw rules
ufw: rule=allow from_ip={{ lookup('dns', item) }}
with_items: groups['servers']
notify:
- Restart ufw
Good luck !
The easiest way is to add connection: local
---
- name: get my public IP
ipify_facts: api_url=http://api.ipify.org
connection: local
- firewalld: rich_rule='rule family=ipv4 source address={{ ipify_public_ip }} accept' permanent=no state=enabled timeout=300
become: true