feat: reimplement various roles

develop
Dave S. 2 years ago
parent 5878ef2e31
commit eb5feb1fb8
  1. 2
      .gitignore
  2. 51
      all.yml
  3. 7
      group_vars/all.yml
  4. 2
      group_vars/infra.yml.template
  5. 7
      mappings.yml
  6. 15
      roles/common/tasks/main.yml
  7. 19
      roles/common/templates/dropbear_init.j2
  8. 2
      roles/container/defaults/main.yml
  9. 99
      roles/container/tasks/main.yml
  10. 8
      roles/coredns/defaults/main.yml
  11. 27
      roles/coredns/tasks/add.yml
  12. 21
      roles/coredns/tasks/add_record.yml
  13. 21
      roles/coredns/tasks/add_records.yml
  14. 14
      roles/coredns/tasks/increase_serial.yml
  15. 13
      roles/coredns/tasks/info.yml
  16. 93
      roles/coredns/tasks/install.yml
  17. 28
      roles/coredns/tasks/install_tls.yml
  18. 107
      roles/coredns/tasks/main.yml
  19. 25
      roles/coredns/tasks/tls.yml
  20. 10
      roles/coredns/templates/corefile.j2
  21. 2
      roles/coredns/templates/init.j2
  22. 20
      roles/coredns/templates/tls.j2
  23. 29
      roles/coredns/templates/zone.j2
  24. 7
      roles/ns-only/tasks/info.yml
  25. 3
      roles/ns-only/tasks/main.yml
  26. 28
      roles/ns/tasks/main.yml
  27. 9
      roles/proxmox/tasks/info.yml
  28. 127
      roles/proxmox/tasks/mail.yml
  29. 85
      roles/proxmox/tasks/main.yml
  30. 1
      roles/proxmox/tasks/rproxy.yml
  31. 4
      tasks/gen_ssh_key.yml
  32. 2
      tasks/includes/stage.yml
  33. 45
      tasks/pre_tasks.yml

2
.gitignore vendored

@ -1,2 +1,4 @@
hosts
keys/
.vscode/
group_vars/infra.yml

@ -3,6 +3,8 @@
serial: "{{ hosts_per_batch | d(1) | int }}"
strategy: "{{ hosts_strategy | d('linear') }}"
tasks:
# TODO: multiple roles
- name: get primary role
set_fact:
host_primary_role: "{%- if primary_role is defined -%}{{ primary_role }}\
@ -11,33 +13,30 @@
{%- endif -%}"
- name: import role mappings
import_tasks: mappings.yml
- name: check if role info file exists
stat:
path: "{{ (playbook_dir, 'roles', host_primary_role, 'tasks', 'info.yml') | path_join }}"
delegate_to: localhost
register: result
no_log: yes
- name: fail if mappings are missing
fail:
msg: role mappings are missing or invalid
when: (common_roles is not defined) or (common_roles | type_debug != 'list')
- name: warn if current role mapping is missing
debug:
msg: "mapping for role \"{{ host_primary_role }}\" is missing - using default role mapping at stage 6"
when: (extra_roles | d({}))[host_primary_role] is not defined
- name: build role mapping
set_fact:
role_mapping: "{{ (((extra_roles | d({}))[host_primary_role] | d([{ 'stage': 6, 'role': host_primary_role }])) +
([] if host_primary_role in (no_common_roles | d([])) else common_roles) +
([{ 'stage': 1, 'role': 'container' }] if 'containers' in group_names else []) +
([{ 'stage': 3, 'role': 'postgres', 'function': 'integrate' }] if host_primary_role in (database_roles | d([])) else [])
) | sort(attribute='stage') }}"
- name: get role info
include_role:
name: "{{ host_primary_role }}"
tasks_from: info.yml
apply:
no_log: yes
when: result.stat.exists
- name: remember selected stages
- name: build role dependency list and stage info
set_fact:
role_deps: "{{ (([{ 'stage': 6, 'role': host_primary_role }] if role_dependency is not defined else [role_dependency]) +
([role_dependency_common] if (role_dependency_no_common | d(false) == false) else []) +
([{ 'stage': 1, 'role': 'container' }] if 'containers' in group_names else []) +
([{ 'stage': 3, 'role': 'postgres', 'function': 'integrate' }] if role_dependency_use_db | d(false) == true else [])
) | flatten(levels=1) | sort(attribute='stage') }}"
selected_stages: "{%- if stage is defined and ((stage | string) is search(',')) -%}{{ stage | string | split(',') | list | map('int') | list }}\
{%- elif (stage is not defined) or ((stage | int) == 0) -%}{{ [1,2,3,4,5,6,7,8,9] }}\
{%- else -%}{{ [stage | int] }}\
@ -47,9 +46,13 @@
- name: show deployment info
debug:
msg: "deploying primary role \"{{ host_primary_role }}\" on host \"{{ inventory_hostname }}\", {{
msg: "deploying role \"{{ host_primary_role }}\" on host \"{{ inventory_hostname }}\", {{
(('stages ' if (selected_stages | length > 1) else 'stage ') ~ (selected_stages | join(', ')))
if ([1,2,3,4,5,6,7,8,9] | symmetric_difference(selected_stages) | list | length > 0) else 'all stages' }}"
if ([1,2,3,4,5,6,7,8,9] | symmetric_difference(selected_stages) | list | length > 0) else 'all stages' }}\n\n{{
'dependencies:\n' ~ (role_deps | map(attribute='stage') | list | zip(
role_deps | map(attribute='role') | list
) | map('join', ': ') | list | join('\n'))
}}"
- name: run pre_tasks

@ -34,3 +34,10 @@ bogons:
services: {}
mail_server: {}
role_dependency_common:
- {stage: 2, role: 'common'}
- {stage: 4, role: 'ns'}
- {stage: 5, role: 'mail-user'}
- {stage: 8, role: 'iptables'}
- {stage: 9, role: 'backup', function: 'setup'}

@ -7,7 +7,7 @@ int_net: 10.0.0.0/8
int_tld: "corp.{{ tld }}"
maintainer_email: "admin@{{ tld }}"
container_default_nameserver: 10.0.0.1
default_nameserver: 10.0.0.1
networks:
srv:

@ -1,12 +1,7 @@
- name: define role list
set_fact:
# common roles for all primary roles
common_roles:
- {stage: 2, role: 'common'}
- {stage: 3, role: 'ns', function: 'add_records'}
- {stage: 5, role: 'mail-user'}
- {stage: 8, role: 'iptables'}
- {stage: 9, role: 'backup', function: 'setup'}
# these primary roles do not inherit common roles
no_common_roles:

@ -15,7 +15,7 @@
set_fact:
ssh_ok: no
host_key_checking: no
ansible_password: "{{ container_password | d(host_password) }}"
ansible_password: "{{ host_password }}"
ansible_ssh_extra_args: "{{ ansible_ssh_extra_args | d('') }} -o StrictHostKeyChecking=no"
- name: try to connect without key checking
@ -87,21 +87,22 @@
notify: restart dropbear
- name: copy dropbear init file
copy:
src: dropbear_init
- name: template dropbear init file
template:
src: dropbear_init.j2
dest: /etc/init.d/dropbear
force: yes
lstrip_blocks: no
notify: restart dropbear
- name: ensure remote host has ansible key in authorized_keys file
lineinfile:
path: /root/.ssh/authorized_keys
line: "{{ container_key.public_key }}"
line: "{{ host_ssh_key.public_key }}"
create: yes
mode: 0400
when: container_key is defined and container_key.public_key is defined
when: host_ssh_key is defined and host_ssh_key.public_key is defined
when: ansible_distribution == 'Alpine'
@ -131,8 +132,8 @@
- name: add etc directory to backup plan
include_role:
name: backup
tasks_from: add.yml
vars:
function: add
backup_items:
- /etc

@ -0,0 +1,19 @@
#!/sbin/openrc-run
depend() {
use logger dns
need net
after firewall
}
start() {
ebegin "Starting dropbear"
/usr/sbin/dropbear ${DROPBEAR_OPTS}
eend $?
}
stop() {
ebegin "Stopping dropbear"
start-stop-daemon --stop --pidfile /var/run/dropbear.pid
eend $?
}

@ -3,5 +3,5 @@ container_pool: production
container_distro: alpine
container_template:
alpine: alpine-3.15-default_20211202_amd64.tar.xz
alpine: alpine-3.17-default_20221129_amd64.tar.xz
debian: debian-11-standard_11.3-1_amd64.tar.zst

