From 30ec8c1bb12db8dce3b448484d1225de957db5c1 Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Sun, 7 Jul 2024 22:24:24 +1000 Subject: [PATCH 1/4] feat: enable retrieval of certbot certs - refactor certbot - add nginx to certbot hosts --- hieradata/country/au/region/syd1.yaml | 1 + hieradata/roles/infra/pki/certbot.eyaml | 2 +- hieradata/roles/infra/pki/certbot.yaml | 2 +- site/profiles/manifests/certbot/haproxy.pp | 9 ++ site/profiles/manifests/certbot/init.pp | 11 +++ .../certbot/{server.pp => letsencrypt.pp} | 15 +--- site/profiles/manifests/certbot/nginx.pp | 89 +++++++++++++++++++ site/profiles/manifests/pki/letsencrypt.pp | 26 ++++++ site/roles/manifests/infra/pki/certbot.pp | 2 +- 9 files changed, 143 insertions(+), 14 deletions(-) create mode 100644 site/profiles/manifests/certbot/haproxy.pp create mode 100644 site/profiles/manifests/certbot/init.pp rename site/profiles/manifests/certbot/{server.pp => letsencrypt.pp} (60%) create mode 100644 site/profiles/manifests/certbot/nginx.pp create mode 100644 site/profiles/manifests/pki/letsencrypt.pp diff --git a/hieradata/country/au/region/syd1.yaml b/hieradata/country/au/region/syd1.yaml index 2a744b7..1fda3f9 100644 --- a/hieradata/country/au/region/syd1.yaml +++ b/hieradata/country/au/region/syd1.yaml @@ -1,2 +1,3 @@ --- timezone::timezone: 'Australia/Sydney' +profiles::pki::letsencrypt: ausyd1nxvm1021.main.unkin.net diff --git a/hieradata/roles/infra/pki/certbot.eyaml b/hieradata/roles/infra/pki/certbot.eyaml index cd3cd9c..d749727 100644 --- a/hieradata/roles/infra/pki/certbot.eyaml +++ b/hieradata/roles/infra/pki/certbot.eyaml @@ -1,2 +1,2 @@ --- -profiles::certbot::server::contact: ENC[PKCS7,MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAJxDjhvXONEm7VoZ74dBxOPxFAw9RrI2WOK1P5YiIWiXUkoOhQpPzy0PUlI4970ActfTi9Kr9fnyZJWr/7TQ/5GQuYvVxMcfWbOmIOA+6CCjR/PWR06lWQuq7eTmwTzQjw7teFZrpXmqutAMNAUEAmPBBKNKfKbOaFz4IWwph1TuXtXDuveu/RE2+8znWukhF92DuFBJSuw6SMDympdbgceq/guQAInMjIXwmCIa7DWCWYDSKw04Ai8yDnYoqaNRs0acbZV6slH49i/cOE6GKTxO8+vR/3TkjEvKH8lY2l37ndH9+pe58arKflm/Inik0zy0TBnHq7/AMmEpRtV0usTA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBUgafckUM981Pb6hn2/9KMgBAblakRJjULF7aZwx/PT09s] +profiles::certbot::init::contact: ENC[PKCS7,MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAJxDjhvXONEm7VoZ74dBxOPxFAw9RrI2WOK1P5YiIWiXUkoOhQpPzy0PUlI4970ActfTi9Kr9fnyZJWr/7TQ/5GQuYvVxMcfWbOmIOA+6CCjR/PWR06lWQuq7eTmwTzQjw7teFZrpXmqutAMNAUEAmPBBKNKfKbOaFz4IWwph1TuXtXDuveu/RE2+8znWukhF92DuFBJSuw6SMDympdbgceq/guQAInMjIXwmCIa7DWCWYDSKw04Ai8yDnYoqaNRs0acbZV6slH49i/cOE6GKTxO8+vR/3TkjEvKH8lY2l37ndH9+pe58arKflm/Inik0zy0TBnHq7/AMmEpRtV0usTA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBUgafckUM981Pb6hn2/9KMgBAblakRJjULF7aZwx/PT09s] diff --git a/hieradata/roles/infra/pki/certbot.yaml b/hieradata/roles/infra/pki/certbot.yaml index d37c8d5..d450604 100644 --- a/hieradata/roles/infra/pki/certbot.yaml +++ b/hieradata/roles/infra/pki/certbot.yaml @@ -1,5 +1,5 @@ --- -profiles::certbot::server::domains: +profiles::certbot::init::domains: - au-syd1-pve.main.unkin.net - au-syd1-pve-api.main.unkin.net - sonarr.main.unkin.net diff --git a/site/profiles/manifests/certbot/haproxy.pp b/site/profiles/manifests/certbot/haproxy.pp new file mode 100644 index 0000000..5fa264b --- /dev/null +++ b/site/profiles/manifests/certbot/haproxy.pp @@ -0,0 +1,9 @@ +# profiles::certbot::haproxy +class profiles::certbot::haproxy { + # export haproxy balancemember + profiles::haproxy::balancemember { "${facts['networking']['fqdn']}_8888": + service => 'be_letsencrypt', + ports => [8888], + options => [] + } +} diff --git a/site/profiles/manifests/certbot/init.pp b/site/profiles/manifests/certbot/init.pp new file mode 100644 index 0000000..e03e311 --- /dev/null +++ b/site/profiles/manifests/certbot/init.pp @@ -0,0 +1,11 @@ +# profiles::certbot::init +class profiles::certbot::init ( + String $contact, + Array[Stdlib::Fqdn] $domains = [], +) { + + include profiles::certbot::nginx + include profiles::certbot::haproxy + include profiles::certbot::letsencrypt + +} diff --git a/site/profiles/manifests/certbot/server.pp b/site/profiles/manifests/certbot/letsencrypt.pp similarity index 60% rename from site/profiles/manifests/certbot/server.pp rename to site/profiles/manifests/certbot/letsencrypt.pp index 30b1179..be9299e 100644 --- a/site/profiles/manifests/certbot/server.pp +++ b/site/profiles/manifests/certbot/letsencrypt.pp @@ -1,7 +1,7 @@ -# profiles::certbot::server -class profiles::certbot::server ( - String $contact, - Array[Stdlib::Fqdn] $domains = [], +# profiles::certbot::letsencrypt +class profiles::certbot::letsencrypt ( + String $contact = $profiles::certbot::init::contact, + Array[Stdlib::Fqdn] $domains = $profiles::certbot::init::domains, ) { class { 'letsencrypt': @@ -22,11 +22,4 @@ class profiles::certbot::server ( domain => $domain, } } - - # export haproxy balancemember - profiles::haproxy::balancemember { "${facts['networking']['fqdn']}_8888": - service => 'be_letsencrypt', - ports => [8888], - options => [] - } } diff --git a/site/profiles/manifests/certbot/nginx.pp b/site/profiles/manifests/certbot/nginx.pp new file mode 100644 index 0000000..87d2cee --- /dev/null +++ b/site/profiles/manifests/certbot/nginx.pp @@ -0,0 +1,89 @@ +# profiles::certbot::nginx +class profiles::certbot::nginx ( + Stdlib::Absolutepath $data_root = '/var/www/', + Stdlib::Fqdn $nginx_vhost = $facts['networking']['fqdn'], + Array[Stdlib::Host] $nginx_aliases = [], + Stdlib::Port $nginx_port = 80, + Stdlib::Port $nginx_ssl_port = 443, + Enum['http','https','both'] $nginx_listen_mode = 'https', + Enum['puppet', 'vault'] $nginx_cert_type = 'vault', +) { + + # select the certificates to use based on cert type + case $nginx_cert_type { + 'puppet': { + $selected_ssl_cert = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.crt" + $selected_ssl_key = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.key" + } + 'vault': { + $selected_ssl_cert = '/etc/pki/tls/vault/certificate.crt' + $selected_ssl_key = '/etc/pki/tls/vault/private.key' + } + default: { + # enum param prevents this ever being reached + } + } + + # set variables based on the listen_mode + case $nginx_listen_mode { + 'http': { + $enable_ssl = false + $ssl_cert = undef + $ssl_key = undef + $listen_port = $nginx_port + $listen_ssl_port = undef + $extras_hash = {} + } + 'https': { + $enable_ssl = true + $ssl_cert = $selected_ssl_cert + $ssl_key = $selected_ssl_key + $listen_port = $nginx_ssl_port + $listen_ssl_port = $nginx_ssl_port + $extras_hash = { + 'subscribe' => [File[$ssl_cert], File[$ssl_key]], + } + } + 'both': { + $enable_ssl = true + $ssl_cert = $selected_ssl_cert + $ssl_key = $selected_ssl_key + $listen_port = $nginx_port + $listen_ssl_port = $nginx_ssl_port + $extras_hash = { + 'subscribe' => [File[$ssl_cert], File[$ssl_key]], + } + } + default: { + # enum param prevents this ever being reached + } + } + + # set the server_names + $server_names = unique([$facts['networking']['fqdn'], $nginx_vhost] + $nginx_aliases) + + # define the default parameters for the nginx server + $defaults = { + 'listen_port' => $listen_port, + 'server_name' => $server_names, + 'use_default_location' => true, + 'access_log' => "/var/log/nginx/${nginx_vhost}_access.log", + 'error_log' => "/var/log/nginx/${nginx_vhost}_error.log", + 'www_root' => "${data_root}/pub", + 'autoindex' => 'on', + 'ssl' => $enable_ssl, + 'ssl_cert' => $ssl_cert, + 'ssl_key' => $ssl_key, + 'ssl_port' => $listen_ssl_port, + } + + # merge the hashes conditionally + $nginx_parameters = merge($defaults, $extras_hash) + + # manage the nginx class + include nginx + + # create the nginx vhost with the merged parameters + create_resources('nginx::resource::server', { $nginx_vhost => $nginx_parameters }) + +} diff --git a/site/profiles/manifests/pki/letsencrypt.pp b/site/profiles/manifests/pki/letsencrypt.pp new file mode 100644 index 0000000..f639673 --- /dev/null +++ b/site/profiles/manifests/pki/letsencrypt.pp @@ -0,0 +1,26 @@ +define profiles::pki::letsencrypt ( + Stdlib::Fqdn $webserver, + Stdlib::Fqdn $domain, + Stdlib::Absolutepath $destination = "/etc/pki/tls/letsencrypt/${domain}", +) { + + file { $destination: + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + } + + $cert_files = ['cert.pem', 'chain.pem', 'fullchain.pem', 'privkey.pem'] + + $cert_files.each |String $file| { + file { "${destination}/${file}": + ensure => file, + source => "https://${webserver}/${domain}/${file}", + owner => 'root', + group => 'root', + mode => '0644', + require => File[$destination], + } + } +} diff --git a/site/roles/manifests/infra/pki/certbot.pp b/site/roles/manifests/infra/pki/certbot.pp index 1fa464c..e1cc2e6 100644 --- a/site/roles/manifests/infra/pki/certbot.pp +++ b/site/roles/manifests/infra/pki/certbot.pp @@ -6,6 +6,6 @@ class roles::infra::pki::certbot { }else{ include profiles::defaults include profiles::base - include profiles::certbot::server + include profiles::certbot::init } } From bd5164fed3c79179b0ce960bdbde2e9b662caf4c Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Mon, 8 Jul 2024 20:22:44 +1000 Subject: [PATCH 2/4] feat: certbot reorg - moved certbot into its own module - added fact to list available certificates - created systemd timer to rsync data to $data_dir/pub - ensure the $data_dir/pub exists - manage selinux for nginx --- hieradata/common.yaml | 4 +- hieradata/country/au/region/syd1.yaml | 2 +- .../au/region/syd1/infra/halb/haproxy.yaml | 11 ++++ hieradata/roles/infra/pki/certbot.eyaml | 2 +- hieradata/roles/infra/pki/certbot.yaml | 6 ++- .../lib/facter/certbot_available_certs.rb | 18 +++++++ .../certbot/manifests}/cert.pp | 4 +- modules/certbot/manifests/client.pp | 23 +++++++++ modules/certbot/manifests/client/cert.pp | 51 +++++++++++++++++++ .../certbot/manifests}/haproxy.pp | 4 +- modules/certbot/manifests/init.pp | 19 +++++++ modules/certbot/manifests/letsencrypt.pp | 37 ++++++++++++++ .../certbot/manifests}/nginx.pp | 20 ++++---- modules/certbot/manifests/selinux.pp | 28 ++++++++++ .../templates/certbot-syncer.service.epp | 10 ++++ .../templates/certbot-syncer.timer.epp | 9 ++++ site/profiles/manifests/certbot/init.pp | 11 ---- .../profiles/manifests/certbot/letsencrypt.pp | 25 --------- site/profiles/manifests/haproxy/server.pp | 1 + site/profiles/manifests/pki/letsencrypt.pp | 26 ---------- site/roles/manifests/infra/pki/certbot.pp | 1 - 21 files changed, 232 insertions(+), 80 deletions(-) create mode 100644 modules/certbot/lib/facter/certbot_available_certs.rb rename {site/profiles/manifests/certbot => modules/certbot/manifests}/cert.pp (86%) create mode 100644 modules/certbot/manifests/client.pp create mode 100644 modules/certbot/manifests/client/cert.pp rename {site/profiles/manifests/certbot => modules/certbot/manifests}/haproxy.pp (74%) create mode 100644 modules/certbot/manifests/init.pp create mode 100644 modules/certbot/manifests/letsencrypt.pp rename {site/profiles/manifests/certbot => modules/certbot/manifests}/nginx.pp (81%) create mode 100644 modules/certbot/manifests/selinux.pp create mode 100644 modules/certbot/templates/certbot-syncer.service.epp create mode 100644 modules/certbot/templates/certbot-syncer.timer.epp delete mode 100644 site/profiles/manifests/certbot/init.pp delete mode 100644 site/profiles/manifests/certbot/letsencrypt.pp delete mode 100644 site/profiles/manifests/pki/letsencrypt.pp diff --git a/hieradata/common.yaml b/hieradata/common.yaml index 17e2ae0..ad6c16f 100644 --- a/hieradata/common.yaml +++ b/hieradata/common.yaml @@ -132,7 +132,9 @@ lookup_options: profiles::nginx::simpleproxy::locations: merge: strategy: deep - + certbot::client::domains: + merge: + strategy: deep facts_path: '/opt/puppetlabs/facter/facts.d' diff --git a/hieradata/country/au/region/syd1.yaml b/hieradata/country/au/region/syd1.yaml index 1fda3f9..4175d66 100644 --- a/hieradata/country/au/region/syd1.yaml +++ b/hieradata/country/au/region/syd1.yaml @@ -1,3 +1,3 @@ --- timezone::timezone: 'Australia/Sydney' -profiles::pki::letsencrypt: ausyd1nxvm1021.main.unkin.net +certbot::client::webserver: ausyd1nxvm1021.main.unkin.net diff --git a/hieradata/country/au/region/syd1/infra/halb/haproxy.yaml b/hieradata/country/au/region/syd1/infra/halb/haproxy.yaml index c6e3cd1..63f1116 100644 --- a/hieradata/country/au/region/syd1/infra/halb/haproxy.yaml +++ b/hieradata/country/au/region/syd1/infra/halb/haproxy.yaml @@ -201,3 +201,14 @@ profiles::pki::vault::alt_names: profiles::haproxy::dns::cnames: - au-syd1-pve.main.unkin.net - au-syd1-pve-api.main.unkin.net + +# letsencrypt certificates +certbot::client::domains: + - au-syd1-pve.main.unkin.net + - au-syd1-pve-api.main.unkin.net + - sonarr.main.unkin.net + - radarr.main.unkin.net + - lidarr.main.unkin.net + - readarr.main.unkin.net + - prowlarr.main.unkin.net + - fafflix.unkin.net diff --git a/hieradata/roles/infra/pki/certbot.eyaml b/hieradata/roles/infra/pki/certbot.eyaml index d749727..12da70b 100644 --- a/hieradata/roles/infra/pki/certbot.eyaml +++ b/hieradata/roles/infra/pki/certbot.eyaml @@ -1,2 +1,2 @@ --- -profiles::certbot::init::contact: ENC[PKCS7,MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAJxDjhvXONEm7VoZ74dBxOPxFAw9RrI2WOK1P5YiIWiXUkoOhQpPzy0PUlI4970ActfTi9Kr9fnyZJWr/7TQ/5GQuYvVxMcfWbOmIOA+6CCjR/PWR06lWQuq7eTmwTzQjw7teFZrpXmqutAMNAUEAmPBBKNKfKbOaFz4IWwph1TuXtXDuveu/RE2+8znWukhF92DuFBJSuw6SMDympdbgceq/guQAInMjIXwmCIa7DWCWYDSKw04Ai8yDnYoqaNRs0acbZV6slH49i/cOE6GKTxO8+vR/3TkjEvKH8lY2l37ndH9+pe58arKflm/Inik0zy0TBnHq7/AMmEpRtV0usTA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBUgafckUM981Pb6hn2/9KMgBAblakRJjULF7aZwx/PT09s] +certbot::contact: ENC[PKCS7,MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAJxDjhvXONEm7VoZ74dBxOPxFAw9RrI2WOK1P5YiIWiXUkoOhQpPzy0PUlI4970ActfTi9Kr9fnyZJWr/7TQ/5GQuYvVxMcfWbOmIOA+6CCjR/PWR06lWQuq7eTmwTzQjw7teFZrpXmqutAMNAUEAmPBBKNKfKbOaFz4IWwph1TuXtXDuveu/RE2+8znWukhF92DuFBJSuw6SMDympdbgceq/guQAInMjIXwmCIa7DWCWYDSKw04Ai8yDnYoqaNRs0acbZV6slH49i/cOE6GKTxO8+vR/3TkjEvKH8lY2l37ndH9+pe58arKflm/Inik0zy0TBnHq7/AMmEpRtV0usTA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBUgafckUM981Pb6hn2/9KMgBAblakRJjULF7aZwx/PT09s] diff --git a/hieradata/roles/infra/pki/certbot.yaml b/hieradata/roles/infra/pki/certbot.yaml index d450604..40d8cba 100644 --- a/hieradata/roles/infra/pki/certbot.yaml +++ b/hieradata/roles/infra/pki/certbot.yaml @@ -1,5 +1,9 @@ --- -profiles::certbot::init::domains: +hiera_include: + - certbot + - profiles::pki::puppetcerts + +certbot::domains: - au-syd1-pve.main.unkin.net - au-syd1-pve-api.main.unkin.net - sonarr.main.unkin.net diff --git a/modules/certbot/lib/facter/certbot_available_certs.rb b/modules/certbot/lib/facter/certbot_available_certs.rb new file mode 100644 index 0000000..cfbe2af --- /dev/null +++ b/modules/certbot/lib/facter/certbot_available_certs.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +Facter.add(:certbot_available_certs) do + confine enc_role: 'roles::infra::pki::certbot' + setcode do + certs_dir = '/etc/letsencrypt/live' + available_certs = [] + + if Dir.exist?(certs_dir) + Dir.children(certs_dir).each do |entry| + fullchain_pem = File.join(certs_dir, entry, 'fullchain.pem') + available_certs << entry if File.exist?(fullchain_pem) + end + end + + available_certs.join(',') + end +end diff --git a/site/profiles/manifests/certbot/cert.pp b/modules/certbot/manifests/cert.pp similarity index 86% rename from site/profiles/manifests/certbot/cert.pp rename to modules/certbot/manifests/cert.pp index 0496095..f923769 100644 --- a/site/profiles/manifests/certbot/cert.pp +++ b/modules/certbot/manifests/cert.pp @@ -1,5 +1,5 @@ -# profiles::certbot::cert -define profiles::certbot::cert ( +# certbot::cert +define certbot::cert ( Stdlib::Fqdn $domain, Array $additional_args = ['--http-01-port=8888'], Boolean $manage_cron = true, diff --git a/modules/certbot/manifests/client.pp b/modules/certbot/manifests/client.pp new file mode 100644 index 0000000..3ca6ef3 --- /dev/null +++ b/modules/certbot/manifests/client.pp @@ -0,0 +1,23 @@ +class certbot::client ( + Array[Stdlib::Fqdn] $domains, + Stdlib::Fqdn $webserver, + Stdlib::Absolutepath $data_dir = '/etc/pki/tls/letsencrypt/', +) { + + mkdir::p {$data_dir:} + file { $data_dir: + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + } + + $domains.each |$domain| { + certbot::client::cert {"${facts['networking']['fqdn']}_download_${domain}": + domain => $domain, + destination => "${data_dir}/${domain}", + webserver => $webserver, + require => File[$data_dir], + } + } +} diff --git a/modules/certbot/manifests/client/cert.pp b/modules/certbot/manifests/client/cert.pp new file mode 100644 index 0000000..b4773dd --- /dev/null +++ b/modules/certbot/manifests/client/cert.pp @@ -0,0 +1,51 @@ +define certbot::client::cert ( + Stdlib::Fqdn $domain, + Stdlib::Fqdn $webserver, + Stdlib::Absolutepath $destination = "/etc/pki/tls/letsencrypt/${domain}", +) { + + file { $destination: + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + } + + $cert_ready_nodes = puppetdb_query(" + facts { + name = 'certbot_available_certs' and value ~ '${domain}' and certname = '${webserver}' + }" + ) + + # Define the certificate files + $cert_files = ['cert.pem', 'chain.pem', 'fullchain.pem', 'privkey.pem'] + + if !empty($cert_ready_nodes) { + $files_to_create = $cert_files.reduce({}) |$acc, $file| { + $acc + { + "${destination}/${file}" => { + ensure => 'file', + source => "https://${webserver}/${domain}/${file}", + owner => 'root', + group => 'root', + mode => '0644', + notify => Exec["concat_${domain}_certs"], + } + } + } + + create_resources(file, $files_to_create) + + exec { "concat_${domain}_certs": + command => "cat ${destination}/fullchain.pem ${destination}/privkey.pem > ${destination}/fullchain_combined.pem", + path => ['/bin', '/usr/bin'], + refreshonly => true, + require => [ + File["${destination}/fullchain.pem"], + File["${destination}/privkey.pem"], + ], + } + } else { + notify { 'Certificates are not yet ready on the generator server.': } + } +} diff --git a/site/profiles/manifests/certbot/haproxy.pp b/modules/certbot/manifests/haproxy.pp similarity index 74% rename from site/profiles/manifests/certbot/haproxy.pp rename to modules/certbot/manifests/haproxy.pp index 5fa264b..ea61ad5 100644 --- a/site/profiles/manifests/certbot/haproxy.pp +++ b/modules/certbot/manifests/haproxy.pp @@ -1,5 +1,5 @@ -# profiles::certbot::haproxy -class profiles::certbot::haproxy { +# certbot::haproxy +class certbot::haproxy { # export haproxy balancemember profiles::haproxy::balancemember { "${facts['networking']['fqdn']}_8888": service => 'be_letsencrypt', diff --git a/modules/certbot/manifests/init.pp b/modules/certbot/manifests/init.pp new file mode 100644 index 0000000..a32914f --- /dev/null +++ b/modules/certbot/manifests/init.pp @@ -0,0 +1,19 @@ +# certbot::init +class certbot ( + String $contact, + Array[Stdlib::Fqdn] $domains = [], + Stdlib::Absolutepath $data_root = '/var/www', + Stdlib::Fqdn $nginx_vhost = $facts['networking']['fqdn'], + Array[Stdlib::Host] $nginx_aliases = [], + Stdlib::Port $nginx_port = 80, + Stdlib::Port $nginx_ssl_port = 443, + Enum['http','https','both'] $nginx_listen_mode = 'https', + Enum['puppet', 'vault'] $nginx_cert_type = 'puppet', +) { + + include certbot::nginx + include certbot::selinux + include certbot::haproxy + include certbot::letsencrypt + +} diff --git a/modules/certbot/manifests/letsencrypt.pp b/modules/certbot/manifests/letsencrypt.pp new file mode 100644 index 0000000..29b6c47 --- /dev/null +++ b/modules/certbot/manifests/letsencrypt.pp @@ -0,0 +1,37 @@ +# certbot::letsencrypt +class certbot::letsencrypt ( + String $contact = $certbot::contact, + Array[Stdlib::Fqdn] $domains = $certbot::domains, + Stdlib::Absolutepath $data_root = $certbot::data_root, +) { + + class { 'letsencrypt': + configure_epel => false, + package_ensure => 'latest', + email => $contact, + } + + # set location_environment + $location_environment = "${facts['country']}-${facts['region']}-${facts['environment']}" + + # collect exported resources + Letsencrypt::Certonly <<| tag == $location_environment |>> + + # statically defined certificate + $domains.each | $domain | { + certbot::cert {$domain: + domain => $domain, + require => Class['letsencrypt'], + } + } + + systemd::timer { 'certbot-syncer.timer': + timer_content => epp('certbot/certbot-syncer.timer.epp'), + service_content => epp('certbot/certbot-syncer.service.epp', { + 'data_root' => $data_root, + }), + active => true, + enable => true, + require => Class['letsencrypt'], + } +} diff --git a/site/profiles/manifests/certbot/nginx.pp b/modules/certbot/manifests/nginx.pp similarity index 81% rename from site/profiles/manifests/certbot/nginx.pp rename to modules/certbot/manifests/nginx.pp index 87d2cee..5170aff 100644 --- a/site/profiles/manifests/certbot/nginx.pp +++ b/modules/certbot/manifests/nginx.pp @@ -1,12 +1,12 @@ -# profiles::certbot::nginx -class profiles::certbot::nginx ( - Stdlib::Absolutepath $data_root = '/var/www/', - Stdlib::Fqdn $nginx_vhost = $facts['networking']['fqdn'], - Array[Stdlib::Host] $nginx_aliases = [], - Stdlib::Port $nginx_port = 80, - Stdlib::Port $nginx_ssl_port = 443, - Enum['http','https','both'] $nginx_listen_mode = 'https', - Enum['puppet', 'vault'] $nginx_cert_type = 'vault', +# certbot::nginx +class certbot::nginx ( + Stdlib::Absolutepath $data_root = $certbot::data_root, + Stdlib::Fqdn $nginx_vhost = $certbot::nginx_vhost, + Array[Stdlib::Host] $nginx_aliases = $certbot::nginx_aliases, + Stdlib::Port $nginx_port = $certbot::nginx_port, + Stdlib::Port $nginx_ssl_port = $certbot::nginx_ssl_port, + Enum['http','https','both'] $nginx_listen_mode = $certbot::nginx_listen_mode, + Enum['puppet', 'vault'] $nginx_cert_type = $certbot::nginx_cert_type, ) { # select the certificates to use based on cert type @@ -59,6 +59,8 @@ class profiles::certbot::nginx ( } } + mkdir::p {"${data_root}/pub":} + # set the server_names $server_names = unique([$facts['networking']['fqdn'], $nginx_vhost] + $nginx_aliases) diff --git a/modules/certbot/manifests/selinux.pp b/modules/certbot/manifests/selinux.pp new file mode 100644 index 0000000..71e2c70 --- /dev/null +++ b/modules/certbot/manifests/selinux.pp @@ -0,0 +1,28 @@ +# certbot::selinux +class certbot::selinux ( + Stdlib::Absolutepath $data_root = $certbot::data_root, +) { + + if $::facts['os']['selinux']['config_mode'] == 'enforcing' { + + # set httpd_sys_content_t to all files under the www_root + selinux::fcontext { "${data_root}/pub": + ensure => 'present', + seltype => 'httpd_sys_content_t', + pathspec => "${data_root}/pub(/.*)?", + } + + # make sure we can connect to other hosts + selboolean { 'httpd_can_network_connect': + persistent => true, + value => 'on', + } + + exec { "restorecon_${data_root}/pub": + path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'], + command => "restorecon -Rv ${data_root}/pub", + refreshonly => true, + subscribe => Selinux::Fcontext["${data_root}/pub"], + } + } +} diff --git a/modules/certbot/templates/certbot-syncer.service.epp b/modules/certbot/templates/certbot-syncer.service.epp new file mode 100644 index 0000000..4123ffe --- /dev/null +++ b/modules/certbot/templates/certbot-syncer.service.epp @@ -0,0 +1,10 @@ +[Unit] +Description=certbot-syncer service + +[Service] +Type=oneshot +ExecStart=/usr/bin/rsync --chmod=D2755,F644 -aL /etc/letsencrypt/live/ <%= $data_root %>/pub/ +User=root +Group=root +PermissionsStartOnly=false +PrivateTmp=no diff --git a/modules/certbot/templates/certbot-syncer.timer.epp b/modules/certbot/templates/certbot-syncer.timer.epp new file mode 100644 index 0000000..52903b8 --- /dev/null +++ b/modules/certbot/templates/certbot-syncer.timer.epp @@ -0,0 +1,9 @@ +[Unit] +Description=certbot-syncer timer + +[Timer] +OnCalendar=hourly +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/site/profiles/manifests/certbot/init.pp b/site/profiles/manifests/certbot/init.pp deleted file mode 100644 index e03e311..0000000 --- a/site/profiles/manifests/certbot/init.pp +++ /dev/null @@ -1,11 +0,0 @@ -# profiles::certbot::init -class profiles::certbot::init ( - String $contact, - Array[Stdlib::Fqdn] $domains = [], -) { - - include profiles::certbot::nginx - include profiles::certbot::haproxy - include profiles::certbot::letsencrypt - -} diff --git a/site/profiles/manifests/certbot/letsencrypt.pp b/site/profiles/manifests/certbot/letsencrypt.pp deleted file mode 100644 index be9299e..0000000 --- a/site/profiles/manifests/certbot/letsencrypt.pp +++ /dev/null @@ -1,25 +0,0 @@ -# profiles::certbot::letsencrypt -class profiles::certbot::letsencrypt ( - String $contact = $profiles::certbot::init::contact, - Array[Stdlib::Fqdn] $domains = $profiles::certbot::init::domains, -) { - - class { 'letsencrypt': - configure_epel => false, - package_ensure => 'latest', - email => $contact, - } - - # set location_environment - $location_environment = "${facts['country']}-${facts['region']}-${facts['environment']}" - - # collect exported resources - Letsencrypt::Certonly <<| tag == $location_environment |>> - - # statically defined certificate - $domains.each | $domain | { - profiles::certbot::cert {$domain: - domain => $domain, - } - } -} diff --git a/site/profiles/manifests/haproxy/server.pp b/site/profiles/manifests/haproxy/server.pp index b16da8e..b19ab18 100644 --- a/site/profiles/manifests/haproxy/server.pp +++ b/site/profiles/manifests/haproxy/server.pp @@ -48,6 +48,7 @@ class profiles::haproxy::server ( require => Class['profiles::haproxy::selinux'] } + include certbot::client # download certbot certs include profiles::haproxy::certlist # manage the certificate list file include profiles::haproxy::mappings # manage the domain to backend mappings include profiles::haproxy::ls_stats # default status listener diff --git a/site/profiles/manifests/pki/letsencrypt.pp b/site/profiles/manifests/pki/letsencrypt.pp deleted file mode 100644 index f639673..0000000 --- a/site/profiles/manifests/pki/letsencrypt.pp +++ /dev/null @@ -1,26 +0,0 @@ -define profiles::pki::letsencrypt ( - Stdlib::Fqdn $webserver, - Stdlib::Fqdn $domain, - Stdlib::Absolutepath $destination = "/etc/pki/tls/letsencrypt/${domain}", -) { - - file { $destination: - ensure => directory, - owner => 'root', - group => 'root', - mode => '0755', - } - - $cert_files = ['cert.pem', 'chain.pem', 'fullchain.pem', 'privkey.pem'] - - $cert_files.each |String $file| { - file { "${destination}/${file}": - ensure => file, - source => "https://${webserver}/${domain}/${file}", - owner => 'root', - group => 'root', - mode => '0644', - require => File[$destination], - } - } -} diff --git a/site/roles/manifests/infra/pki/certbot.pp b/site/roles/manifests/infra/pki/certbot.pp index e1cc2e6..357d1a6 100644 --- a/site/roles/manifests/infra/pki/certbot.pp +++ b/site/roles/manifests/infra/pki/certbot.pp @@ -6,6 +6,5 @@ class roles::infra::pki::certbot { }else{ include profiles::defaults include profiles::base - include profiles::certbot::init } } From 899e2cbf49ff4b8f81850261210dfef7edc4243a Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Mon, 8 Jul 2024 22:56:24 +1000 Subject: [PATCH 3/4] feat: haproxy updates - use letsencrypt certificates - add fafflix and jellyfin backends --- .../au/region/syd1/infra/halb/haproxy.yaml | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/hieradata/country/au/region/syd1/infra/halb/haproxy.yaml b/hieradata/country/au/region/syd1/infra/halb/haproxy.yaml index 63f1116..78e59fc 100644 --- a/hieradata/country/au/region/syd1/infra/halb/haproxy.yaml +++ b/hieradata/country/au/region/syd1/infra/halb/haproxy.yaml @@ -12,6 +12,7 @@ profiles::haproxy::mappings: - 'readarr.main.unkin.net be_readarr' - 'prowlarr.main.unkin.net be_prowlarr' - 'jellyfin.main.unkin.net be_jellyfin' + - 'fafflix.unkin.net be_jellyfin' fe_https: ensure: present mappings: @@ -23,6 +24,7 @@ profiles::haproxy::mappings: - 'readarr.main.unkin.net be_readarr' - 'prowlarr.main.unkin.net be_prowlarr' - 'jellyfin.main.unkin.net be_jellyfin' + - 'fafflix.unkin.net be_jellyfin' profiles::haproxy::frontends: fe_http: @@ -32,12 +34,14 @@ profiles::haproxy::frontends: fe_https: options: acl: - - 'acl_ausyd1pve req.hdr(host) -i https://au-syd1-pve.main.unkin.net' - - 'acl_sonarr req.hdr(host) -i https://sonarr.main.unkin.net' - - 'acl_radarr req.hdr(host) -i https://radarr.main.unkin.net' - - 'acl_lidarr req.hdr(host) -i https://lidarr.main.unkin.net' - - 'acl_readarr req.hdr(host) -i https://readarr.main.unkin.net' - - 'acl_prowlarr req.hdr(host) -i https://prowlarr.main.unkin.net' + - 'acl_ausyd1pve req.hdr(host) -i au-syd1-pve.main.unkin.net' + - 'acl_sonarr req.hdr(host) -i sonarr.main.unkin.net' + - 'acl_radarr req.hdr(host) -i radarr.main.unkin.net' + - 'acl_lidarr req.hdr(host) -i lidarr.main.unkin.net' + - 'acl_readarr req.hdr(host) -i readarr.main.unkin.net' + - 'acl_prowlarr req.hdr(host) -i prowlarr.main.unkin.net' + - 'acl_jellyfin req.hdr(host) -i jellyfin.main.unkin.net' + - 'acl_fafflix req.hdr(host) -i fafflix.unkin.net' - 'acl_internalsubnets src 198.18.0.0/16 10.10.12.0/24' use_backend: - "%[req.hdr(host),lower,map(/etc/haproxy/fe_https.map,be_default)]" @@ -50,6 +54,8 @@ profiles::haproxy::frontends: - 'set-header X-Frame-Options DENY if acl_lidarr' - 'set-header X-Frame-Options DENY if acl_readarr' - 'set-header X-Frame-Options DENY if acl_prowlarr' + - 'set-header X-Frame-Options DENY if acl_jellyfin' + - 'set-header X-Frame-Options DENY if acl_fafflix' - 'set-header X-Content-Type-Options nosniff' - 'set-header X-XSS-Protection 1;mode=block' @@ -184,17 +190,20 @@ profiles::haproxy::backends: profiles::haproxy::certlist::enabled: true profiles::haproxy::certlist::certificates: + - /etc/pki/tls/letsencrypt/au-syd1-pve.main.unkin.net/fullchain_combined.pem + - /etc/pki/tls/letsencrypt/au-syd1-pve-api.main.unkin.net/fullchain_combined.pem + - /etc/pki/tls/letsencrypt/sonarr.main.unkin.net/fullchain_combined.pem + - /etc/pki/tls/letsencrypt/radarr.main.unkin.net/fullchain_combined.pem + - /etc/pki/tls/letsencrypt/lidarr.main.unkin.net/fullchain_combined.pem + - /etc/pki/tls/letsencrypt/readarr.main.unkin.net/fullchain_combined.pem + - /etc/pki/tls/letsencrypt/prowlarr.main.unkin.net/fullchain_combined.pem + - /etc/pki/tls/letsencrypt/fafflix.unkin.net/fullchain_combined.pem - /etc/pki/tls/vault/certificate.pem # additional altnames profiles::pki::vault::alt_names: - au-syd1-pve.main.unkin.net - au-syd1-pve-api.main.unkin.net - - sonarr.main.unkin.net - - radarr.main.unkin.net - - lidarr.main.unkin.net - - readarr.main.unkin.net - - prowlarr.main.unkin.net - jellyfin.main.unkin.net # additional cnames From d9a2966ffddc0abc0992fa8668ae3bc81bc7672f Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Mon, 8 Jul 2024 23:17:38 +1000 Subject: [PATCH 4/4] fix: certbot selinux and rsync - fix rsync to use 755 permissions - add rsync selinux booleans --- modules/certbot/manifests/selinux.pp | 12 ++++++++++++ modules/certbot/templates/certbot-syncer.service.epp | 4 +--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/modules/certbot/manifests/selinux.pp b/modules/certbot/manifests/selinux.pp index 71e2c70..d2d5b0b 100644 --- a/modules/certbot/manifests/selinux.pp +++ b/modules/certbot/manifests/selinux.pp @@ -17,6 +17,18 @@ class certbot::selinux ( persistent => true, value => 'on', } + selboolean { 'rsync_client': + persistent => true, + value => 'on', + } + selboolean { 'rsync_export_all_ro': + persistent => true, + value => 'on', + } + selboolean { 'rsync_full_access': + persistent => true, + value => 'on', + } exec { "restorecon_${data_root}/pub": path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'], diff --git a/modules/certbot/templates/certbot-syncer.service.epp b/modules/certbot/templates/certbot-syncer.service.epp index 4123ffe..122ba93 100644 --- a/modules/certbot/templates/certbot-syncer.service.epp +++ b/modules/certbot/templates/certbot-syncer.service.epp @@ -3,8 +3,6 @@ Description=certbot-syncer service [Service] Type=oneshot -ExecStart=/usr/bin/rsync --chmod=D2755,F644 -aL /etc/letsencrypt/live/ <%= $data_root %>/pub/ +ExecStart=/usr/bin/rsync --chmod=755 -aL /etc/letsencrypt/live/ <%= $data_root %>/pub/ User=root Group=root -PermissionsStartOnly=false -PrivateTmp=no