1
0

nut and acme working

This commit is contained in:
michael 2024-01-11 18:15:16 +13:00
parent ba7cda511e
commit c6755e8d97
19 changed files with 287 additions and 70 deletions

View File

@ -1,2 +1,3 @@
nut_client_admin_username: nut-admin
nut_client_primary_username: nut-primary nut_client_primary_username: nut-primary
nut_client_secondary_username: nut-secondary nut_client_secondary_username: nut-secondary

View File

@ -1 +1 @@
acme_certifcate_account_email: acme.hv00@balsillie.email acme_certificate_account_email: acme.hv00@balsillie.email

View File

@ -3,6 +3,7 @@ nut_client_shutdown_cmd: /usr/bin/poweroff
nut_client_shutdown_exit: "true" nut_client_shutdown_exit: "true"
nut_client_hostsync: 120 nut_client_hostsync: 120
nut_client_notify_cmd: /scripts/notify.sh nut_client_notify_cmd: /scripts/notify.sh
nut_client_min_supplies: 1
nut_client_ups_devices: nut_client_ups_devices:
- name: ups0 - name: ups0
host: hv00.balsillie.house host: hv00.balsillie.house
@ -10,5 +11,27 @@ nut_client_ups_devices:
port: 3493 port: 3493
powervalue: 1 powervalue: 1
nut_client_notify_flags: nut_client_notify_flags:
- name: ONLINE
flags: SYSLOG+WALL+EXEC
- name: ONBATT
flags: SYSLOG+WALL+EXEC
- name: LOWBATT
flags: SYSLOG+WALL+EXEC
- name: FSD
flags: SYSLOG+WALL+EXEC
- name: COMMOK
flags: SYSLOG+WALL+EXEC
- name: COMMBAD
flags: SYSLOG+WALL+EXEC
- name: SHUTDOWN - name: SHUTDOWN
flags: EXEC flags: SYSLOG+WALL+EXEC
- name: REPLBATT
flags: SYSLOG+WALL+EXEC
- name: NOCOMM
flags: SYSLOG+WALL+EXEC
- name: NOPARENT
flags: SYSLOG+WALL+EXEC
- name: BYPASS
flags: SYSLOG+WALL+EXEC
- name: NOTBYPASS
flags: SYSLOG+WALL+EXEC

View File

@ -1,6 +1,6 @@
nut_server_listen_address: 10.192.110.100 nut_server_listen_address: 10.192.110.100
nut_server_listen_port: 3493 nut_server_listen_port: 3493
nut_server_certificate_file: /etc/ssl/private/hv00.balsillie.house.plain.combined.pem
nut_server_ups_devices: nut_server_ups_devices:
- name: ups0 - name: ups0
driver: usbhid-ups driver: usbhid-ups

View File

@ -1 +1 @@
acme_certifcate_account_email: acme.kube00@balsillie.email acme_certificate_account_email: acme.kube00@balsillie.email

View File

@ -1,4 +1,9 @@
--- ansible_connection: ssh
ansible_host: kube01.balsillie.net ansible_host: kube00.balsillie.house
ssh_public_key_string: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGtk+mk1+J3sZ3CA/yS7XV2wH913IdJj0gznmb/nI2nV ladmin@kube01.balsillie.net ansible_fqdn: kube00.balsillie.house
k8s_remove_control_plane_taint: true ansible_remote_addr: 10.192.110.110
ansible_port: 22
ansible_user: ladmin
ansible_become_user: root
ansible_become_method: sudo
static_fqdn: hv00.balsillie.house

View File

@ -1,8 +1,15 @@
nut_client_local_server: false nut_client_local_server: false
nut_client_shutdown_cmd: /scripts/shutdown.sh
nut_client_server_list: nut_client_shutdown_exit: "false"
- host: hv00.balsillie.house nut_client_hostsync: 15
nut_client_notify_cmd: /scripts/notify.sh
nut_client_min_supplies: 1
nut_client_ups_devices:
- name: ups0
host: hv00.balsillie.house
type: secondary
port: 3493 port: 3493
ssl: true powervalue: 1
username: "{{ nut_client_username }}" nut_client_notify_flags:
password: "{{ nut_client_password }}" - name: SHUTDOWN
flags: SYSLOG+WALL+EXEC

View File