@ -1,8 +1,9 @@
- name: specify connection parameters
set_fact:
pm_api_host: "{{ hostvars[selected_node]['ansible_host'] | mandatory }}"
pm_api_host: "{{ hostvars[selected_node]['ansible_host'] }}"
pm_api_user: "{{ hostvars[selected_node]['api_user'] | d('root@pam') }}"
pm_api_password: "{{ hostvars[selected_node]['api_password'] | d(hostvars[selected_node]['ansible_password']) }}"
pm_api_password: "{{ hostvars[selected_node]['api_password'] |
d(hostvars[selected_node]['host_password'] | d(hostvars[selected_node]['ansible_password'])) }}"
pm_lxc_storage: "{{ hostvars[selected_node]['lxc_storage'] | d('local-zfs') }}"
no_log: yes
@ -12,7 +13,7 @@
msg: some container parameters are missing or invalid
when: (container_distro is not defined) or (container_template is not mapping) or
(container_template[container_distro] is not defined) or
(container_id is not defined) or (container_password is not defined)
(container_id is not defined)
- name: ensure pool exists on cluster node
@ -26,9 +27,12 @@
- block:
- name: ensure pip3 is installed on local node
- name: ensure python dependencies are installed on local node
package:
name: py3-pip
name:
- py3-pip
- py3-requests
- py3-netaddr
run_once: yes
@ -55,6 +59,21 @@
timeout: 20
- name: build container network section
set_fact:
container_network_cfg: "{{ {
'name': 'eth0',
'hwaddr': container_mac | d(mac_prefix | community.general.random_mac(seed=inventory_hostname)),
'ip': ansible_host ~ '/' ~ networks[container_network].gw | ansible.utils.ipaddr('prefix'),
'gw': networks[container_network].gw | ansible.utils.ipaddr('address'),
'bridge': container_bridge | d('vmbr0'),
'firewall': 0,
'tag': networks[container_network].tag | d(None),
'type': 'veth',
'mtu': container_mtu | d(hostvars[selected_node]['container_mtu'] | d(1500))
} | dict2items | rejectattr('value', 'equalto', None) | list | items2dict }}"
- name: create container if not exists
community.general.proxmox:
node: "{{ selected_node }}"
@ -62,31 +81,31 @@
api_user: "{{ pm_api_user }}"
api_password: "{{ pm_api_password }}"
cores: "{{ hardware.cores }}"
cpus: "{{ hardware.cpus }}"
cpuunits: "{{ hardware.cpuunits }}"
disk: "{{ hardware.disk | string }}"
memory: "{{ hardware.memory }}"
swap: "{{ hardware.swap }}"
cores: "{{ host_hardware.cores }}"
cpus: "{{ host_hardware.cpus }}"
cpuunits: "{{ host_hardware.cpuunits }}"
disk: "{{ host_hardware.disk | string }}"
memory: "{{ host_hardware.memory }}"
swap: "{{ host_hardware.swap }}"
description: "{{ container_description | d(omit) }}"
hostname: "{{ inventory_hostname }}"
hostname: "{{ host_name }}"
pool: "{{ container_pool | d(omit) }}"
vmid: "{{ container_id }}"
password: "{{ container_password }}"
pubkey: "{{ (container_key | d({})).public_key | d(omit) }}"
password: "{{ host_password }}"
pubkey: "{{ (host_ssh_key | d({})).public_key | d(omit) }}"
ostemplate: "local:vztmpl/{{ container_template[container_distro] }}"
netif: "{\"net0\":\
\"name=eth0,hwaddr={{ container_mac | d(mac_prefix | community.general.random_mac(seed=inventory_hostname)) }},\
ip={{ ansible_host }}/{{ networks[container_network].gw | ansible.utils.ipaddr('prefix') }},\
gw={{ networks[container_network].gw | ansible.utils.ipaddr('address') }},\
bridge=vmbr0,\
firewall=0,\
tag={{ networks[container_network].tag }},\
type=veth,\
mtu={{ container_mtu | d(hostvars[selected_node]['container_mtu'] | d(1500)) }}\"}"
onboot: yes
proxmox_default_behavior: no_defaults
storage: "{{ pm_lxc_storage }}"
unprivileged: yes
timeout: 240
netif: "{{ { 'net0': container_network_cfg.keys() | zip(container_network_cfg.values()) |
map('join', '=') | join(',') } | to_json(sort_keys=true) }}"
nameserver: "{%- if container_nameserver is defined -%}\
{{ hostvars[container_nameserver]['ansible_host'] }}\
{%- elif services.filtering_ns is defined -%}\
@ -95,16 +114,11 @@
{%- else -%}
{{ hostvars[services.filtering_ns.hostname]['ansible_host'] }}\
{%- endif -%}
{%- elif container_default_nameserver is defined -%}\
{{ container_default_nameserver }}\
{%- elif nameserver is defined -%}\
{{ nameserver }}\
{%- else -%}\
{{ omit }}\
{%- endif -%}"
onboot: yes
proxmox_default_behavior: no_defaults
storage: "{{ pm_lxc_storage }}"
unprivileged: yes
timeout: 240
mounts: >-
{ {%- for item in (container_mounts | d([])) -%}
@ -115,39 +129,39 @@
- block:
- name: add features to lxc config
lineinfile:
path: "/etc/pve/lxc/{{ container_id }}.conf"
path: "{{ ('/etc/pve/lxc', container_id ~ '.conf') | path_join }}"
line: "features: {{ container_features | join(',') }}"
when: container_features | d([]) | length > 0
- name: check that lxc config is correct
lineinfile:
path: "/etc/pve/lxc/{{ container_id }}.conf"
path: "{{ ('/etc/pve/lxc', container_id ~ '.conf') | path_join }}"
regexp: "^{{ item.name }}:(\\s*).*$"
line: "{{ item.name | mandatory }}:\\g<1>{{ item.value | mandatory }}"
backrefs: yes
loop:
- { name: cpus, value: "{{ hardware.cpus }}" }
- { name: cores, value: "{{ [hardware.cores, hostvars[selected_node]['max_cores'] | d(hardware.cores)] | min }}" }
- { name: cpuunits, value: "{{ hardware.cpuunits }}" }
- { name: memory, value: "{{ hardware.memory }}" }
- { name: swap, value: "{{ hardware.swap }}" }
- { name: cpus, value: "{{ host_hardware.cpus }}" }
- { name: cores, value: "{{ [host_hardware.cores, hostvars[selected_node]['max_cores'] | d(host_hardware.cores)] | min }}" }
- { name: cpuunits, value: "{{ host_hardware.cpuunits }}" }
- { name: memory, value: "{{ host_hardware.memory }}" }
- { name: swap, value: "{{ host_hardware.swap }}" }
- { name: onboot, value: "{{ '1' if (container_active | d(true) == true) else '0' }}" }
- name: set startup order and delay
lineinfile:
path: "/etc/pve/lxc/{{ container_id }}.conf"
path: "{{ ('/etc/pve/lxc', container_id ~ '.conf') | path_join }}"
regexp: '^startup:.*$'
line: "startup: {{ 'order=' ~ (container_order | d(role_dependency[host_primary_role] | d('0'))) ~ ((',up=' ~ container_startup_delay) if container_startup_delay is defined else '') }}"
line: "startup: {{ 'order=' ~ (container_order | d(role_dependency_index | d('0'))) ~ ((',up=' ~ container_startup_delay) if container_startup_delay is defined else '') }}"
insertbefore: '^[^\#]'
firstmatch: yes
when: (container_order is defined) or (role_dependency[host_primary_role] is defined) or (container_startup_delay is defined)
when: (container_order is defined) or (role_dependency_index is defined) or (container_startup_delay is defined)
- name: ensure that cpulimit is not set
lineinfile:
path: "/etc/pve/lxc/{{ container_id }}.conf"
path: "{{ ('/etc/pve/lxc', container_id ~ '.conf') | path_join }}"
regexp: '^cpulimit:.*$'
state: absent
@ -163,6 +177,7 @@
vmid: "{{ container_id }}"
proxmox_default_behavior: no_defaults
state: "{{ 'started' if (container_active | d(true) == true) else 'stopped' }}"
unprivileged: yes
- name: end playbook for current host if container is set to inactive
@ -179,7 +194,7 @@
delay: 2
changed_when: no
delegate_to: 127.0.0.1
delegate_to: localhost
- name: preconfigure container

@ -2,8 +2,8 @@ coredns_user: coredns
coredns_group: coredns
coredns_conf_dir: /etc/coredns
coredns_conf_file: "{{ coredns_conf_dir }}/coredns.conf"
coredns_tls_file: "{{ coredns_conf_dir }}/tls.conf"
coredns_conf_file: "{{ (coredns_conf_dir, 'coredns.conf') | path_join }}"
coredns_tls_file: "{{ (coredns_conf_dir, 'tls.conf') | path_join }}"
coredns_cert_file: "{{ coredns_conf_dir }}/ecc384.crt"
coredns_key_file: "{{ coredns_conf_dir }}/ecc384.key"
coredns_cert_file: "{{ (coredns_conf_dir, 'ecc384.crt') | path_join }}"
coredns_key_file: "{{ (coredns_conf_dir, 'ecc384.key') | path_join }}"

@ -0,0 +1,27 @@
- name: add default record
include_tasks:
file: add_record.yml
apply:
delegate_to: "{{ services.internal_ns }}"
vars:
record: {}
when: (records | d([]) | length) == 0
- name: process other items
include_tasks:
file: add_record.yml
apply:
delegate_to: "{{ services.internal_ns }}"
loop: "{{ records | d([]) }}"
loop_control:
loop_var: record
- name: restart coredns
service:
name: coredns
state: restarted
delegate_to: "{{ services.internal_ns }}"
when: (ns_instant | d(false) == false) and
((ns_records_changed | d(false) == true) or (ns_serial_changed | d(false) == true))

@ -10,21 +10,13 @@
when: record.zone is defined and record.zone is not string
- name: check if record zone exists
fail:
msg: '"{{ record.zone }}" does not seem to be a valid zone'
when: (record.zone is defined) and
(record.zone != 'root') and
((int_zones is not defined) or (record.zone not in int_zones))
- name: construct record parameters
set_fact:
ns_zone: "{%- if (record.zone is defined) and (record.zone != 'root') -%}{{ record.zone }}\
{%- else -%}{{ ns_tld | d(int_tld) }}\
{%- endif -%}"
ns_name: "{%- if record.name is defined -%}{{ record.name }}\
{%- else -%}{{ inventory_hostname }}\
{%- else -%}{{ host_name }}\
{%- endif -%}"
ns_type: "{%- if record.type is defined -%}{{ record.type | upper }}\
{%- else -%}A\
@ -33,6 +25,7 @@
{%- else -%}{{ ansible_host }}\
{%- endif -%}"
- name: set ns_quote
set_fact:
ns_quote: "{{ '\"' if ns_type == 'TXT' else '' }}"
@ -60,9 +53,9 @@
- name: slurp zone file
slurp:
src: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}"
src: "{{ (coredns_conf_dir, ns_zone ~ '.zone') | path_join }}"
register: zf
changed_when: false
changed_when: no
- name: enumerate stdout lines to check if an entry already exists
@ -84,7 +77,7 @@
- name: replace the record
lineinfile:
path: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}"
path: "{{ (coredns_conf_dir, ns_zone ~ '.zone') | path_join }}"
regexp: '^\s*{{ ns_name | regex_escape() }}\s+IN\s+{{ ns_type | regex_escape() }}\s+'
line: "{{ ns_name }}\tIN\t{{ ns_type }}\t{{ ns_quote ~ ns_value ~ ns_quote }}"
backrefs: yes
@ -96,7 +89,7 @@
- name: add the record if it is missing
lineinfile:
path: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}"
path: "{{ (coredns_conf_dir, ns_zone ~ '.zone') | path_join }}"
line: "{{ ns_name }}\tIN\t{{ ns_type }}\t{{ ns_quote ~ ns_value ~ ns_quote }}"
when: not ns_exists
register: rr2
@ -109,6 +102,8 @@
- name: change serial
include_tasks: increase_serial.yml
vars:
zone: "{{ ns_zone }}"
when: ns_records_changed | d(false) == true

