Compare commits
10 commits
80a85f3916
...
da2445f2c7
| Author | SHA1 | Date | |
|---|---|---|---|
| da2445f2c7 | |||
| 1e1e423772 | |||
| 437031aaa3 | |||
| 292758900e | |||
| 8018ce0eb1 | |||
| 28e119cee2 | |||
| 3b9507e5c4 | |||
| 7ff93a5ac3 | |||
|
|
d644868602 | ||
|
|
a6b99691fb |
39 changed files with 1201 additions and 55 deletions
|
|
@ -29,6 +29,7 @@ managed_users:
|
||||||
shell: /bin/bash
|
shell: /bin/bash
|
||||||
home: /home/graham
|
home: /home/graham
|
||||||
admin: true
|
admin: true
|
||||||
|
password: "$6$VwHy94JE9eBN3Tex$nCmD8F7O0cq9hKW8esrwbTVh19QEq7bRlPga9u4ZtcnEPy1g6CKgOxVH9JEGWhuIqIHypEgaLwpicTF.h5wkd1"
|
||||||
authorized_keys:
|
authorized_keys:
|
||||||
- type: github
|
- type: github
|
||||||
value: gmcintire
|
value: gmcintire
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ bind_allow_transfer:
|
||||||
bind_zones:
|
bind_zones:
|
||||||
- "{{ beanjar_org_zone }}"
|
- "{{ beanjar_org_zone }}"
|
||||||
- "{{ gridmap_org_zone }}"
|
- "{{ gridmap_org_zone }}"
|
||||||
- "{{ mcintire_me_zone }}"
|
|
||||||
- "{{ manero_org_zone }}"
|
- "{{ manero_org_zone }}"
|
||||||
- "{{ ntxarms_com_zone }}"
|
- "{{ ntxarms_com_zone }}"
|
||||||
- "{{ towerops_net_zone }}"
|
- "{{ towerops_net_zone }}"
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
---
|
|
||||||
# mcintire.me DNS zone configuration
|
|
||||||
mcintire_me_zone:
|
|
||||||
name: mcintire.me
|
|
||||||
type: master
|
|
||||||
create_reverse_zones: false
|
|
||||||
name_servers:
|
|
||||||
- ns1.as393837.net.
|
|
||||||
- ns2.as393837.net.
|
|
||||||
- ns-global.kjsl.com.
|
|
||||||
mail_servers:
|
|
||||||
- name: mail
|
|
||||||
preference: 10
|
|
||||||
- name: mail.nsnw.ca.
|
|
||||||
preference: 20
|
|
||||||
hosts:
|
|
||||||
- name: mail
|
|
||||||
ip: 107.174.178.20
|
|
||||||
- name: photos
|
|
||||||
ip: 204.110.191.8
|
|
||||||
- name: git
|
|
||||||
ip: 172.245.56.83
|
|
||||||
- name: vm1
|
|
||||||
ip: 172.245.56.83
|
|
||||||
other_name_servers:
|
|
||||||
- ha.mcintire.me. IN CNAME q1l09qiycnaagngmjsg1qas0rhqcfoou.ui.nabu.casa.
|
|
||||||
- _acme-challenge.ha.mcintire.me. IN CNAME _acme-challenge.q1l09qiycnaagngmjsg1qas0rhqcfoou.ui.nabu.casa.
|
|
||||||
- autodiscover.mcintire.me. IN CNAME mail.w5isp.com.
|
|
||||||
- autoconfig.mcintire.me. IN CNAME mail.w5isp.com.
|
|
||||||
- em977211.mcintire.me. IN CNAME return.smtp2go.net.
|
|
||||||
- s977211._domainkey.mcintire.me. IN CNAME dkim.smtp2go.net.
|
|
||||||
- link.mcintire.me. IN CNAME track.smtp2go.net.
|
|
||||||
- _autodiscover._tcp.mcintire.me. IN SRV 0 0 443 mail.w5isp.com.
|
|
||||||
text:
|
|
||||||
- name: "@"
|
|
||||||
text: '"v=spf1 mx a ip4:107.174.178.20 ~all"'
|
|
||||||
- name: _dmarc
|
|
||||||
text: '"v=DMARC1; p=quarantine; rua=mailto:postmaster@mcintire.me; ruf=mailto:postmaster@mcintire.me; fo=1"'
|
|
||||||
- name: dkim._domainkey
|
|
||||||
text: '"v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0rQie7Hz5AmDbVUX+rKNgp6Hf7crtWyfy6qKbqnrxmmernz1rQ6HyOrHhFAlc8nVLNKr8XP2DOROb1jAnrjndZo9I/ymbrrrCBsi9w6zAht2BheijO/R9k5CDRjeSafm6bg0oMKihtNMIdXvEj9ND8hDpZZKxtOrKFH7zLm4CPmm7jf0gqZH2yK+AA3OYUGSYa1OT0LtdMXadk0IVOI2VYf37Hzb3RUvGOYMVkT0xi+23DiyFk7AyCiyv3LQVBMT+/bwyd4k3yVVn2cr9+Nor+HXVjqASLtqcFLMf1SuX0ezSAjBG7BbqQr5G6Jz+n5YglqEIUKVYzJFE7JdDmqQYQIDAQAB"'
|
|
||||||
- name: "@"
|
|
||||||
text: '"yahoo-verification-key=Pt59XUhQSd7dbVc0x6TQD+mBEtOOTMHFRV1ZG78h4Ug="'
|
|
||||||
|
|
@ -72,6 +72,8 @@ vntx_net_zone:
|
||||||
ip: 204.110.191.221
|
ip: 204.110.191.221
|
||||||
- name: net
|
- name: net
|
||||||
ip: 104.238.146.79
|
ip: 104.238.146.79
|
||||||
|
- name: support
|
||||||
|
ip: 204.110.191.231
|
||||||
- name: uisp
|
- name: uisp
|
||||||
ip: 204.110.191.224
|
ip: 204.110.191.224
|
||||||
- name: dns
|
- name: dns
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,6 @@ bind_zones:
|
||||||
- name: aprs.me
|
- name: aprs.me
|
||||||
type: secondary
|
type: secondary
|
||||||
primaries: [204.110.191.222]
|
primaries: [204.110.191.222]
|
||||||
- name: mcintire.me
|
|
||||||
type: secondary
|
|
||||||
primaries: [204.110.191.222]
|
|
||||||
- name: manero.org
|
- name: manero.org
|
||||||
type: secondary
|
type: secondary
|
||||||
primaries: [204.110.191.222]
|
primaries: [204.110.191.222]
|
||||||
|
|
|
||||||
17
ansible/host_vars/hi.yml
Normal file
17
ansible/host_vars/hi.yml
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
|
tailscale_skip_connect: true
|
||||||
|
|
||||||
|
firewall_allow_rules:
|
||||||
|
- port: 22
|
||||||
|
proto: tcp
|
||||||
|
comment: SSH
|
||||||
|
- port: 80
|
||||||
|
proto: tcp
|
||||||
|
comment: HTTP
|
||||||
|
- port: 443
|
||||||
|
proto: tcp
|
||||||
|
comment: HTTPS
|
||||||
|
- port: 2222
|
||||||
|
proto: tcp
|
||||||
|
comment: Forgejo SSH
|
||||||
|
|
@ -7,6 +7,10 @@ ansible_ssh_common_args: '-o StrictHostKeyChecking=accept-new'
|
||||||
opensearch_heap_min: "4g"
|
opensearch_heap_min: "4g"
|
||||||
opensearch_heap_max: "4g"
|
opensearch_heap_max: "4g"
|
||||||
|
|
||||||
|
# OpenSearch security — admin credentials
|
||||||
|
opensearch_admin_password_hash: "$2b$12$gp3Lk2cCejFzjfacq1Ax0OHapD5XOUNqMN2TtzmA7EMpcZ6wcB71a"
|
||||||
|
opensearch_admin_password: "1QW8gf8DNfqfkC1saSiw"
|
||||||
|
|
||||||
# Firewall — Caddy needs HTTP/HTTPS open for Let's Encrypt + traffic
|
# Firewall — Caddy needs HTTP/HTTPS open for Let's Encrypt + traffic
|
||||||
firewall_allow_rules:
|
firewall_allow_rules:
|
||||||
- port: 80
|
- port: 80
|
||||||
|
|
@ -15,3 +19,30 @@ firewall_allow_rules:
|
||||||
- port: 443
|
- port: 443
|
||||||
proto: tcp
|
proto: tcp
|
||||||
comment: HTTPS
|
comment: HTTPS
|
||||||
|
- port: 514
|
||||||
|
proto: udp
|
||||||
|
from_ip: 204.110.188.0/22
|
||||||
|
comment: Syslog UDP (VNTX)
|
||||||
|
- port: 514
|
||||||
|
proto: udp
|
||||||
|
from_ip: 10.0.0.0/8
|
||||||
|
comment: Syslog UDP (home LAN)
|
||||||
|
- port: 514
|
||||||
|
proto: udp
|
||||||
|
from_ip: 100.64.0.0/10
|
||||||
|
comment: Syslog UDP (Tailscale)
|
||||||
|
- port: 514
|
||||||
|
proto: tcp
|
||||||
|
from_ip: 204.110.188.0/22
|
||||||
|
comment: Syslog TCP (VNTX)
|
||||||
|
- port: 514
|
||||||
|
proto: tcp
|
||||||
|
from_ip: 10.0.0.0/8
|
||||||
|
comment: Syslog TCP (home LAN)
|
||||||
|
- port: 514
|
||||||
|
proto: tcp
|
||||||
|
from_ip: 100.64.0.0/10
|
||||||
|
comment: Syslog TCP (Tailscale)
|
||||||
|
|
||||||
|
# Fluent Bit — uses same admin credentials as Dashboards
|
||||||
|
fluentbit_opensearch_password: "{{ opensearch_admin_password }}"
|
||||||
|
|
|
||||||
16
ansible/host_vars/support.vntx.net.yml
Normal file
16
ansible/host_vars/support.vntx.net.yml
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
---
|
||||||
|
ansible_host: 204.110.191.231
|
||||||
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
|
ansible_ssh_common_args: '-o StrictHostKeyChecking=accept-new'
|
||||||
|
tailscale_skip_connect: true
|
||||||
|
|
||||||
|
firewall_allow_rules:
|
||||||
|
- port: 22
|
||||||
|
proto: tcp
|
||||||
|
comment: SSH
|
||||||
|
- port: 80
|
||||||
|
proto: tcp
|
||||||
|
comment: HTTP
|
||||||
|
- port: 443
|
||||||
|
proto: tcp
|
||||||
|
comment: HTTPS
|
||||||
|
|
@ -8,6 +8,7 @@ unimus.vntx.net
|
||||||
monitor.vntx.net
|
monitor.vntx.net
|
||||||
librenms.vntx.net
|
librenms.vntx.net
|
||||||
uisp.vntx.net
|
uisp.vntx.net
|
||||||
|
support.vntx.net ansible_host=204.110.191.231
|
||||||
|
|
||||||
[librenms_servers]
|
[librenms_servers]
|
||||||
librenms.vntx.net
|
librenms.vntx.net
|
||||||
|
|
@ -18,6 +19,7 @@ monitor.vntx.net
|
||||||
[home_servers]
|
[home_servers]
|
||||||
skippy.w5isp.com
|
skippy.w5isp.com
|
||||||
mail.mcintire.me ansible_host=107.174.178.20
|
mail.mcintire.me ansible_host=107.174.178.20
|
||||||
|
hi ansible_host=74.50.113.232
|
||||||
dokku.w5isp.com
|
dokku.w5isp.com
|
||||||
aprs.w5isp.com
|
aprs.w5isp.com
|
||||||
prom.w5isp.com ansible_host=10.0.19.31
|
prom.w5isp.com ansible_host=10.0.19.31
|
||||||
|
|
@ -28,8 +30,15 @@ prom.w5isp.com
|
||||||
[node_exporter_servers:children]
|
[node_exporter_servers:children]
|
||||||
prometheus_servers
|
prometheus_servers
|
||||||
|
|
||||||
|
[tailscale_servers]
|
||||||
|
hi
|
||||||
|
support.vntx.net
|
||||||
|
|
||||||
[dokku_servers]
|
[dokku_servers]
|
||||||
|
|
||||||
|
[forgejo_servers]
|
||||||
|
hi
|
||||||
|
|
||||||
[aprsc_servers]
|
[aprsc_servers]
|
||||||
aprs.w5isp.com
|
aprs.w5isp.com
|
||||||
|
|
||||||
|
|
@ -38,6 +47,7 @@ skippy.w5isp.com
|
||||||
netbox.vntx.net
|
netbox.vntx.net
|
||||||
uisp.vntx.net
|
uisp.vntx.net
|
||||||
logs.vntx.net
|
logs.vntx.net
|
||||||
|
hi
|
||||||
|
|
||||||
[netbox_servers]
|
[netbox_servers]
|
||||||
netbox.vntx.net
|
netbox.vntx.net
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,15 @@
|
||||||
community.general.timezone:
|
community.general.timezone:
|
||||||
name: "{{ timezone }}"
|
name: "{{ timezone }}"
|
||||||
|
|
||||||
|
- name: Install and configure Tailscale
|
||||||
|
hosts: tailscale_servers
|
||||||
|
become: true
|
||||||
|
gather_facts: true
|
||||||
|
tags:
|
||||||
|
- tailscale
|
||||||
|
roles:
|
||||||
|
- tailscale
|
||||||
|
|
||||||
- name: Apply firewall configuration
|
- name: Apply firewall configuration
|
||||||
hosts: all:!proxmox_servers:!irc_limited
|
hosts: all:!proxmox_servers:!irc_limited
|
||||||
become: true
|
become: true
|
||||||
|
|
@ -355,6 +364,15 @@
|
||||||
roles:
|
roles:
|
||||||
- dokku
|
- dokku
|
||||||
|
|
||||||
|
- name: Install and configure Forgejo
|
||||||
|
hosts: forgejo_servers
|
||||||
|
become: true
|
||||||
|
gather_facts: true
|
||||||
|
tags:
|
||||||
|
- forgejo
|
||||||
|
roles:
|
||||||
|
- forgejo
|
||||||
|
|
||||||
- name: Configure node_exporter targets
|
- name: Configure node_exporter targets
|
||||||
hosts: node_exporter_servers
|
hosts: node_exporter_servers
|
||||||
become: true
|
become: true
|
||||||
|
|
@ -410,3 +428,13 @@
|
||||||
- logs
|
- logs
|
||||||
roles:
|
roles:
|
||||||
- opensearch
|
- opensearch
|
||||||
|
|
||||||
|
- name: Install and configure Fluent Bit syslog collector
|
||||||
|
hosts: opensearch_servers
|
||||||
|
become: true
|
||||||
|
gather_facts: true
|
||||||
|
tags:
|
||||||
|
- fluentbit
|
||||||
|
- logs
|
||||||
|
roles:
|
||||||
|
- fluentbit
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ base_common_packages:
|
||||||
base_packages_by_os_family:
|
base_packages_by_os_family:
|
||||||
Debian:
|
Debian:
|
||||||
- sudo
|
- sudo
|
||||||
|
- curl
|
||||||
|
- direnv
|
||||||
- jq
|
- jq
|
||||||
- sysstat
|
- sysstat
|
||||||
- smartmontools
|
- smartmontools
|
||||||
|
|
|
||||||
17
ansible/roles/caddy/templates/Caddyfile-hi.j2
Normal file
17
ansible/roles/caddy/templates/Caddyfile-hi.j2
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
servers {
|
||||||
|
protocols h1 h2
|
||||||
|
}
|
||||||
|
admin off
|
||||||
|
persist_config off
|
||||||
|
}
|
||||||
|
|
||||||
|
git.mcintire.me {
|
||||||
|
reverse_proxy http://127.0.0.1:3000
|
||||||
|
encode gzip
|
||||||
|
|
||||||
|
log {
|
||||||
|
output file /var/log/caddy/git.mcintire.me.log
|
||||||
|
format json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,19 @@
|
||||||
{{ opensearch_caddy_domain | default(inventory_hostname) }} {
|
{{ opensearch_caddy_domain | default(inventory_hostname) }} {
|
||||||
|
@os_denied {
|
||||||
|
path /os/*
|
||||||
|
not remote_ip 10.0.0.0/8 100.64.0.0/10 204.110.188.0/22
|
||||||
|
}
|
||||||
|
respond @os_denied 403
|
||||||
|
|
||||||
|
# OpenSearch API — restricted to internal subnets
|
||||||
|
handle_path /os/* {
|
||||||
|
reverse_proxy https://127.0.0.1:9200 {
|
||||||
|
transport http {
|
||||||
|
tls_insecure_skip_verify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reverse_proxy 127.0.0.1:{{ opensearch_dashboards_port | default('5601') }} {
|
reverse_proxy 127.0.0.1:{{ opensearch_dashboards_port | default('5601') }} {
|
||||||
header_up X-Forwarded-Host {host}
|
header_up X-Forwarded-Host {host}
|
||||||
header_up X-Real-IP {remote_host}
|
header_up X-Real-IP {remote_host}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,13 @@
|
||||||
path: /etc/apt/sources.list.d/ppa-linuxfactory-or-kr.list
|
path: /etc/apt/sources.list.d/ppa-linuxfactory-or-kr.list
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
|
- name: "Add Signed-By to debian.sources mirror entries"
|
||||||
|
ansible.builtin.replace:
|
||||||
|
path: /etc/apt/sources.list.d/debian.sources
|
||||||
|
regexp: '(URIs: mirror\+file://[^\n]+)\n(Suites:[^\n]+)\n(Components:[^\n]+)'
|
||||||
|
replace: '\1\n\2\n\3\nSigned-By: /usr/share/keyrings/debian-archive-keyring.gpg'
|
||||||
|
when: ansible_facts['distribution_release'] == 'trixie'
|
||||||
|
|
||||||
- name: "Install updates"
|
- name: "Install updates"
|
||||||
ansible.builtin.apt:
|
ansible.builtin.apt:
|
||||||
name: "*"
|
name: "*"
|
||||||
|
|
|
||||||
30
ansible/roles/fluentbit/defaults/main.yml
Normal file
30
ansible/roles/fluentbit/defaults/main.yml
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
# Fluent Bit — lightweight syslog collector for logs.vntx.net
|
||||||
|
# Installed via official apt repo, configured for RFC 3164 syslog (MikroTik).
|
||||||
|
|
||||||
|
# --- Package ---
|
||||||
|
fluentbit_package: fluent-bit
|
||||||
|
|
||||||
|
# --- Repo ---
|
||||||
|
fluentbit_apt_key_url: "https://packages.fluentbit.io/fluentbit.key"
|
||||||
|
fluentbit_apt_keyring: /etc/apt/keyrings/fluentbit.gpg
|
||||||
|
|
||||||
|
# --- User ---
|
||||||
|
fluentbit_user: fluentbit
|
||||||
|
fluentbit_group: fluentbit
|
||||||
|
|
||||||
|
# --- Paths ---
|
||||||
|
fluentbit_config_dir: /etc/fluent-bit
|
||||||
|
fluentbit_log_dir: /var/log/fluent-bit
|
||||||
|
|
||||||
|
# --- Syslog Input ---
|
||||||
|
fluentbit_syslog_port: 514
|
||||||
|
fluentbit_syslog_bind: "0.0.0.0"
|
||||||
|
|
||||||
|
# --- OpenSearch Output ---
|
||||||
|
fluentbit_opensearch_host: "127.0.0.1"
|
||||||
|
fluentbit_opensearch_port: 9200
|
||||||
|
fluentbit_opensearch_index: syslog
|
||||||
|
fluentbit_opensearch_user: "{{ opensearch_admin_username | default('admin') }}"
|
||||||
|
# Plaintext password for Fluent Bit → OpenSearch — override in host_vars or vault.
|
||||||
|
fluentbit_opensearch_password: ""
|
||||||
6
ansible/roles/fluentbit/handlers/main.yml
Normal file
6
ansible/roles/fluentbit/handlers/main.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
- name: Restart fluent-bit
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: fluent-bit
|
||||||
|
state: restarted
|
||||||
|
daemon_reload: true
|
||||||
139
ansible/roles/fluentbit/tasks/main.yml
Normal file
139
ansible/roles/fluentbit/tasks/main.yml
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
---
|
||||||
|
# Installs and configures Fluent Bit to receive syslog (RFC 3164) on UDP/TCP
|
||||||
|
# port 514 and forward to the local OpenSearch instance.
|
||||||
|
|
||||||
|
- name: Ensure /etc/apt/keyrings exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /etc/apt/keyrings
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Download Fluent Bit apt signing key
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: "{{ fluentbit_apt_key_url }}"
|
||||||
|
dest: /tmp/fluentbit.key
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Dearmor and install Fluent Bit apt key
|
||||||
|
ansible.builtin.shell:
|
||||||
|
cmd: gpg --dearmor < /tmp/fluentbit.key > {{ fluentbit_apt_keyring }}
|
||||||
|
creates: "{{ fluentbit_apt_keyring }}"
|
||||||
|
|
||||||
|
- name: Add Fluent Bit apt repository
|
||||||
|
ansible.builtin.deb822_repository:
|
||||||
|
name: fluentbit
|
||||||
|
types: [deb]
|
||||||
|
uris: https://packages.fluentbit.io/ubuntu/noble
|
||||||
|
suites: [noble]
|
||||||
|
components: [main]
|
||||||
|
signed_by: "{{ fluentbit_apt_keyring }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Install fluent-bit
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ fluentbit_package }}"
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
- name: Stop and disable packaged fluent-bit service
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: fluent-bit
|
||||||
|
state: stopped
|
||||||
|
enabled: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Create fluentbit group
|
||||||
|
ansible.builtin.group:
|
||||||
|
name: "{{ fluentbit_group }}"
|
||||||
|
system: true
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create fluentbit user
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: "{{ fluentbit_user }}"
|
||||||
|
group: "{{ fluentbit_group }}"
|
||||||
|
system: true
|
||||||
|
shell: /usr/sbin/nologin
|
||||||
|
home: "{{ fluentbit_log_dir }}"
|
||||||
|
create_home: false
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create fluentbit directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ fluentbit_user }}"
|
||||||
|
group: "{{ fluentbit_group }}"
|
||||||
|
mode: "0750"
|
||||||
|
loop:
|
||||||
|
- "{{ fluentbit_config_dir }}"
|
||||||
|
- "{{ fluentbit_log_dir }}"
|
||||||
|
|
||||||
|
- name: Render parsers.conf
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: parsers.conf.j2
|
||||||
|
dest: "{{ fluentbit_config_dir }}/parsers.conf"
|
||||||
|
owner: root
|
||||||
|
group: "{{ fluentbit_group }}"
|
||||||
|
mode: "0640"
|
||||||
|
notify: Restart fluent-bit
|
||||||
|
|
||||||
|
- name: Render fluent-bit.conf
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: fluent-bit.conf.j2
|
||||||
|
dest: "{{ fluentbit_config_dir }}/fluent-bit.conf"
|
||||||
|
owner: root
|
||||||
|
group: "{{ fluentbit_group }}"
|
||||||
|
mode: "0640"
|
||||||
|
notify: Restart fluent-bit
|
||||||
|
|
||||||
|
- name: Install fluent-bit systemd unit
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: fluent-bit.service.j2
|
||||||
|
dest: /etc/systemd/system/fluent-bit.service
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
notify: Restart fluent-bit
|
||||||
|
|
||||||
|
- name: Enable and start fluent-bit
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: fluent-bit
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
daemon_reload: true
|
||||||
|
|
||||||
|
- name: Create syslog-* index pattern in Dashboards
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "http://127.0.0.1:{{ opensearch_dashboards_port | default('5601') }}/api/saved_objects/index-pattern/syslog-*"
|
||||||
|
method: POST
|
||||||
|
user: "{{ fluentbit_opensearch_user }}"
|
||||||
|
password: "{{ fluentbit_opensearch_password }}"
|
||||||
|
force_basic_auth: true
|
||||||
|
headers:
|
||||||
|
osd-xsrf: "true"
|
||||||
|
Content-Type: "application/json"
|
||||||
|
body_format: json
|
||||||
|
body:
|
||||||
|
attributes:
|
||||||
|
title: "syslog-*"
|
||||||
|
timeFieldName: "@timestamp"
|
||||||
|
status_code: [200, 201, 409]
|
||||||
|
|
||||||
|
- name: Set syslog-* as default index in Dashboards
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "http://127.0.0.1:{{ opensearch_dashboards_port | default('5601') }}/api/saved_objects/config/{{ opensearch_dashboards_version | default('2.19.6') }}"
|
||||||
|
method: PUT
|
||||||
|
user: "{{ fluentbit_opensearch_user }}"
|
||||||
|
password: "{{ fluentbit_opensearch_password }}"
|
||||||
|
force_basic_auth: true
|
||||||
|
headers:
|
||||||
|
osd-xsrf: "true"
|
||||||
|
Content-Type: "application/json"
|
||||||
|
body_format: json
|
||||||
|
body:
|
||||||
|
attributes:
|
||||||
|
defaultIndex: "syslog-*"
|
||||||
|
status_code: [200, 409]
|
||||||
40
ansible/roles/fluentbit/templates/fluent-bit.conf.j2
Normal file
40
ansible/roles/fluentbit/templates/fluent-bit.conf.j2
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# {{ ansible_managed | default('Managed by Ansible') }}
|
||||||
|
# Fluent Bit configuration for logs.vntx.net
|
||||||
|
# Receives RFC 3164 syslog from MikroTik, Ubiquiti, Cambium, etc.
|
||||||
|
|
||||||
|
[SERVICE]
|
||||||
|
Flush 5
|
||||||
|
Daemon off
|
||||||
|
Log_Level info
|
||||||
|
parsers_file {{ fluentbit_config_dir }}/parsers.conf
|
||||||
|
|
||||||
|
[INPUT]
|
||||||
|
Name syslog
|
||||||
|
Listen {{ fluentbit_syslog_bind }}
|
||||||
|
Port {{ fluentbit_syslog_port }}
|
||||||
|
Mode udp
|
||||||
|
parser syslog-loose
|
||||||
|
raw_message_key raw
|
||||||
|
|
||||||
|
[INPUT]
|
||||||
|
Name syslog
|
||||||
|
Listen {{ fluentbit_syslog_bind }}
|
||||||
|
Port {{ fluentbit_syslog_port }}
|
||||||
|
Mode tcp
|
||||||
|
parser syslog-loose
|
||||||
|
raw_message_key raw
|
||||||
|
|
||||||
|
[OUTPUT]
|
||||||
|
Name opensearch
|
||||||
|
Match *
|
||||||
|
Host {{ fluentbit_opensearch_host }}
|
||||||
|
Port {{ fluentbit_opensearch_port }}
|
||||||
|
Index {{ fluentbit_opensearch_index }}
|
||||||
|
HTTP_User ${FLUENTBIT_OPENSEARCH_USER}
|
||||||
|
HTTP_Passwd ${FLUENTBIT_OPENSEARCH_PASSWORD}
|
||||||
|
tls On
|
||||||
|
tls.verify Off
|
||||||
|
Suppress_Type_Name On
|
||||||
|
Logstash_Format On
|
||||||
|
Logstash_Prefix {{ fluentbit_opensearch_index }}
|
||||||
|
Retry_Limit false
|
||||||
41
ansible/roles/fluentbit/templates/fluent-bit.service.j2
Normal file
41
ansible/roles/fluentbit/templates/fluent-bit.service.j2
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# {{ ansible_managed | default('Managed by Ansible') }}
|
||||||
|
# Fluent Bit systemd unit — overrides the packaged unit to add
|
||||||
|
# AmbientCapabilities for privileged-port binding and credential env vars.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Fluent Bit syslog collector
|
||||||
|
Documentation=https://docs.fluentbit.io/
|
||||||
|
After=network-online.target opensearch.service
|
||||||
|
Wants=network-online.target
|
||||||
|
Requires=opensearch.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User={{ fluentbit_user }}
|
||||||
|
Group={{ fluentbit_group }}
|
||||||
|
|
||||||
|
Environment=FLUENTBIT_OPENSEARCH_USER={{ fluentbit_opensearch_user }}
|
||||||
|
Environment=FLUENTBIT_OPENSEARCH_PASSWORD={{ fluentbit_opensearch_password }}
|
||||||
|
|
||||||
|
ExecStart=/opt/fluent-bit/bin/fluent-bit \
|
||||||
|
--config={{ fluentbit_config_dir }}/fluent-bit.conf
|
||||||
|
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
LimitNOFILE=65536
|
||||||
|
|
||||||
|
# Bind to privileged port 514 without running as root
|
||||||
|
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||||
|
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||||
|
|
||||||
|
NoNewPrivileges=true
|
||||||
|
ProtectHome=true
|
||||||
|
ProtectSystem=full
|
||||||
|
ProtectKernelTunables=true
|
||||||
|
ProtectKernelModules=true
|
||||||
|
ProtectControlGroups=true
|
||||||
|
PrivateTmp=true
|
||||||
|
ReadWritePaths={{ fluentbit_log_dir }}
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
11
ansible/roles/fluentbit/templates/parsers.conf.j2
Normal file
11
ansible/roles/fluentbit/templates/parsers.conf.j2
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# {{ ansible_managed | default('Managed by Ansible') }}
|
||||||
|
# Syslog parser for mixed network gear (MikroTik, Ubiquiti, Cambium, etc.)
|
||||||
|
# Handles both standard RFC 3164 and bare/partial formats.
|
||||||
|
|
||||||
|
[PARSER]
|
||||||
|
Name syslog-loose
|
||||||
|
Format regex
|
||||||
|
Regex ^(\<(?<pri>[0-9]+)\>)?((?<time>[A-Z][a-z]{2}\s+\d+\s+\d{2}:\d{2}:\d{2})\s+(?<host>\S+)\s+)?(?<ident>\S+)\s+(?<message>.*)$
|
||||||
|
Time_Key time
|
||||||
|
Time_Format %b %d %H:%M:%S
|
||||||
|
Time_Keep On
|
||||||
10
ansible/roles/forgejo/defaults/main.yml
Normal file
10
ansible/roles/forgejo/defaults/main.yml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
forgejo_version: "10"
|
||||||
|
forgejo_runner_version: "12"
|
||||||
|
forgejo_http_port: 3000
|
||||||
|
forgejo_ssh_port: 2222
|
||||||
|
forgejo_hostname: git.mcintire.me
|
||||||
|
forgejo_data_dir: /opt/forgejo
|
||||||
|
forgejo_admin_user: graham
|
||||||
|
forgejo_admin_email: graham@mcintire.me
|
||||||
|
forgejo_admin_password: "{{ lookup('env', 'FORGEJO_ADMIN_PASSWORD') | default('changeme123', true) }}"
|
||||||
5
ansible/roles/forgejo/handlers/main.yml
Normal file
5
ansible/roles/forgejo/handlers/main.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
- name: restart forgejo
|
||||||
|
ansible.builtin.command: docker compose restart
|
||||||
|
args:
|
||||||
|
chdir: "{{ forgejo_data_dir }}"
|
||||||
178
ansible/roles/forgejo/tasks/main.yml
Normal file
178
ansible/roles/forgejo/tasks/main.yml
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
---
|
||||||
|
- name: Install prerequisites
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- ca-certificates
|
||||||
|
- curl
|
||||||
|
- gnupg
|
||||||
|
- apt-transport-https
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
- name: Check if Docker is installed
|
||||||
|
ansible.builtin.command: which docker
|
||||||
|
register: docker_installed
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Add Docker GPG key
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: https://download.docker.com/linux/debian/gpg
|
||||||
|
dest: /usr/share/keyrings/docker-archive-keyring.asc
|
||||||
|
mode: '0644'
|
||||||
|
when: docker_installed.rc != 0
|
||||||
|
|
||||||
|
- name: Add Docker repository
|
||||||
|
ansible.builtin.deb822_repository:
|
||||||
|
name: docker
|
||||||
|
types: deb
|
||||||
|
uris: https://download.docker.com/linux/debian
|
||||||
|
suites: "{{ ansible_facts['distribution_release'] }}"
|
||||||
|
components: stable
|
||||||
|
architectures: "{{ ansible_facts['architecture'] | replace('x86_64', 'amd64') }}"
|
||||||
|
signed_by: /usr/share/keyrings/docker-archive-keyring.asc
|
||||||
|
state: present
|
||||||
|
when: docker_installed.rc != 0
|
||||||
|
|
||||||
|
- name: Install Docker packages
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- docker-ce
|
||||||
|
- docker-ce-cli
|
||||||
|
- containerd.io
|
||||||
|
- docker-compose-plugin
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
when: docker_installed.rc != 0
|
||||||
|
|
||||||
|
- name: Ensure Docker service is started and enabled
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: docker
|
||||||
|
state: started
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
- name: Add ansible user to docker group
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: ansible
|
||||||
|
groups: docker
|
||||||
|
append: true
|
||||||
|
|
||||||
|
- name: Create Forgejo data directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ forgejo_data_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Deploy docker-compose.yml
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ forgejo_data_dir }}/docker-compose.yml"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Check if Forgejo is running
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: docker compose ps --services --filter "status=running"
|
||||||
|
chdir: "{{ forgejo_data_dir }}"
|
||||||
|
register: forgejo_running
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Check if Forgejo data exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ forgejo_data_dir }}/data/gitea/conf/app.ini"
|
||||||
|
register: forgejo_data_exists
|
||||||
|
|
||||||
|
- name: Start Forgejo if not running
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: docker compose up -d forgejo
|
||||||
|
chdir: "{{ forgejo_data_dir }}"
|
||||||
|
when: "'forgejo' not in forgejo_running.stdout_lines | default([])"
|
||||||
|
|
||||||
|
- name: Wait for Forgejo web UI
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: http://127.0.0.1:3000/
|
||||||
|
method: GET
|
||||||
|
status_code: 200
|
||||||
|
register: web_ready
|
||||||
|
retries: 30
|
||||||
|
delay: 2
|
||||||
|
until: web_ready.status == 200
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Check if admin user exists
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: http://127.0.0.1:3000/api/v1/users/{{ forgejo_admin_user }}
|
||||||
|
method: GET
|
||||||
|
status_code: [200, 404]
|
||||||
|
register: admin_check
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Create admin user
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: >
|
||||||
|
docker exec -u git -w /data/gitea forgejo forgejo admin user create
|
||||||
|
--config /data/gitea/conf/app.ini
|
||||||
|
--username {{ forgejo_admin_user }}
|
||||||
|
--password {{ forgejo_admin_password }}
|
||||||
|
--email {{ forgejo_admin_email }}
|
||||||
|
--admin
|
||||||
|
when:
|
||||||
|
- forgejo_data_exists.stat.exists
|
||||||
|
- admin_check.status == 404
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Create runner data directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ forgejo_data_dir }}/runner"
|
||||||
|
state: directory
|
||||||
|
owner: "1000"
|
||||||
|
group: "1000"
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Deploy runner config
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: runner-config.yaml.j2
|
||||||
|
dest: "{{ forgejo_data_dir }}/runner/config.yaml"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Check if runner is registered
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ forgejo_data_dir }}/runner/.runner"
|
||||||
|
register: runner_registered
|
||||||
|
|
||||||
|
- name: Generate runner token
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: >
|
||||||
|
docker exec -u git -w /data/gitea forgejo forgejo actions generate-runner-token --config /data/gitea/conf/app.ini
|
||||||
|
register: runner_token
|
||||||
|
changed_when: false
|
||||||
|
when: not runner_registered.stat.exists
|
||||||
|
|
||||||
|
- name: Register runner
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: >
|
||||||
|
docker run --rm
|
||||||
|
-v {{ forgejo_data_dir }}/runner:/data
|
||||||
|
-v /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
--network forgejo_forgejo
|
||||||
|
data.forgejo.org/forgejo/runner:{{ forgejo_runner_version }}
|
||||||
|
forgejo-runner register
|
||||||
|
--no-interactive
|
||||||
|
--instance http://forgejo:3000
|
||||||
|
--token {{ runner_token.stdout }}
|
||||||
|
--name "forgejo-runner-{{ ansible_hostname }}"
|
||||||
|
--labels "ubuntu-latest:docker://node:20-bookworm,ubuntu-22.04:docker://node:20-bookworm,ubuntu-24.04:docker://node:20-bookworm"
|
||||||
|
when: not runner_registered.stat.exists
|
||||||
|
|
||||||
|
- name: Start runner
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: docker compose up -d runner
|
||||||
|
chdir: "{{ forgejo_data_dir }}"
|
||||||
|
register: runner_started
|
||||||
|
changed_when: "'Starting' in runner_started.stdout or 'Creating' in runner_started.stdout"
|
||||||
50
ansible/roles/forgejo/templates/docker-compose.yml.j2
Normal file
50
ansible/roles/forgejo/templates/docker-compose.yml.j2
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
services:
|
||||||
|
forgejo:
|
||||||
|
image: codeberg.org/forgejo/forgejo:{{ forgejo_version }}
|
||||||
|
container_name: forgejo
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- forgejo
|
||||||
|
volumes:
|
||||||
|
- {{ forgejo_data_dir }}/data:/data
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:{{ forgejo_http_port }}:3000"
|
||||||
|
- "0.0.0.0:{{ forgejo_ssh_port }}:22"
|
||||||
|
environment:
|
||||||
|
- USER_UID=1000
|
||||||
|
- USER_GID=1000
|
||||||
|
- FORGEJO__server__ROOT_URL=https://{{ forgejo_hostname }}
|
||||||
|
- FORGEJO__server__SSH_DOMAIN={{ forgejo_hostname }}
|
||||||
|
- FORGEJO__server__HTTP_PORT={{ forgejo_http_port }}
|
||||||
|
- FORGEJO__server__SSH_PORT={{ forgejo_ssh_port }}
|
||||||
|
- FORGEJO__server__DOMAIN={{ forgejo_hostname }}
|
||||||
|
- FORGEJO__database__DB_TYPE=sqlite3
|
||||||
|
- FORGEJO__database__PATH=/data/gitea/gitea.db
|
||||||
|
- FORGEJO__security__INSTALL_LOCK=true
|
||||||
|
- FORGEJO__service__DISABLE_REGISTRATION=true
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:3000"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
runner:
|
||||||
|
image: data.forgejo.org/forgejo/runner:{{ forgejo_runner_version }}
|
||||||
|
container_name: forgejo-runner
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
forgejo:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- forgejo
|
||||||
|
user: "0:0"
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- {{ forgejo_data_dir }}/runner:/data
|
||||||
|
command: ["forgejo-runner", "daemon", "--config", "/data/config.yaml"]
|
||||||
|
working_dir: /data
|
||||||
|
|
||||||
|
networks:
|
||||||
|
forgejo:
|
||||||
18
ansible/roles/forgejo/templates/runner-config.yaml.j2
Normal file
18
ansible/roles/forgejo/templates/runner-config.yaml.j2
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
log:
|
||||||
|
level: info
|
||||||
|
|
||||||
|
runner:
|
||||||
|
file: .runner
|
||||||
|
capacity: 2
|
||||||
|
labels:
|
||||||
|
- "ubuntu-latest:docker://node:20-bookworm"
|
||||||
|
- "ubuntu-22.04:docker://node:20-bookworm"
|
||||||
|
- "ubuntu-24.04:docker://node:20-bookworm"
|
||||||
|
|
||||||
|
cache:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
container:
|
||||||
|
network: ""
|
||||||
|
privileged: false
|
||||||
|
docker_host: automount
|
||||||
10
ansible/roles/forgejo/templates/runner.yaml.j2
Normal file
10
ansible/roles/forgejo/templates/runner.yaml.j2
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
log:
|
||||||
|
level: info
|
||||||
|
|
||||||
|
runner:
|
||||||
|
file: /data/runner/.runner
|
||||||
|
capacity: 2
|
||||||
|
labels:
|
||||||
|
- "ubuntu-latest:docker://node:20-bookworm"
|
||||||
|
- "ubuntu-22.04:docker://node:20-bookworm"
|
||||||
|
- "ubuntu-24.04:docker://node:20-bookworm"
|
||||||
|
|
@ -27,6 +27,17 @@ opensearch_discovery_type: single-node
|
||||||
# Plugins to install (empty by default)
|
# Plugins to install (empty by default)
|
||||||
opensearch_plugins: []
|
opensearch_plugins: []
|
||||||
|
|
||||||
|
# --- Security Plugin ---
|
||||||
|
opensearch_security_enabled: true
|
||||||
|
opensearch_admin_username: admin
|
||||||
|
# bcrypt hash of the admin password — generate with:
|
||||||
|
# python3 -c "import bcrypt; print(bcrypt.hashpw(b'<password>', bcrypt.gensalt()).decode())"
|
||||||
|
# Override in host_vars or vault.
|
||||||
|
opensearch_admin_password_hash: ""
|
||||||
|
# Plaintext admin password (for Dashboards to authenticate to OpenSearch).
|
||||||
|
# Override in host_vars or vault.
|
||||||
|
opensearch_admin_password: ""
|
||||||
|
|
||||||
# Sysctl: vm.max_map_count required by OpenSearch
|
# Sysctl: vm.max_map_count required by OpenSearch
|
||||||
opensearch_vm_max_map_count: 262144
|
opensearch_vm_max_map_count: 262144
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,55 @@
|
||||||
mode: "0640"
|
mode: "0640"
|
||||||
notify: Restart opensearch
|
notify: Restart opensearch
|
||||||
|
|
||||||
|
- name: Check if demo TLS certs exist
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ opensearch_config_dir }}/{{ item }}"
|
||||||
|
loop:
|
||||||
|
- esnode.pem
|
||||||
|
- esnode-key.pem
|
||||||
|
- root-ca.pem
|
||||||
|
register: opensearch_demo_certs
|
||||||
|
when: opensearch_security_enabled | default(true)
|
||||||
|
|
||||||
|
- name: Generate self-signed TLS certs for OpenSearch
|
||||||
|
ansible.builtin.shell:
|
||||||
|
cmd: |
|
||||||
|
set -e
|
||||||
|
openssl req -x509 -newkey rsa:4096 \
|
||||||
|
-keyout {{ opensearch_config_dir }}/esnode-key.pem \
|
||||||
|
-out {{ opensearch_config_dir }}/esnode.pem \
|
||||||
|
-days 3650 -nodes \
|
||||||
|
-subj "/CN={{ opensearch_node_name }}" \
|
||||||
|
-addext "subjectAltName=DNS:localhost,DNS:{{ inventory_hostname }},IP:127.0.0.1"
|
||||||
|
cp {{ opensearch_config_dir }}/esnode.pem {{ opensearch_config_dir }}/root-ca.pem
|
||||||
|
chown {{ opensearch_user }}:{{ opensearch_group }} {{ opensearch_config_dir }}/esnode.pem {{ opensearch_config_dir }}/esnode-key.pem {{ opensearch_config_dir }}/root-ca.pem
|
||||||
|
chmod 600 {{ opensearch_config_dir }}/esnode-key.pem
|
||||||
|
creates: "{{ opensearch_config_dir }}/esnode.pem"
|
||||||
|
when:
|
||||||
|
- opensearch_security_enabled | default(true)
|
||||||
|
- (opensearch_demo_certs.results | selectattr('stat.exists', 'equalto', false) | list | length) > 0
|
||||||
|
notify: Restart opensearch
|
||||||
|
|
||||||
|
- name: Render internal_users.yml
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: internal_users.yml.j2
|
||||||
|
dest: "{{ opensearch_config_dir }}/opensearch-security/internal_users.yml"
|
||||||
|
owner: "{{ opensearch_user }}"
|
||||||
|
group: "{{ opensearch_group }}"
|
||||||
|
mode: "0640"
|
||||||
|
when: opensearch_security_enabled | default(true)
|
||||||
|
notify: Restart opensearch
|
||||||
|
|
||||||
|
- name: Render roles_mapping.yml
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: roles_mapping.yml.j2
|
||||||
|
dest: "{{ opensearch_config_dir }}/opensearch-security/roles_mapping.yml"
|
||||||
|
owner: "{{ opensearch_user }}"
|
||||||
|
group: "{{ opensearch_group }}"
|
||||||
|
mode: "0640"
|
||||||
|
when: opensearch_security_enabled | default(true)
|
||||||
|
notify: Restart opensearch
|
||||||
|
|
||||||
- name: Render jvm.options
|
- name: Render jvm.options
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: jvm.options.j2
|
src: jvm.options.j2
|
||||||
|
|
@ -106,6 +155,25 @@
|
||||||
state: started
|
state: started
|
||||||
daemon_reload: true
|
daemon_reload: true
|
||||||
|
|
||||||
|
- name: Create syslog index template
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "https://127.0.0.1:{{ opensearch_http_port }}/_index_template/syslog"
|
||||||
|
method: PUT
|
||||||
|
user: "{{ opensearch_admin_username }}"
|
||||||
|
password: "{{ opensearch_admin_password }}"
|
||||||
|
force_basic_auth: true
|
||||||
|
validate_certs: false
|
||||||
|
body_format: json
|
||||||
|
body:
|
||||||
|
index_patterns: ["syslog-*"]
|
||||||
|
template:
|
||||||
|
settings:
|
||||||
|
number_of_shards: 1
|
||||||
|
number_of_replicas: 0
|
||||||
|
priority: 100
|
||||||
|
status_code: [200, 201]
|
||||||
|
when: opensearch_security_enabled | default(true)
|
||||||
|
|
||||||
# --- OpenSearch Dashboards ---
|
# --- OpenSearch Dashboards ---
|
||||||
|
|
||||||
- name: Create opensearch-dashboards directories
|
- name: Create opensearch-dashboards directories
|
||||||
|
|
|
||||||
13
ansible/roles/opensearch/templates/internal_users.yml.j2
Normal file
13
ansible/roles/opensearch/templates/internal_users.yml.j2
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# {{ ansible_managed | default('Managed by Ansible') }}
|
||||||
|
#
|
||||||
|
# OpenSearch Security — internal user database.
|
||||||
|
# Applied on security index initialization (plugins.security.allow_default_init_securityindex: true).
|
||||||
|
---
|
||||||
|
_meta:
|
||||||
|
type: "internalusers"
|
||||||
|
config_version: 2
|
||||||
|
|
||||||
|
{{ opensearch_admin_username }}:
|
||||||
|
hash: "{{ opensearch_admin_password_hash }}"
|
||||||
|
reserved: true
|
||||||
|
description: "Admin user — managed by Ansible"
|
||||||
|
|
@ -6,6 +6,12 @@ server.host: 127.0.0.1
|
||||||
server.port: {{ opensearch_dashboards_port }}
|
server.port: {{ opensearch_dashboards_port }}
|
||||||
|
|
||||||
opensearch.hosts:
|
opensearch.hosts:
|
||||||
- {{ opensearch_dashboards_opensearch_url }}
|
- https://127.0.0.1:{{ opensearch_http_port }}
|
||||||
|
|
||||||
|
{% if opensearch_security_enabled | default(true) %}
|
||||||
|
opensearch.username: {{ opensearch_admin_username }}
|
||||||
|
opensearch.password: {{ opensearch_admin_password }}
|
||||||
|
opensearch.ssl.verificationMode: none
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
opensearch.requestTimeout: 30000
|
opensearch.requestTimeout: 30000
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,26 @@ transport.port: {{ opensearch_transport_port }}
|
||||||
# Single-node discovery (no cluster formation needed)
|
# Single-node discovery (no cluster formation needed)
|
||||||
discovery.type: {{ opensearch_discovery_type }}
|
discovery.type: {{ opensearch_discovery_type }}
|
||||||
|
|
||||||
# Security — disabled for internal-only binding on loopback
|
# Security — TLS with demo certs, internal user database
|
||||||
|
{% if opensearch_security_enabled | default(true) %}
|
||||||
|
plugins.security.disabled: false
|
||||||
|
{% if opensearch_security_allow_default_init | default(true) %}
|
||||||
|
plugins.security.allow_default_init_securityindex: true
|
||||||
|
{% endif %}
|
||||||
|
plugins.security.authcz.admin_dn:
|
||||||
|
- "CN={{ opensearch_node_name }}"
|
||||||
|
- "CN={{ inventory_hostname }}"
|
||||||
|
plugins.security.ssl.transport.pemcert_filepath: {{ opensearch_config_dir }}/esnode.pem
|
||||||
|
plugins.security.ssl.transport.pemkey_filepath: {{ opensearch_config_dir }}/esnode-key.pem
|
||||||
|
plugins.security.ssl.transport.pemtrustedcas_filepath: {{ opensearch_config_dir }}/root-ca.pem
|
||||||
|
plugins.security.ssl.transport.enforce_hostname_verification: false
|
||||||
|
plugins.security.ssl.http.enabled: true
|
||||||
|
plugins.security.ssl.http.pemcert_filepath: {{ opensearch_config_dir }}/esnode.pem
|
||||||
|
plugins.security.ssl.http.pemkey_filepath: {{ opensearch_config_dir }}/esnode-key.pem
|
||||||
|
plugins.security.ssl.http.pemtrustedcas_filepath: {{ opensearch_config_dir }}/root-ca.pem
|
||||||
|
{% else %}
|
||||||
plugins.security.disabled: true
|
plugins.security.disabled: true
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
# Performance
|
# Performance
|
||||||
indices.memory.index_buffer_size: 20%
|
indices.memory.index_buffer_size: 20%
|
||||||
|
|
|
||||||
48
ansible/roles/opensearch/templates/roles_mapping.yml.j2
Normal file
48
ansible/roles/opensearch/templates/roles_mapping.yml.j2
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# {{ ansible_managed | default('Managed by Ansible') }}
|
||||||
|
#
|
||||||
|
# OpenSearch Security — role mappings.
|
||||||
|
# Maps users and backend roles to OpenSearch roles defined in roles.yml.
|
||||||
|
---
|
||||||
|
_meta:
|
||||||
|
type: "rolesmapping"
|
||||||
|
config_version: 2
|
||||||
|
|
||||||
|
all_access:
|
||||||
|
reserved: false
|
||||||
|
users:
|
||||||
|
- "{{ opensearch_admin_username }}"
|
||||||
|
backend_roles:
|
||||||
|
- "admin"
|
||||||
|
description: "Maps admin to all_access"
|
||||||
|
|
||||||
|
own_index:
|
||||||
|
reserved: false
|
||||||
|
users:
|
||||||
|
- "*"
|
||||||
|
description: "Allow full access to an index named like the username"
|
||||||
|
|
||||||
|
logstash:
|
||||||
|
reserved: false
|
||||||
|
backend_roles:
|
||||||
|
- "logstash"
|
||||||
|
|
||||||
|
kibana_user:
|
||||||
|
reserved: false
|
||||||
|
backend_roles:
|
||||||
|
- "kibanauser"
|
||||||
|
description: "Maps kibanauser to kibana_user"
|
||||||
|
|
||||||
|
readall:
|
||||||
|
reserved: false
|
||||||
|
backend_roles:
|
||||||
|
- "readall"
|
||||||
|
|
||||||
|
manage_snapshots:
|
||||||
|
reserved: false
|
||||||
|
backend_roles:
|
||||||
|
- "snapshotrestore"
|
||||||
|
|
||||||
|
kibana_server:
|
||||||
|
reserved: true
|
||||||
|
users:
|
||||||
|
- "kibanaserver"
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
name: tailscale
|
name: tailscale
|
||||||
types: deb
|
types: deb
|
||||||
uris: https://pkgs.tailscale.com/stable/debian
|
uris: https://pkgs.tailscale.com/stable/debian
|
||||||
suites: bookworm
|
suites: "{{ ansible_facts['distribution_release'] }}"
|
||||||
components: main
|
components: main
|
||||||
signed_by: /usr/share/keyrings/tailscale-archive-keyring.gpg
|
signed_by: /usr/share/keyrings/tailscale-archive-keyring.gpg
|
||||||
state: present
|
state: present
|
||||||
|
|
@ -31,7 +31,10 @@
|
||||||
|
|
||||||
- name: Connect to Tailscale
|
- name: Connect to Tailscale
|
||||||
ansible.builtin.command: "tailscale up --authkey={{ tailscale_authkey }} {{ tailscale_args | default('') }}"
|
ansible.builtin.command: "tailscale up --authkey={{ tailscale_authkey }} {{ tailscale_args | default('') }}"
|
||||||
when: tailscale_status.rc != 0 or 'BackendState":"Running"' not in tailscale_status.stdout
|
when:
|
||||||
|
- not (tailscale_skip_connect | default(false))
|
||||||
|
- tailscale_authkey | length > 0
|
||||||
|
- tailscale_status.rc != 0 or 'BackendState":"Running"' not in tailscale_status.stdout
|
||||||
register: tailscale_up
|
register: tailscale_up
|
||||||
changed_when: tailscale_up.rc == 0
|
changed_when: tailscale_up.rc == 0
|
||||||
|
|
||||||
|
|
@ -39,11 +42,14 @@
|
||||||
ansible.builtin.command: tailscale ip -4
|
ansible.builtin.command: tailscale ip -4
|
||||||
register: tailscale_ip_result
|
register: tailscale_ip_result
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
- name: Set Tailscale IP fact
|
- name: Set Tailscale IP fact
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
tailscale_ip: "{{ tailscale_ip_result.stdout | trim }}"
|
tailscale_ip: "{{ tailscale_ip_result.stdout | trim }}"
|
||||||
|
when: tailscale_ip_result.rc == 0
|
||||||
|
|
||||||
- name: Display Tailscale IP
|
- name: Display Tailscale IP
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
msg: "Tailscale IP: {{ tailscale_ip }}"
|
msg: "Tailscale IP: {{ tailscale_ip }}"
|
||||||
|
when: tailscale_ip_result.rc == 0
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,4 @@ spec:
|
||||||
selfHeal: true
|
selfHeal: true
|
||||||
syncOptions:
|
syncOptions:
|
||||||
- CreateNamespace=true
|
- CreateNamespace=true
|
||||||
|
- PrunePropagationPolicy=foreground
|
||||||
|
|
|
||||||
|
|
@ -1174,3 +1174,314 @@ resource "cloudflare_zero_trust_tunnel_cloudflared_config" "towerops_dev" {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# mcintire.me Zone
|
||||||
|
#
|
||||||
|
# Migrated from self-hosted BIND9 (ns1.as393837.net) to Cloudflare.
|
||||||
|
#
|
||||||
|
# IMPORTANT: The zone is created fresh (no import block). After the first
|
||||||
|
# `tofu apply`, run `tofu state show cloudflare_zone.mcintire_me` to get the
|
||||||
|
# assigned name_servers, then update tofu/dns.tf with those values before
|
||||||
|
# running `tofu apply` a second time to update Porkbun's NS records.
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
resource "cloudflare_zone" "mcintire_me" {
|
||||||
|
account = {
|
||||||
|
id = local.cloudflare_account_id
|
||||||
|
}
|
||||||
|
name = "mcintire.me"
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# mcintire.me - A records
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_a_mail" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "A"
|
||||||
|
name = "mail"
|
||||||
|
content = "107.174.178.20"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_a_photos" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "A"
|
||||||
|
name = "photos"
|
||||||
|
content = "204.110.191.8"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_a_git" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "A"
|
||||||
|
name = "git"
|
||||||
|
content = "74.50.113.232"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_a_hi" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "A"
|
||||||
|
name = "hi"
|
||||||
|
content = "74.50.113.232"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_a_vm1" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "A"
|
||||||
|
name = "vm1"
|
||||||
|
content = "172.245.56.83"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# mcintire.me - AAAA records
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_aaaa_git" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "AAAA"
|
||||||
|
name = "git"
|
||||||
|
content = "2604:4500:0009:003d:1c00:bfff:fe00:0464"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_aaaa_hi" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "AAAA"
|
||||||
|
name = "hi"
|
||||||
|
content = "2604:4500:0009:003d:1c00:bfff:fe00:0464"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# mcintire.me - MX records
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_mx_root_primary" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "MX"
|
||||||
|
name = "mcintire.me"
|
||||||
|
content = "mail.mcintire.me"
|
||||||
|
priority = 10
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_mx_root_backup" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "MX"
|
||||||
|
name = "mcintire.me"
|
||||||
|
content = "mail.nsnw.ca"
|
||||||
|
priority = 20
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# mcintire.me - CNAME records
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_cname_ha" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "CNAME"
|
||||||
|
name = "ha"
|
||||||
|
content = "q1l09qiycnaagngmjsg1qas0rhqcfoou.ui.nabu.casa"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_cname_acme_ha" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "CNAME"
|
||||||
|
name = "_acme-challenge.ha"
|
||||||
|
content = "_acme-challenge.q1l09qiycnaagngmjsg1qas0rhqcfoou.ui.nabu.casa"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_cname_autodiscover" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "CNAME"
|
||||||
|
name = "autodiscover"
|
||||||
|
content = "mail.w5isp.com"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_cname_autoconfig" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "CNAME"
|
||||||
|
name = "autoconfig"
|
||||||
|
content = "mail.w5isp.com"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_cname_em977211" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "CNAME"
|
||||||
|
name = "em977211"
|
||||||
|
content = "return.smtp2go.net"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_cname_dkim_s977211" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "CNAME"
|
||||||
|
name = "s977211._domainkey"
|
||||||
|
content = "dkim.smtp2go.net"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_cname_link" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "CNAME"
|
||||||
|
name = "link"
|
||||||
|
content = "track.smtp2go.net"
|
||||||
|
proxied = false
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# mcintire.me - SRV records
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_srv_autodiscover" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "SRV"
|
||||||
|
name = "_autodiscover._tcp"
|
||||||
|
ttl = 86400
|
||||||
|
|
||||||
|
data = {
|
||||||
|
priority = 0
|
||||||
|
weight = 0
|
||||||
|
port = 443
|
||||||
|
target = "mail.w5isp.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
ignore_changes = [priority]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# mcintire.me - TXT records
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_txt_spf" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "TXT"
|
||||||
|
name = "mcintire.me"
|
||||||
|
content = "v=spf1 mx a ip4:107.174.178.20 ~all"
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_txt_dmarc" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "TXT"
|
||||||
|
name = "_dmarc"
|
||||||
|
content = "v=DMARC1; p=quarantine; rua=mailto:postmaster@mcintire.me; ruf=mailto:postmaster@mcintire.me; fo=1"
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_txt_dkim" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "TXT"
|
||||||
|
name = "dkim._domainkey"
|
||||||
|
content = "v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0rQie7Hz5AmDbVUX+rKNgp6Hf7crtWyfy6qKbqnrxmmernz1rQ6HyOrHhFAlc8nVLNKr8XP2DOROb1jAnrjndZo9I/ymbrrrCBsi9w6zAht2BheijO/R9k5CDRjeSafm6bg0oMKihtNMIdXvEj9ND8hDpZZKxtOrKFH7zLm4CPmm7jf0gqZH2yK+AA3OYUGSYa1OT0LtdMXadk0IVOI2VYf37Hzb3RUvGOYMVkT0xi+23DiyFk7AyCiyv3LQVBMT+/bwyd4k3yVVn2cr9+Nor+HXVjqASLtqcFLMf1SuX0ezSAjBG7BbqQr5G6Jz+n5YglqEIUKVYzJFE7JdDmqQYQIDAQAB"
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_dns_record" "mcintire_me_txt_yahoo_verification" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
type = "TXT"
|
||||||
|
name = "mcintire.me"
|
||||||
|
content = "yahoo-verification-key=Pt59XUhQSd7dbVc0x6TQD+mBEtOOTMHFRV1ZG78h4Ug="
|
||||||
|
ttl = 86400
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# mcintire.me - Zone settings
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
resource "cloudflare_zone_setting" "mcintire_me_min_tls_version" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
setting_id = "min_tls_version"
|
||||||
|
value = "1.2"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_zone_setting" "mcintire_me_always_use_https" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
setting_id = "always_use_https"
|
||||||
|
value = "on"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_zone_setting" "mcintire_me_tls_1_3" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
setting_id = "tls_1_3"
|
||||||
|
value = "zrt"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_zone_setting" "mcintire_me_zero_rtt" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
setting_id = "0rtt"
|
||||||
|
value = "on"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_zone_setting" "mcintire_me_ssl" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
setting_id = "ssl"
|
||||||
|
value = "full"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_zone_setting" "mcintire_me_security_header" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
setting_id = "security_header"
|
||||||
|
value = {
|
||||||
|
strict_transport_security = {
|
||||||
|
enabled = true
|
||||||
|
max_age = 15552000
|
||||||
|
include_subdomains = true
|
||||||
|
preload = true
|
||||||
|
nosniff = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# mcintire.me - Bot management
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
resource "cloudflare_bot_management" "mcintire_me" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
is_robots_txt_managed = false
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# mcintire.me - Firewall
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
resource "cloudflare_ruleset" "mcintire_me_firewall" {
|
||||||
|
zone_id = cloudflare_zone.mcintire_me.id
|
||||||
|
name = "default"
|
||||||
|
kind = "zone"
|
||||||
|
phase = "http_request_firewall_custom"
|
||||||
|
|
||||||
|
rules = [{
|
||||||
|
action = "block"
|
||||||
|
expression = local.firewall_expression
|
||||||
|
description = "block abusers"
|
||||||
|
enabled = true
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ locals {
|
||||||
"gridmap.org" = local.cloudflare_ns
|
"gridmap.org" = local.cloudflare_ns
|
||||||
"gunincrements.com" = local.porkbun_ns
|
"gunincrements.com" = local.porkbun_ns
|
||||||
"manero.org" = local.porkbun_ns
|
"manero.org" = local.porkbun_ns
|
||||||
"mcintire.me" = local.as393837_ns
|
"mcintire.me" = local.cloudflare_ns
|
||||||
"ntxarms.com" = local.as393837_ns
|
"ntxarms.com" = local.as393837_ns
|
||||||
"qth.social" = local.porkbun_ns
|
"qth.social" = local.porkbun_ns
|
||||||
# towerops.net is not opted in to Porkbun API access
|
# towerops.net is not opted in to Porkbun API access
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,19 @@ storage:
|
||||||
overwrite: true
|
overwrite: true
|
||||||
contents:
|
contents:
|
||||||
inline: flatcar-resolver1
|
inline: flatcar-resolver1
|
||||||
|
- path: /etc/resolv.conf
|
||||||
|
mode: 0644
|
||||||
|
overwrite: true
|
||||||
|
contents:
|
||||||
|
inline: |
|
||||||
|
nameserver 1.1.1.1
|
||||||
|
nameserver 9.9.9.9
|
||||||
|
- path: /etc/systemd/resolved.conf.d/no-stub.conf
|
||||||
|
mode: 0644
|
||||||
|
contents:
|
||||||
|
inline: |
|
||||||
|
[Resolve]
|
||||||
|
DNSStubListener=no
|
||||||
- path: /etc/systemd/network/00-eth0.network
|
- path: /etc/systemd/network/00-eth0.network
|
||||||
mode: 0644
|
mode: 0644
|
||||||
contents:
|
contents:
|
||||||
|
|
@ -30,8 +43,8 @@ storage:
|
||||||
[Network]
|
[Network]
|
||||||
Address=204.110.191.240/26
|
Address=204.110.191.240/26
|
||||||
Gateway=204.110.191.254
|
Gateway=204.110.191.254
|
||||||
DNS=9.9.9.9
|
|
||||||
DNS=1.1.1.1
|
DNS=1.1.1.1
|
||||||
|
DNS=9.9.9.9
|
||||||
|
|
||||||
[Address]
|
[Address]
|
||||||
Address=2606:1c80::240/64
|
Address=2606:1c80::240/64
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,19 @@ storage:
|
||||||
overwrite: true
|
overwrite: true
|
||||||
contents:
|
contents:
|
||||||
inline: flatcar-resolver2
|
inline: flatcar-resolver2
|
||||||
|
- path: /etc/resolv.conf
|
||||||
|
mode: 0644
|
||||||
|
overwrite: true
|
||||||
|
contents:
|
||||||
|
inline: |
|
||||||
|
nameserver 1.1.1.1
|
||||||
|
nameserver 9.9.9.9
|
||||||
|
- path: /etc/systemd/resolved.conf.d/no-stub.conf
|
||||||
|
mode: 0644
|
||||||
|
contents:
|
||||||
|
inline: |
|
||||||
|
[Resolve]
|
||||||
|
DNSStubListener=no
|
||||||
- path: /etc/systemd/network/00-eth0.network
|
- path: /etc/systemd/network/00-eth0.network
|
||||||
mode: 0644
|
mode: 0644
|
||||||
contents:
|
contents:
|
||||||
|
|
@ -30,8 +43,8 @@ storage:
|
||||||
[Network]
|
[Network]
|
||||||
Address=204.110.191.250/26
|
Address=204.110.191.250/26
|
||||||
Gateway=204.110.191.254
|
Gateway=204.110.191.254
|
||||||
DNS=9.9.9.9
|
|
||||||
DNS=1.1.1.1
|
DNS=1.1.1.1
|
||||||
|
DNS=9.9.9.9
|
||||||
|
|
||||||
[Address]
|
[Address]
|
||||||
Address=2606:1c80::250/64
|
Address=2606:1c80::250/64
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ module "flatcar_resolver1" {
|
||||||
storage_root = "local-lvm"
|
storage_root = "local-lvm"
|
||||||
storage_ignition = "local"
|
storage_ignition = "local"
|
||||||
butane_conf = "${path.module}/flatcar-resolver.bu"
|
butane_conf = "${path.module}/flatcar-resolver.bu"
|
||||||
butane_snippet_path = "${path.module}"
|
butane_snippet_path = path.module
|
||||||
|
|
||||||
network_devices = [
|
network_devices = [
|
||||||
{
|
{
|
||||||
|
|
@ -57,7 +57,7 @@ module "flatcar_resolver2" {
|
||||||
storage_root = "local-lvm"
|
storage_root = "local-lvm"
|
||||||
storage_ignition = "local"
|
storage_ignition = "local"
|
||||||
butane_conf = "${path.module}/flatcar-resolver2.bu"
|
butane_conf = "${path.module}/flatcar-resolver2.bu"
|
||||||
butane_snippet_path = "${path.module}"
|
butane_snippet_path = path.module
|
||||||
|
|
||||||
network_devices = [
|
network_devices = [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue