mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-04-29 18:48:39 +02:00
Optimized cloudflare implementation
This commit is contained in:
parent
04deeef385
commit
d796158c61
@ -79,6 +79,8 @@ activate_all_timers: false # Activates all timers, indep
|
|||||||
# You SHOULD NOT enable this on production servers
|
# You SHOULD NOT enable this on production servers
|
||||||
enable_debug: false
|
enable_debug: false
|
||||||
|
|
||||||
|
dns_provider: cloudflare # The DNS Provider\Registrar for the domain
|
||||||
|
|
||||||
# Which ACME method to use: webroot, cloudflare, or hetzner
|
# Which ACME method to use: webroot, cloudflare, or hetzner
|
||||||
certbot_acme_challenge_method: "cloudflare"
|
certbot_acme_challenge_method: "cloudflare"
|
||||||
certbot_credentials_dir: /etc/certbot
|
certbot_credentials_dir: /etc/certbot
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
collections:
|
collections:
|
||||||
- name: kewlfft.aur
|
- name: kewlfft.aur
|
||||||
|
- name: community.general
|
||||||
pacman:
|
pacman:
|
||||||
- ansible
|
- ansible
|
||||||
- python-passlib
|
- python-passlib
|
||||||
|
37
roles/dns-records-cloudflare/README.md
Normal file
37
roles/dns-records-cloudflare/README.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Cloudflare DNS Records
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This Ansible role automates the management of DNS A-records in Cloudflare zones. It uses the [community.general.cloudflare_dns](https://docs.ansible.com/ansible/latest/collections/community/general/cloudflare_dns_module.html) module to create or update A-records for a list of domains, automatically detects the correct zone for each record, and supports configurable proxy settings.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Looping over a provided list of domains (`cloudflare_domains`), this role:
|
||||||
|
- Determines the zone name by extracting the last two labels of each domain.
|
||||||
|
- Ensures an A-record for each domain points to the specified IP (`cloudflare_target_ip`).
|
||||||
|
- Honors the `proxied` flag to switch between DNS-only and Cloudflare-proxied modes.
|
||||||
|
- Provides an optional debug task (`enable_debug`) to output the domain list before changes.
|
||||||
|
|
||||||
|
Ideal for environments where bulk or dynamic DNS updates are needed, this role abstracts away the complexity of Cloudflare’s zone and record API.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Cloudflare DNS Records delivers an idempotent, scalable solution for managing A-records across multiple Cloudflare zones. Whether you need to onboard hundreds of domains or toggle proxy settings in CI/CD pipelines, this role handles the orchestration and ensures consistency.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Automatic Zone Detection:** Parses each domain to derive its zone (`example.com`) without manual intervention.
|
||||||
|
- **Bulk Record Management:** Creates or updates A-records for all entries in `cloudflare_domains`.
|
||||||
|
- **Proxy Toggle:** Configure `proxied: true` or `false` per record to switch between DNS-only and proxied modes.
|
||||||
|
- **Debug Support:** Enable `enable_debug` to print the domain list for validation before execution.
|
||||||
|
- **Flexible Authentication:** Supports both API token (`api_token`) and Global API key + email.
|
||||||
|
- **Low-TTL Option:** Use `ttl: 1` for rapid DNS propagation during dynamic updates.
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
Kevin Veen-Birkenbach
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
CyMaIS NonCommercial License (CNCL)
|
||||||
|
<https://s.veen.world/cncl>
|
26
roles/dns-records-cloudflare/meta/main.yml
Normal file
26
roles/dns-records-cloudflare/meta/main.yml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
galaxy_info:
|
||||||
|
author: "Kevin Veen-Birkenbach"
|
||||||
|
description: "Manages DNS A-records in Cloudflare zones."
|
||||||
|
license: "CyMaIS NonCommercial License (CNCL)"
|
||||||
|
license_url: "https://s.veen.world/cncl"
|
||||||
|
company: |
|
||||||
|
Kevin Veen-Birkenbach
|
||||||
|
Consulting & Coaching Solutions
|
||||||
|
https://www.veen.world
|
||||||
|
min_ansible_version: "2.9"
|
||||||
|
platforms:
|
||||||
|
- name: "All"
|
||||||
|
versions:
|
||||||
|
- "all"
|
||||||
|
galaxy_tags:
|
||||||
|
- "cloudflare"
|
||||||
|
- "dns"
|
||||||
|
- "records"
|
||||||
|
- "ansible"
|
||||||
|
- "network"
|
||||||
|
- "automation"
|
||||||
|
repository: "https://s.veen.world/cymais"
|
||||||
|
issue_tracker_url: "https://s.veen.world/cymaisissues"
|
||||||
|
documentation: "https://s.veen.world/cymais"
|
||||||
|
dependencies: []
|
18
roles/dns-records-cloudflare/tasks/main.yml
Normal file
18
roles/dns-records-cloudflare/tasks/main.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
- name: "Debug: cloudflare_domains"
|
||||||
|
debug:
|
||||||
|
var: cloudflare_domains
|
||||||
|
when: enable_debug
|
||||||
|
|
||||||
|
- name: Create or update Cloudflare A-record for {{ item }}
|
||||||
|
community.general.cloudflare_dns:
|
||||||
|
api_token: "{{ cloudflare_api_token }}"
|
||||||
|
zone: "{{ item.split('.')[-2:] | join('.') }}"
|
||||||
|
state: present
|
||||||
|
type: A
|
||||||
|
name: "{{ item }}"
|
||||||
|
content: "{{ cloudflare_target_ip }}"
|
||||||
|
ttl: 1
|
||||||
|
proxied: "{{ cloudflare_target_ip }}"
|
||||||
|
loop: "{{ cloudflare_domains }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item }}"
|
@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
- name: "include role nginx-domain-setup for {{application_id}}"
|
# Docker Central Database Role can't be used here
|
||||||
include_role:
|
|
||||||
name: nginx-domain-setup
|
|
||||||
|
|
||||||
- name: "include docker-compose role"
|
- name: "include docker-compose role"
|
||||||
include_role:
|
include_role:
|
||||||
name: docker-compose
|
name: docker-compose
|
||||||
|
|
||||||
|
- name: "include role nginx-domain-setup for {{application_id}}"
|
||||||
|
include_role:
|
||||||
|
name: nginx-domain-setup
|
||||||
|
|
||||||
- name: pull docker repository
|
- name: pull docker repository
|
||||||
git:
|
git:
|
||||||
repo: "https://github.com/bigbluebutton/docker.git"
|
repo: "https://github.com/bigbluebutton/docker.git"
|
||||||
|
@ -33,8 +33,6 @@ RAILS_SECRET={{applications.bigbluebutton.credentials.rails_secret}}
|
|||||||
POSTGRESQL_SECRET={{applications.bigbluebutton.credentials.postgresql_secret}}
|
POSTGRESQL_SECRET={{applications.bigbluebutton.credentials.postgresql_secret}}
|
||||||
FSESL_PASSWORD={{applications.bigbluebutton.credentials.fsesl_password}}
|
FSESL_PASSWORD={{applications.bigbluebutton.credentials.fsesl_password}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ====================================
|
# ====================================
|
||||||
# CONNECTION
|
# CONNECTION
|
||||||
# ====================================
|
# ====================================
|
||||||
|
@ -4,9 +4,7 @@ docker_compose_file_origine: "{{ docker_compose.directories.services }}docker-c
|
|||||||
docker_compose_file_final: "{{ docker_compose.directories.instance }}docker-compose.yml"
|
docker_compose_file_final: "{{ docker_compose.directories.instance }}docker-compose.yml"
|
||||||
|
|
||||||
# Database configuration
|
# Database configuration
|
||||||
database_instance: "bigbluebutton"
|
database_type: "postgres"
|
||||||
database_name: "multiple_databases"
|
|
||||||
database_username: "postgres"
|
|
||||||
database_password: "{{ applications.bigbluebutton.credentials.postgresql_secret }}"
|
database_password: "{{ applications.bigbluebutton.credentials.postgresql_secret }}"
|
||||||
|
|
||||||
domain: "{{ domains[application_id] }}"
|
domain: "{{ domains[application_id] }}"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
database_instance: "{{ 'central-' + database_type if applications[application_id].features.database | bool else application_id }}"
|
database_instance: "{{ 'central-' + database_type if applications[application_id].features.database | bool else application_id }}"
|
||||||
database_host: "{{ 'central-' + database_type if applications[application_id].features.database | bool else 'database' }}"
|
database_host: "{{ 'central-' + database_type if applications[application_id].features.database | bool else 'database' }}"
|
||||||
database_name: "{{ application_id }}"
|
database_name: "{{ applications[application_id].credentials.database.name | default( application_id ) }}" # The overwritte configuration is needed by bigbluebutton
|
||||||
database_username: "{{ application_id }}"
|
database_username: "{{ applications[application_id].credentials.database.username | default( application_id )}}" # The overwritte configuration is needed by bigbluebutton
|
||||||
database_port: "{{ 3306 if database_type == 'mariadb' else 5432 }}"
|
database_port: "{{ 3306 if database_type == 'mariadb' else 5432 }}"
|
||||||
database_env: "{{docker_compose.directories.env}}{{database_type}}.env"
|
database_env: "{{docker_compose.directories.env}}{{database_type}}.env"
|
||||||
database_url_jdbc: "jdbc:{{ database_type if database_type == 'mariadb' else 'postgresql' }}://{{ database_host }}:{{ database_port }}/{{ database_name }}"
|
database_url_jdbc: "jdbc:{{ database_type if database_type == 'mariadb' else 'postgresql' }}://{{ database_host }}:{{ database_port }}/{{ database_name }}"
|
||||||
|
@ -2,8 +2,5 @@ server {
|
|||||||
listen {{ports.public.ldaps.ldap}}ssl;
|
listen {{ports.public.ldaps.ldap}}ssl;
|
||||||
proxy_pass 127.0.0.1:{{ports.localhost.ldap.ldap}};
|
proxy_pass 127.0.0.1:{{ports.localhost.ldap.ldap}};
|
||||||
|
|
||||||
# SSL Configuration for LDAPS
|
|
||||||
{% include 'roles/letsencrypt/templates/ssl_credentials.j2' %}
|
{% include 'roles/letsencrypt/templates/ssl_credentials.j2' %}
|
||||||
ssl_protocols TLSv1.2 TLSv1.3;
|
|
||||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
listen 443 ssl;
|
listen 443 ssl http2;
|
||||||
listen [::]:443 ssl;
|
listen [::]:443 ssl http2;
|
||||||
http2 on;
|
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ecdh_curve X25519:P-256;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
|
||||||
|
|
||||||
ssl_session_timeout 1d;
|
ssl_session_timeout 1d;
|
||||||
ssl_session_cache shared:SSL:50m;
|
ssl_session_cache shared:SSL:50m;
|
||||||
ssl_session_tickets on;
|
ssl_session_tickets on;
|
||||||
ssl_prefer_server_ciphers on;
|
|
||||||
add_header Strict-Transport-Security max-age=15768000;
|
add_header Strict-Transport-Security max-age=15768000;
|
||||||
ssl_stapling on;
|
ssl_stapling on;
|
||||||
ssl_stapling_verify on;
|
ssl_stapling_verify on;
|
||||||
{% include 'roles/letsencrypt/templates/ssl_credentials.j2' %}
|
{% include 'roles/letsencrypt/templates/ssl_credentials.j2' %}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
--domains "{{ all_domains | join(',') }}"
|
--domains "{{ all_domains | join(',') }}"
|
||||||
--certbot-email "{{ users.administrator.email }}"
|
--certbot-email "{{ users.administrator.email }}"
|
||||||
--certbot-acme-challenge-method "{{ certbot_acme_challenge_method }}"
|
--certbot-acme-challenge-method "{{ certbot_acme_challenge_method }}"
|
||||||
|
--chunk-size 100
|
||||||
{% if certbot_acme_challenge_method != 'webroot' %}
|
{% if certbot_acme_challenge_method != 'webroot' %}
|
||||||
--certbot-credentials-file "{{ certbot_credentials_file }}"
|
--certbot-credentials-file "{{ certbot_credentials_file }}"
|
||||||
--certbot-dns-propagation-seconds "{{ certbot_dns_propagation_wait_seconds }}"
|
--certbot-dns-propagation-seconds "{{ certbot_dns_propagation_wait_seconds }}"
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
---
|
---
|
||||||
# 1. Filter all domains with the “www.” prefix
|
- name: "Debug: all_domains"
|
||||||
|
debug:
|
||||||
|
var: all_domains
|
||||||
|
when: enable_debug
|
||||||
|
|
||||||
- name: Filter www-prefixed domains from all_domains
|
- name: Filter www-prefixed domains from all_domains
|
||||||
set_fact:
|
set_fact:
|
||||||
www_domains: "{{ all_domains | select('match', '^www\\.') | list }}"
|
www_domains: "{{ all_domains | select('match', '^www\\.') | list }}"
|
||||||
|
|
||||||
# 2. Build redirect mappings (www.domain → domain)
|
|
||||||
- name: Build redirect mappings for www domains
|
- name: Build redirect mappings for www domains
|
||||||
set_fact:
|
set_fact:
|
||||||
domain_mappings: >-
|
domain_mappings: >-
|
||||||
@ -14,10 +17,19 @@
|
|||||||
| list
|
| list
|
||||||
}}
|
}}
|
||||||
|
|
||||||
# 3. Include the nginx-redirect-domain role to apply these mappings
|
|
||||||
- name: Include nginx-redirect-domain role for www-to-bare redirects
|
- name: Include nginx-redirect-domain role for www-to-bare redirects
|
||||||
include_role:
|
include_role:
|
||||||
name: nginx-redirect-domain
|
name: nginx-redirect-domain
|
||||||
vars:
|
vars:
|
||||||
domain_mappings: "{{ domain_mappings }}"
|
domain_mappings: "{{ domain_mappings }}"
|
||||||
when: certbot_flavor == 'dedicated'
|
when: certbot_flavor == 'dedicated'
|
||||||
|
|
||||||
|
- name: Include DNS role to set redirects
|
||||||
|
include_role:
|
||||||
|
name: dns-records-cloudflare
|
||||||
|
vars:
|
||||||
|
cloudflare_api_token: "{{ certbot_dns_api_token }}"
|
||||||
|
cloudflare_domains: "{{ www_domains }}"
|
||||||
|
cloudflare_target_ip: "{{ networks.internet.ip4 }}"
|
||||||
|
cloudflare_proxied_false: false
|
||||||
|
when: dns_provider == 'cloudflare'
|
@ -62,22 +62,28 @@
|
|||||||
set_fact:
|
set_fact:
|
||||||
service_provider: "{{ defaults_service_provider | combine(service_provider | default({}, true), recursive=True) }}"
|
service_provider: "{{ defaults_service_provider | combine(service_provider | default({}, true), recursive=True) }}"
|
||||||
|
|
||||||
- name: Collect all domains (domains, redirect sources + www)
|
- name: Gather base domains (without www)
|
||||||
set_fact:
|
set_fact:
|
||||||
all_domains: >-
|
base_domains: >-
|
||||||
{{
|
{{
|
||||||
(
|
domains.values()
|
||||||
(
|
| flatten
|
||||||
domains.values() | flatten
|
|
||||||
+ (redirect_domain_mappings | map(attribute='source') | list)
|
+ (redirect_domain_mappings | map(attribute='source') | list)
|
||||||
)
|
|
||||||
+ (
|
|
||||||
domains.values() | flatten
|
|
||||||
+ (redirect_domain_mappings | map(attribute='source') | list)
|
|
||||||
) | map('regex_replace', '^(.*)$', 'www.\\1') | list
|
|
||||||
) | unique | sort
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
- name: Initialise all_domains as empty list
|
||||||
|
set_fact:
|
||||||
|
all_domains: []
|
||||||
|
|
||||||
|
- name: Build all_domains with base + www via loop
|
||||||
|
set_fact:
|
||||||
|
all_domains: "{{ all_domains + [ item, 'www.' ~ item ] }}"
|
||||||
|
loop: "{{ base_domains }}"
|
||||||
|
|
||||||
|
- name: Deduplicate and sort all_domains
|
||||||
|
set_fact:
|
||||||
|
all_domains: "{{ all_domains | unique | sort }}"
|
||||||
|
|
||||||
- name: "Merged Variables"
|
- name: "Merged Variables"
|
||||||
# Add new merged variables here
|
# Add new merged variables here
|
||||||
debug:
|
debug:
|
||||||
|
@ -66,7 +66,7 @@ defaults_applications:
|
|||||||
'iframe': true,
|
'iframe': true,
|
||||||
'ldap': false,
|
'ldap': false,
|
||||||
'oidc': true,
|
'oidc': true,
|
||||||
'database': true,
|
'database': false,
|
||||||
}) }}{% raw %}
|
}) }}{% raw %}
|
||||||
credentials:
|
credentials:
|
||||||
# shared_secret: # Needs to be defined in inventory file
|
# shared_secret: # Needs to be defined in inventory file
|
||||||
@ -75,6 +75,9 @@ defaults_applications:
|
|||||||
# postgresql_secret: # Needs to be defined in inventory file
|
# postgresql_secret: # Needs to be defined in inventory file
|
||||||
# fsesl_password: # Needs to be defined in inventory file
|
# fsesl_password: # Needs to be defined in inventory file
|
||||||
# turn_secret: # Needs to be defined in inventory file
|
# turn_secret: # Needs to be defined in inventory file
|
||||||
|
database:
|
||||||
|
name: "multiple_databases"
|
||||||
|
username: "postgres2"
|
||||||
urls:
|
urls:
|
||||||
api: "{{ web_protocol }}://{{domains.bigbluebutton}}/bigbluebutton/" # API Address used by Nextcloud Integration
|
api: "{{ web_protocol }}://{{domains.bigbluebutton}}/bigbluebutton/" # API Address used by Nextcloud Integration
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user