@ -1,21 +0,0 @@
- name: add default record
include_tasks: add_record.yml
vars:
record: {}
when: (ns_records | d([]) | length) == 0
- name: process other items
include_tasks: add_record.yml
loop: "{{ ns_records | d([]) }}"
loop_control:
loop_var: record
- name: restart coredns
service:
name: coredns
state: restarted
when: (ns_instant | d(false) == false) and
((ns_records_changed | d(false) == true) or
(ns_serial_changed | d(false) == true))

@ -1,13 +1,19 @@
- name: fail if zone is not defined
fail:
msg: zone is not defined
when: zone is not defined
- name: slurp zone file
slurp:
src: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}"
src: "{{ (coredns_conf_dir, zone ~ '.zone') | path_join }}"
register: zf
changed_when: false
changed_when: no
- name: get SOA serial value
set_fact:
ns_old_serial: '{{ zf.content | b64decode | regex_search(''@\s+IN\s+SOA\s+\S+\s+\S+\s*\(\s*(\d+)'', ''\1'') | first }}'
ns_old_serial: '{{ zf.content | b64decode | regex_search(''@\s+IN\s+SOA\s+\S+\s+\S+\s*\(\s*(\d+)'', ''\1'') | first | string }}'
- name: get current date
@ -36,7 +42,7 @@
- name: insert new serial
replace:
path: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}"
path: "{{ (coredns_conf_dir, zone ~ '.zone') | path_join }}"
regexp: '(@\s+IN\s+SOA\s+\S+\s+\S+\s*\(\s*){{ ns_old_serial }}'
replace: '\g<1>{{ ns_new_serial }}'
register: result

@ -0,0 +1,13 @@
- name: set role information
set_fact:
role_dependency:
- {stage: 3, role: 'coredns'}
- {stage: 5, role: 'coredns', tasks_from: 'tls.yml'}
role_dependency_index: 0
role_hardware:
cores: 4
memory: 128
swap: 64
disk: 0.3

@ -1,93 +0,0 @@
- name: install coredns and dependencies
include_tasks: tasks/install_packages.yml
vars:
package:
- coredns
- alpine: coredns-openrc
- name: create user and group
include_tasks: tasks/create_user.yml
vars:
user:
name: "{{ coredns_user }}"
group: "{{ coredns_group }}"
- name: create config directory
file:
path: "{{ coredns_conf_dir }}"
state: directory
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
notify: restart coredns
- name: template corefile
template:
src: corefile.j2
dest: "{{ coredns_conf_file }}"
force: yes
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
mode: 0400
notify: restart coredns
- name: template empty tls file if missing
copy:
content: ''
dest: "{{ coredns_tls_file }}"
force: no
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
mode: 0400
notify: restart coredns
- name: template root zone if missing
template:
src: zone.j2
dest: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}"
force: no
mode: 0400
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
notify: restart coredns
- name: edit service config
lineinfile:
path: /etc/conf.d/coredns
regexp: "^COREDNS_CONFIG="
line: "COREDNS_CONFIG={{ coredns_conf_file | quote }}"
notify: restart coredns
- name: template init script
template:
src: init.j2
dest: /etc/init.d/coredns
force: yes
mode: 0755
notify: restart coredns
- name: flush handlers
meta: flush_handlers
- name: add directories to backup plan
include_role:
name: backup
vars:
function: add
backup_items:
- "{{ coredns_conf_dir }}"
- name: enable and start coredns
service:
name: coredns
enabled: yes
state: started

@ -1,28 +0,0 @@
- name: deploy ecc384 cert
include_role:
name: ca
vars:
function: certs
ca_options:
mode: '0400'
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
concat_inter: true
preset: web
ocsp_must_staple: false
notify: restart coredns
ca_certs:
- type: ecc384
key: "{{ coredns_key_file }}"
cert: "{{ coredns_cert_file }}"
- name: template tls snippet file
template:
src: tls.j2
dest: "{{ coredns_tls_file }}"
force: yes
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
mode: 0400
notify: restart coredns

@ -1,13 +1,102 @@
- name: install coredns
include_tasks: install.yml
when: function == 'install'
- name: build default tld list
set_fact:
coredns_tld_list: "{{ [ ns_tld | d(int_tld) ] }}"
when: coredns_tld_list is not defined
- name: install coredns tls enhancements
include_tasks: install_tls.yml
when: function == 'install_tls'
- name: install coredns and dependencies
include_tasks: tasks/install_packages.yml
vars:
package:
- coredns
- alpine: coredns-openrc
- name: add records
include_tasks: add_records.yml
when: function == 'add_records'
- name: create user and group
include_tasks: tasks/create_user.yml
vars:
user:
name: "{{ coredns_user }}"
group: "{{ coredns_group }}"
- name: create config directory
file:
path: "{{ coredns_conf_dir }}"
state: directory
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
notify: restart coredns
- name: template corefile
template:
src: corefile.j2
dest: "{{ coredns_conf_file }}"
force: yes
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
mode: 0400
notify: restart coredns
- name: template empty tls file if missing
copy:
content: ''
dest: "{{ coredns_tls_file }}"
force: no
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
mode: 0400
notify: restart coredns
- name: template all zones if missing
template:
src: zone.j2
dest: "{{ (coredns_conf_dir, zone ~ '.zone') | path_join }}"
force: no
mode: 0400
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
notify: restart coredns
loop: "{{ coredns_tld_list }}"
loop_control:
loop_var: zone
- name: edit service config
lineinfile:
path: /etc/conf.d/coredns
regexp: "^COREDNS_CONFIG="
line: "COREDNS_CONFIG={{ coredns_conf_file | quote }}"
notify: restart coredns
- name: template init script
template:
src: init.j2
dest: /etc/init.d/coredns
force: yes
mode: 0755
notify: restart coredns
- name: flush handlers
meta: flush_handlers
- name: add directories to backup plan
include_role:
name: backup
tasks_from: add.yml
vars:
backup_items:
- "{{ coredns_conf_dir }}"
- name: enable and start coredns
service:
name: coredns
enabled: yes
state: started

@ -0,0 +1,25 @@
- block:
- name: deploy ecc384 cert
include_role:
name: certs
vars:
certs:
cert: "{{ coredns_cert_file }}"
key: "{{ coredns_key_file }}"
ecc: yes
post_hook: service coredns restart
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
- name: template tls snippet file
template:
src: tls.j2
dest: "{{ coredns_tls_file }}"
force: yes
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
mode: 0400
notify: restart coredns
when: host_tls

@ -1,6 +1,5 @@
(common) {
root {{ (coredns_conf_dir ~ '/') | quote }}
file {{ ((ns_tld | d(int_tld)) ~ '.zone') | quote }}
any
bufsize {{ ns_edns0_bufsize | d(1232) }}
@ -8,8 +7,11 @@
loadbalance
}
{{ ns_tld | d(int_tld) }} {
import common
}
{% for zone in coredns_tld_list %}
{{ zone }} {
import common
file {{ (zone ~ '.zone') | quote }}
}
{% endfor %}
import {{ coredns_tls_file | quote }}

@ -4,7 +4,7 @@ name="$SVCNAME"
directory="{{ coredns_conf_dir }}"
command="/usr/bin/coredns"
command_args="-conf ${COREDNS_CONFIG} ${COREDNS_EXTRA_ARGS}"
command_user="{{ coredns_user }}:{{ coredns_group }}"
command_user="{{ coredns_user ~ ':' ~ coredns_group }}"
pidfile="/var/run/$SVCNAME.pid"
command_background=true
start_stop_daemon_args="--stdout-logger logger --stderr-logger logger"

