/ansible-configs

A place to store off my ansible configurations

Primary LanguageShell

Ansible-configs

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.

Bootstrapping an nginx server:

NOTE: This only sets up Nginx and a few security options, it does not setup a website:

PREREQUISITES:

  • 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.

Steps:

  1. Clone the repo

    git clone https://github.com/mshafer1/ansible-configs.git

  2. change-directory into the repo

    cd ansible-configs

  3. Create a hosts file.

    On Linux, the majority of configuration is stored in the /etc directory. Ansible is no exception to this. Create /etc/ansible/hosts file containing:

    [nginx]
    localhost ansible_connection=local SSH_PORT=22

    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

  4. Use _bootstrap.sh to install Ansible and Python (required to install Ansible)

    ./_bootstrap.sh

    It 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)

  5. Once that has finished, close an 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).

  6. Check that it worked by running

    which ansible

    You should see an output like:

    /root/.local/bin/ansible (where "root" may be "/home/<your username>")

  7. Use ansible-playbook to run the nginx playbook

    ansible-playbook playbooks/nginx.yml

    This should:

How do I check that it worked?

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)

Using CloudFlare 0 Trust tunnel and fail2ban

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.

source

So, ... I set to work figuring out how to adapt the concept to work with the Rulesets API.

The result was this:

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_token your token (used by the script to authenticate)
  • cloudflare_email your email (used as "username" in conjunction with the token to authenticate)
  • cloudflare_zones list of zone IDs to apply the rules to (note, this setup will ban for all zones regardless of offending domain)
  • enable_cloud_flare_block set 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 as iptables). Enabling nginx's 'ngx_http_realip_module' is also triggered with this variable (this tells nginx to look at the X-Forwarded-For header for the IP of the requestor - not Cloudflare - and use in logs for fail2ban to pick up).

Optional variables for further control:

  • required_country_codes list 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_sources list of IPs for nginx to examine the X-Forwarded-For IP and replace in logs as the source IP. (Note: this defaults to a list containing: (1) 127.0.0.1/8 to handle cloudflared running on localhost, (2) 172.17.0.0/16 to handle cloudflared running in Docker, and (3) 192.168.1.1/24 to 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)

Example yaml ansible hosts file:

#/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

Validating

  1. 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)

  1. Log into CloudFlare dashboard and navigate to:

    A. Websites -> {your domain} -> Security -> WAF

    B. 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.254
    • 192.168.1.0 (assuming followed step above)

    Note: if required_country_codes, full rule syntax should in include ip.src in ... OR not 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")

  2. Unban user

    fail2ban-client unban 192.168.1.0

  3. Refresh Cloudflare dashboard -> IP should be removed from list of blocked (note, 127.255.255.254 will always be included to provide a simpler syntax and keep the expression valid)