WIP
This commit is contained in:
4
example/ansible/.gitignore
vendored
Normal file
4
example/ansible/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/ca/
|
||||
/.vault_pass
|
||||
/ansible_local.env
|
||||
/known_hosts
|
||||
8
example/ansible/ansible.cfg
Normal file
8
example/ansible/ansible.cfg
Normal file
@@ -0,0 +1,8 @@
|
||||
[defaults]
|
||||
inventory = ./inventory/
|
||||
gathering = smart
|
||||
vault_password_file = ./.vault_pass
|
||||
|
||||
[ssh_connection]
|
||||
pipelining = True
|
||||
ssh_args = -o ControlMaster=auto -o ControlPersist=300s -o StrictHostKeyChecking=no -o UserKnownHostsFile=./known_hosts
|
||||
19
example/ansible/ansible_local.env_example
Normal file
19
example/ansible/ansible_local.env_example
Normal file
@@ -0,0 +1,19 @@
|
||||
# Example of a ansible_local.env file that is used to customize the local
|
||||
# operation of Ansible with environment variables.
|
||||
|
||||
# Usage:
|
||||
# 1. Copy ansible/ansible_local.env.example to ansible/ansible_local.env or create a new version.
|
||||
# 2. Customize the contents of the ansible_local.env file, there can only be definitions of environment variables.
|
||||
# cf.: https://docs.ansible.com/ansible/latest/reference_appendices/config.html
|
||||
# 3. The run_ansible.sh script will automatically source the ansible/ansible_local.env file if it exists before running ansible.
|
||||
|
||||
# The ansible_local.env file is ignored by Git (present in.gitignore).
|
||||
|
||||
# Example of using the ANSIBLE_STRATEGY_PLUGINS and ANSIBLE_STRATEGY environment variables to enable Mitogen (speeds up the execution of Ansible playbooks by a factor of 2 to 10).
|
||||
# cf.: https://mitogen.networkgenomics.com/ansible_detailed.html
|
||||
|
||||
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
|
||||
1
example/ansible/filter_plugins
Symbolic link
1
example/ansible/filter_plugins
Symbolic link
@@ -0,0 +1 @@
|
||||
../../filter_plugins
|
||||
31
example/ansible/inventory/groups.yml
Normal file
31
example/ansible/inventory/groups.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
linux:
|
||||
vars:
|
||||
ansible_user: "root"
|
||||
|
||||
debian13:
|
||||
vars:
|
||||
ansible_python_interpreter: "/usr/bin/python3.13"
|
||||
|
||||
ubuntu24:
|
||||
vars:
|
||||
ansible_python_interpreter: "/usr/bin/python3.12"
|
||||
|
||||
waf:
|
||||
hosts:
|
||||
waf1:
|
||||
waf2:
|
||||
waf3:
|
||||
|
||||
mysql:
|
||||
hosts:
|
||||
sql1:
|
||||
|
||||
nfs:
|
||||
hosts:
|
||||
nfs1:
|
||||
|
||||
www:
|
||||
hosts:
|
||||
www1:
|
||||
www2:
|
||||
www3:
|
||||
7
example/ansible/inventory/multipass.sh
Executable file
7
example/ansible/inventory/multipass.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
multipass list --format=json |jq '{
|
||||
_meta: {hostvars: [.list[] | {(.name): {ansible_host: .ipv4[0]}}] | add},
|
||||
linux: {hosts: [.list[].name]},
|
||||
ubuntu24: {hosts: [.list[].name]},
|
||||
}'
|
||||
25
example/ansible/play-config.yml
Normal file
25
example/ansible/play-config.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
- name: Web Application Firewalls (config)
|
||||
hosts: waf
|
||||
vars_files:
|
||||
- "vars/common.yml"
|
||||
- "vars/secrets.yml"
|
||||
vars:
|
||||
local_ca_certs_ca_passphrase: "{{ secrets.ca.passphrase }}"
|
||||
local_ca_certs_default_country_name: "{{ common.certificates.country_name }}"
|
||||
local_ca_certs_default_locality_name: "{{ common.certificates.locality_name }}"
|
||||
local_ca_certs_default_organization_name: "{{ common.certificates.organization_name }}"
|
||||
local_ca_certs_default_email_address: "{{ common.certificates.email_address }}"
|
||||
local_ca_certs_list:
|
||||
- cn: "test.lab"
|
||||
domains:
|
||||
- "DNS:test.lab"
|
||||
- "DNS:{{ ansible_fqdn }}"
|
||||
- "DNS:{{ ansible_hostname }}"
|
||||
- "IP:{{ ansible_default_ipv4.address }}"
|
||||
caddy_config_only: true
|
||||
caddy_sites: "{{ common.sites }}"
|
||||
roles:
|
||||
- "local_ca_certs"
|
||||
- "caddy"
|
||||
tags:
|
||||
- "waf"
|
||||
229
example/ansible/play-main.yml
Normal file
229
example/ansible/play-main.yml
Normal file
@@ -0,0 +1,229 @@
|
||||
- name: Gather facts (implicit) and packages facts
|
||||
hosts: all
|
||||
tasks:
|
||||
- name: Gather packages facts
|
||||
ansible.builtin.package_facts:
|
||||
tags:
|
||||
- "always"
|
||||
|
||||
- name: Create local CA
|
||||
hosts: all
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- "vars/common.yml"
|
||||
- "vars/secrets.yml"
|
||||
vars:
|
||||
local_ca_common_name: "Lab CA"
|
||||
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:
|
||||
- "local_ca"
|
||||
|
||||
- name: Common
|
||||
hosts: all
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- "vars/common.yml"
|
||||
- "vars/secrets.yml"
|
||||
vars:
|
||||
common_default_packages:
|
||||
- "net-tools"
|
||||
- "htop"
|
||||
- "aptitude"
|
||||
- "screen"
|
||||
- "tcpdump"
|
||||
roles:
|
||||
- "common"
|
||||
tags:
|
||||
- "common"
|
||||
|
||||
- name: Web Application Firewalls (install)
|
||||
hosts: waf
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- "vars/common.yml"
|
||||
- "vars/secrets.yml"
|
||||
vars:
|
||||
local_ca_certs_ca_passphrase: "{{ secrets.ca.passphrase }}"
|
||||
local_ca_certs_default_country_name: "{{ common.certificates.country_name }}"
|
||||
local_ca_certs_default_locality_name: "{{ common.certificates.locality_name }}"
|
||||
local_ca_certs_default_organization_name: "{{ common.certificates.organization_name }}"
|
||||
local_ca_certs_default_email_address: "{{ common.certificates.email_address }}"
|
||||
local_ca_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_servers: ["waf1", "waf2", "waf3"]
|
||||
consul_server: true
|
||||
consul_services:
|
||||
- name: "www"
|
||||
port: 443
|
||||
check_http: "http://{{ ansible_default_ipv4.address }}:80/"
|
||||
# keepalived_script_user: "byow"
|
||||
# keepalived_monitored_process: "caddy"
|
||||
# keepalived_vrrp_password: "{{ secrets.keepalived.secret }}"
|
||||
# keepalived_vrrp_ips:
|
||||
# - master: "waf1"
|
||||
# virtual_router_id: 251
|
||||
# addr: "{{ ansible_default_ipv4.address | regex_replace('\\.[0-9]+$', '') }}.251/24"
|
||||
# - master: "waf2"
|
||||
# virtual_router_id: 252
|
||||
# addr: "{{ ansible_default_ipv4.address | regex_replace('\\.[0-9]+$', '') }}.252/24"
|
||||
# - master: "waf3"
|
||||
# virtual_router_id: 253
|
||||
# addr: "{{ ansible_default_ipv4.address | regex_replace('\\.[0-9]+$', '') }}.253/24"
|
||||
# # Multipass network doesn't seem to support well multicast.
|
||||
# keepalived_unicast_peers:
|
||||
# - "{{ hostvars['waf1'].ansible_default_ipv4.address }}"
|
||||
# - "{{ hostvars['waf2'].ansible_default_ipv4.address }}"
|
||||
# - "{{ hostvars['waf3'].ansible_default_ipv4.address }}"
|
||||
unbound_listen_interfaces:
|
||||
- "{{ ansible_default_ipv4.address }}"
|
||||
unbound_stub_zones:
|
||||
- name: "{{ common.consul.datacenter }}.{{ common.consul.domain }}"
|
||||
stub_to: "127.0.0.1@8600"
|
||||
caddy_sites: "{{ common.sites }}"
|
||||
ovh_ldp_cluster: "gra2.logs.ovh.com"
|
||||
ovh_ldp_token: ¨{{ secrets.ovh_ldp.token }}
|
||||
roles:
|
||||
- "local_ca_certs"
|
||||
- "consul"
|
||||
- "caddy"
|
||||
# - "keepalived"
|
||||
- "unbound"
|
||||
- "ovh_ldp"
|
||||
tags:
|
||||
- "waf"
|
||||
|
||||
- name: MySQL servers
|
||||
hosts: mysql
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- "vars/common.yml"
|
||||
- "vars/secrets.yml"
|
||||
vars:
|
||||
local_ca_certs_ca_passphrase: "{{ secrets.ca.passphrase }}"
|
||||
local_ca_certs_default_country_name: "{{ common.certificates.country_name }}"
|
||||
local_ca_certs_default_locality_name: "{{ common.certificates.locality_name }}"
|
||||
local_ca_certs_default_organization_name: "{{ common.certificates.organization_name }}"
|
||||
local_ca_certs_default_email_address: "{{ common.certificates.email_address }}"
|
||||
local_ca_certs_list:
|
||||
- cn: "{{ ansible_fqdn }}"
|
||||
domains:
|
||||
- "DNS:{{ ansible_fqdn }}"
|
||||
- "DNS:{{ ansible_hostname }}"
|
||||
- "IP:{{ ansible_default_ipv4.address }}"
|
||||
mysql_databases:
|
||||
- "wordpress"
|
||||
mysql_users:
|
||||
- name: "wordpress"
|
||||
password: "{{ secrets.wordpress.mysql_password }}"
|
||||
priv: "wordpress.*:ALL"
|
||||
host: "{{ ansible_default_ipv4.network }}/255.255.255.0"
|
||||
consul_domain: "{{ common.consul.domain }}"
|
||||
consul_datacenter: "{{ common.consul.datacenter }}"
|
||||
consul_secret_key: "{{ secrets.consul.secret_key }}"
|
||||
consul_key_file: "/etc/ssl/private/{{ ansible_fqdn }}.key"
|
||||
consul_cert_file: "/etc/ssl/certs/{{ ansible_fqdn }}.crt"
|
||||
consul_servers: ["waf1", "waf2", "waf3"]
|
||||
consul_services:
|
||||
- name: "test-lab-mysql"
|
||||
port: 3306
|
||||
check_tcp: "{{ ansible_default_ipv4.address }}:3306"
|
||||
roles:
|
||||
- "local_ca_certs"
|
||||
- "mysql"
|
||||
- "consul"
|
||||
tags:
|
||||
- "mysql"
|
||||
|
||||
- name: NFS servers
|
||||
hosts: nfs
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- "vars/common.yml"
|
||||
- "vars/secrets.yml"
|
||||
vars:
|
||||
nfs_server_exports:
|
||||
- path: "/srv/wordpress"
|
||||
owner: 1001
|
||||
group: 33
|
||||
clients:
|
||||
- address: "www1"
|
||||
options: "rw,no_root_squash"
|
||||
- address: "www2"
|
||||
options: "rw,no_root_squash"
|
||||
- address: "www3"
|
||||
options: "rw,no_root_squash"
|
||||
roles:
|
||||
- "nfs_server"
|
||||
tags:
|
||||
- "nfs"
|
||||
|
||||
- name: HTTP Servers
|
||||
hosts: www
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- "vars/common.yml"
|
||||
- "vars/secrets.yml"
|
||||
vars:
|
||||
local_ca_certs_ca_passphrase: "{{ secrets.ca.passphrase }}"
|
||||
local_ca_certs_default_country_name: "{{ common.certificates.country_name }}"
|
||||
local_ca_certs_default_locality_name: "{{ common.certificates.locality_name }}"
|
||||
local_ca_certs_default_organization_name: "{{ common.certificates.organization_name }}"
|
||||
local_ca_certs_default_email_address: "{{ common.certificates.email_address }}"
|
||||
local_ca_certs_list:
|
||||
- cn: "{{ ansible_fqdn }}"
|
||||
domains:
|
||||
- "DNS:{{ ansible_fqdn }}"
|
||||
- "DNS:{{ ansible_hostname }}"
|
||||
- "IP:{{ ansible_default_ipv4.address }}"
|
||||
nfs_client_mounts:
|
||||
- mount_point: "/var/www/wordpress"
|
||||
server: "nfs1:/srv/wordpress"
|
||||
owner: 1001
|
||||
group: 33
|
||||
wordpress_create_master: "www1"
|
||||
wordpress_site: "test.lab"
|
||||
wordpress_url: "test.lab"
|
||||
wordpress_site_title: "Lab Test"
|
||||
wordpress_admin_user: "spock"
|
||||
wordpress_admin_password: "{{ secrets.wordpress.admin_password }}"
|
||||
wordpress_admin_email: "seb@itik.fr"
|
||||
wordpress_themes: ["twentytwentyfive"]
|
||||
wordpress_active_theme: "twentytwentyfive"
|
||||
wordpress_db_host: "sql1"
|
||||
wordpress_db_pass: "{{ secrets.wordpress.mysql_password }}"
|
||||
consul_domain: "{{ common.consul.domain }}"
|
||||
consul_datacenter: "{{ common.consul.datacenter }}"
|
||||
consul_secret_key: "{{ secrets.consul.secret_key }}"
|
||||
consul_key_file: "/etc/ssl/private/{{ ansible_fqdn }}.key"
|
||||
consul_cert_file: "/etc/ssl/certs/{{ ansible_fqdn }}.crt"
|
||||
consul_servers: ["waf1", "waf2", "waf3"]
|
||||
consul_services:
|
||||
- name: "test-lab-www"
|
||||
port: 80
|
||||
check_http: "http://localhost:80/"
|
||||
roles:
|
||||
- "local_ca_certs"
|
||||
- "nfs_client"
|
||||
- "wordpress"
|
||||
- "consul"
|
||||
tags:
|
||||
- "www"
|
||||
1
example/ansible/roles
Symbolic link
1
example/ansible/roles
Symbolic link
@@ -0,0 +1 @@
|
||||
../../roles
|
||||
21
example/ansible/run_ansible.sh
Executable file
21
example/ansible/run_ansible.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
ANSIBLE_CONFIG=./ansible.cfg
|
||||
export ANSIBLE_CONFIG
|
||||
|
||||
PLAY="main"
|
||||
if [ "$1" == "--play" ]; then
|
||||
shift
|
||||
PLAY="$1"
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ -f "./ansible_local.env" ]; then
|
||||
. ./ansible_local.env
|
||||
fi
|
||||
|
||||
if [ -f "./requirements.yml" ]; then
|
||||
ansible-galaxy install -r requirements.yml
|
||||
fi
|
||||
|
||||
ansible-lint --strict --project-dir . play-${PLAY}.yml && time ansible-playbook play-${PLAY}.yml $*
|
||||
41
example/ansible/vars/common.yml
Normal file
41
example/ansible/vars/common.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
common:
|
||||
|
||||
certificates:
|
||||
country_name: "FR"
|
||||
locality_name: "Vannes"
|
||||
organization_name: "iTik"
|
||||
email_address: "ca@itik.fr"
|
||||
|
||||
consul:
|
||||
domain: "itik.fr"
|
||||
datacenter: "lab"
|
||||
|
||||
sites:
|
||||
- name: "test"
|
||||
site: "test.lab"
|
||||
paths:
|
||||
- addrs:
|
||||
- "http://www1"
|
||||
- "http://www2"
|
||||
- "http://www3"
|
||||
custom_cert: true
|
||||
custom_cert_file: "/etc/ssl/certs/test.lab.crt"
|
||||
custom_key_file: "/etc/ssl/private/test.lab.key"
|
||||
crs_plugins:
|
||||
- "wordpress-rule-exclusions"
|
||||
crs_exceptions:
|
||||
# Cf. https://github.com/owasp-modsecurity/ModSecurity/wiki/Reference-Manual-(v3.x)
|
||||
# before_request:
|
||||
# - 'SecRule REQUEST_FILENAME "@endsWith /wp-admin/admin-ajax.php" "id:1,nolog,ctl:ruleRemoveById=932260"'
|
||||
after_response:
|
||||
- 'SecRuleUpdateTargetById 932260 "!ARGS:tag-name"'
|
||||
header_cross_origin_embedder_policy: "unsafe-none"
|
||||
header_content_security_policy:
|
||||
worker-src: "'self' blob:"
|
||||
img-src: "'self' data: https://secure.gravatar.com/avatar/"
|
||||
font-src: "'self' data:"
|
||||
script-src: "'self' 'unsafe-eval'"
|
||||
script-src-elem: "'self' 'unsafe-inline'"
|
||||
style-src-attr: "'self' 'unsafe-inline'"
|
||||
style-src-elem: "'self' 'unsafe-inline'"
|
||||
frame-src: "'self' blob:"
|
||||
24
example/ansible/vars/secrets.yml
Normal file
24
example/ansible/vars/secrets.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
30356233646632316565363533613033376333306433626366623230633838356230363461383135
|
||||
3834363137353762316262363134643763353632306362640a613538306235633565356563613532
|
||||
64643862613431313666363130376338356538323035346532636331316637646235346236333331
|
||||
6336313466313434640a316437343866343061383838383362633638363633363535363330333463
|
||||
64616330333361643166663061306338616265316262646339663438306465623231336139653764
|
||||
63353862303538636636306430333464383339316233326133623564613337306266353730616564
|
||||
63366562626135626136663665353663323265346438346131363838383263663665653937393066
|
||||
32353061396661346138386561633734353634363164663438656331383663323035613264653265
|
||||
38646164633465363238623232393731633761393466326466653430316532633139636533613033
|
||||
39303764363861353666356239306366633662643865663033383235336663623632373566383330
|
||||
32363334653936393962633266666439623130616161373231313037343735616361303131383230
|
||||
62333863313432353536363962623161383434363136316264663061343038633065316232313334
|
||||
38653233356135623431343166356464666663636330373663303663326561363333633837303337
|
||||
66616464393661653835636665353439353539393530623730656331316235643032336337616436
|
||||
64373163373932653038613765633061306331363962333932383564333735353534646637303237
|
||||
62376561303364386662343331373631343166326261636362623432323437643735663437333564
|
||||
39323961626131616334323131393963323231626638393231326631306337306230666138323830
|
||||
63373331636234646431666332633633353637313338353536663539303531663938336132356134
|
||||
30323631646666396239323261366435656434623537343935393531633966643135633561633636
|
||||
31626266366432613936643937646537636164646334316562396639363132313862616433653535
|
||||
34666537653433663466323730373363363064393334386133366365383435616436623963626634
|
||||
31376162306565623262663732356463616464376231356432316137373138356466393663653035
|
||||
613336396164633836626637393036303336
|
||||
5
example/tofu/.gitignore
vendored
Normal file
5
example/tofu/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.terraform/
|
||||
.terraform.lock.hcl
|
||||
.terraform.tfstate.lock.info
|
||||
terraform.tfstate
|
||||
terraform.tfstate.backup
|
||||
4
example/tofu/cloud-init.yml
Normal file
4
example/tofu/cloud-init.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
users:
|
||||
- name: "root"
|
||||
ssh_authorized_keys:
|
||||
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOHAAcWecBuLe9gt/NLC5b3DCl68knbwCFcHrH9wPPTk seb@itik.fr"
|
||||
10
example/tofu/infra.auto.tfvars
Normal file
10
example/tofu/infra.auto.tfvars
Normal file
@@ -0,0 +1,10 @@
|
||||
vms = {
|
||||
waf1 = {},
|
||||
waf2 = {},
|
||||
waf3 = {},
|
||||
sql1 = {},
|
||||
nfs1 = {},
|
||||
www1 = {},
|
||||
www2 = {},
|
||||
www3 = {},
|
||||
}
|
||||
11
example/tofu/main.tf
Normal file
11
example/tofu/main.tf
Normal file
@@ -0,0 +1,11 @@
|
||||
provider "multipass" {}
|
||||
|
||||
resource "multipass_instance" "this" {
|
||||
for_each = var.vms
|
||||
name = each.key
|
||||
cpus = each.value.cpus
|
||||
memory = each.value.memory
|
||||
disk = each.value.disk
|
||||
image = each.value.image
|
||||
cloudinit_file = "cloud-init.yml"
|
||||
}
|
||||
8
example/tofu/terraform.tf
Normal file
8
example/tofu/terraform.tf
Normal file
@@ -0,0 +1,8 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
multipass = {
|
||||
source = "larstobi/multipass"
|
||||
version = "1.4.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
9
example/tofu/variables.tf
Normal file
9
example/tofu/variables.tf
Normal file
@@ -0,0 +1,9 @@
|
||||
variable "vms" {
|
||||
description = "Liste des machines virtuelles"
|
||||
type = map(object({
|
||||
cpus = optional(number, 2),
|
||||
memory = optional(string, "3g"),
|
||||
disk = optional(string, "12g"),
|
||||
image = optional(string, "24.04"),
|
||||
}))
|
||||
}
|
||||
Reference in New Issue
Block a user