@ -1,9 +1,13 @@
tls://{{ ns_tld | d(int_tld) }}:853 {
import common
tls {{ coredns_cert_file | quote }} {{ coredns_key_file | quote }}
}
{% for zone in coredns_tld_list %}
tls://{{ zone }}:853 {
import common
file {{ (zone ~ '.zone') | quote }}
tls {{ coredns_cert_file | quote }} {{ coredns_key_file | quote }}
}
https://{{ ns_tld | d(int_tld) }} {
import common
tls {{ coredns_cert_file | quote }} {{ coredns_key_file | quote }}
}
https://{{ zone }} {
import common
file {{ (zone ~ '.zone') | quote }}
tls {{ coredns_cert_file | quote }} {{ coredns_key_file | quote }}
}
{% endfor %}

@ -1,32 +1,13 @@
{%- set primary_ns = inventory_hostname -%}
{%- if ns_server_group is defined -%}
{%- set primary_ns = hostvars[groups[ns_server_group][0]]['inventory_hostname'] -%}
{%- endif -%}
{%- set this_name = (ns_name | d(inventory_hostname)) -%}
{%- set this_primary_name = (hostvars[primary_ns]['ns_name'] | d(hostvars[primary_ns]['inventory_hostname'])) -%}
{%- set this_tld = (hostvars[primary_ns]['ns_tld'] | d(ns_tld) | d(int_tld)) -%}
$ORIGIN {{ this_tld }}.
$ORIGIN {{ zone }}.
$TTL {{ ns_ttl | d(300) }}
@ IN SOA {{ this_name ~ '.' ~ this_tld }}. {{ (ns_admin | replace('@', '.')) if ns_admin is defined else ('admin' ~ '.' ~ this_tld) }}. (
2021010101
@ IN SOA {{ host_name ~ '.' ~ zone }}. {{ (ns_admin | replace('@', '.')) if ns_admin is defined else ('admin' ~ '.' ~ zone) }}. (
2023010101
{{ ns_refresh | d(1200) }}
{{ ns_retry | d(300) }}
{{ ns_expire | d(1209600) }}
{{ ns_neg_ttl | d(300) }}
)
{% if ns_server_group is defined -%}
{% for host in groups[ns_server_group] -%}
@ IN NS {{ (hostvars[host]['ns_name'] | d(hostvars[host]['inventory_hostname'])) ~ '.' ~ this_tld }}.
{{ hostvars[host]['ns_name'] | d(hostvars[host]['inventory_hostname']) }} IN A {{ hostvars[host]['ansible_host'] }}
{% endfor -%}
{% else -%}
@ IN NS {{ this_primary_name ~ '.' ~ this_tld }}.
{{ this_primary_name }} IN A {{ ansible_host }}
{% endif -%}
@ IN NS {{ host_name ~ '.' ~ zone }}.
{{ host_name }} IN A {{ ansible_host }}

@ -0,0 +1,7 @@
- name: set role information
set_fact:
role_dependency:
- { stage: 3, role: 'ns' }
role_dependency_index: 1
role_dependency_no_common: yes

@ -0,0 +1,3 @@
- name: add internal ns records
include_role:
name: ns

@ -1,16 +1,12 @@
- name: ns installation
include_tasks: install.yml
when: function == 'install'
- block:
- name: add records
include_tasks: add_records.yml
when: services.internal_ns is defined
- debug:
msg: internal nameserver is not defined
when: services.internal_ns is not defined
when: function == 'add_records'
- name: add internal ns records with coredns
block:
- set_fact:
records_tmp: "{{ records | d([]) }}"
- include_role:
name: coredns
tasks_from: add.yml
vars:
records: "{{ records_tmp }}"
when: services.internal_ns is defined

@ -0,0 +1,9 @@
- name: set role information
set_fact:
role_dependency:
- {stage: 1, role: 'common'}
- {stage: 1, role: 'proxmox'}
- {stage: 5, role: 'proxmox', tasks_from: 'rproxy'}
- {stage: 6, role: 'proxmox', tasks_from: 'mail'}
role_dependency_index: 0

@ -1,72 +1,75 @@
- name: install libsasl2-modules
package:
name: libsasl2-modules
- block:
- name: install libsasl2-modules
package:
name: libsasl2-modules
- name: edit postfix config
lineinfile:
path: /etc/postfix/main.cf
regexp: '^{{ item.name | regex_escape() }}([^\S\r\n]*)=([^\S\r\n]*)'
line: '{{ item.name }} = {{ item.value }}'
notify: restart postfix
loop:
- { name: myhostname, value: "{{ host_fqdn }}" }
- { name: relayhost, value: "{{ mail_server.mta_actual_hostname ~ '.' ~ int_tld }}:465" }
- { name: sender_canonical_classes, value: "envelope_sender, header_sender" }
- { name: sender_canonical_maps, value: "regexp:/etc/postfix/sender_canonical_maps" }
- { name: smtp_header_checks, value: "regexp:/etc/postfix/header_check" }
- { name: smtp_use_tls, value: "yes" }
- { name: smtp_sasl_auth_enable, value: "yes" }
- { name: smtp_sasl_security_options, value: "noanonymous" }
- { name: smtp_tls_wrappermode, value: "yes" }
- { name: smtp_tls_security_level, value: "encrypt" }
- { name: smtp_sasl_password_maps, value: "texthash:/etc/postfix/sasl_passwd" }
- { name: smtp_tls_CAfile, value: "/etc/ssl/certs/ca-certificates.crt" }
- { name: notify_classes, value: "" }
- { name: mydestination, value: "" }
- name: edit postfix config
lineinfile:
path: /etc/postfix/main.cf
regexp: '^{{ item.name | regex_escape() }}([^\S\r\n]*)=([^\S\r\n]*)'
line: '{{ item.name }} = {{ item.value }}'
notify: restart postfix
loop:
- { name: myhostname, value: "{{ host_fqdn }}" }
- { name: relayhost, value: "{{ mail_server.mta_actual_hostname ~ '.' ~ int_tld }}:465" }
- { name: sender_canonical_classes, value: "envelope_sender, header_sender" }
- { name: sender_canonical_maps, value: "regexp:/etc/postfix/sender_canonical_maps" }
- { name: smtp_header_checks, value: "regexp:/etc/postfix/header_check" }
- { name: smtp_use_tls, value: "yes" }
- { name: smtp_sasl_auth_enable, value: "yes" }
- { name: smtp_sasl_security_options, value: "noanonymous" }
- { name: smtp_tls_wrappermode, value: "yes" }
- { name: smtp_tls_security_level, value: "encrypt" }
- { name: smtp_sasl_password_maps, value: "texthash:/etc/postfix/sasl_passwd" }
- { name: smtp_tls_CAfile, value: "/etc/ssl/certs/ca-certificates.crt" }
- { name: notify_classes, value: "" }
- { name: mydestination, value: "" }
- name: edit master.cf
lineinfile:
path: /etc/postfix/master.cf
regexp: '^bounce([^\S\r\n]+)unix'
line: 'bounce unix - - n - 0 discard'
notify: restart postfix
- name: edit master.cf
lineinfile:
path: /etc/postfix/master.cf
regexp: '^bounce([^\S\r\n]+)unix'
line: 'bounce unix - - n - 0 discard'
notify: restart postfix
- name: create postfix files
copy:
dest: "/etc/postfix/{{ item.name }}"
content: "{{ item.content }}"
mode: "{{ item.mode | d(omit) }}"
notify: restart postfix
loop:
- name: sasl_passwd
content: "{{ mail_server.mta_actual_hostname ~ '.' ~ int_tld ~ ':465 ' ~
mail_account.username ~ '@' ~ mail_server.tld ~ ':' ~ mail_account.password }}"
mode: '0600'
- name: sender_canonical_maps
content: '/.+/ {{ host_name }}@{{ mail_server.tld }}'
- name: header_check
content: '/From:.*/ REPLACE From: {{ host_name }} <{{ host_name }}@{{ mail_server.tld }}>'
- name: create postfix files
copy:
dest: "/etc/postfix/{{ item.name }}"
content: "{{ item.content }}"
mode: "{{ item.mode | d(omit) }}"
notify: restart postfix
loop:
- name: sasl_passwd
content: "{{ mail_server.mta_actual_hostname ~ '.' ~ int_tld ~ ':465 ' ~
mail_account.username ~ '@' ~ mail_server.tld ~ ':' ~ mail_account.password }}"
mode: '0600'
- name: sender_canonical_maps
content: '/.+/ {{ host_name }}@{{ mail_server.tld }}'
- name: header_check
content: '/From:.*/ REPLACE From: {{ host_name }} <{{ host_name }}@{{ mail_server.tld }}>'
- name: edit crontab mail config
lineinfile:
path: /etc/crontab
regexp: '^MAILTO='
line: 'MAILTO=""'
insertafter: '^PATH='
- name: edit crontab mail config
lineinfile:
path: /etc/crontab
regexp: '^MAILTO='
line: 'MAILTO=""'
insertafter: '^PATH='
- name: edit zed config file
lineinfile:
path: /etc/zfs/zed.d/zed.rc
regexp: '^{{ item.name | upper | regex_escape() }}='
line: '{{ item.name | upper }}="{{ item.value }}"'
notify: restart zed
loop:
- { name: zed_email_addr, value: "{{ maintainer_email }}" }
- { name: zed_email_prog, value: mail }
- { name: zed_email_opts, value: "-s '@SUBJECT@' @ADDRESS@ -r {{ mail_account.username ~ '@' ~ mail_server.tld }}" }
- { name: zed_notify_verbose, value: 1 }
- name: edit zed config file
lineinfile:
path: /etc/zfs/zed.d/zed.rc
regexp: '^{{ item.name | upper | regex_escape() }}='
line: '{{ item.name | upper }}="{{ item.value }}"'
notify: restart zed
loop:
- { name: zed_email_addr, value: "{{ maintainer_email }}" }
- { name: zed_email_prog, value: mail }
- { name: zed_email_opts, value: "-s '@SUBJECT@' @ADDRESS@ -r {{ mail_account.username ~ '@' ~ mail_server.tld }}" }
- { name: zed_notify_verbose, value: 1 }
when: (mail_account is mapping) and (mail_server is mapping)