@ -12,7 +12,6 @@
name: nut name: nut
state: latest state: latest
update_cache: true update_cache: true
upgrade: false
- name: Setup NUT servers - name: Setup NUT servers
gather_facts: false gather_facts: false
@ -20,9 +19,9 @@
become: true become: true
roles: roles:
- role: acme_certificate - role: acme_certificate
vars: acme_certificate_subject: "{{ ansible_host }}"
acme_certificate_subject: "{{ ansible_hostname }}" acme_certificate_zone: balsillie.house
acme_certificate_zone: balsillie.house acme_certificate_restart_services: ['nut-server.service']
- role: nut_server - role: nut_server
- name: Setup NUT clients - name: Setup NUT clients

View File

@ -1,6 +1,26 @@
--- ---
- name: Create ACME account directory - name: Install required python libraries system wide
when: ansible_facts['os_family'] == "Archlinux"
community.general.pacman:
name:
- python-cryptography
- python-dnspython
state: latest
update_cache: true
- name: Set certificate path facts
ansible.builtin.set_fact:
acme_certificate_certificate_path: "/etc/ssl/private/{{ acme_certificate_subject }}.pem"
acme_certificate_chain_path: "/etc/ssl/private/{{ acme_certificate_subject }}.chain.pem"
acme_certificate_combined_path: "/etc/ssl/private/{{ acme_certificate_subject }}.combined.pem"
acme_certificate_csr_path: "/etc/ssl/private/{{ acme_certificate_subject }}.csr"
acme_certificate_fullchain_path: "/etc/ssl/private/{{ acme_certificate_subject }}.fullchain.pem"
acme_certificate_key_path: "/etc/ssl/private/{{ acme_certificate_subject }}.key"
acme_certificate_plain_combined_path: "/etc/ssl/private/{{ acme_certificate_subject }}.plain.combined.pem"
acme_certificate_plain_key_path: "/etc/ssl/private/{{ acme_certificate_subject }}.plain.key"
- name: Create ACME account key directory
ansible.builtin.file: ansible.builtin.file:
group: root group: root
mode: '0700' mode: '0700'
@ -12,29 +32,30 @@
community.crypto.openssl_privatekey: community.crypto.openssl_privatekey:
cipher: auto cipher: auto
curve: secp384r1 curve: secp384r1
format: pkcs1 format: auto_ignore
group: root group: root
mode: '0600' mode: '0600'
owner: root owner: root
passphrase: "{{ acme_certificate_account_key_passphrase }}" passphrase: "{{ acme_certificate_account_key_passphrase }}"
path: /etc/ssl/private/ACME/account.key path: /etc/ssl/private/ACME/account.key
size: 384 size: 4096
state: present state: present
type: Ed25519 type: RSA
- name: Generate RSA private key - name: Generate RSA private key
community.crypto.openssl_privatekey: community.crypto.openssl_privatekey:
cipher: auto cipher: auto
curve: secp384r1 curve: secp384r1
format: pkcs1 format: auto_ignore
group: root group: root
mode: '0600' mode: '0600'
owner: root owner: root
passphrase: "{{ ssl_passphrase }}" passphrase: "{{ ssl_passphrase }}"
path: "/etc/ssl/private/{{ acme_certificate_subject }}.key" path: "{{ acme_certificate_key_path }}"
size: 4096 size: 4096
state: present state: present
type: RSA type: RSA
register: genrsa_private_key
- name: Generate CSR - name: Generate CSR
community.crypto.openssl_csr: community.crypto.openssl_csr:
@ -47,8 +68,9 @@
mode: '0600' mode: '0600'
organization_name: "{{ acme_certificate_csr_organization }}" organization_name: "{{ acme_certificate_csr_organization }}"
owner: root owner: root
path: "/etc/ssl/private/{{ acme_certificate_subject }}.csr" path: "{{ acme_certificate_csr_path }}"
privatekey_path: "/etc/ssl/private/{{ acme_certificate_subject }}.key" privatekey_passphrase: "{{ ssl_passphrase }}"
privatekey_path: "{{ acme_certificate_key_path }}"
state: present state: present
state_or_province_name: "{{ acme_certificate_csr_state }}" state_or_province_name: "{{ acme_certificate_csr_state }}"
use_common_name_for_san: true use_common_name_for_san: true
@ -60,10 +82,11 @@
account_key_src: /etc/ssl/private/ACME/account.key account_key_src: /etc/ssl/private/ACME/account.key
acme_directory: "{{ acme_certificate_directory }}" acme_directory: "{{ acme_certificate_directory }}"
acme_version: 2 acme_version: 2
chain_dest: "/etc/ssl/private/{{ acme_certificate_subject }}.chain" chain_dest: "{{ acme_certificate_chain_path }}"
challenge: dns-01 challenge: dns-01
csr: "/etc/ssl/private/{{ acme_certificate_subject }}.csr" csr: "{{ acme_certificate_csr_path }}"
dest: "/etc/ssl/private/{{ acme_certificate_subject }}.crt" dest: "{{ acme_certificate_certificate_path }}"
fullchain_dest: "{{ acme_certificate_fullchain_path }}"
modify_account: true modify_account: true
select_crypto_backend: cryptography select_crypto_backend: cryptography
terms_agreed: true terms_agreed: true
@ -87,13 +110,18 @@
key_secret: "{{ rfc2136_key_secret }}" key_secret: "{{ rfc2136_key_secret }}"
port: 53 port: 53
protocol: tcp protocol: tcp
record: "{{ challenge.challenge_data[acme_certificate_subject]['dns-01'].record }}" record: "{{ challenge.challenge_data[acme_certificate_subject]['dns-01'].record }}."
server: "{{ rfc2136_server_address }}" server: "{{ rfc2136_server_address }}"
state: present state: present
ttl: 3600 ttl: 3600
type: TXT type: TXT
value: "{{ challenge.challenge_data[acme_certificate_subject]['dns-01'].resource_value }}" value: "{{ challenge.challenge_data[acme_certificate_subject]['dns-01'].resource_value }}"
zone: "{{ acme_certificate_zone }}" # zone: "{{ acme_certificate_zone }}"
register: nsupdate_result
- name: Debug nsupdate result
ansible.builtin.debug:
var: nsupdate_result
- name: Retrieve ACME certificate - name: Retrieve ACME certificate
community.crypto.acme_certificate: community.crypto.acme_certificate:
@ -102,12 +130,12 @@
account_key_src: /etc/ssl/private/ACME/account.key account_key_src: /etc/ssl/private/ACME/account.key
acme_directory: "{{ acme_certificate_directory }}" acme_directory: "{{ acme_certificate_directory }}"
acme_version: 2 acme_version: 2
chain_dest: "/etc/ssl/private/{{ acme_certificate_subject }}.chain" chain_dest: "{{ acme_certificate_chain_path }}"
challenge: dns-01 challenge: dns-01
csr: "/etc/ssl/private/{{ acme_certificate_subject }}.csr" csr: "{{ acme_certificate_csr_path }}"
data: "{{ challenge }}" data: "{{ challenge }}"
dest: "/etc/ssl/private/{{ acme_certificate_subject }}.crt" dest: "{{ acme_certificate_certificate_path }}"
modify_account: true fullchain_dest: "{{ acme_certificate_fullchain_path }}"
select_crypto_backend: cryptography select_crypto_backend: cryptography
terms_agreed: true terms_agreed: true
validate_certs: true validate_certs: true
@ -119,10 +147,72 @@
key_secret: "{{ rfc2136_key_secret }}" key_secret: "{{ rfc2136_key_secret }}"
port: 53 port: 53
protocol: tcp protocol: tcp
record: "{{ challenge.challenge_data[acme_certificate_subject]['dns-01'].record }}" record: "{{ challenge.challenge_data[acme_certificate_subject]['dns-01'].record }}."
server: "{{ rfc2136_server_address }}" server: "{{ rfc2136_server_address }}"
state: absent state: absent
ttl: 3600 ttl: 3600
type: TXT type: TXT
value: "{{ challenge.challenge_data[acme_certificate_subject]['dns-01'].resource_value }}" value: "{{ challenge.challenge_data[acme_certificate_subject]['dns-01'].resource_value }}"
zone: "{{ acme_certificate_zone }}" zone: "{{ acme_certificate_zone }}"
- name: Slurp fullchain contents
ansible.builtin.slurp:
src: "{{ acme_certificate_fullchain_path }}"
register: acme_certificate_fullchain_content
- name: Slurp private key contents
ansible.builtin.slurp:
src: "{{ acme_certificate_key_path }}"
register: acme_certificate_key_content
- name: Create combined cert file
ansible.builtin.template:
dest: "{{ acme_certificate_combined_path }}"
group: root
mode: '0600'
owner: root
src: combined.pem.j2
- name: Check if plain key file exists
ansible.builtin.stat:
path: "{{ acme_certificate_plain_key_path }}"
register: plain_key_file
- name: Create a plain text copy of the SSL private key # noqa: no-handler
when: |
genrsa_private_key.changed or
not plain_key_file.stat.exists
ansible.builtin.command:
cmd: openssl rsa -in {{ acme_certificate_key_path }} -passin pass:{{ ssl_passphrase }} -out {{ acme_certificate_plain_key_path }}
changed_when: true
- name: Slurp plain text private key contents
ansible.builtin.slurp:
src: "{{ acme_certificate_plain_key_path }}"
register: acme_certificate_key_content
- name: Create plain text combined cert file
ansible.builtin.template:
dest: "{{ acme_certificate_plain_combined_path }}"
group: root
mode: '0600'
owner: root
src: combined.pem.j2
- name: Dependant services block
when:
- (acme_certificate_restart_services | default([]) | length) >= 1
- challenge is changed
block:
- name: Check state of running services
ansible.builtin.service_facts:
- name: Restart dependant services
when:
- ansible_facts.services[item] is defined
- ansible_facts.services[item].state in ['running','failed']
ansible.builtin.service:
name: "{{ item }}"
state: restarted
loop: "{{ acme_certificate_restart_services }}"

