[[TOC]]
This is a collection of Ansible playbooks and supporting documents that I use to configure servers quickly. Some of these may be useful to others, so I share them.
NOTE: This only sets up Nginx and a few security options, it does not setup a website:
- Git installed
- A text editor installed (to create a config file) -> Let me Google that for you. If you're not familiar with any, Nano is easy to pickup, or (if you have a desktop environment) gedit is simple to use with a window.
-
Clone the repo
git clone https://github.com/mshafer1/ansible-configs.git -
change-directory into the repo
cd ansible-configs -
Create a
hostsfile.On Linux, the majority of configuration is stored in the
/etcdirectory. Ansible is no exception to this. Create/etc/ansible/hostsfile containing:all: vars: certbot_email: ... hosts: localhost: ansible_connection: local SSH_PORT: 22 reboot_controller: True grub_handled: False system_up_to_date__upgrade_mode: safe children: nginx: hosts: localhost:
NOTE: the SSH_PORT is used to adjust SSHD and firewalld to only allow ssh on that port. While 22 is the default, many people recommend choosing a non-standard port for security-through-obscurity
-
Use
_bootstrap.shto install Ansible and Python (required to install Ansible)./_bootstrap.shIt will prompt to confirm before installing:
After this operation, 290 MB of additional disk space will be used. Do you want to continue? [Y/n]The 'Y/n' syntax means that it wants a yes or no, but if you put nothing (and press enter) it will default to "yes" (denoted by the capital Y)
-
Once that has finished, close and re-open your shell to load in the changes to environment variables (if connected via SSH, disconnect and reconnect; if using a terminal window, close and re-open).
-
Check that it worked by running
which ansibleYou should see an output like:
/root/.local/bin/ansible(where "root" may be "/home/<your username>") -
Use
ansible-playbookto run the nginx playbookansible-playbook playbooks/nginx.ymlThis should:
-
Install:
-
Configure nginx to return status code 444 for HTTP and HTTPS requests on the default server -> using a self-signed cert for "example.com"
This is because nginx will default serve the first cert it finds when asked for https on the default site. Because it is assumed that anyone requesting a site from the server via IP address is a bad-actor doing web scanning, blocking them and not telling them what website(s) are actually hosted on this server seems like a good idea. -
Configure fail2ban to flag and block a number of situations
-
Since we removed the default "Welcome to nginx" page (or, default site), we did also add a /status route that will report the server status - BUT ONLY FOR REQUESTS WITHIN LOCALHOST.
So, we can check if it worked by running
curl http://localhost/status
Should get a response like:
Active connections: 1
server accepts handled requests
1 1 1
Reading: 0 Writing: 1 Waiting: 0
(may need to install curl if this is a completely new server)
Why? (click to expand if you want background)
I started working on using Fail2Ban's built-in Cloudflare action and got it working (and found how to validate) only to be met with a header saying:
The Firewall Rules API and the associated Cloudflare Filters API are now deprecated. These APIs will stop working on 2025-01-15. You must migrate any automation based on the Firewall Rules API or Cloudflare Filters API to the Rulesets API before this date to prevent any issues.
So, ... I set to work figuring out how to adapt the concept to work with the Rulesets API.
The result was this:
- A logging config that sets nginx logs to show the forwarded IP
- a custom
cloufdflare-banaction that is generated usingzoneIDs (roughly equivalent to domain names) - a Python helper script that handles the posting the current block rule (idempotent)
If using the nginx role (see section above), you can configure fail2ban to use firewall rules in CloudFlare to ban bad actors coming in over the CloudFlare 0 Trust Tunnel. The actual source IP will be logged and banned.
A few variables are required to be set to enable this:
cloudflare_tokenyour token (used by the script to authenticate)cloudflare_emailyour email (used as "username" in conjunction with the token to authenticate)cloudflare_zoneslist of zone IDs to apply the rules to (note, this setup will ban for all zones regardless of offending domain)enable_cloud_flare_blockset this to "true" to enable the action (without this, default is to template the action file if other vars are present, but leave the fail2ban action asiptables). Enabling nginx's 'ngx_http_realip_module' is also triggered with this variable (this tells nginx to look at theX-Forwarded-Forheader for the IP of the requestor - not Cloudflare - and use in logs for fail2ban to pick up).
Optional variables for further control:
required_country_codeslist of county abbreviations to require the source IP is from (i.e., always block if NOT from one of these. This may be useful if you only anticipate users from your home country are legitimate users, and you don't mind if VPN users are unable to access your site)nginx_real_ip_sourceslist of IPs for nginx to examine theX-Forwarded-ForIP and replace in logs as the source IP. (Note: this defaults to a list containing: (1)127.0.0.1/8to handle cloudflared running on localhost, (2)172.17.0.0/16to handle cloudflared running in Docker, and (3)192.168.1.1/24to handle cloudflared running on another host in a home-lab environment. If your use does not fit one of these, you will likely need to set this as a host or group var)
#/etc/ansible/hosts
all:
hosts:
server_1:
ansible_user: service_account
ansible_host: 127.0.0.1
# ...
enable_cloud_flare_block: true
cloudflare_token: 'token_value'
cloudflare_email: 'user@example.com'
cloudflare_zones:
- deadbeef # domain 1
# ...
required_country_codes:
- US # USA
- MX # Mexico
- CA # Canada
nginx:
hosts:
server_1: {} # add server_1 to the nginx group- Get some IPs blocked
Option a: let the rules get hit
Option b: fail2ban-client set nginx-nohome banip 192.168.1.0 (bans 192.168.1.0 under the nginx-nohome jail defined in the nginx role)
-
Log into CloudFlare dashboard and navigate to:
A.
Websites->{your domain}->Security->WAFB. Click on on "Custom rules"
C. Should see a rule named "Block bad actors", click on it
D. Should see that it is set to block IP addresses in:
127.255.255.254192.168.1.0(assuming followed step above)
Note: if
required_country_codes, full rule syntax should in includeip.src in ...ORnot ip.geoip.country in {...}such that IPs that are NOT from specified countries OR are in the naughty list will be blocked (via "Choose action" -> "Block") -
Unban user
fail2ban-client unban 192.168.1.0 -
Refresh Cloudflare dashboard -> IP should be removed from list of blocked (note,
127.255.255.254will always be included to provide a simpler syntax and keep the expression valid)