@ -3,16 +3,83 @@
proxmox_cfg: "{{ proxmox_default_config | d({}) | combine(proxmox_config | d({}), recursive=true) }}"
- name: proxmox installation
include_tasks: install.yml
when: function == 'install'
- name: install extra proxmox packages
package:
name: "{{ item }}"
loop: "{{ proxmox_default_packages + (proxmox_packages | d([])) }}"
- name: proxmox reverse proxy configuration
include_tasks: rproxy.yml
when: function == 'rproxy'
- block:
- name: set cpu scheduler in cron
cron:
name: set cpu scheduler
special_time: reboot
job: 'echo {{ proxmox_cfg.cpu_governor | quote }} | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor > /dev/null'
user: root
- name: proxmox mail configuration
include_tasks: mail.yml
when: (function == 'mail') and (mail_account is mapping) and (mail_server is mapping)
- block:
- name: get current cpu scheduler types
shell:
cmd: cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
register: result
changed_when: no
- name: change cpu scheduler
shell:
cmd: 'echo {{ proxmox_cfg.cpu_governor | quote }} | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor'
when: (result.stdout_lines | unique | length > 1) or ((result.stdout_lines | unique)[0] != proxmox_cfg.cpu_governor)
rescue:
- name: report that cpu scheduler cannot be changed
debug:
msg: failed to change cpu scheduler
when: proxmox_cfg.cpu_governor is string
- name: disable enterprise repo
apt_repository:
repo: deb https://enterprise.proxmox.com/debian/pve bullseye pve-enterprise
filename: pve-enterprise.list
state: absent
update_cache: no
- name: enable community repo
apt_repository:
repo: deb http://download.proxmox.com/debian/pve bullseye pve-no-subscription
filename: pve-community.list
state: present
update_cache: no
- name: set datacenter configuration
lineinfile:
path: /etc/pve/datacenter.cfg
regexp: "^{{ item.key }}: "
line: "{{ item.key }}: {{ item.value }}"
mode: 0640
owner: root
group: www-data
create: yes
loop: "{{ proxmox_cfg.datacenter | dict2items }}"
- name: enable auto-reboot on kernel panic
copy:
dest: /etc/sysctl.d/90-auto-reboot.conf
content: "kernel.panic = 5\n"
mode: 0644
when: proxmox_cfg.auto_reboot | d(true) == true
- name: set max arc cache size for zfs
lineinfile:
path: /etc/modprobe.d/zfs.conf
regexp: "^options zfs zfs_arc_max="
line: "options zfs zfs_arc_max={{ proxmox_cfg.zfs_arc_max }}"
create: yes
mode: 0644
when: proxmox_cfg.zfs_arc_max is defined