View File

@ -0,0 +1,2 @@
{{ acme_certificate_fullchain_content['content'] | b64decode }}
{{ acme_certificate_key_content['content'] | b64decode }}

View File

@ -0,0 +1,5 @@
- name: Restart nut-monitor
when: not nut_monitor_started.changed
ansible.builtin.service:
name: nut-monitor.service
state: restarted

View File

@ -6,18 +6,32 @@
owner: root owner: root
group: nut group: nut
mode: '0640' mode: '0640'
notify:
- Restart nut-monitor
- name: Ensure nut-monitor systemd drop in directory exists
when: not ( nut_client_local_server | default(true) )
ansible.builtin.file:
path: /etc/systemd/system/nut-monitor.service.d
state: directory
owner: root
group: root
mode: '0755'
- name: Copy nut-monitor systemd drop in file - name: Copy nut-monitor systemd drop in file
when: not ( nut_client_local_server | default(true) ) when: not ( nut_client_local_server | default(true) )
ansible.builtin.template: ansible.builtin.copy:
src: nut-monitor_override.conf src: nut-monitor_override.conf
dest: /etc/systemd/system/nut-monitor.service.d/override.conf dest: /etc/systemd/system/nut-monitor.service.d/override.conf
owner: root owner: root
group: root group: root
mode: '0644' mode: '0644'
notify:
- Restart nut-monitor
- name: Start and enable nut-monitor - name: Start and enable nut-monitor
ansible.builtin.service: ansible.builtin.service:
name: nut-monitor name: nut-monitor.service
state: restarted state: started
enabled: true enabled: true
register: nut_monitor_started

