commit 3d0d6c61ec0c569691658690e8aae966b34f082c Author: Frédéric CAMPO Date: Sat Apr 25 20:00:25 2026 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0392959 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +playbooks/vars/*.yml +playbooks/vars/*.yaml +playbooks/group_vars/*.yml +playbooks/group_vars/*.yaml +playbooks/host_vars/*.yml +playbooks/host_vars/*.yaml +inventory +ansible_collections +roles diff --git a/README.md b/README.md new file mode 100644 index 0000000..8b9a558 --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# ansible-scripts-home +###### by Frédéric CAMPO + +## TODO: +- Setup the default reverse proxy virtual host (template is ready default-reverse.j2) +- Idiotproofing the playbook (setting up default values everywhere) + +## 1. Installation +From the repository folder : +```bash +ansible-galaxy install -r requirements.yaml +``` + +## 2. Create your hosts vars file. +Example file: + +playbooks/host_vars/webserver.yml +```yaml +site: + (virtual host fqdn): + enabled: true + upstream: '127.0.0.1:8080' + tls: true + (other virtual host fqdn): + enabled: true + upstream: '127.0.0.1:12700' + tls: true +``` + +## 3. Launch the playbook diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..e403471 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,5 @@ +[defaults] +inventory = inventory +collections_path = . +roles_path = ./roles +interpreter_python = auto_silent diff --git a/playbooks/git.yml b/playbooks/git.yml new file mode 100644 index 0000000..4bec63b --- /dev/null +++ b/playbooks/git.yml @@ -0,0 +1,41 @@ +- name: Setup Forgejo + hosts: git + pre_tasks: + - name: Install dependencies + ansible.builtin.apt: + pkg: + - curl + - apt-transport-https + state: present + tasks: + - name: Configure Forgejo apt sources + ansible.builtin.blockinfile: + path: /etc/apt/sources.list.d/forgejo-stable.sources + create: true + block: | + Types: deb + URIs: https://code.forgejo.org/api/packages/apt/debian + Suites: lts + Components: main + Architectures: amd64 + Signed-By: /etc/apt/keyrings/forgejo.asc + mode: '644' + + - name: Create keyrings folder + ansible.builtin.file: + path: /etc/apt/keyrings + owner: root + state: directory + mode: '755' + + - name: Adding forgejo gpg key to apt keyring + ansible.builtin.get_url: + url: https://code.forgejo.org/api/packages/apt/debian/repository.key + dest: /etc/apt/keyrings/forgejo.asc + mode: '644' + + - name: Install forgejo + ansible.builtin.apt: + pkg: + - forgejo + state: present diff --git a/playbooks/reverseproxy.yml b/playbooks/reverseproxy.yml new file mode 100644 index 0000000..c372c6e --- /dev/null +++ b/playbooks/reverseproxy.yml @@ -0,0 +1,81 @@ +- name: Nginx reverse proxy configuration + hosts: reverseproxy + handlers: + - name: Restart nginx + ansible.builtin.service: + name: nginx + state: restarted + tasks: + - name: Makes sure the nginx package is installed + ansible.builtin.apt: + pkg: + - nginx-full + + - name: Nginx security configuration template + ansible.builtin.template: + src: "templates/nginx/snippets/security-hardening.conf.j2" + dest: "/etc/nginx/snippets/security-hardening.conf" + mode: '0644' + notify: Restart nginx + + - name: Nginx security headers configuration template + ansible.builtin.template: + src: "templates/nginx/snippets/security-headers.conf.j2" + dest: "/etc/nginx/snippets/security-headers.conf" + mode: '0644' + notify: Restart nginx + + - name: Create dhparam files + community.crypto.openssl_dhparam: + path: "/etc/nginx/dhparam.pem" + size: 4096 + + - name: Certificates generation + ansible.builtin.include_role: + name: geerlingguy.certbot + loop: "{{ site | dict2items }}" + when: "{{ item.value.tls | default(False) }}" + vars: + certbot_admin_email: "{{ acme_account.email }}" + certbot_install_method: package + certbot_auto_renew: true + certbot_auto_renew_user: "root" + certbot_create_if_missing: true + certbot_testmode: "{{ acme_account.testing | default(False) }}" + certbot_certs: + - name: "{{ item.key }}" + domains: + - "{{ item.key }}" + + - name: Nginx website configuration template + ansible.builtin.template: + src: "templates/nginx/sites-available/default-reverse.j2" + dest: "/etc/nginx/sites-available/{{ item.key }}" + mode: '0644' + loop: "{{ site | dict2items }}" + when: "item.value.enabled" + notify: Restart nginx + + - name: Removing disabled websites from nginx configuration + ansible.builtin.file: + path: "/etc/nginx/sites-available/{{ item.key }}" + state: absent + loop: "{{ site | dict2items }}" + when: "not item.value.enabled" + + - name: Disable websites in nginx configuration + ansible.builtin.file: + path: "/etc/nginx/sites-enabled/{{ item.key }}" + state: absent + loop: "{{ site | dict2items }}" + when: "not item.value.enabled" + notify: Restart nginx + + - name: Enable websites in nginx configuration + ansible.builtin.file: + src: "/etc/nginx/sites-available/{{ item.key }}" + dest: "/etc/nginx/sites-enabled/{{ item.key }}" + state: link + loop: "{{ site | dict2items }}" + when: "item.value.enabled" + notify: Restart nginx diff --git a/playbooks/templates/nginx/sites-available/00-default-deny.conf.j2 b/playbooks/templates/nginx/sites-available/00-default-deny.conf.j2 new file mode 100644 index 0000000..135f79b --- /dev/null +++ b/playbooks/templates/nginx/sites-available/00-default-deny.conf.j2 @@ -0,0 +1,15 @@ +# ANSIBLE MAINTAINED FILE - DO NOT EDIT MANUALLY +server { + listen 80 default_server; + listen [::]:80 default_server; + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + + server_name _; + + # Self-signed or snakeoil cert just to complete the TLS handshake + ssl_certificate /etc/letsencrypt/live/{{ item.key }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ item.key }}/privkey.pem; + + return 444; +} \ No newline at end of file diff --git a/playbooks/templates/nginx/sites-available/default-reverse.j2 b/playbooks/templates/nginx/sites-available/default-reverse.j2 new file mode 100644 index 0000000..6acf90d --- /dev/null +++ b/playbooks/templates/nginx/sites-available/default-reverse.j2 @@ -0,0 +1,41 @@ +# ANSIBLE MAINTAINED FILE - DO NOT EDIT MANUALLY +upstream {{ item.key }} { + server {{ item.value.upstream }}; +} + +server { + server_name {{ item.key }}; + listen 443 ssl; + listen [::]:443 ssl; + http2 on; + include /etc/nginx/snippets/security-hardening.conf; + ssl_certificate /etc/letsencrypt/live/{{ item.key }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ item.key }}/privkey.pem; + + location / { + include /etc/nginx/snippets/security-headers.conf; + proxy_pass http://{{ item.key }}; + proxy_set_header Connection $http_connection; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_connect_timeout 15; + proxy_send_timeout 15; + limit_except GET POST { + deny all; + } + } + +} + +server { + server_name {{ item.key }}; + listen 80; + listen [::]:80; + + return 301 https://$host$request_uri; + } + diff --git a/playbooks/templates/nginx/snippets/security-hardening.conf.j2 b/playbooks/templates/nginx/snippets/security-hardening.conf.j2 new file mode 100644 index 0000000..3c91cf8 --- /dev/null +++ b/playbooks/templates/nginx/snippets/security-hardening.conf.j2 @@ -0,0 +1,13 @@ +# ANSIBLE MAINTAINED FILE - DO NOT EDIT MANUALLY +ssl_protocols TLSv1.3; +ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1:secp384r1; +ssl_prefer_server_ciphers off; +ssl_dhparam /etc/nginx/dhparam.pem; + +client_max_body_size 512m; +client_body_buffer_size 16k; +large_client_header_buffers 4 16k; +client_body_timeout 30s; +client_header_timeout 30s; +send_timeout 30s; +keepalive_timeout 65s; diff --git a/playbooks/templates/nginx/snippets/security-headers.conf.j2 b/playbooks/templates/nginx/snippets/security-headers.conf.j2 new file mode 100644 index 0000000..d08f28d --- /dev/null +++ b/playbooks/templates/nginx/snippets/security-headers.conf.j2 @@ -0,0 +1,7 @@ +# ANSIBLE MAINTAINED FILE - DO NOT EDIT MANUALLY +add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always; +add_header X-Content-Type-Options "nosniff" always; +add_header X-Frame-Options "SAMEORIGIN" always; +add_header Content-Security-Policy "default-src 'none'; script-src 'self' 'nonce-{RANDOM}' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; img-src 'self' data:; font-src 'self'; connect-src 'self'; upgrade-insecure-requests" always; +add_header Referrer-Policy "strict-origin-when-cross-origin" always; +add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=()" always; \ No newline at end of file diff --git a/requirements.yaml b/requirements.yaml new file mode 100644 index 0000000..6ad070e --- /dev/null +++ b/requirements.yaml @@ -0,0 +1,4 @@ +collections: + - community.general +roles: + - name: geerlingguy.certbot