WIP
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
[defaults]
|
[defaults]
|
||||||
inventory = ./inventory/
|
inventory = ./inventory/
|
||||||
|
gathering = smart
|
||||||
|
vault_password_file = ./.vault_pass
|
||||||
|
|
||||||
[ssh_connection]
|
[ssh_connection]
|
||||||
pipelining = True
|
pipelining = True
|
||||||
|
|||||||
5
ansible/ansible_local.env_example
Normal file
5
ansible/ansible_local.env_example
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
ANSIBLE_STRATEGY_PLUGINS=/home/seb/.local/share/pipx/venvs/ansible/lib/python3.13/site-packages/ansible_mitogen/plugins/strategy
|
||||||
|
export ANSIBLE_STRATEGY_PLUGINS
|
||||||
|
|
||||||
|
ANSIBLE_STRATEGY=mitogen_linear
|
||||||
|
export ANSIBLE_STRATEGY
|
||||||
24
ansible/play-config.yml
Normal file
24
ansible/play-config.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
- name: Web Application Firewalls (config)
|
||||||
|
hosts: waf
|
||||||
|
vars_files:
|
||||||
|
- "vars/common.yml"
|
||||||
|
- "vars/secrets.yml"
|
||||||
|
vars:
|
||||||
|
certs_ca_passphrase: "{{ secrets.ca.passphrase }}"
|
||||||
|
certs_default_country_name: "{{ common.certificates.country_name }}"
|
||||||
|
certs_default_locality_name: "{{ common.certificates.locality_name }}"
|
||||||
|
certs_default_organization_name: "{{ common.certificates.organization_name }}"
|
||||||
|
certs_default_email_address: "{{ common.certificates.email_address }}"
|
||||||
|
certs_list:
|
||||||
|
- cn: "test.lab"
|
||||||
|
domains:
|
||||||
|
- "DNS:test.lab"
|
||||||
|
- "DNS:{{ ansible_fqdn }}"
|
||||||
|
- "DNS:{{ ansible_hostname }}"
|
||||||
|
- "IP:{{ ansible_default_ipv4.address }}"
|
||||||
|
waf_config_sites: "{{ common.sites }}"
|
||||||
|
roles:
|
||||||
|
- "certs"
|
||||||
|
- "waf_config"
|
||||||
|
tags:
|
||||||
|
- "waf"
|
||||||
@@ -10,14 +10,15 @@
|
|||||||
hosts: all
|
hosts: all
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
vars_files:
|
vars_files:
|
||||||
- "vars.yml"
|
- "vars/common.yml"
|
||||||
|
- "vars/secrets.yml"
|
||||||
vars:
|
vars:
|
||||||
local_ca_common_name: "Lab CA"
|
local_ca_common_name: "Lab CA"
|
||||||
local_ca_passphrase: "{{ vault.ca.passphrase }}"
|
local_ca_passphrase: "{{ secrets.ca.passphrase }}"
|
||||||
local_ca_country_name: "FR"
|
local_ca_country_name: "{{ common.certificates.country_name }}"
|
||||||
local_ca_locality_name: "Vannes"
|
local_ca_locality_name: "{{ common.certificates.locality_name }}"
|
||||||
local_ca_organization_name: "iTik"
|
local_ca_organization_name: "{{ common.certificates.organization_name }}"
|
||||||
local_ca_email_address: "ca@itik.fr"
|
local_ca_email_address: "{{ common.certificates.email_address }}"
|
||||||
roles:
|
roles:
|
||||||
- "local_ca"
|
- "local_ca"
|
||||||
tags:
|
tags:
|
||||||
@@ -26,6 +27,9 @@
|
|||||||
- name: Proxy server
|
- name: Proxy server
|
||||||
hosts: proxy
|
hosts: proxy
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
|
vars_files:
|
||||||
|
- "vars/common.yml"
|
||||||
|
- "vars/secrets.yml"
|
||||||
vars:
|
vars:
|
||||||
squid_authorized_networks:
|
squid_authorized_networks:
|
||||||
- "{{ ansible_default_ipv4.network }}/24"
|
- "{{ ansible_default_ipv4.network }}/24"
|
||||||
@@ -38,7 +42,8 @@
|
|||||||
hosts: all
|
hosts: all
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
vars_files:
|
vars_files:
|
||||||
- "vars.yml"
|
- "vars/common.yml"
|
||||||
|
- "vars/secrets.yml"
|
||||||
vars:
|
vars:
|
||||||
common_proxy_server: "{{ hostvars['proxy1'].ansible_default_ipv4.address }}:3128"
|
common_proxy_server: "{{ hostvars['proxy1'].ansible_default_ipv4.address }}:3128"
|
||||||
roles:
|
roles:
|
||||||
@@ -49,39 +54,66 @@
|
|||||||
- name: HTTP Servers
|
- name: HTTP Servers
|
||||||
hosts: www
|
hosts: www
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
|
vars_files:
|
||||||
|
- "vars/common.yml"
|
||||||
|
- "vars/secrets.yml"
|
||||||
roles:
|
roles:
|
||||||
- "www"
|
- "www"
|
||||||
tags:
|
tags:
|
||||||
- "www"
|
- "www"
|
||||||
|
|
||||||
- name: Web Application Firewalls
|
- name: Web Application Firewalls (install)
|
||||||
hosts: waf
|
hosts: waf
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
vars_files:
|
vars_files:
|
||||||
- "vars.yml"
|
- "vars/common.yml"
|
||||||
|
- "vars/secrets.yml"
|
||||||
vars:
|
vars:
|
||||||
cert_domains:
|
certs_ca_passphrase: "{{ secrets.ca.passphrase }}"
|
||||||
|
certs_default_country_name: "{{ common.certificates.country_name }}"
|
||||||
|
certs_default_locality_name: "{{ common.certificates.locality_name }}"
|
||||||
|
certs_default_organization_name: "{{ common.certificates.organization_name }}"
|
||||||
|
certs_default_email_address: "{{ common.certificates.email_address }}"
|
||||||
|
certs_list:
|
||||||
|
# Consul
|
||||||
|
- cn: "server.{{ common.consul.datacenter }}.{{ common.consul.domain }}"
|
||||||
|
domains:
|
||||||
|
- "DNS:server.{{ common.consul.datacenter }}.{{ common.consul.domain }}"
|
||||||
|
# Sites
|
||||||
|
- cn: "test.lab"
|
||||||
|
domains:
|
||||||
- "DNS:test.lab"
|
- "DNS:test.lab"
|
||||||
- "DNS:{{ ansible_fqdn }}"
|
- "DNS:{{ ansible_fqdn }}"
|
||||||
- "DNS:{{ ansible_hostname }}"
|
- "DNS:{{ ansible_hostname }}"
|
||||||
- "IP:{{ ansible_default_ipv4.address }}"
|
- "IP:{{ ansible_default_ipv4.address }}"
|
||||||
- "DNS:server.{{ consul_datacenter }}.{{ consul_domain }}"
|
consul_domain: "{{ common.consul.domain }}"
|
||||||
cert_country_name: "FR"
|
consul_datacenter: "{{ common.consul.datacenter }}"
|
||||||
cert_locality_name: "Vannes"
|
consul_secret_key: "{{ secrets.consul.secret_key }}"
|
||||||
cert_organization_name: "iTik"
|
|
||||||
cert_email_address: "ca@itik.fr"
|
|
||||||
consul_domain: "itik.fr"
|
|
||||||
consul_datacenter: "lab"
|
|
||||||
consul_secret_key: "{{ vault.consul.secret_key }}"
|
|
||||||
consul_nodes:
|
consul_nodes:
|
||||||
- "waf1"
|
- "waf1"
|
||||||
- "waf2"
|
- "waf2"
|
||||||
- "waf3"
|
- "waf3"
|
||||||
bgwaf_cluster: false
|
# FIXME: -> Cady modules
|
||||||
bgwaf_sites: "{{ waf.sites }}"
|
waf_install_cluster: true
|
||||||
|
vip_script_user: "caddy"
|
||||||
|
vip_monitored_process: "caddy"
|
||||||
|
vip_vrrp_password: "{{ secrets.keepalived.secret }}"
|
||||||
|
vip_vrrp_ips:
|
||||||
|
- master: "waf1"
|
||||||
|
virtual_router_id: 11
|
||||||
|
addr: "{{ {{ ansible_default_ipv4.address }} | split('.')[0-3] | join('.') }}.250"
|
||||||
|
- master: "waf2"
|
||||||
|
virtual_router_id: 12
|
||||||
|
addr: "{{ {{ ansible_default_ipv4.address }} | split('.')[0-3] | join('.') }}.251"
|
||||||
|
- master: "waf3"
|
||||||
|
virtual_router_id: 13
|
||||||
|
addr: "{{ {{ ansible_default_ipv4.address }} | split('.')[0-3] | join('.') }}.252"
|
||||||
|
waf_config_sites: "{{ common.sites }}"
|
||||||
roles:
|
roles:
|
||||||
- "cert"
|
- "certs"
|
||||||
- "consul"
|
- "consul"
|
||||||
- "bgwaf"
|
- "waf_install"
|
||||||
|
- "vip"
|
||||||
|
- "waf_config"
|
||||||
tags:
|
tags:
|
||||||
- "bgwaf"
|
- "waf"
|
||||||
|
|||||||
@@ -1,201 +0,0 @@
|
|||||||
- name: Remove packaged Go
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name:
|
|
||||||
- "golang"
|
|
||||||
state: "absent"
|
|
||||||
autoremove: true
|
|
||||||
purge: true
|
|
||||||
|
|
||||||
- name: Install requirements
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name:
|
|
||||||
- "git"
|
|
||||||
- "libnss3-tools"
|
|
||||||
|
|
||||||
- name: Create Go directory
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "/usr/local/go-{{ bgwaf_go_version }}"
|
|
||||||
state: "directory"
|
|
||||||
mode: "0755"
|
|
||||||
|
|
||||||
- name: Install Go
|
|
||||||
ansible.builtin.unarchive:
|
|
||||||
src: "https://go.dev/dl/go{{ bgwaf_go_version }}.linux-amd64.tar.gz"
|
|
||||||
dest: "/usr/local/go-{{ bgwaf_go_version }}"
|
|
||||||
remote_src: true
|
|
||||||
|
|
||||||
- name: Link Go
|
|
||||||
ansible.builtin.file:
|
|
||||||
src: "/usr/local/go-{{ bgwaf_go_version }}/go/bin/go"
|
|
||||||
dest: "/usr/local/bin/go"
|
|
||||||
state: "link"
|
|
||||||
|
|
||||||
- name: Install xcaddy
|
|
||||||
when: |
|
|
||||||
'xcaddy' not in ansible_facts.packages
|
|
||||||
or ansible_facts.packages['xcaddy'][0]['version'] != bgwaf_xcaddy_version
|
|
||||||
ansible.builtin.apt:
|
|
||||||
deb: "{{ bgwaf_xcaddy_download }}/v{{ bgwaf_xcaddy_version }}/xcaddy_{{ bgwaf_xcaddy_version }}_linux_amd64.deb"
|
|
||||||
force: true
|
|
||||||
|
|
||||||
- name: Create Caddy build command
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
bgwaf_build_command: >
|
|
||||||
xcaddy build v{{ bgwaf_caddy_version }}
|
|
||||||
{% if bgwaf_cluster %} --with github.com/pteich/caddy-tlsconsul{% endif %}
|
|
||||||
--with github.com/corazawaf/coraza-caddy/v2@v{{ bgwaf_coraza_caddy_version }}
|
|
||||||
--with github.com/mholt/caddy-ratelimit
|
|
||||||
--with github.com/steffenbusch/caddy-bot-barrier
|
|
||||||
--output /usr/local/bin/caddy
|
|
||||||
|
|
||||||
- name: Test Caddy version
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: "/usr/local/bin/.caddy.build"
|
|
||||||
content: "{{ bgwaf_build_command }}"
|
|
||||||
mode: "0644"
|
|
||||||
register: bgwaf_test_caddy_version
|
|
||||||
|
|
||||||
- name: Build Caddy
|
|
||||||
# noqa: no-handler
|
|
||||||
when: "bgwaf_test_caddy_version.changed"
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: "{{ bgwaf_build_command }}"
|
|
||||||
creates: "/usr/local/bin/caddy"
|
|
||||||
notify:
|
|
||||||
- "Restart Caddy"
|
|
||||||
|
|
||||||
- name: Create caddy system group
|
|
||||||
ansible.builtin.group:
|
|
||||||
name: "caddy"
|
|
||||||
system: true
|
|
||||||
|
|
||||||
- name: Create caddy system user
|
|
||||||
ansible.builtin.user:
|
|
||||||
name: "caddy"
|
|
||||||
group: "caddy"
|
|
||||||
groups: ["ssl-cert"]
|
|
||||||
password: "!"
|
|
||||||
system: true
|
|
||||||
home: "/opt/caddy"
|
|
||||||
|
|
||||||
- name: Create caddy config directories
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ item }}"
|
|
||||||
state: "directory"
|
|
||||||
group: "caddy"
|
|
||||||
mode: "0750"
|
|
||||||
loop:
|
|
||||||
- "/etc/caddy"
|
|
||||||
- "/etc/caddy/plugins"
|
|
||||||
- "/etc/caddy/sites"
|
|
||||||
|
|
||||||
- name: Create caddy log dir
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "/var/log/caddy"
|
|
||||||
state: "directory"
|
|
||||||
group: "caddy"
|
|
||||||
mode: "0770"
|
|
||||||
|
|
||||||
- name: Install OWASP CRS
|
|
||||||
ansible.builtin.unarchive:
|
|
||||||
src: "https://github.com/coreruleset/coreruleset/archive/refs/tags/v{{ bgwaf_owasp_crs_version }}.tar.gz"
|
|
||||||
dest: "/etc/caddy"
|
|
||||||
group: "caddy"
|
|
||||||
remote_src: true
|
|
||||||
|
|
||||||
- name: Install plugins
|
|
||||||
loop: "{{ bgwaf_crs_plugins }}"
|
|
||||||
loop_control:
|
|
||||||
loop_var: "plugin"
|
|
||||||
ansible.builtin.include_tasks: "install_plugin.yml"
|
|
||||||
|
|
||||||
- name: Create sites config directories
|
|
||||||
loop: "{{ bgwaf_sites }}"
|
|
||||||
loop_control:
|
|
||||||
loop_var: "site"
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "/etc/caddy/sites/{{ site.name }}"
|
|
||||||
state: "directory"
|
|
||||||
group: "caddy"
|
|
||||||
mode: "0750"
|
|
||||||
|
|
||||||
- name: Generate sites coraza.conf config file
|
|
||||||
loop: "{{ bgwaf_sites }}"
|
|
||||||
loop_control:
|
|
||||||
loop_var: "site"
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: "templates/coraza.conf"
|
|
||||||
dest: "/etc/caddy/sites/{{ site.name }}/coraza.conf"
|
|
||||||
group: "caddy"
|
|
||||||
mode: "0640"
|
|
||||||
notify:
|
|
||||||
- "Reload Caddy"
|
|
||||||
|
|
||||||
- name: Generate sites crs-setup config file
|
|
||||||
loop: "{{ bgwaf_sites }}"
|
|
||||||
loop_control:
|
|
||||||
loop_var: "site"
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: "templates/crs-setup.conf"
|
|
||||||
dest: "/etc/caddy/sites/{{ site.name }}/crs-setup.conf"
|
|
||||||
group: "caddy"
|
|
||||||
mode: "0640"
|
|
||||||
notify:
|
|
||||||
- "Reload Caddy"
|
|
||||||
|
|
||||||
- name: Generate sites exclusions before request file
|
|
||||||
loop: "{{ bgwaf_sites }}"
|
|
||||||
loop_control:
|
|
||||||
loop_var: "site"
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: "templates/exclusions-request-before.conf"
|
|
||||||
dest: "/etc/caddy/sites/{{ site.name }}/exclusions-request-before.conf"
|
|
||||||
group: "caddy"
|
|
||||||
mode: "0640"
|
|
||||||
notify:
|
|
||||||
- "Reload Caddy"
|
|
||||||
|
|
||||||
- name: Generate sites exclusions after response file
|
|
||||||
loop: "{{ bgwaf_sites }}"
|
|
||||||
loop_control:
|
|
||||||
loop_var: "site"
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: "templates/exclusions-response-after.conf"
|
|
||||||
dest: "/etc/caddy/sites/{{ site.name }}/exclusions-response-after.conf"
|
|
||||||
group: "caddy"
|
|
||||||
mode: "0640"
|
|
||||||
notify:
|
|
||||||
- "Reload Caddy"
|
|
||||||
|
|
||||||
- name: Generate Caddyfile
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: "templates/Caddyfile"
|
|
||||||
dest: "/etc/caddy/Caddyfile"
|
|
||||||
group: "caddy"
|
|
||||||
mode: "0640"
|
|
||||||
notify:
|
|
||||||
- "Reload Caddy"
|
|
||||||
|
|
||||||
- name: Copy bot barrier template
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: "files/bot_barrier_template.html"
|
|
||||||
dest: "/etc/caddy/bot_barrier_template.html"
|
|
||||||
group: "caddy"
|
|
||||||
mode: "0640"
|
|
||||||
notify:
|
|
||||||
- "Reload Caddy"
|
|
||||||
|
|
||||||
- name: Deploy caddy service file
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: "templates/caddy.service"
|
|
||||||
dest: "/etc/systemd/system/caddy.service"
|
|
||||||
mode: "0644"
|
|
||||||
notify:
|
|
||||||
- "Restart Caddy"
|
|
||||||
|
|
||||||
- name: Enable and start Caddy
|
|
||||||
ansible.builtin.service:
|
|
||||||
name: "caddy"
|
|
||||||
state: "started"
|
|
||||||
enabled: true
|
|
||||||
daemon_reload: true
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
bgwaf_xcaddy_download: "https://github.com/caddyserver/xcaddy/releases/download"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# Defaults
|
|
||||||
cert_not_after: "+365d" # valid for one year
|
|
||||||
cert_not_before: "-1d" # valid since yesterday
|
|
||||||
|
|
||||||
# Required
|
|
||||||
cert_domains: []
|
|
||||||
cert_country_name: None
|
|
||||||
cert_locality_name: None
|
|
||||||
cert_organization_name: None
|
|
||||||
cert_email_address: None
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
- name: Install requirements
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name:
|
|
||||||
- "ssl-cert"
|
|
||||||
|
|
||||||
- name: Copy CA certificate file on server
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: "ca/ca-certificate.crt"
|
|
||||||
dest: "/etc/ssl/certs/local-ca.crt"
|
|
||||||
mode: "0644"
|
|
||||||
|
|
||||||
- name: Create private key for new certificate
|
|
||||||
community.crypto.openssl_privatekey:
|
|
||||||
path: "/etc/ssl/private/local.key"
|
|
||||||
mode: "0640"
|
|
||||||
group: "ssl-cert"
|
|
||||||
|
|
||||||
- name: Create CSR for new certificate
|
|
||||||
community.crypto.openssl_csr:
|
|
||||||
path: "/etc/ssl/certs/local.csr"
|
|
||||||
privatekey_path: "/etc/ssl/private/local.key"
|
|
||||||
common_name: "{{ cert_domains[0] }}"
|
|
||||||
subject_alt_name: "{{ cert_domains }}"
|
|
||||||
country_name: "{{ cert_country_name }}"
|
|
||||||
locality_name: "{{ cert_locality_name }}"
|
|
||||||
organization_name: "{{ cert_organization_name }}"
|
|
||||||
email_address: "{{ cert_email_address }}"
|
|
||||||
return_content: true
|
|
||||||
register: cert_csr
|
|
||||||
|
|
||||||
- name: Sign certificate with our CA
|
|
||||||
delegate_to: "localhost"
|
|
||||||
# noqa: no-handler
|
|
||||||
when: "cert_csr.changed"
|
|
||||||
community.crypto.x509_certificate_pipe:
|
|
||||||
csr_content: "{{ cert_csr.csr }}"
|
|
||||||
provider: "ownca"
|
|
||||||
ownca_path: "ca/ca-certificate.crt"
|
|
||||||
ownca_privatekey_path: "ca/ca-certificate.key"
|
|
||||||
ownca_privatekey_passphrase: "{{ vault.ca.passphrase }}"
|
|
||||||
ownca_not_after: "{{ cert_not_after }}"
|
|
||||||
ownca_not_before: "{{ cert_not_before }}"
|
|
||||||
register: cert_certificate
|
|
||||||
|
|
||||||
- name: Write certificate file on server
|
|
||||||
# noqa: no-handler
|
|
||||||
when: "cert_csr.changed"
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: "/etc/ssl/certs/local.crt"
|
|
||||||
content: "{{ cert_certificate.certificate }}"
|
|
||||||
mode: "0644"
|
|
||||||
notify:
|
|
||||||
- "Reboot host"
|
|
||||||
19
ansible/roles/certs/defaults/main.yml
Normal file
19
ansible/roles/certs/defaults/main.yml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Defaults
|
||||||
|
certs_default_country_name: null
|
||||||
|
certs_default_locality_name: null
|
||||||
|
certs_default_organization_name: null
|
||||||
|
certs_default_email_address: null
|
||||||
|
certs_default_not_after: "+365d" # valid for one year
|
||||||
|
certs_default_not_before: "-1d" # valid since yesterday
|
||||||
|
|
||||||
|
# Required
|
||||||
|
certs_ca_passphrase: null
|
||||||
|
certs_list: {}
|
||||||
|
# - cn: <string>
|
||||||
|
# domains: <array of strings>
|
||||||
|
# country_name: <string>
|
||||||
|
# locality_name: <string>
|
||||||
|
# organization_name: <string>
|
||||||
|
# email_address: <string>
|
||||||
|
# not_after: <string>
|
||||||
|
# not_before: <string>
|
||||||
42
ansible/roles/certs/tasks/create_cert.yml
Normal file
42
ansible/roles/certs/tasks/create_cert.yml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
- name: Create private key for new certificate
|
||||||
|
community.crypto.openssl_privatekey:
|
||||||
|
path: "/etc/ssl/private/{{ cert.cn }}.key"
|
||||||
|
mode: "0640"
|
||||||
|
group: "ssl-cert"
|
||||||
|
|
||||||
|
- name: Create CSR for new certificate
|
||||||
|
community.crypto.openssl_csr:
|
||||||
|
path: "/etc/ssl/certs/{{ cert.cn }}.csr"
|
||||||
|
privatekey_path: "/etc/ssl/private/{{ cert.cn }}.key"
|
||||||
|
common_name: "{{ cert.cn }}"
|
||||||
|
subject_alt_name: "{{ cert.domains }}"
|
||||||
|
country_name: "{{ cert.country_name | default(certs_default_country_name) | mandatory }}"
|
||||||
|
locality_name: "{{ cert.locality_name | default(certs_default_locality_name) | mandatory }}"
|
||||||
|
organization_name: "{{ cert.organization_name | default(certs_default_organization_name) | mandatory }}"
|
||||||
|
email_address: "{{ cert.email_address | default(certs_default_email_address) | mandatory }}"
|
||||||
|
return_content: true
|
||||||
|
register: certs_csr
|
||||||
|
|
||||||
|
- name: Sign certificate with our CA
|
||||||
|
delegate_to: "localhost"
|
||||||
|
# noqa: no-handler
|
||||||
|
when: "certs_csr.changed"
|
||||||
|
community.crypto.x509_certificate_pipe:
|
||||||
|
csr_content: "{{ certs_csr.csr }}"
|
||||||
|
provider: "ownca"
|
||||||
|
ownca_path: "ca/ca-certificate.crt"
|
||||||
|
ownca_privatekey_path: "ca/ca-certificate.key"
|
||||||
|
ownca_privatekey_passphrase: "{{ certs_ca_passphrase }}"
|
||||||
|
ownca_not_after: "{{ cert.not_after | default(certs_default_not_after) }}"
|
||||||
|
ownca_not_before: "{{ cert.not_before | default(certs_default_not_before) }}"
|
||||||
|
register: certs_certificate
|
||||||
|
|
||||||
|
- name: Write certificate file on server
|
||||||
|
# noqa: no-handler
|
||||||
|
when: "certs_csr.changed"
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: "/etc/ssl/certs/{{ cert.cn }}.crt"
|
||||||
|
content: "{{ certs_certificate.certificate }}"
|
||||||
|
mode: "0644"
|
||||||
|
notify:
|
||||||
|
- "Reboot host"
|
||||||
16
ansible/roles/certs/tasks/main.yml
Normal file
16
ansible/roles/certs/tasks/main.yml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
- name: Install requirements
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- "ssl-cert"
|
||||||
|
|
||||||
|
- name: Copy CA certificate file on server
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "ca/ca-certificate.crt"
|
||||||
|
dest: "/etc/ssl/certs/local-ca.crt"
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Create certs
|
||||||
|
loop: "{{ certs_list }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: "cert"
|
||||||
|
ansible.builtin.include_tasks: "create_cert.yml"
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
# Required
|
# Required
|
||||||
consul_datacenter: null
|
consul_datacenter: null
|
||||||
|
consul_domain: null
|
||||||
consul_secret_key: null
|
consul_secret_key: null
|
||||||
consul_nodes: []
|
consul_nodes: []
|
||||||
consul_domain: None
|
|
||||||
|
|
||||||
# Defaults
|
# Defaults
|
||||||
consul_version: "1.22.2"
|
consul_version: "1.22.2"
|
||||||
consul_key_file: "/etc/ssl/private/local.key"
|
consul_key_file: "/etc/ssl/private/server.{{ consul_datacenter }}.{{ consul_domain }}.key"
|
||||||
consul_cert_file: "/etc/ssl/certs/local.crt"
|
consul_cert_file: "/etc/ssl/certs/server.{{ consul_datacenter }}.{{ consul_domain }}.crt"
|
||||||
consul_ca_file: "/etc/ssl/certs/local-ca.crt"
|
consul_ca_file: "/etc/ssl/certs/local-ca.crt"
|
||||||
consul_client_addr: "0.0.0.0"
|
consul_client_addr: "0.0.0.0"
|
||||||
consul_bind_addr: "{{ ansible_default_ipv4.address }}"
|
consul_bind_addr: "{{ ansible_default_ipv4.address }}"
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ local_ca_key_size: 4096
|
|||||||
local_ca_key_type: "RSA"
|
local_ca_key_type: "RSA"
|
||||||
|
|
||||||
# Required
|
# Required
|
||||||
local_ca_common_name: None
|
local_ca_common_name: null
|
||||||
local_ca_passphrase: None
|
local_ca_passphrase: null
|
||||||
local_ca_country_name: None
|
local_ca_country_name: null
|
||||||
local_ca_locality_name: None
|
local_ca_locality_name: null
|
||||||
local_ca_organization_name: None
|
local_ca_organization_name: null
|
||||||
local_ca_email_address: None
|
local_ca_email_address: null
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
community.crypto.openssl_csr:
|
community.crypto.openssl_csr:
|
||||||
path: "ca/ca-certificate.csr"
|
path: "ca/ca-certificate.csr"
|
||||||
privatekey_path: "ca/ca-certificate.key"
|
privatekey_path: "ca/ca-certificate.key"
|
||||||
privatekey_passphrase: "{{ vault.ca.passphrase }}"
|
privatekey_passphrase: "{{ local_ca_passphrase }}"
|
||||||
common_name: "{{ local_ca_common_name }}"
|
common_name: "{{ local_ca_common_name }}"
|
||||||
use_common_name_for_san: false # since we do not specify SANs, don't use CN as a SAN
|
use_common_name_for_san: false # since we do not specify SANs, don't use CN as a SAN
|
||||||
country_name: "{{ local_ca_country_name }}"
|
country_name: "{{ local_ca_country_name }}"
|
||||||
@@ -47,5 +47,5 @@
|
|||||||
path: "ca/ca-certificate.crt"
|
path: "ca/ca-certificate.crt"
|
||||||
csr_content: "{{ local_ca_csr.csr }}"
|
csr_content: "{{ local_ca_csr.csr }}"
|
||||||
privatekey_path: "ca/ca-certificate.key"
|
privatekey_path: "ca/ca-certificate.key"
|
||||||
privatekey_passphrase: "{{ vault.ca.passphrase }}"
|
privatekey_passphrase: "{{ local_ca_passphrase }}"
|
||||||
provider: "selfsigned"
|
provider: "selfsigned"
|
||||||
|
|||||||
16
ansible/roles/vip/defaults/main.yml
Normal file
16
ansible/roles/vip/defaults/main.yml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Required
|
||||||
|
vip_script_user: null
|
||||||
|
vip_monitored_process: null
|
||||||
|
vip_vrrp_password: null # Max 8 characters
|
||||||
|
vip_vrrp_ips: null
|
||||||
|
# - master: <string>
|
||||||
|
# virtual_router_id: <int>
|
||||||
|
# addr: <string>
|
||||||
|
|
||||||
|
# Optionnal
|
||||||
|
vip_alerts_to: null
|
||||||
|
# - <string>
|
||||||
|
|
||||||
|
# Required if length vip_alerts_to > 0
|
||||||
|
vip_smtp_from: null
|
||||||
|
vip_smtp_relay: null
|
||||||
4
ansible/roles/vip/handlers/main.yml
Normal file
4
ansible/roles/vip/handlers/main.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
- name: Restart keepalived
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: "keepalived"
|
||||||
|
state: "restarted"
|
||||||
28
ansible/roles/vip/tasks/main.yml
Normal file
28
ansible/roles/vip/tasks/main.yml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
- name: Installation des paquetages
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- "keepalived"
|
||||||
|
notify:
|
||||||
|
- "Restart keepalived"
|
||||||
|
|
||||||
|
- name: Tell kernel to allow binding non-local IP
|
||||||
|
ansible.posix.sysctl:
|
||||||
|
name: "net.ipv4.ip_nonlocal_bind"
|
||||||
|
value: "1"
|
||||||
|
sysctl_set: true
|
||||||
|
notify:
|
||||||
|
- "Restart keepalived"
|
||||||
|
|
||||||
|
- name: Generate keepalived.conf file
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "templates/keepalived.conf"
|
||||||
|
dest: "/etc/keepalived/keepalived.conf"
|
||||||
|
mode: "0640"
|
||||||
|
notify:
|
||||||
|
- "Restart keepalived"
|
||||||
|
|
||||||
|
- name: Activate and start keepalived
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: "keepalived"
|
||||||
|
state: "started"
|
||||||
|
enabled: true
|
||||||
45
ansible/roles/vip/templates/keepalived.conf
Normal file
45
ansible/roles/vip/templates/keepalived.conf
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
global_defs {
|
||||||
|
enable_script_security
|
||||||
|
script_user "{{ vip_script_user }}"
|
||||||
|
{% if vip_alerts_to | default([]) | length > 0 %}
|
||||||
|
|
||||||
|
notification_email {
|
||||||
|
{% for dest in vip_alerts_to %}
|
||||||
|
{{ dest }}
|
||||||
|
{% endfor %}
|
||||||
|
}
|
||||||
|
notification_email_from {{ vip_smtp_from }}
|
||||||
|
smtp_server {{ vip_smtp_relay }}
|
||||||
|
smtp_connect_timeout 30
|
||||||
|
router_id {{ ansible_hostname }}
|
||||||
|
{% endif %}
|
||||||
|
}
|
||||||
|
|
||||||
|
vrrp_script chk_{{ vip_monitored_process }} {
|
||||||
|
script "/usr/bin/killall -0 {{ vip_monitored_process }}" # Check if process is running
|
||||||
|
interval 2 # Check every 2 seconds
|
||||||
|
weight 2 # Weight to influence master election
|
||||||
|
}
|
||||||
|
{% for ip in vip_vrrp_ips %}
|
||||||
|
|
||||||
|
# master: {{ ip.master }}
|
||||||
|
vrrp_instance VI_{{ ip.virtual_router_id }} {
|
||||||
|
state {{ (ansible_hostname==ip.master) | ternary('MASTER', 'BACKUP') }}
|
||||||
|
interface eth0
|
||||||
|
virtual_router_id {{ ip.virtual_router_id }}
|
||||||
|
priority {{ (ansible_hostname==ip.master) | ternary('101', '100') }}
|
||||||
|
advert_int 1
|
||||||
|
promote_secondaries
|
||||||
|
smtp_alert true
|
||||||
|
authentication {
|
||||||
|
auth_type PASS
|
||||||
|
auth_pass {{ vip_vrrp_password }}
|
||||||
|
}
|
||||||
|
virtual_ipaddress {
|
||||||
|
{{ ip.addr }}
|
||||||
|
}
|
||||||
|
track_script {
|
||||||
|
chk_{{ vip_monitored_process }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{% endfor %}
|
||||||
@@ -1,42 +1,17 @@
|
|||||||
bgwaf_go_version: "1.25.5"
|
# Defaults
|
||||||
bgwaf_xcaddy_version: "0.4.5"
|
waf_config_owasp_crs_version: "4.21.0"
|
||||||
bgwaf_caddy_version: "2.10.2"
|
|
||||||
bgwaf_coraza_caddy_version: "2.1.0" # Coraza v3.3.3
|
|
||||||
bgwaf_owasp_crs_version: "4.21.0"
|
|
||||||
|
|
||||||
# Cluster mode (e.g. with consul)
|
|
||||||
bgwaf_cluster: false
|
|
||||||
|
|
||||||
# Required unless not site.custom_cert
|
# Required unless not site.custom_cert
|
||||||
bgwaf_email: null
|
waf_config_email: null
|
||||||
|
|
||||||
# Required if site.bot_barrier
|
# Required if site.bot_barrier
|
||||||
bgwaf_bot_barrier_secret: null
|
waf_config_bot_barrier_secret: null
|
||||||
|
|
||||||
# Optionnal
|
# Optionnal
|
||||||
bgwaf_local_ca_name: null
|
waf_config_local_ca_name: null
|
||||||
bgwaf_ca_root: null
|
waf_config_ca_root: null
|
||||||
|
|
||||||
# Cf.: https://github.com/coreruleset/plugin-registry
|
waf_config_sites: []
|
||||||
bgwaf_crs_plugins:
|
|
||||||
- name: "drupal-rule-exclusions"
|
|
||||||
version: "1.0.0"
|
|
||||||
- name: "wordpress-rule-exclusions"
|
|
||||||
version: "1.2.0"
|
|
||||||
- name: "nextcloud-rule-exclusions"
|
|
||||||
version: "1.5.0"
|
|
||||||
- name: "dokuwiki-rule-exclusions"
|
|
||||||
version: "1.0.0"
|
|
||||||
- name: "phpmyadmin-rule-exclusions"
|
|
||||||
version: "1.0.0"
|
|
||||||
- name: "roundcube-rule-exclusions"
|
|
||||||
version: "1.0.4"
|
|
||||||
provider: "EsadCetiner"
|
|
||||||
- name: "sogo-rule-exclusions"
|
|
||||||
version: "1.0.4"
|
|
||||||
provider: "EsadCetiner"
|
|
||||||
|
|
||||||
bgwaf_sites: []
|
|
||||||
# - name: ""
|
# - name: ""
|
||||||
# site: ""
|
# site: ""
|
||||||
# paths:
|
# paths:
|
||||||
@@ -55,15 +30,19 @@ bgwaf_sites: []
|
|||||||
# after_response:
|
# after_response:
|
||||||
# - ""
|
# - ""
|
||||||
|
|
||||||
bgwaf_defaults:
|
waf_config_defaults:
|
||||||
redirect_from_aliases: true
|
redirect_from_aliases: true
|
||||||
custom_cert: true
|
custom_cert: true
|
||||||
custom_cert_file: ""
|
custom_cert_file: ""
|
||||||
custom_key_file: ""
|
custom_key_file: ""
|
||||||
|
|
||||||
rate_events: 1000
|
rate_events: 1000
|
||||||
rate_window: "1m"
|
rate_window: "1m"
|
||||||
|
|
||||||
bot_barrier: false
|
bot_barrier: false
|
||||||
log_only: true
|
|
||||||
|
# CRS defaults
|
||||||
|
log_only: false
|
||||||
paranoia_level: 1
|
paranoia_level: 1
|
||||||
detection_paranoia_level: null
|
detection_paranoia_level: null
|
||||||
enforce_bodyproc_urlencoded: 1
|
enforce_bodyproc_urlencoded: 1
|
||||||
@@ -100,8 +79,12 @@ bgwaf_defaults:
|
|||||||
- ".asa/"
|
- ".asa/"
|
||||||
- ".asax/"
|
- ".asax/"
|
||||||
- ".ascx/"
|
- ".ascx/"
|
||||||
|
- ".back/"
|
||||||
- ".backup/"
|
- ".backup/"
|
||||||
- ".bak/"
|
- ".bak/"
|
||||||
|
- ".bck/"
|
||||||
|
- ".bk/"
|
||||||
|
- ".bkp/"
|
||||||
- ".bat/"
|
- ".bat/"
|
||||||
- ".cdx/"
|
- ".cdx/"
|
||||||
- ".cer/"
|
- ".cer/"
|
||||||
@@ -158,9 +141,11 @@ bgwaf_defaults:
|
|||||||
- ".reg/"
|
- ".reg/"
|
||||||
- ".resources/"
|
- ".resources/"
|
||||||
- ".resx/"
|
- ".resx/"
|
||||||
|
- ".sav/"
|
||||||
- ".save/"
|
- ".save/"
|
||||||
- ".scr/"
|
- ".scr/"
|
||||||
- ".sct/"
|
- ".sct/"
|
||||||
|
- ".sh/"
|
||||||
- ".shs/"
|
- ".shs/"
|
||||||
- ".sql/"
|
- ".sql/"
|
||||||
- ".sqlite/"
|
- ".sqlite/"
|
||||||
4
ansible/roles/waf_config/handlers/main.yml
Normal file
4
ansible/roles/waf_config/handlers/main.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
- name: Reload Caddy
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: "caddy"
|
||||||
|
state: "reloaded"
|
||||||
75
ansible/roles/waf_config/tasks/main.yml
Normal file
75
ansible/roles/waf_config/tasks/main.yml
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
- name: Create sites config directories
|
||||||
|
loop: "{{ waf_config_sites }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: "site"
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/etc/caddy/sites/{{ site.name }}"
|
||||||
|
state: "directory"
|
||||||
|
group: "caddy"
|
||||||
|
mode: "0750"
|
||||||
|
|
||||||
|
- name: Generate sites coraza.conf config file
|
||||||
|
loop: "{{ waf_config_sites }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: "site"
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "templates/coraza.conf"
|
||||||
|
dest: "/etc/caddy/sites/{{ site.name }}/coraza.conf"
|
||||||
|
group: "caddy"
|
||||||
|
mode: "0640"
|
||||||
|
notify:
|
||||||
|
- "Reload Caddy"
|
||||||
|
|
||||||
|
- name: Generate sites crs-setup config file
|
||||||
|
loop: "{{ waf_config_sites }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: "site"
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "templates/crs-setup.conf"
|
||||||
|
dest: "/etc/caddy/sites/{{ site.name }}/crs-setup.conf"
|
||||||
|
group: "caddy"
|
||||||
|
mode: "0640"
|
||||||
|
notify:
|
||||||
|
- "Reload Caddy"
|
||||||
|
|
||||||
|
- name: Generate sites exclusions before request file
|
||||||
|
loop: "{{ waf_config_sites }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: "site"
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "templates/exclusions-request-before.conf"
|
||||||
|
dest: "/etc/caddy/sites/{{ site.name }}/exclusions-request-before.conf"
|
||||||
|
group: "caddy"
|
||||||
|
mode: "0640"
|
||||||
|
notify:
|
||||||
|
- "Reload Caddy"
|
||||||
|
|
||||||
|
- name: Generate sites exclusions after response file
|
||||||
|
loop: "{{ waf_config_sites }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: "site"
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "templates/exclusions-response-after.conf"
|
||||||
|
dest: "/etc/caddy/sites/{{ site.name }}/exclusions-response-after.conf"
|
||||||
|
group: "caddy"
|
||||||
|
mode: "0640"
|
||||||
|
notify:
|
||||||
|
- "Reload Caddy"
|
||||||
|
|
||||||
|
- name: Generate Caddyfile
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "templates/Caddyfile"
|
||||||
|
dest: "/etc/caddy/Caddyfile"
|
||||||
|
group: "caddy"
|
||||||
|
mode: "0640"
|
||||||
|
notify:
|
||||||
|
- "Reload Caddy"
|
||||||
|
|
||||||
|
- name: Copy bot barrier template
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "files/bot_barrier_template.html"
|
||||||
|
dest: "/etc/caddy/bot_barrier_template.html"
|
||||||
|
group: "caddy"
|
||||||
|
mode: "0640"
|
||||||
|
notify:
|
||||||
|
- "Reload Caddy"
|
||||||
@@ -2,13 +2,13 @@
|
|||||||
# storage redis
|
# storage redis
|
||||||
grace_period 10s
|
grace_period 10s
|
||||||
order coraza_waf first
|
order coraza_waf first
|
||||||
{% if bgwaf_email | default(None) != None %}
|
{% if waf_config_email | default(None) != None %}
|
||||||
email "{{ bgwaf_email }}"
|
email "{{ waf_config_email }}"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if bgwaf_ca_root | default(None) != None %}
|
{% if waf_config_ca_root | default(None) != None %}
|
||||||
tls {
|
tls {
|
||||||
ca_root "{{ bgwaf_ca_root }}"
|
ca_root "{{ waf_config_ca_root }}"
|
||||||
}
|
}
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -17,17 +17,17 @@
|
|||||||
include "http.handlers.waf"
|
include "http.handlers.waf"
|
||||||
output file /var/log/caddy/waf.log
|
output file /var/log/caddy/waf.log
|
||||||
}
|
}
|
||||||
{% if bgwaf_local_ca_name | default(None) != None %}
|
{% if waf_config_local_ca_name | default(None) != None %}
|
||||||
|
|
||||||
pki {
|
pki {
|
||||||
ca local {
|
ca local {
|
||||||
name "{{ bgwaf_local_ca_name }}"
|
name "{{ waf_config_local_ca_name }}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
}
|
}
|
||||||
|
|
||||||
{% for site in bgwaf_sites %}
|
{% for site in waf_config_sites %}
|
||||||
{% if (site.redirect_from_aliases | default(true)) and (site.aliases | default([]) | length) > 0 %}
|
{% if (site.redirect_from_aliases | default(true)) and (site.aliases | default([]) | length) > 0 %}
|
||||||
{{ site.aliases | join(', ') }} {
|
{{ site.aliases | join(', ') }} {
|
||||||
redir https://{{ site.site }}{uri}
|
redir https://{{ site.site }}{uri}
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% if site.bot_barrier | default (false) %}
|
{% if site.bot_barrier | default (false) %}
|
||||||
bot_barrier {
|
bot_barrier {
|
||||||
secret {{ bgwaf_bot_barrier_secret }}
|
secret {{ waf_config_bot_barrier_secret }}
|
||||||
complexity 18
|
complexity 18
|
||||||
valid_for 30m
|
valid_for 30m
|
||||||
seed_cookie_name __chall_{{ site.name }}_seed
|
seed_cookie_name __chall_{{ site.name }}_seed
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
Include "/etc/caddy/plugins/*-config.conf"
|
Include "/etc/caddy/plugins/*-config.conf"
|
||||||
Include "/etc/caddy/plugins/*-before.conf"
|
Include "/etc/caddy/plugins/*-before.conf"
|
||||||
Include "/etc/caddy/sites/{{ site.name }}/exclusions-request-before.conf"
|
Include "/etc/caddy/sites/{{ site.name }}/exclusions-request-before.conf"
|
||||||
Include "/etc/caddy/coreruleset-{{ bgwaf_owasp_crs_version }}/rules/*.conf"
|
Include "/etc/caddy/coreruleset-{{ waf_config_owasp_crs_version }}/rules/*.conf"
|
||||||
Include "/etc/caddy/sites/{{ site.name }}/exclusions-response-after.conf"
|
Include "/etc/caddy/sites/{{ site.name }}/exclusions-response-after.conf"
|
||||||
Include "/etc/caddy/plugins/*-after.conf"
|
Include "/etc/caddy/plugins/*-after.conf"
|
||||||
SecRuleEngine On
|
SecRuleEngine On
|
||||||
@@ -10,9 +10,9 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.blocking_paranoia_level={{ site.paranoia_level | default(bgwaf_defaults.paranoia_level) }}"
|
setvar:tx.blocking_paranoia_level={{ site.paranoia_level | default(waf_config_defaults.paranoia_level) }}"
|
||||||
{% if site.detection_paranoia_level | default(bgwaf_defaults.detection_paranoia_level) != None %}
|
{% if site.detection_paranoia_level | default(waf_config_defaults.detection_paranoia_level) != None %}
|
||||||
|
|
||||||
## Detection paranoia level
|
## Detection paranoia level
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -22,8 +22,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.detection_paranoia_level={{ site.detection_paranoia_level | default(bgwaf_defaults.detection_paranoia_level) }}"
|
setvar:tx.detection_paranoia_level={{ site.detection_paranoia_level | default(waf_config_defaults.detection_paranoia_level) }}"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
## Enforce Body Processor URLENCODED
|
## Enforce Body Processor URLENCODED
|
||||||
@@ -34,8 +34,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.enforce_bodyproc_urlencoded={{ site.enforce_bodyproc_urlencoded | default(bgwaf_defaults.enforce_bodyproc_urlencoded) }}"
|
setvar:tx.enforce_bodyproc_urlencoded={{ site.enforce_bodyproc_urlencoded | default(waf_config_defaults.enforce_bodyproc_urlencoded) }}"
|
||||||
|
|
||||||
## Anomaly Scoring Mode Severity Levels
|
## Anomaly Scoring Mode Severity Levels
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -45,11 +45,11 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.critical_anomaly_score={{ site.critical_anomaly_score | default(bgwaf_defaults.critical_anomaly_score) }},\
|
setvar:tx.critical_anomaly_score={{ site.critical_anomaly_score | default(waf_config_defaults.critical_anomaly_score) }},\
|
||||||
setvar:tx.error_anomaly_score={{ site.error_anomaly_score | default(bgwaf_defaults.error_anomaly_score) }},\
|
setvar:tx.error_anomaly_score={{ site.error_anomaly_score | default(waf_config_defaults.error_anomaly_score) }},\
|
||||||
setvar:tx.warning_anomaly_score={{ site.warning_anomaly_score | default(bgwaf_defaults.warning_anomaly_score) }},\
|
setvar:tx.warning_anomaly_score={{ site.warning_anomaly_score | default(waf_config_defaults.warning_anomaly_score) }},\
|
||||||
setvar:tx.notice_anomaly_score={{ site.notice_anomaly_score | default(bgwaf_defaults.notice_anomaly_score) }}"
|
setvar:tx.notice_anomaly_score={{ site.notice_anomaly_score | default(waf_config_defaults.notice_anomaly_score) }}"
|
||||||
|
|
||||||
## Anomaly Scoring Mode Blocking Threshold Levels
|
## Anomaly Scoring Mode Blocking Threshold Levels
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -59,9 +59,9 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.inbound_anomaly_score_threshold={% if site.log_only | default(bgwaf_defaults.log_only) %}1000{% else %}{{ site.inbound_anomaly_score_threshold | default(bgwaf_defaults.inbound_anomaly_score_threshold) }}{% endif %},\
|
setvar:tx.inbound_anomaly_score_threshold={% if site.log_only | default(waf_config_defaults.log_only) %}1000{% else %}{{ site.inbound_anomaly_score_threshold | default(waf_config_defaults.inbound_anomaly_score_threshold) }}{% endif %},\
|
||||||
setvar:tx.outbound_anomaly_score_threshold={% if site.log_only | default(bgwaf_defaults.log_only) %}1000{% else %}{{ site.outbound_anomaly_score_threshold | default(bgwaf_defaults.outbound_anomaly_score_threshold) }}{% endif %}"
|
setvar:tx.outbound_anomaly_score_threshold={% if site.log_only | default(waf_config_defaults.log_only) %}1000{% else %}{{ site.outbound_anomaly_score_threshold | default(waf_config_defaults.outbound_anomaly_score_threshold) }}{% endif %}"
|
||||||
|
|
||||||
## Application Specific Rule Exclusions
|
## Application Specific Rule Exclusions
|
||||||
# FIXME
|
# FIXME
|
||||||
@@ -87,8 +87,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.reporting_level={{ site.reporting_level | default(bgwaf_defaults.reporting_level) }}"
|
setvar:tx.reporting_level={{ site.reporting_level | default(waf_config_defaults.reporting_level) }}"
|
||||||
|
|
||||||
## Early Anomaly Scoring Mode Blocking
|
## Early Anomaly Scoring Mode Blocking
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -98,7 +98,7 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.early_blocking=0"
|
setvar:tx.early_blocking=0"
|
||||||
|
|
||||||
## Initialize Default Collections
|
## Initialize Default Collections
|
||||||
@@ -109,7 +109,7 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.enable_default_collections=1"
|
setvar:tx.enable_default_collections=1"
|
||||||
|
|
||||||
## HTTP Policy Settings
|
## HTTP Policy Settings
|
||||||
@@ -120,8 +120,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:'tx.allowed_methods={{ site.allowed_methods | default(bgwaf_defaults.allowed_methods) | join(" ") }}'"
|
setvar:'tx.allowed_methods={{ site.allowed_methods | default(waf_config_defaults.allowed_methods) | join(" ") }}'"
|
||||||
|
|
||||||
# Content-Types that a client is allowed to send in a request
|
# Content-Types that a client is allowed to send in a request
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -131,8 +131,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:'tx.allowed_request_content_type={{ site.allowed_request_content_type | default(bgwaf_defaults.allowed_request_content_type) | join(" ") }}'"
|
setvar:'tx.allowed_request_content_type={{ site.allowed_request_content_type | default(waf_config_defaults.allowed_request_content_type) | join(" ") }}'"
|
||||||
|
|
||||||
## Allowed HTTP versions
|
## Allowed HTTP versions
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -142,8 +142,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:'tx.allowed_http_versions={{ site.allowed_http_versions | default(bgwaf_defaults.allowed_http_versions) | join(" ") }}'"
|
setvar:'tx.allowed_http_versions={{ site.allowed_http_versions | default(waf_config_defaults.allowed_http_versions) | join(" ") }}'"
|
||||||
|
|
||||||
## Forbidden file extensions
|
## Forbidden file extensions
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -153,8 +153,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:'tx.restricted_extensions={{ site.restricted_extensions | default(bgwaf_defaults.restricted_extensions) | join(" ") }}'"
|
setvar:'tx.restricted_extensions={{ site.restricted_extensions | default(waf_config_defaults.restricted_extensions) | join(" ") }}'"
|
||||||
|
|
||||||
## Restricted request headers
|
## Restricted request headers
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -164,8 +164,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:'tx.restricted_headers_basic={{ site.restricted_headers_basic | default(bgwaf_defaults.restricted_headers_basic) | join(" ") }}'"
|
setvar:'tx.restricted_headers_basic={{ site.restricted_headers_basic | default(waf_config_defaults.restricted_headers_basic) | join(" ") }}'"
|
||||||
|
|
||||||
## Extended restricted request headers (forbidden at a higher paranoia level)
|
## Extended restricted request headers (forbidden at a higher paranoia level)
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -175,8 +175,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:'tx.restricted_headers_extended={{ site.restricted_headers_extended | default(bgwaf.restricted_headers_extended) | join(" ") }}'"
|
setvar:'tx.restricted_headers_extended={{ site.restricted_headers_extended | default(waf_config_defaults.restricted_headers_extended) | join(" ") }}'"
|
||||||
|
|
||||||
# Content-Types charsets that a client is allowed to send in a request
|
# Content-Types charsets that a client is allowed to send in a request
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -186,8 +186,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:'tx.allowed_request_content_type_charset={{ bgwaf_defaults.allowed_request_content_type_charset | default(bgwaf_defaults.allowed_request_content_type_charset) | join(" ") }}'"
|
setvar:'tx.allowed_request_content_type_charset={{ waf_config_defaults.allowed_request_content_type_charset | default(waf_config_defaults.allowed_request_content_type_charset) | join(" ") }}'"
|
||||||
|
|
||||||
# Block request if number of arguments is too high
|
# Block request if number of arguments is too high
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -197,8 +197,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.max_num_args={{ site.max_num_args | default(bgwaf_defaults.max_num_args) }}"
|
setvar:tx.max_num_args={{ site.max_num_args | default(waf_config_defaults.max_num_args) }}"
|
||||||
|
|
||||||
# Block request if the length of any argument name is too high
|
# Block request if the length of any argument name is too high
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -208,8 +208,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.arg_name_length={{ site.arg_name_length | default(bgwaf_defaults.arg_name_length) }}"
|
setvar:tx.arg_name_length={{ site.arg_name_length | default(waf_config_defaults.arg_name_length) }}"
|
||||||
|
|
||||||
# Block request if the length of any argument value is too high
|
# Block request if the length of any argument value is too high
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -219,8 +219,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.arg_length={{ site.arg_length | default(bgwaf_defaults.arg_length) }}"
|
setvar:tx.arg_length={{ site.arg_length | default(waf_config_defaults.arg_length) }}"
|
||||||
|
|
||||||
# Block request if the total length of all combined arguments is too high
|
# Block request if the total length of all combined arguments is too high
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -230,8 +230,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.total_arg_length={{ site.total_arg_length | default(bgwaf_defaults.total_arg_length) }}"
|
setvar:tx.total_arg_length={{ site.total_arg_length | default(waf_config_defaults.total_arg_length) }}"
|
||||||
|
|
||||||
# Block request if the file size of any individual uploaded file is too high
|
# Block request if the file size of any individual uploaded file is too high
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -241,8 +241,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.max_file_size={{ site.max_file_size | default(bgwaf_defaults.max_file_size) }}"
|
setvar:tx.max_file_size={{ site.max_file_size | default(waf_config_defaults.max_file_size) }}"
|
||||||
|
|
||||||
# Block request if the total size of all combined uploaded files is too high
|
# Block request if the total size of all combined uploaded files is too high
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -252,8 +252,8 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.combined_file_sizes={{ site.combined_file_sizes | default(bgwaf_defaults.combined_file_sizes) }}"
|
setvar:tx.combined_file_sizes={{ site.combined_file_sizes | default(waf_config_defaults.combined_file_sizes) }}"
|
||||||
|
|
||||||
## Easing In / Sampling Percentage
|
## Easing In / Sampling Percentage
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -262,8 +262,8 @@ SecAction \
|
|||||||
pass,\
|
pass,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.sampling_percentage={{ site.sampling_percentage | default(bgwaf_defaults.sampling_percentage) }}"
|
setvar:tx.sampling_percentage={{ site.sampling_percentage | default(waf_config_defaults.sampling_percentage) }}"
|
||||||
|
|
||||||
## Check UTF-8 encoding
|
## Check UTF-8 encoding
|
||||||
SecAction \
|
SecAction \
|
||||||
@@ -273,7 +273,7 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.crs_validate_utf8_encoding=1"
|
setvar:tx.crs_validate_utf8_encoding=1"
|
||||||
|
|
||||||
## Skip Checking Responses
|
## Skip Checking Responses
|
||||||
@@ -290,7 +290,7 @@ SecAction \
|
|||||||
# t:none,\
|
# t:none,\
|
||||||
# nolog,\
|
# nolog,\
|
||||||
# tag:'OWASP_CRS',\
|
# tag:'OWASP_CRS',\
|
||||||
# ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
# ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
# setvar:tx.crs_skip_response_analysis=1"
|
# setvar:tx.crs_skip_response_analysis=1"
|
||||||
|
|
||||||
## End of setup
|
## End of setup
|
||||||
@@ -301,5 +301,5 @@ SecAction \
|
|||||||
t:none,\
|
t:none,\
|
||||||
nolog,\
|
nolog,\
|
||||||
tag:'OWASP_CRS',\
|
tag:'OWASP_CRS',\
|
||||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||||
setvar:tx.crs_setup_version={{ bgwaf_owasp_crs_version | regex_replace('\.', '') }}"
|
setvar:tx.crs_setup_version={{ waf_config_owasp_crs_version | regex_replace('\.', '') }}"
|
||||||
27
ansible/roles/waf_install/defaults/main.yml
Normal file
27
ansible/roles/waf_install/defaults/main.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
waf_install_go_version: "1.25.5"
|
||||||
|
waf_install_xcaddy_version: "0.4.5"
|
||||||
|
waf_install_caddy_version: "2.10.2"
|
||||||
|
waf_install_coraza_caddy_version: "2.1.0" # Coraza v3.3.3
|
||||||
|
waf_install_owasp_crs_version: "4.21.0"
|
||||||
|
|
||||||
|
# Cluster mode (e.g. with consul)
|
||||||
|
waf_install_cluster: false
|
||||||
|
|
||||||
|
# Cf.: https://github.com/coreruleset/plugin-registry
|
||||||
|
waf_install_crs_plugins:
|
||||||
|
- name: "drupal-rule-exclusions"
|
||||||
|
version: "1.0.0"
|
||||||
|
- name: "wordpress-rule-exclusions"
|
||||||
|
version: "1.2.0"
|
||||||
|
- name: "nextcloud-rule-exclusions"
|
||||||
|
version: "1.5.0"
|
||||||
|
- name: "dokuwiki-rule-exclusions"
|
||||||
|
version: "1.0.0"
|
||||||
|
- name: "phpmyadmin-rule-exclusions"
|
||||||
|
version: "1.0.0"
|
||||||
|
- name: "roundcube-rule-exclusions"
|
||||||
|
version: "1.0.4"
|
||||||
|
provider: "EsadCetiner"
|
||||||
|
- name: "sogo-rule-exclusions"
|
||||||
|
version: "1.0.4"
|
||||||
|
provider: "EsadCetiner"
|
||||||
@@ -3,8 +3,3 @@
|
|||||||
name: "caddy"
|
name: "caddy"
|
||||||
state: "restarted"
|
state: "restarted"
|
||||||
daemon_reload: true
|
daemon_reload: true
|
||||||
|
|
||||||
- name: Reload Caddy
|
|
||||||
ansible.builtin.service:
|
|
||||||
name: "caddy"
|
|
||||||
state: "reloaded"
|
|
||||||
@@ -3,27 +3,27 @@
|
|||||||
url: "https://github.com/{{ plugin.provider | default('coreruleset') }}/{{ plugin.name }}-plugin/archive/refs/tags/v{{ plugin.version }}.tar.gz"
|
url: "https://github.com/{{ plugin.provider | default('coreruleset') }}/{{ plugin.name }}-plugin/archive/refs/tags/v{{ plugin.version }}.tar.gz"
|
||||||
dest: "/usr/local/src/"
|
dest: "/usr/local/src/"
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
register: "bgwaf_plugin_downloaded"
|
register: "waf_install_plugin_downloaded"
|
||||||
|
|
||||||
- name: Deploy plugin {{ plugin.name }}
|
- name: Deploy plugin {{ plugin.name }}
|
||||||
# noqa: no-handler
|
# noqa: no-handler
|
||||||
when: "bgwaf_plugin_downloaded.changed"
|
when: "waf_install_plugin_downloaded.changed"
|
||||||
block:
|
block:
|
||||||
|
|
||||||
- name: Get temp dir {{ plugin.name }}
|
- name: Get temp dir {{ plugin.name }}
|
||||||
ansible.builtin.tempfile:
|
ansible.builtin.tempfile:
|
||||||
state: "directory"
|
state: "directory"
|
||||||
register: "bgwaf_temp_plugin_dir"
|
register: "waf_install_temp_plugin_dir"
|
||||||
|
|
||||||
- name: Unarchive plugin {{ plugin.name }}
|
- name: Unarchive plugin {{ plugin.name }}
|
||||||
ansible.builtin.unarchive:
|
ansible.builtin.unarchive:
|
||||||
src: "/usr/local/src/{{ plugin.name }}-plugin-{{ plugin.version }}.tar.gz"
|
src: "/usr/local/src/{{ plugin.name }}-plugin-{{ plugin.version }}.tar.gz"
|
||||||
dest: "{{ bgwaf_temp_plugin_dir.path }}"
|
dest: "{{ waf_install_temp_plugin_dir.path }}"
|
||||||
remote_src: true
|
remote_src: true
|
||||||
|
|
||||||
- name: Copy plugin files {{ plugin.name }}
|
- name: Copy plugin files {{ plugin.name }}
|
||||||
ansible.builtin.copy:
|
ansible.builtin.copy:
|
||||||
src: "{{ bgwaf_temp_plugin_dir.path }}/{{ plugin.name }}-plugin-{{ plugin.version }}/plugins/"
|
src: "{{ waf_install_temp_plugin_dir.path }}/{{ plugin.name }}-plugin-{{ plugin.version }}/plugins/"
|
||||||
dest: "/etc/caddy/plugins/"
|
dest: "/etc/caddy/plugins/"
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
# directory_mode: "0750"
|
# directory_mode: "0750"
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
mode: "0750"
|
mode: "0750"
|
||||||
|
|
||||||
- name: Delete temp dir {{ plugin.name }}
|
- name: Delete temp dir {{ plugin.name }}
|
||||||
when: "bgwaf_temp_plugin_dir.path is defined"
|
when: "waf_install_temp_plugin_dir.path is defined"
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "{{ bgwaf_temp_plugin_dir.path }}"
|
path: "{{ waf_install_temp_plugin_dir.path }}"
|
||||||
state: "absent"
|
state: "absent"
|
||||||
125
ansible/roles/waf_install/tasks/main.yml
Normal file
125
ansible/roles/waf_install/tasks/main.yml
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
- name: Remove packaged Go
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- "golang"
|
||||||
|
state: "absent"
|
||||||
|
autoremove: true
|
||||||
|
purge: true
|
||||||
|
|
||||||
|
- name: Install requirements
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- "git"
|
||||||
|
- "libnss3-tools"
|
||||||
|
|
||||||
|
- name: Create Go directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/usr/local/go-{{ waf_install_go_version }}"
|
||||||
|
state: "directory"
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Install Go
|
||||||
|
ansible.builtin.unarchive:
|
||||||
|
src: "https://go.dev/dl/go{{ waf_install_go_version }}.linux-amd64.tar.gz"
|
||||||
|
dest: "/usr/local/go-{{ waf_install_go_version }}"
|
||||||
|
remote_src: true
|
||||||
|
|
||||||
|
- name: Link Go
|
||||||
|
ansible.builtin.file:
|
||||||
|
src: "/usr/local/go-{{ waf_install_go_version }}/go/bin/go"
|
||||||
|
dest: "/usr/local/bin/go"
|
||||||
|
state: "link"
|
||||||
|
|
||||||
|
# FIXME: no .deb
|
||||||
|
- name: Install xcaddy
|
||||||
|
when: |
|
||||||
|
'xcaddy' not in ansible_facts.packages
|
||||||
|
or ansible_facts.packages['xcaddy'][0]['version'] != waf_install_xcaddy_version
|
||||||
|
ansible.builtin.apt:
|
||||||
|
deb: "{{ waf_install_xcaddy_download }}/v{{ waf_install_xcaddy_version }}/xcaddy_{{ waf_install_xcaddy_version }}_linux_amd64.deb"
|
||||||
|
force: true
|
||||||
|
|
||||||
|
- name: Create Caddy build command
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
waf_install_build_command: >
|
||||||
|
xcaddy build v{{ waf_install_caddy_version }}
|
||||||
|
{% if waf_install_cluster %} --with github.com/pteich/caddy-tlsconsul{% endif %}
|
||||||
|
--with github.com/corazawaf/coraza-caddy/v2@v{{ waf_install_coraza_caddy_version }}
|
||||||
|
--with github.com/mholt/caddy-ratelimit
|
||||||
|
--with github.com/steffenbusch/caddy-bot-barrier
|
||||||
|
--output /usr/local/bin/caddy
|
||||||
|
|
||||||
|
- name: Test Caddy version
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: "/usr/local/bin/.caddy.build"
|
||||||
|
content: "{{ waf_install_build_command }}"
|
||||||
|
mode: "0644"
|
||||||
|
register: waf_install_test_caddy_version
|
||||||
|
|
||||||
|
- name: Build Caddy
|
||||||
|
# noqa: no-handler
|
||||||
|
when: "waf_install_test_caddy_version.changed"
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "{{ waf_install_build_command }}"
|
||||||
|
creates: "/usr/local/bin/caddy"
|
||||||
|
notify:
|
||||||
|
- "Restart Caddy"
|
||||||
|
|
||||||
|
- name: Create caddy system group
|
||||||
|
ansible.builtin.group:
|
||||||
|
name: "caddy"
|
||||||
|
system: true
|
||||||
|
|
||||||
|
- name: Create caddy system user
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: "caddy"
|
||||||
|
group: "caddy"
|
||||||
|
groups: ["ssl-cert"]
|
||||||
|
password: "!"
|
||||||
|
system: true
|
||||||
|
home: "/opt/caddy"
|
||||||
|
|
||||||
|
- name: Create caddy config directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: "directory"
|
||||||
|
group: "caddy"
|
||||||
|
mode: "0750"
|
||||||
|
loop:
|
||||||
|
- "/etc/caddy"
|
||||||
|
- "/etc/caddy/plugins"
|
||||||
|
- "/etc/caddy/sites"
|
||||||
|
|
||||||
|
- name: Create caddy log dir
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/var/log/caddy"
|
||||||
|
state: "directory"
|
||||||
|
group: "caddy"
|
||||||
|
mode: "0770"
|
||||||
|
|
||||||
|
- name: Install OWASP CRS
|
||||||
|
ansible.builtin.unarchive:
|
||||||
|
src: "https://github.com/coreruleset/coreruleset/archive/refs/tags/v{{ waf_install_owasp_crs_version }}.tar.gz"
|
||||||
|
dest: "/etc/caddy"
|
||||||
|
group: "caddy"
|
||||||
|
remote_src: true
|
||||||
|
|
||||||
|
- name: Install plugins
|
||||||
|
loop: "{{ waf_install_crs_plugins }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: "plugin"
|
||||||
|
ansible.builtin.include_tasks: "install_plugin.yml"
|
||||||
|
|
||||||
|
- name: Deploy caddy service file
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "templates/caddy.service"
|
||||||
|
dest: "/etc/systemd/system/caddy.service"
|
||||||
|
mode: "0644"
|
||||||
|
notify:
|
||||||
|
- "Restart Caddy"
|
||||||
|
|
||||||
|
- name: Enable Caddy
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: "caddy"
|
||||||
|
enabled: true
|
||||||
|
daemon_reload: true
|
||||||
1
ansible/roles/waf_install/vars/main.yml
Normal file
1
ansible/roles/waf_install/vars/main.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
waf_install_xcaddy_download: "https://github.com/caddyserver/xcaddy/releases/download"
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
vault:
|
common:
|
||||||
ca:
|
|
||||||
passphrase: "plopplop"
|
certificates:
|
||||||
consul:
|
country_name: "FR"
|
||||||
secret_key: "MZu7pu72IxVkGzSjkB0ZGd+RTp5n34ByxOoxB+BKaSc="
|
locality_name: "Vannes"
|
||||||
|
organization_name: "iTik"
|
||||||
|
email_address: "ca@itik.fr"
|
||||||
|
|
||||||
|
consul:
|
||||||
|
domain: "itik.fr"
|
||||||
|
datacenter: "lab"
|
||||||
|
|
||||||
waf:
|
|
||||||
sites:
|
sites:
|
||||||
- name: "test"
|
- name: "test"
|
||||||
site: "test.lab"
|
site: "test.lab"
|
||||||
@@ -13,12 +18,9 @@ waf:
|
|||||||
- "http://www1"
|
- "http://www1"
|
||||||
- "http://www2"
|
- "http://www2"
|
||||||
- "http://www3"
|
- "http://www3"
|
||||||
log_only: true
|
|
||||||
# paranoia_level: 1
|
|
||||||
# detection_paranoia_level: null
|
|
||||||
custom_cert: true
|
custom_cert: true
|
||||||
custom_cert_file: "/etc/ssl/certs/local.crt"
|
custom_cert_file: "/etc/ssl/certs/test.lab.crt"
|
||||||
custom_key_file: "/etc/ssl/private/local.key"
|
custom_key_file: "/etc/ssl/private/test.lab.key"
|
||||||
# exceptions:
|
# exceptions:
|
||||||
# before_request:
|
# before_request:
|
||||||
# - 'SecRule REQUEST_URI "@beginsWith /?bin/sh" "id:1,nolog,ctl:ruleRemoveById=932160"'
|
# - 'SecRule REQUEST_URI "@beginsWith /?bin/sh" "id:1,nolog,ctl:ruleRemoveById=932160"'
|
||||||
13
ansible/vars/secrets.yml
Normal file
13
ansible/vars/secrets.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
61643639653530613066383464333939383034643565386434616361653331656237303835653837
|
||||||
|
3431646133336265393237383366653364373039376365340a396438643530383965343865383837
|
||||||
|
62636338366437356661356561356138383032353133396461643362323536303965353564666232
|
||||||
|
3735363038323139620a386364633933303139623436626337346535663737386264303036323866
|
||||||
|
31303762336638313961383034386137376566383662323961336536303230303063396661333135
|
||||||
|
66646133333565656233303461356166303862303037663133383534613263383130316261643738
|
||||||
|
65656165346432636363393436646532643531393066346332326561656230316232383866643665
|
||||||
|
36626333656335626534333737633231396561633831653464383036323431616431306433623139
|
||||||
|
61346630663636313463376237353036343264613936366539393165623265656233303864386563
|
||||||
|
63386661343061373930383139376666353035373531386230306432663132653130633039616665
|
||||||
|
38383735326339353738383166623932316564636634343830326432613563306436666532313562
|
||||||
|
65326431346639636338
|
||||||
2
tofu/.gitignore
vendored
2
tofu/.gitignore
vendored
@@ -1,2 +1,4 @@
|
|||||||
/.terraform/
|
/.terraform/
|
||||||
/.terraform.lock.hcl
|
/.terraform.lock.hcl
|
||||||
|
/terraform.tfstate
|
||||||
|
/terraform.tfstate.backup
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"version":4,"terraform_version":"1.11.2","serial":31,"lineage":"5ba1e29d-946a-a982-e845-5fae39bcee6e","outputs":{},"resources":[{"mode":"managed","type":"multipass_instance","name":"this","provider":"provider[\"registry.opentofu.org/larstobi/multipass\"]","instances":[{"index_key":"proxy1","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"20g","image":"24.04","memory":"8g","name":"proxy1"},"sensitive_attributes":[]},{"index_key":"waf1","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"waf1"},"sensitive_attributes":[]},{"index_key":"waf2","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"waf2"},"sensitive_attributes":[]},{"index_key":"waf3","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"waf3"},"sensitive_attributes":[]},{"index_key":"www1","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"www1"},"sensitive_attributes":[]},{"index_key":"www2","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"www2"},"sensitive_attributes":[]},{"index_key":"www3","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"www3"},"sensitive_attributes":[]}]}],"check_results":null}
|
{"version":4,"terraform_version":"1.11.2","serial":37,"lineage":"5ba1e29d-946a-a982-e845-5fae39bcee6e","outputs":{},"resources":[{"mode":"managed","type":"multipass_instance","name":"this","provider":"provider[\"registry.opentofu.org/larstobi/multipass\"]","instances":[{"index_key":"proxy1","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"20g","image":"24.04","memory":"8g","name":"proxy1"},"sensitive_attributes":[]},{"index_key":"waf1","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"waf1"},"sensitive_attributes":[]},{"index_key":"waf2","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"waf2"},"sensitive_attributes":[]},{"index_key":"waf3","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"waf3"},"sensitive_attributes":[]},{"index_key":"www1","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"www1"},"sensitive_attributes":[]},{"index_key":"www2","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"www2"},"sensitive_attributes":[]},{"index_key":"www3","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"www3"},"sensitive_attributes":[]}]}],"check_results":null}
|
||||||
1
tofu/_t/terraform.tfstate.backup
Normal file
1
tofu/_t/terraform.tfstate.backup
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":4,"terraform_version":"1.11.2","serial":36,"lineage":"5ba1e29d-946a-a982-e845-5fae39bcee6e","outputs":{},"resources":[{"mode":"managed","type":"multipass_instance","name":"this","provider":"provider[\"registry.opentofu.org/larstobi/multipass\"]","instances":[{"index_key":"proxy1","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"20g","image":"24.04","memory":"8g","name":"proxy1"},"sensitive_attributes":[]},{"index_key":"waf3","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"waf3"},"sensitive_attributes":[]},{"index_key":"www1","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"www1"},"sensitive_attributes":[]},{"index_key":"www2","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"www2"},"sensitive_attributes":[]},{"index_key":"www3","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"www3"},"sensitive_attributes":[]}]}],"check_results":null}
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":4,"terraform_version":"1.11.2","serial":30,"lineage":"5ba1e29d-946a-a982-e845-5fae39bcee6e","outputs":{},"resources":[{"mode":"managed","type":"multipass_instance","name":"this","provider":"provider[\"registry.opentofu.org/larstobi/multipass\"]","instances":[{"index_key":"proxy1","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"20g","image":"24.04","memory":"8g","name":"proxy1"},"sensitive_attributes":[]},{"index_key":"waf2","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"waf2"},"sensitive_attributes":[]},{"index_key":"waf3","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"waf3"},"sensitive_attributes":[]},{"index_key":"www1","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"www1"},"sensitive_attributes":[]},{"index_key":"www2","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"www2"},"sensitive_attributes":[]},{"index_key":"www3","schema_version":0,"attributes":{"cloudinit_file":"cloud-init.yml","cpus":2,"disk":"12g","image":"24.04","memory":"2g","name":"www3"},"sensitive_attributes":[]}]}],"check_results":null}
|
|
||||||
Reference in New Issue
Block a user