View File

@ -1,6 +1,6 @@
# File configured by Ansible playbook # File configured by Ansible playbook
# Configuration reference: # Reference documentation:
# https://man.archlinux.org/man/upsmon.conf.5 # https://networkupstools.org/docs/man/upsmon.conf.html
{% for ups in nut_client_ups_devices %} {% for ups in nut_client_ups_devices %}
{% if ups.type == 'primary' %} {% if ups.type == 'primary' %}
@ -21,13 +21,13 @@ HOSTSYNC {{ nut_client_hostsync | default('30') }}
POLLFREQALERT 5 POLLFREQALERT 5
POLLFREQ 5 POLLFREQ 5
MINSUPPLIES {{ nut_client_min_supplies | default('1') }} MINSUPPLIES {{ nut_client_min_supplies | default('1') }}
CERTPATH /usr/ssl/certs CERTPATH /etc/ssl/certs
FORCESSL 1 FORCESSL 1
CERTVERIFY 1 CERTVERIFY 1
NOTIFYCMD {{ nut_client_notify_cmd | default('/usr/bin/notify-send') }} NOTIFYCMD "{{ nut_client_notify_cmd | default('/usr/bin/notify-send') }}"
{% for message in nut_client_notify_messages %} {% for message in (nut_client_notify_messages | default([])) %}
NOTIFYMSG {{ message.name }} {{ message.message }} NOTIFYMSG {{ message.name }} {{ message.message }}
{% endfor %} {% endfor %}
{% for notify in nut_client_notify_flags %} {% for notify in (nut_client_notify_flags | default([])) %}
NOTIFYFLAG {{ notify.name }} {{ notify.flags }} NOTIFYFLAG {{ notify.name }} {{ notify.flags }}
{% endfor %} {% endfor %}

View File

@ -0,0 +1,11 @@
- name: Restart nut-driver-enumerator
when: not nut_driver_enumerator_started.changed
ansible.builtin.service:
name: nut-driver-enumerator.service
state: restarted
- name: Restart nut-server
when: not nut_server_started.changed
ansible.builtin.service:
name: nut-server.service
state: restarted

View File

