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
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1,15 @@
|
||||
# certbot::cert
|
||||
define certbot::cert (
|
||||
Stdlib::Fqdn $domain,
|
||||
Array $additional_args = ['--http-01-port=8888'],
|
||||
Boolean $manage_cron = true,
|
||||
) {
|
||||
|
||||
$location_environment = "${facts['country']}-${facts['region']}-${facts['environment']}"
|
||||
|
||||
@@letsencrypt::certonly { $domain:
|
||||
additional_args => $additional_args,
|
||||
manage_cron => $manage_cron,
|
||||
tag => $location_environment,
|
||||
}
|
||||
}
|
||||
@@ -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],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.': }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# certbot::haproxy
|
||||
class certbot::haproxy {
|
||||
# export haproxy balancemember
|
||||
profiles::haproxy::balancemember { "${facts['networking']['fqdn']}_8888":
|
||||
service => 'be_letsencrypt',
|
||||
ports => [8888],
|
||||
options => []
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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'],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
# 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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
mkdir::p {"${data_root}/pub":}
|
||||
|
||||
# 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 })
|
||||
|
||||
}
|
||||
@@ -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"],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,9 @@
|
||||
[Unit]
|
||||
Description=certbot-syncer timer
|
||||
|
||||
[Timer]
|
||||
OnCalendar=hourly
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
Reference in New Issue
Block a user