diff --git a/playbooks/maxscale.yml b/playbooks/maxscale.yml new file mode 100644 index 0000000..7852259 --- /dev/null +++ b/playbooks/maxscale.yml @@ -0,0 +1,6 @@ +- name: Configure MaxScale + hosts: all + tasks: + - name: Configure MaxScale to install in the server + import_role: + name: maxscale \ No newline at end of file diff --git a/roles/maxscale/defaults/main.yaml b/roles/maxscale/defaults/main.yaml new file mode 100644 index 0000000..dd63441 --- /dev/null +++ b/roles/maxscale/defaults/main.yaml @@ -0,0 +1,15 @@ +downloads: + - url: https://r.mariadb.com/downloads/mariadb_repo_setup + dest: /tmp/mariadb_repo_setup + mode: u=rwx,g=rx,o=rx +certificates: + - { content: '{{ maxscale_config.admin_cert }}', dest: '/etc/ssl/private/cert.pem', owner: 'root', group: 'maxscale', mode: 'u=rw,g=r,o=r' } + - { content: '{{ maxscale_config.admin_key }}', dest: '/etc/ssl/private/key.pem', owner: 'root', group: 'maxscale', mode: 'u=rw,g=r,o=' } + - { content: '{{ maxscale_config.db_cert_pem }}', dest: '/etc/ssl/private/db-cert.pem', owner: 'root', group: 'maxscale', mode: 'u=rw,g=r,o=' } + - { content: '{{ maxscale_config.db_ca_pem }}', dest: '/etc/ssl/private/db-ca.pem', owner: 'root', group: 'maxscale', mode: 'u=rw,g=r,o=' } + - { content: '{{ maxscale_config.db_key }}', dest: '/etc/ssl/private/db-key.pem', owner: 'root', group: 'maxscale', mode: 'u=rw,g=r,o=' } +maxscale_templates: + - { src: 'maxscale.cnf.j2', dest: '/etc/maxscale.cnf' } + - { src: 'keepalived.conf.j2', dest: '/etc/keepalived/keepalived.conf' } + - { src: 'override.conf.j2', dest: '/etc/systemd/system/maxscale.service.d/override.conf' } + - { src: '.secrets', dest: '/var/lib/maxscale/.secrets', owner: 'maxscale', group: 'maxscale', mode: 'u=r,g=,o=' } \ No newline at end of file diff --git a/roles/maxscale/handlers/main.yml b/roles/maxscale/handlers/main.yml new file mode 100644 index 0000000..465e069 --- /dev/null +++ b/roles/maxscale/handlers/main.yml @@ -0,0 +1,16 @@ +- name: reload-systemd + command: + cmd: systemctl daemon-reload +- name: restart-maxscale + systemd: + name: maxscale + state: restarted + enabled: yes +- name: restart-keepalived + systemd: + name: keepalived + state: restarted + enabled: yes +- name: reload-systemd + command: + cmd: systemctl daemon-reload diff --git a/roles/maxscale/tasks/main.yml b/roles/maxscale/tasks/main.yml new file mode 100644 index 0000000..52f03c8 --- /dev/null +++ b/roles/maxscale/tasks/main.yml @@ -0,0 +1,3 @@ +- import_tasks: maxscale.yml + tags: maxscale + diff --git a/roles/maxscale/tasks/maxscale.yml b/roles/maxscale/tasks/maxscale.yml new file mode 100644 index 0000000..01f044b --- /dev/null +++ b/roles/maxscale/tasks/maxscale.yml @@ -0,0 +1,67 @@ +- name: Ensure required packages for MaxScale are installed + apt: + name: keepalived + state: present + install_recommends: no + update_cache: true +- name: Download required setup files + get_url: + url: "{{ item.url }}" + dest: "{{ item.dest }}" + mode: "{{ item.mode }}" + register: mariadb_repo_script + loop: "{{ downloads }}" +- name: Run MariaDB repository setup script + command: + cmd: "/bin/bash /tmp/mariadb_repo_setup --mariadb-server-version={{ db.version | default('10.11.10') }} --mariadb-maxscale-version={{ db.maxscale | default('23.08.9') }}" + creates: "/etc/apt/sources.list.d/mariadb.list" + when: mariadb_repo_script.changed +- name: Ensure systemd override directory exists + file: + path: /etc/systemd/system/maxscale.service.d + state: directory + owner: root + group: root + mode: 'u=rwx,g=rx,o=rx' +- name: Install maxscale + apt: + name: maxscale + state: present + install_recommends: no + update_cache: true +- name: Ensure /etc/ssl/private has correct permissions and ownership + file: + path: /etc/ssl/private + state: directory + owner: root + group: maxscale + mode: "u=rwx,g=rx,o=" +- name: Deploy templated configuration files + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: "{{ item.owner | default('root') }}" + group: "{{ item.group | default('root') }}" + mode: "{{ item.mode | default('u=rw,g=r,o=r') }}" + loop: "{{ maxscale_templates }}" + notify: + - restart-keepalived + - restart-maxscale + - reload-systemd +- name: Insert certificates + no_log: true + copy: + content: "{{ item.content }}" + dest: "{{ item.dest }}" + owner: "{{ item.owner }}" + group: "{{ item.group }}" + mode: "{{ item.mode }}" + loop: "{{ certificates }}" + notify: + - restart-maxscale + + + + + + diff --git a/roles/maxscale/templates/.secrets b/roles/maxscale/templates/.secrets new file mode 100644 index 0000000..a0d02d5 --- /dev/null +++ b/roles/maxscale/templates/.secrets @@ -0,0 +1,6 @@ +{ + "description": "MaxScale encryption/decryption key", + "maxscale_version": "6.2.4", + "encryption_cipher": "EVP_aes_256_cbc", + "encryption_key": "{{ lookup(passbolt, 'maxscale_encryption_key', folder_parent_id=passbolt_folder).password }}" +} \ No newline at end of file diff --git a/roles/maxscale/templates/keepalived.conf.j2 b/roles/maxscale/templates/keepalived.conf.j2 new file mode 100644 index 0000000..ed9a5e9 --- /dev/null +++ b/roles/maxscale/templates/keepalived.conf.j2 @@ -0,0 +1,40 @@ +{% set k = keepalive %} +global_defs { + script_user root + enable_script_security +} + +vrrp_script check_maxscale { + script "/usr/bin/pgrep maxscale" + interval 4 + timeout 4 + rise 3 + fall 3 +} + +{% for vip in k.vips %} +vrrp_instance {{ vip.name }} { + interface {{ k.interface }} + state BACKUP + priority {{ k.priorities.master if vip.host == inventory_hostname_short else k.priorities.backup }} + virtual_router_id {{ vip.vrid }} + advert_int 1 + accept + unicast_src_ip {{ ansible_host }} + + unicast_peer { +{% for peer in k.peers if peer.host != inventory_hostname %} + {{ peer.ip }} +{% endfor %} + } + + + virtual_ipaddress { + {{ vip.vip }} + } + + track_script { + check_maxscale + } +} +{% endfor %} diff --git a/roles/maxscale/templates/maxscale.cnf.j2 b/roles/maxscale/templates/maxscale.cnf.j2 new file mode 100644 index 0000000..4f641b2 --- /dev/null +++ b/roles/maxscale/templates/maxscale.cnf.j2 @@ -0,0 +1,90 @@ +# MaxScale documentation: +# https://mariadb.com/kb/en/mariadb-maxscale-2208/ +# https://mariadb.com/kb/en/mariadb-maxscale-2208-mariadb-maxscale-configuration-guide/ + +[maxscale] +threads=auto +admin_host=0.0.0.0 +admin_port=443 +admin_ssl_cert={{ maxscale_config.admin_cert_path }} +admin_ssl_key={{ maxscale_config.admin_key_path }} +syslog=false +log_warning=false +logdir=/var/log/maxscale/ +query_classifier_cache_size=250M +config_sync_cluster={{ maxscale_config.config_sync_cluster }} +config_sync_user={{ maxscale_config.config_sync_user }} +config_sync_password={{ lookup(passbolt, 'maxscale_config.config_sync_password', folder_parent_id=passbolt_folder).password }} + +{% for server in maxscale_config.db_servers %} +[{{ server.name }}] +type=server +address={{ server.address }} +port=3306 +protocol=MariaDBBackend +{% endfor %} + +[MariaDB-Monitor] +type=monitor +module=mariadbmon +servers={{ maxscale_config.db_servers | map(attribute='name') | join(',') }} +user={{ maxscale_config.monitor_user }} +password={{ lookup(passbolt, 'maxscale_config.monitor_password', folder_parent_id=passbolt_folder).password }} +monitor_interval=2s +replication_user={{ maxscale_config.repl_user }} +replication_password={{ lookup(passbolt, 'maxscale_config.repl_password', folder_parent_id=passbolt_folder).password }} +switchover_timeout=1m +cooperative_monitoring_locks=majority_of_running + +[Read-Write-Service] +type=service +router=readwritesplit +servers=db1,db2 +user={{ maxscale_config.rw_user }} +password={{ lookup(passbolt, 'maxscale_config.rw_password', folder_parent_id=passbolt_folder).password }} +master_accept_reads=true +strict_multi_stmt=true +strict_sp_calls=true +slave_connections=0 +max_slave_connections=0 +use_sql_variables_in=master + +[Read-Only-Service] +type=service +router=readconnroute +servers=db1,db2 +user={{ maxscale_config.ro_user }} +password={{ lookup(passbolt, 'maxscale_config.ro_password', folder_parent_id=passbolt_folder).password }} +router_options=slave + +[Read-Write-Listener-SSL] +type=listener +service=Read-Write-Service +protocol=MariaDBClient +port=3306 +ssl=true +ssl_cert={{ maxscale_config.db_cert_path }} +ssl_key={{ maxscale_config.db_key_path }} +ssl_ca_cert={{ maxscale_config.db_ca_path }} + +[Read-Only-Listener-SSL] +type=listener +service=Read-Only-Service +protocol=MariaDBClient +port=3307 +ssl=true +ssl_cert={{ maxscale_config.db_cert_path }} +ssl_key={{ maxscale_config.db_key_path }} +ssl_ca_cert={{ maxscale_config.db_ca_path }} + +[Read-Write-Listener] +type=listener +service=Read-Write-Service +protocol=MariaDBClient +port=3308 + +[Read-Only-Listener] +type=listener +service=Read-Only-Service +protocol=MariaDBClient +port=3309 diff --git a/roles/maxscale/templates/override.conf.j2 b/roles/maxscale/templates/override.conf.j2 new file mode 100644 index 0000000..7ff5b18 --- /dev/null +++ b/roles/maxscale/templates/override.conf.j2 @@ -0,0 +1,4 @@ +[Service] +ExecStartPre=+setcap CAP_NET_BIND_SERVICE=+eip /bin/maxscale +WatchdogSec=10m +Restart=on-abnormal