@ -1,43 +1,72 @@
- name: Template out ups.conf - name: Template out ups.conf
ansible.builtin.template: ansible.builtin.template:
src: ups.conf.j2
dest: /etc/nut/ups.conf dest: /etc/nut/ups.conf
owner: root
group: root group: root
mode: '0644' mode: '0644'
owner: root
- name: Start and enable nut-enumerator src: ups.conf.j2
ansible.builtin.service: trim_blocks: true
name: nut-driver-enumerator notify:
state: restarted - Restart nut-driver-enumerator
enabled: true
- name: Template out upsd.conf - name: Template out upsd.conf
ansible.builtin.template: ansible.builtin.template:
src: upsd.conf.j2
dest: /etc/nut/upsd.conf dest: /etc/nut/upsd.conf
owner: root
group: nut group: nut
mode: '0640' mode: '0640'
owner: root
src: upsd.conf.j2
trim_blocks: true
notify:
- Restart nut-server
- name: Template out upsd.users - name: Template out upsd.users
ansible.builtin.template: ansible.builtin.template:
src: upsd.users.j2
dest: /etc/nut/upsd.users dest: /etc/nut/upsd.users
owner: root
group: nut group: nut
mode: '0640' mode: '0640'
owner: root
src: upsd.users.j2
trim_blocks: true
notify:
- Restart nut-server
- name: Open nut server firewall port - name: Open nut server firewall port (UFW)
community.general.ufw: community.general.ufw:
rule: allow rule: allow
to_ip: "{{ nut_server_listen_address }}" to_ip: "{{ nut_server_listen_address | string }}"
to_port: "{{ nut_server_listen_port }}}}" to_port: "{{ nut_server_listen_port | string }}"
proto: tcp proto: tcp
comment: "NUT server" comment: "NUT server"
- name: Chown nut server cert to nut user
ansible.builtin.file:
group: nut
mode: '0600'
owner: nut
path: "{{ nut_server_certificate_file }}"
notify:
- Restart nut-server
- name: Start and enable nut-driver-enumerator
ansible.builtin.service:
name: nut-driver-enumerator.service
state: started
enabled: true
register: nut_driver_enumerator_started
- name: Start and enable nut-server - name: Start and enable nut-server
ansible.builtin.service: ansible.builtin.service:
name: nut-server name: nut-server.service
state: restarted state: started
enabled: true enabled: true
register: nut_server_started
- name: Start and enable nut targets
ansible.builtin.service:
name: "{{ item }}"
state: started
enabled: true
loop:
- nut-driver.target
- nut.target

View File

@ -1,5 +1,12 @@
{% for ups in ups_devices %} # File configured via Ansible playbook
[ups{{ loop.index }}] # Reference documentation:
# https://networkupstools.org/docs/man/ups.conf.html
maxretry = 5
{% for ups in nut_server_ups_devices %}
[{{ ups.name }}]
driver = {{ ups.driver }} driver = {{ ups.driver }}
port = {{ ups.port }} port = {{ ups.port }}
{% endfor %} {% endfor %}

View File

@ -0,0 +1,18 @@
# File configured via Ansible playbook
# Reference documentation:
# https://networkupstools.org/docs/man/upsd.conf.html
# MAXAGE 15
# TRACKINGDELAY 3600
# ALLOW_NO_DEVICE false
# STATEPATH /var/run/nut
LISTEN {{ nut_server_listen_address }} {{ nut_server_listen_port }}
LISTEN localhost {{ nut_server_listen_port }}
# MAXCONN 1024
CERTFILE {{ nut_server_certificate_file }}
# CERTPATH /usr/local/ups/etc/cert/upsd
# CERTIDENT "my nut server" "MyPasSw0rD"
# CERTREQUEST REQUIRE
DISABLE_WEAK_SSL true
# DEBUG_MIN 2

View File

@ -1,11 +1,17 @@
# File configured via Ansible playbook
# Reference documentation:
# https://networkupstools.org/docs/man/upsd.users.html
[{{ nut_client_admin_username }}]
password = {{ nut_client_admin_password }}
actions = set
actions = fsd
instcmds = all
[{{ nut_client_primary_username }}] [{{ nut_client_primary_username }}]
password = {{ nut_client_primary_password }} password = {{ nut_client_primary_password }}
upsmon primary upsmon primary
actions = SET
instcmds = ALL
[{{ nut_client_secondary_username }}] [{{ nut_client_secondary_username }}]
password = {{ nut_client_secondary_password }} password = {{ nut_client_secondary_password }}
upsmon secondary upsmon secondary
actions = SET
instcmds = ALL