WIP
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
[defaults]
|
||||
inventory = ./inventory/
|
||||
gathering = smart
|
||||
vault_password_file = ./.vault_pass
|
||||
|
||||
[ssh_connection]
|
||||
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
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- "vars.yml"
|
||||
- "vars/common.yml"
|
||||
- "vars/secrets.yml"
|
||||
vars:
|
||||
local_ca_common_name: "Lab CA"
|
||||
local_ca_passphrase: "{{ vault.ca.passphrase }}"
|
||||
local_ca_country_name: "FR"
|
||||
local_ca_locality_name: "Vannes"
|
||||
local_ca_organization_name: "iTik"
|
||||
local_ca_email_address: "ca@itik.fr"
|
||||
local_ca_passphrase: "{{ secrets.ca.passphrase }}"
|
||||
local_ca_country_name: "{{ common.certificates.country_name }}"
|
||||
local_ca_locality_name: "{{ common.certificates.locality_name }}"
|
||||
local_ca_organization_name: "{{ common.certificates.organization_name }}"
|
||||
local_ca_email_address: "{{ common.certificates.email_address }}"
|
||||
roles:
|
||||
- "local_ca"
|
||||
tags:
|
||||
@@ -26,6 +27,9 @@
|
||||
- name: Proxy server
|
||||
hosts: proxy
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- "vars/common.yml"
|
||||
- "vars/secrets.yml"
|
||||
vars:
|
||||
squid_authorized_networks:
|
||||
- "{{ ansible_default_ipv4.network }}/24"
|
||||
@@ -38,7 +42,8 @@
|
||||
hosts: all
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- "vars.yml"
|
||||
- "vars/common.yml"
|
||||
- "vars/secrets.yml"
|
||||
vars:
|
||||
common_proxy_server: "{{ hostvars['proxy1'].ansible_default_ipv4.address }}:3128"
|
||||
roles:
|
||||
@@ -49,39 +54,66 @@
|
||||
- name: HTTP Servers
|
||||
hosts: www
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- "vars/common.yml"
|
||||
- "vars/secrets.yml"
|
||||
roles:
|
||||
- "www"
|
||||
tags:
|
||||
- "www"
|
||||
|
||||
- name: Web Application Firewalls
|
||||
- name: Web Application Firewalls (install)
|
||||
hosts: waf
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- "vars.yml"
|
||||
- "vars/common.yml"
|
||||
- "vars/secrets.yml"
|
||||
vars:
|
||||
cert_domains:
|
||||
- "DNS:test.lab"
|
||||
- "DNS:{{ ansible_fqdn }}"
|
||||
- "DNS:{{ ansible_hostname }}"
|
||||
- "IP:{{ ansible_default_ipv4.address }}"
|
||||
- "DNS:server.{{ consul_datacenter }}.{{ consul_domain }}"
|
||||
cert_country_name: "FR"
|
||||
cert_locality_name: "Vannes"
|
||||
cert_organization_name: "iTik"
|
||||
cert_email_address: "ca@itik.fr"
|
||||
consul_domain: "itik.fr"
|
||||
consul_datacenter: "lab"
|
||||
consul_secret_key: "{{ vault.consul.secret_key }}"
|
||||
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:{{ ansible_fqdn }}"
|
||||
- "DNS:{{ ansible_hostname }}"
|
||||
- "IP:{{ ansible_default_ipv4.address }}"
|
||||
consul_domain: "{{ common.consul.domain }}"
|
||||
consul_datacenter: "{{ common.consul.datacenter }}"
|
||||
consul_secret_key: "{{ secrets.consul.secret_key }}"
|
||||
consul_nodes:
|
||||
- "waf1"
|
||||
- "waf2"
|
||||
- "waf3"
|
||||
bgwaf_cluster: false
|
||||
bgwaf_sites: "{{ waf.sites }}"
|
||||
# FIXME: -> Cady modules
|
||||
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:
|
||||
- "cert"
|
||||
- "certs"
|
||||
- "consul"
|
||||
- "bgwaf"
|
||||
- "waf_install"
|
||||
- "vip"
|
||||
- "waf_config"
|
||||
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
|
||||
consul_datacenter: null
|
||||
consul_domain: null
|
||||
consul_secret_key: null
|
||||
consul_nodes: []
|
||||
consul_domain: None
|
||||
|
||||
# Defaults
|
||||
consul_version: "1.22.2"
|
||||
consul_key_file: "/etc/ssl/private/local.key"
|
||||
consul_cert_file: "/etc/ssl/certs/local.crt"
|
||||
consul_key_file: "/etc/ssl/private/server.{{ consul_datacenter }}.{{ consul_domain }}.key"
|
||||
consul_cert_file: "/etc/ssl/certs/server.{{ consul_datacenter }}.{{ consul_domain }}.crt"
|
||||
consul_ca_file: "/etc/ssl/certs/local-ca.crt"
|
||||
consul_client_addr: "0.0.0.0"
|
||||
consul_bind_addr: "{{ ansible_default_ipv4.address }}"
|
||||
|
||||
@@ -3,9 +3,9 @@ local_ca_key_size: 4096
|
||||
local_ca_key_type: "RSA"
|
||||
|
||||
# Required
|
||||
local_ca_common_name: None
|
||||
local_ca_passphrase: None
|
||||
local_ca_country_name: None
|
||||
local_ca_locality_name: None
|
||||
local_ca_organization_name: None
|
||||
local_ca_email_address: None
|
||||
local_ca_common_name: null
|
||||
local_ca_passphrase: null
|
||||
local_ca_country_name: null
|
||||
local_ca_locality_name: null
|
||||
local_ca_organization_name: null
|
||||
local_ca_email_address: null
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
community.crypto.openssl_csr:
|
||||
path: "ca/ca-certificate.csr"
|
||||
privatekey_path: "ca/ca-certificate.key"
|
||||
privatekey_passphrase: "{{ vault.ca.passphrase }}"
|
||||
privatekey_passphrase: "{{ local_ca_passphrase }}"
|
||||
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
|
||||
country_name: "{{ local_ca_country_name }}"
|
||||
@@ -47,5 +47,5 @@
|
||||
path: "ca/ca-certificate.crt"
|
||||
csr_content: "{{ local_ca_csr.csr }}"
|
||||
privatekey_path: "ca/ca-certificate.key"
|
||||
privatekey_passphrase: "{{ vault.ca.passphrase }}"
|
||||
privatekey_passphrase: "{{ local_ca_passphrase }}"
|
||||
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"
|
||||
bgwaf_xcaddy_version: "0.4.5"
|
||||
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
|
||||
# Defaults
|
||||
waf_config_owasp_crs_version: "4.21.0"
|
||||
|
||||
# Required unless not site.custom_cert
|
||||
bgwaf_email: null
|
||||
waf_config_email: null
|
||||
|
||||
# Required if site.bot_barrier
|
||||
bgwaf_bot_barrier_secret: null
|
||||
waf_config_bot_barrier_secret: null
|
||||
|
||||
# Optionnal
|
||||
bgwaf_local_ca_name: null
|
||||
bgwaf_ca_root: null
|
||||
waf_config_local_ca_name: null
|
||||
waf_config_ca_root: null
|
||||
|
||||
# Cf.: https://github.com/coreruleset/plugin-registry
|
||||
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: []
|
||||
waf_config_sites: []
|
||||
# - name: ""
|
||||
# site: ""
|
||||
# paths:
|
||||
@@ -55,15 +30,19 @@ bgwaf_sites: []
|
||||
# after_response:
|
||||
# - ""
|
||||
|
||||
bgwaf_defaults:
|
||||
waf_config_defaults:
|
||||
redirect_from_aliases: true
|
||||
custom_cert: true
|
||||
custom_cert_file: ""
|
||||
custom_key_file: ""
|
||||
|
||||
rate_events: 1000
|
||||
rate_window: "1m"
|
||||
|
||||
bot_barrier: false
|
||||
log_only: true
|
||||
|
||||
# CRS defaults
|
||||
log_only: false
|
||||
paranoia_level: 1
|
||||
detection_paranoia_level: null
|
||||
enforce_bodyproc_urlencoded: 1
|
||||
@@ -100,8 +79,12 @@ bgwaf_defaults:
|
||||
- ".asa/"
|
||||
- ".asax/"
|
||||
- ".ascx/"
|
||||
- ".back/"
|
||||
- ".backup/"
|
||||
- ".bak/"
|
||||
- ".bck/"
|
||||
- ".bk/"
|
||||
- ".bkp/"
|
||||
- ".bat/"
|
||||
- ".cdx/"
|
||||
- ".cer/"
|
||||
@@ -158,9 +141,11 @@ bgwaf_defaults:
|
||||
- ".reg/"
|
||||
- ".resources/"
|
||||
- ".resx/"
|
||||
- ".sav/"
|
||||
- ".save/"
|
||||
- ".scr/"
|
||||
- ".sct/"
|
||||
- ".sh/"
|
||||
- ".shs/"
|
||||
- ".sql/"
|
||||
- ".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
|
||||
grace_period 10s
|
||||
order coraza_waf first
|
||||
{% if bgwaf_email | default(None) != None %}
|
||||
email "{{ bgwaf_email }}"
|
||||
{% if waf_config_email | default(None) != None %}
|
||||
email "{{ waf_config_email }}"
|
||||
{% endif %}
|
||||
|
||||
{% if bgwaf_ca_root | default(None) != None %}
|
||||
{% if waf_config_ca_root | default(None) != None %}
|
||||
tls {
|
||||
ca_root "{{ bgwaf_ca_root }}"
|
||||
ca_root "{{ waf_config_ca_root }}"
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
@@ -17,17 +17,17 @@
|
||||
include "http.handlers.waf"
|
||||
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 {
|
||||
ca local {
|
||||
name "{{ bgwaf_local_ca_name }}"
|
||||
name "{{ waf_config_local_ca_name }}"
|
||||
}
|
||||
}
|
||||
{% 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 %}
|
||||
{{ site.aliases | join(', ') }} {
|
||||
redir https://{{ site.site }}{uri}
|
||||
@@ -79,7 +79,7 @@
|
||||
{% endif %}
|
||||
{% if site.bot_barrier | default (false) %}
|
||||
bot_barrier {
|
||||
secret {{ bgwaf_bot_barrier_secret }}
|
||||
secret {{ waf_config_bot_barrier_secret }}
|
||||
complexity 18
|
||||
valid_for 30m
|
||||
seed_cookie_name __chall_{{ site.name }}_seed
|
||||
@@ -106,7 +106,7 @@
|
||||
Include "/etc/caddy/plugins/*-config.conf"
|
||||
Include "/etc/caddy/plugins/*-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/plugins/*-after.conf"
|
||||
SecRuleEngine On
|
||||
@@ -10,9 +10,9 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:tx.blocking_paranoia_level={{ site.paranoia_level | default(bgwaf_defaults.paranoia_level) }}"
|
||||
{% if site.detection_paranoia_level | default(bgwaf_defaults.detection_paranoia_level) != None %}
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
setvar:tx.blocking_paranoia_level={{ site.paranoia_level | default(waf_config_defaults.paranoia_level) }}"
|
||||
{% if site.detection_paranoia_level | default(waf_config_defaults.detection_paranoia_level) != None %}
|
||||
|
||||
## Detection paranoia level
|
||||
SecAction \
|
||||
@@ -22,8 +22,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:tx.detection_paranoia_level={{ site.detection_paranoia_level | default(bgwaf_defaults.detection_paranoia_level) }}"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
setvar:tx.detection_paranoia_level={{ site.detection_paranoia_level | default(waf_config_defaults.detection_paranoia_level) }}"
|
||||
{% endif %}
|
||||
|
||||
## Enforce Body Processor URLENCODED
|
||||
@@ -34,8 +34,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:tx.enforce_bodyproc_urlencoded={{ site.enforce_bodyproc_urlencoded | default(bgwaf_defaults.enforce_bodyproc_urlencoded) }}"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
setvar:tx.enforce_bodyproc_urlencoded={{ site.enforce_bodyproc_urlencoded | default(waf_config_defaults.enforce_bodyproc_urlencoded) }}"
|
||||
|
||||
## Anomaly Scoring Mode Severity Levels
|
||||
SecAction \
|
||||
@@ -45,11 +45,11 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:tx.critical_anomaly_score={{ site.critical_anomaly_score | default(bgwaf_defaults.critical_anomaly_score) }},\
|
||||
setvar:tx.error_anomaly_score={{ site.error_anomaly_score | default(bgwaf_defaults.error_anomaly_score) }},\
|
||||
setvar:tx.warning_anomaly_score={{ site.warning_anomaly_score | default(bgwaf_defaults.warning_anomaly_score) }},\
|
||||
setvar:tx.notice_anomaly_score={{ site.notice_anomaly_score | default(bgwaf_defaults.notice_anomaly_score) }}"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
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(waf_config_defaults.error_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(waf_config_defaults.notice_anomaly_score) }}"
|
||||
|
||||
## Anomaly Scoring Mode Blocking Threshold Levels
|
||||
SecAction \
|
||||
@@ -59,9 +59,9 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_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.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 %}"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
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(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
|
||||
# FIXME
|
||||
@@ -87,8 +87,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:tx.reporting_level={{ site.reporting_level | default(bgwaf_defaults.reporting_level) }}"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
setvar:tx.reporting_level={{ site.reporting_level | default(waf_config_defaults.reporting_level) }}"
|
||||
|
||||
## Early Anomaly Scoring Mode Blocking
|
||||
SecAction \
|
||||
@@ -98,7 +98,7 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
setvar:tx.early_blocking=0"
|
||||
|
||||
## Initialize Default Collections
|
||||
@@ -109,7 +109,7 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
setvar:tx.enable_default_collections=1"
|
||||
|
||||
## HTTP Policy Settings
|
||||
@@ -120,8 +120,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:'tx.allowed_methods={{ site.allowed_methods | default(bgwaf_defaults.allowed_methods) | join(" ") }}'"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
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
|
||||
SecAction \
|
||||
@@ -131,8 +131,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:'tx.allowed_request_content_type={{ site.allowed_request_content_type | default(bgwaf_defaults.allowed_request_content_type) | join(" ") }}'"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
setvar:'tx.allowed_request_content_type={{ site.allowed_request_content_type | default(waf_config_defaults.allowed_request_content_type) | join(" ") }}'"
|
||||
|
||||
## Allowed HTTP versions
|
||||
SecAction \
|
||||
@@ -142,8 +142,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:'tx.allowed_http_versions={{ site.allowed_http_versions | default(bgwaf_defaults.allowed_http_versions) | join(" ") }}'"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
setvar:'tx.allowed_http_versions={{ site.allowed_http_versions | default(waf_config_defaults.allowed_http_versions) | join(" ") }}'"
|
||||
|
||||
## Forbidden file extensions
|
||||
SecAction \
|
||||
@@ -153,8 +153,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:'tx.restricted_extensions={{ site.restricted_extensions | default(bgwaf_defaults.restricted_extensions) | join(" ") }}'"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
setvar:'tx.restricted_extensions={{ site.restricted_extensions | default(waf_config_defaults.restricted_extensions) | join(" ") }}'"
|
||||
|
||||
## Restricted request headers
|
||||
SecAction \
|
||||
@@ -164,8 +164,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:'tx.restricted_headers_basic={{ site.restricted_headers_basic | default(bgwaf_defaults.restricted_headers_basic) | join(" ") }}'"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
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)
|
||||
SecAction \
|
||||
@@ -175,8 +175,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:'tx.restricted_headers_extended={{ site.restricted_headers_extended | default(bgwaf.restricted_headers_extended) | join(" ") }}'"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
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
|
||||
SecAction \
|
||||
@@ -186,8 +186,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_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(" ") }}'"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
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
|
||||
SecAction \
|
||||
@@ -197,8 +197,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:tx.max_num_args={{ site.max_num_args | default(bgwaf_defaults.max_num_args) }}"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
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
|
||||
SecAction \
|
||||
@@ -208,8 +208,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:tx.arg_name_length={{ site.arg_name_length | default(bgwaf_defaults.arg_name_length) }}"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
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
|
||||
SecAction \
|
||||
@@ -219,8 +219,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:tx.arg_length={{ site.arg_length | default(bgwaf_defaults.arg_length) }}"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
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
|
||||
SecAction \
|
||||
@@ -230,8 +230,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:tx.total_arg_length={{ site.total_arg_length | default(bgwaf_defaults.total_arg_length) }}"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
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
|
||||
SecAction \
|
||||
@@ -241,8 +241,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:tx.max_file_size={{ site.max_file_size | default(bgwaf_defaults.max_file_size) }}"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
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
|
||||
SecAction \
|
||||
@@ -252,8 +252,8 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:tx.combined_file_sizes={{ site.combined_file_sizes | default(bgwaf_defaults.combined_file_sizes) }}"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
setvar:tx.combined_file_sizes={{ site.combined_file_sizes | default(waf_config_defaults.combined_file_sizes) }}"
|
||||
|
||||
## Easing In / Sampling Percentage
|
||||
SecAction \
|
||||
@@ -262,8 +262,8 @@ SecAction \
|
||||
pass,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:tx.sampling_percentage={{ site.sampling_percentage | default(bgwaf_defaults.sampling_percentage) }}"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
setvar:tx.sampling_percentage={{ site.sampling_percentage | default(waf_config_defaults.sampling_percentage) }}"
|
||||
|
||||
## Check UTF-8 encoding
|
||||
SecAction \
|
||||
@@ -273,7 +273,7 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
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"
|
||||
|
||||
## Skip Checking Responses
|
||||
@@ -290,7 +290,7 @@ SecAction \
|
||||
# t:none,\
|
||||
# nolog,\
|
||||
# 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"
|
||||
|
||||
## End of setup
|
||||
@@ -301,5 +301,5 @@ SecAction \
|
||||
t:none,\
|
||||
nolog,\
|
||||
tag:'OWASP_CRS',\
|
||||
ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\
|
||||
setvar:tx.crs_setup_version={{ bgwaf_owasp_crs_version | regex_replace('\.', '') }}"
|
||||
ver:'OWASP_CRS/{{ waf_config_owasp_crs_version }}',\
|
||||
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"
|
||||
state: "restarted"
|
||||
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"
|
||||
dest: "/usr/local/src/"
|
||||
mode: "0644"
|
||||
register: "bgwaf_plugin_downloaded"
|
||||
register: "waf_install_plugin_downloaded"
|
||||
|
||||
- name: Deploy plugin {{ plugin.name }}
|
||||
# noqa: no-handler
|
||||
when: "bgwaf_plugin_downloaded.changed"
|
||||
when: "waf_install_plugin_downloaded.changed"
|
||||
block:
|
||||
|
||||
- name: Get temp dir {{ plugin.name }}
|
||||
ansible.builtin.tempfile:
|
||||
state: "directory"
|
||||
register: "bgwaf_temp_plugin_dir"
|
||||
register: "waf_install_temp_plugin_dir"
|
||||
|
||||
- name: Unarchive plugin {{ plugin.name }}
|
||||
ansible.builtin.unarchive:
|
||||
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
|
||||
|
||||
- name: Copy plugin files {{ plugin.name }}
|
||||
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/"
|
||||
mode: "0644"
|
||||
# directory_mode: "0750"
|
||||
@@ -41,7 +41,7 @@
|
||||
mode: "0750"
|
||||
|
||||
- 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:
|
||||
path: "{{ bgwaf_temp_plugin_dir.path }}"
|
||||
path: "{{ waf_install_temp_plugin_dir.path }}"
|
||||
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:
|
||||
ca:
|
||||
passphrase: "plopplop"
|
||||
consul:
|
||||
secret_key: "MZu7pu72IxVkGzSjkB0ZGd+RTp5n34ByxOoxB+BKaSc="
|
||||
common:
|
||||
|
||||
certificates:
|
||||
country_name: "FR"
|
||||
locality_name: "Vannes"
|
||||
organization_name: "iTik"
|
||||
email_address: "ca@itik.fr"
|
||||
|
||||
consul:
|
||||
domain: "itik.fr"
|
||||
datacenter: "lab"
|
||||
|
||||
waf:
|
||||
sites:
|
||||
- name: "test"
|
||||
site: "test.lab"
|
||||
@@ -13,12 +18,9 @@ waf:
|
||||
- "http://www1"
|
||||
- "http://www2"
|
||||
- "http://www3"
|
||||
log_only: true
|
||||
# paranoia_level: 1
|
||||
# detection_paranoia_level: null
|
||||
custom_cert: true
|
||||
custom_cert_file: "/etc/ssl/certs/local.crt"
|
||||
custom_key_file: "/etc/ssl/private/local.key"
|
||||
custom_cert_file: "/etc/ssl/certs/test.lab.crt"
|
||||
custom_key_file: "/etc/ssl/private/test.lab.key"
|
||||
# exceptions:
|
||||
# before_request:
|
||||
# - '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.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