@ -9,4 +9,3 @@
conf:
http:
ssl_conf_command: []

@ -13,12 +13,12 @@
mode: 0400
regenerate: full_idempotence
type: ed25519
register: container_key
register: host_ssh_key
- name: fail if public key is missing
fail:
msg: public key is missing
when: container_key.public_key is not defined
when: host_ssh_key.public_key is not defined
delegate_to: localhost

@ -11,6 +11,6 @@
- name: include roles for selected stage
include_tasks: tasks/includes/role.yml
loop: "{{ role_mapping | selectattr('stage', 'equalto', (this_stage | int)) | list }}"
loop: "{{ role_deps | selectattr('stage', 'equalto', (this_stage | int)) | list }}"
loop_control:
loop_var: this_role

@ -1,15 +1,31 @@
- name: determine host info
- name: set host name
set_fact:
host_name: "{{ actual_hostname | d(inventory_hostname) }}"
host_tld: "{%- if branch is defined -%}{{ branch }}.{%- endif -%}{{ tld if (use_external_tld | d(false) == true) else int_tld }}"
host_tls: "{{ use_tls | d(true) }}"
host_protocol: "{{ 'https' if (use_tls | d(true)) else 'http' }}"
host_metrics: "{{ services.prometheus is defined and (use_metrics | d(true) == true) }}"
host_mail: "{{ mail_server.mta_hostname is defined and (use_mail | d(true) == true) }}"
host_backups: "{{ services.backup is defined and (use_backups | d(true) == true) }}"
host_name: "{{ inventory_hostname }}"
when: host_name is not defined
- name: determine host fqdn and uri
- name: set host tld
set_fact:
host_tld: "{{ ((host_branch ~ '.') if host_branch is defined else '') ~ (tld if (host_external_tld | d(false) == true) else int_tld) }}"
when: host_tld is not defined
- name: set host tls
set_fact:
host_tls: yes
when: host_tls is not defined
- name: set other host variables
set_fact:
host_protocol: "{{ 'https' if host_tls else 'http' }}"
host_metrics: "{{ services.prometheus is defined and (host_metrics | d(true) == true) }}"
host_mail: "{{ mail_server.mta_hostname is defined and (host_mail | d(true) == true) }}"
host_backups: "{{ services.backup is defined and (host_backups | d(true) == true) }}"
host_is_container: "{{ ('containers' in group_names) or (host_is_container | d(false) == true) }}"
- name: set host fqdn and uri
set_fact:
host_fqdn: "{{ host_name ~ '.' ~ host_tld }}"
host_url: "{{ host_protocol }}://{{ host_name ~ '.' ~ host_tld }}"
@ -23,19 +39,20 @@
- name: select a cluster node
include_tasks: tasks/select_node.yml
when: "'containers' in group_names"
when: host_is_container
- name: set hardware information
set_fact:
hardware: "{{ default_container_hardware | combine(role_hardware[host_primary_role] | d({})) |
combine((container_hardware if 'containers' in group_names else host_hardware) | d({})) }}"
host_hardware: "{{ (default_container_hardware | combine(role_hardware | d({})) |
combine(host_hardware | d({}))) if host_is_container
else (host_hardware | d({})) }}"
- name: clamp hardware cores to max node number
set_fact:
hardware: "{{ hardware | combine({'cores': ([hardware.cores, hostvars[selected_node]['max_cores'] | d(hardware.cores)] | min)}) }}"
when: "not ('containers' in group_names) and (selected_node is defined) and (hostvars[selected_node]['max_cores'] is defined)"
host_hardware: "{{ host_hardware | combine({'cores': ([host_hardware.cores, hostvars[selected_node]['max_cores'] | d(host_hardware.cores)] | min)}) }}"
when: "host_is_container and (selected_node is defined) and (hostvars[selected_node]['max_cores'] is defined)"
- block:

Loading…
Cancel
Save