Merge pull request 'feat: add vault server profile' (#113) from neoloc/vault_server into develop
Reviewed-on: unkinben/puppet-prod#113
This commit is contained in:
commit
73a21059f8
@ -28,6 +28,7 @@ mod 'puppet-selinux', '4.1.0'
|
|||||||
mod 'puppet-prometheus', '13.4.0'
|
mod 'puppet-prometheus', '13.4.0'
|
||||||
mod 'puppet-grafana', '13.1.0'
|
mod 'puppet-grafana', '13.1.0'
|
||||||
mod 'puppet-consul', '8.0.0'
|
mod 'puppet-consul', '8.0.0'
|
||||||
|
mod 'puppet-vault', '4.1.0'
|
||||||
|
|
||||||
# other
|
# other
|
||||||
mod 'ghoneycutt-puppet', '3.3.0'
|
mod 'ghoneycutt-puppet', '3.3.0'
|
||||||
@ -36,6 +37,7 @@ mod 'dalen-puppetdbquery', '3.0.1'
|
|||||||
mod 'markt-galera', '3.1.0'
|
mod 'markt-galera', '3.1.0'
|
||||||
mod 'kogitoapp-minio', '1.1.4'
|
mod 'kogitoapp-minio', '1.1.4'
|
||||||
mod 'broadinstitute-certs', '3.0.1'
|
mod 'broadinstitute-certs', '3.0.1'
|
||||||
|
mod 'stm-file_capability', '6.0.0'
|
||||||
|
|
||||||
mod 'bind',
|
mod 'bind',
|
||||||
:git => 'https://git.unkin.net/unkinben/puppet-bind.git',
|
:git => 'https://git.unkin.net/unkinben/puppet-bind.git',
|
||||||
|
|||||||
48
doc/vault/setup.md
Normal file
48
doc/vault/setup.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# root ca
|
||||||
|
vault secrets enable -path=pki_root pki
|
||||||
|
|
||||||
|
vault write -field=certificate pki_root/root/generate/internal \
|
||||||
|
common_name="unkin.net" \
|
||||||
|
issuer_name="unkinroot-2024" \
|
||||||
|
ttl=87600h > unkinroot_2024_ca.crt
|
||||||
|
|
||||||
|
vault read pki_root/issuer/$(vault list -format=json pki_root/issuers/ | jq -r '.[]') | tail -n 6
|
||||||
|
|
||||||
|
vault write pki_root/roles/2024-servers allow_any_name=true
|
||||||
|
|
||||||
|
vault write pki_root/config/urls \
|
||||||
|
issuing_certificates="$VAULT_ADDR/v1/pki_root/ca" \
|
||||||
|
crl_distribution_points="$VAULT_ADDR/v1/pki_root/crl"
|
||||||
|
|
||||||
|
# intermediate
|
||||||
|
vault secrets enable -path=pki_int pki
|
||||||
|
vault secrets tune -max-lease-ttl=43800h pki_int
|
||||||
|
|
||||||
|
vault write -format=json pki_int/intermediate/generate/internal \
|
||||||
|
common_name="unkin.net Intermediate Authority" \
|
||||||
|
issuer_name="unkin-dot-net-intermediate" \
|
||||||
|
| jq -r '.data.csr' > pki_intermediate.csr
|
||||||
|
|
||||||
|
vault write -format=json pki_root/root/sign-intermediate \
|
||||||
|
issuer_ref="unkinroot-2024" \
|
||||||
|
csr=@pki_intermediate.csr \
|
||||||
|
format=pem_bundle ttl="43800h" \
|
||||||
|
| jq -r '.data.certificate' > intermediate.cert.pem
|
||||||
|
|
||||||
|
vault write pki_int/intermediate/set-signed certificate=@intermediate.cert.pem
|
||||||
|
|
||||||
|
# create role
|
||||||
|
vault write pki_int/roles/unkin-dot-net \
|
||||||
|
issuer_ref="$(vault read -field=default pki_int/config/issuers)" \
|
||||||
|
allowed_domains="unkin.net" \
|
||||||
|
allow_subdomains=true \
|
||||||
|
max_ttl="2160h"
|
||||||
|
|
||||||
|
# test generating a domain cert
|
||||||
|
vault write pki_int/issue/unkin-dot-net common_name="test.unkin.net" ttl="24h"
|
||||||
|
vault write pki_int/issue/unkin-dot-net common_name="test.main.unkin.net" ttl="24h"
|
||||||
|
vault write pki_int/issue/unkin-dot-net common_name="*.test.main.unkin.net" ttl="24h"
|
||||||
|
|
||||||
|
|
||||||
|
# remove expired certificates
|
||||||
|
vault write pki_int/tidy tidy_cert_store=true tidy_revoked_certs=true
|
||||||
@ -49,6 +49,7 @@ profiles::packages::base::add:
|
|||||||
- sysstat
|
- sysstat
|
||||||
- tmux
|
- tmux
|
||||||
- traceroute
|
- traceroute
|
||||||
|
- unzip
|
||||||
- vim
|
- vim
|
||||||
- vnstat
|
- vnstat
|
||||||
- wget
|
- wget
|
||||||
|
|||||||
7
hieradata/roles/infra/storage/vault.eyaml
Normal file
7
hieradata/roles/infra/storage/vault.eyaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
vault::unseal_keys:
|
||||||
|
- ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAobuA26wCD25sP6t0w3VgcrjBdpwVsglUz119X/y9o5FHkUibXuHkesNktUKzSMWpVBV+EsoTQ9HFisUOX3ykSIyYOVntm4BTECYBZKAyVXzkolAqX32IWtYqV4H4eKb3/OXw8zayJn9cPWbQkVtNDq3mZUMzgGj46DPFpH8aNQOI/xpovldY+WK1wo6WY7MGSCKw/+0mXK1Qa6wjh2K1X8cCg344ODZQD/h2SCT25qYPFVSBEzFwzQyLWULFOozg5RdE4OXkviqtq2PFtWxCD4S87WiG4elpttJAH0bbKFJs4PMZFgi0HdHqnMHXWiQgB/A9lNRhSPaU16Y2OTJ2HzBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCw46SHa6ZZKMhxpG8VG7fJgDDj4cQ2/7//RszV99oDP3OyCHRPt6PylAyWVBCxj54faILV/2OaF3GwW05gWzlmwVI=]
|
||||||
|
- ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAKeXpQMz90SUeIojz659+AX9hdTn5EiPOprrdI4EjqPL5BItr2xkrk8XbDnhlgM6PWwbo5jzEKBYGFTRbnHHF6/xdQQoUALMyhD3SSwDZOv8B92zSWkRMUpXlrUFMJeHldDMXS9enpg4Y4jL7i7GWsf7PEuEOTidNid3ZViKT32miSoJvGRENZvGyYA8Rd1Vh+3lIxtJNWqEUiw6yDUUO6H8bRKQ0JVBxW4JQOkLeaKbz+M2WjvE+PDeYykCWaApzfcxE3XPxv7MhBLJskf/37h/pHFGLhAUEcATiXrdUHzDuGnCLHQohW4B6NnKH7GNTby7Nbxzuq5zA3g9yavKj1DBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCbXFapwcT7R268E9Zih4i2gDC4cSSmU+33i5j6uKbgydDGqeooT4j2GzWCr0Ya52aVZnoeqYEFdp+dBFcCnvwFTQU=]
|
||||||
|
- ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEApI/exTnGbzLFuIYAVqLi27O8CxBXDOPDB5K9GVIDIL8pyXoqv8LDO1fkg0TZJREZIHUNBwx4DNg0ruveuEcHXTleLLKGk51Cn89YQB3bvUPJ7BfBq8GRV6TpNNj50jstjGqyesw+q4r9cx8F/l1qxlHBmJPT6h332GXO1Fzmh6wIF+poqD2KfsbppOtk/YGLtdTa87RuNS0eQ9LcayMIqWE2+vrkUlEtjNYgNWHnKFQhlB0kety4IKV6rdZd9thVIbyQctJmoNSf8mB2vLm+ufgQqQHc6RpwwZEkAaX+i6pACN44tgEnFuQ96KMW+GX5LCZ7cAUfrLXDNoGfbve2LDBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBC/1fBbDfgMoKR98FOvafR2gDDhENLMdjZWJBNHmMYJj2xYOnfv9tAe7F/JCIPrs2yPMwriyzOsgoAHFGkznKWHyvw=]
|
||||||
|
- ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAbx8zkPuZRlyeA/27xJZqXyjNkEA4JjsJQPh7BwuiLAqXUDeLLcUWTPOZ/YcJUS2IxLcYXsyWC/WAuhvKrLPCObHDndyWOq32sjI2ywaehMJc2w2cG0Iq4wdHo9Plfmu8T2jA2Tbe/cSuV84bh+toBTIKgckqulcBcgCMKSb5NUbdb33pB/YGieUMdrMfVyLVQUT88lmIXpKkfPN4z49cGEHXxbI7mgi7iUM0JbDJDddkH3jD1v3AI8Cr+/3y68+KMMxPVn1kwzPmLAjxkIJ/WySf7uEBEPrbshvsqS0D+OLk4ujOoBb3dpk5o07O6Sv4UA3R3Qa3Co63l8hGykjNSzBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBA70ywaIoOH465wLatsqHP3gDDB+GjjyySugoeismeS+5WMCuepilQ9mBned/nqw0i+8+WrNhsSTTP23hmpWeYAdug=]
|
||||||
|
- ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAoVY4a2yUJnvWJAC1gs0+ZgYcMMI1ZDGniNbIc4h6vb3ic7OPSa+QKZtEyboNSGWyLgLDhO6IPeeW+YgOhwo6tpgltBu34/1czwWiRSd9pZo7kq9J+UnnmvXxlfcD9S/hGAqzv+ouPQjWcpOm9rMYGrq78e3Z/VnscA3LtdtQVQtXLFERCIc3xCDNat47rQnWLvCGsDMSqCbUFOX/xnExmifLnHoRlOrg8K+Iw+oIIbI6LlOiE1lb5b8ml8RqckcKTx3ppRQiVNSCGIrjyVyWLtOU+zDmHFqsSf6JLZ0Twlfboafu2/Iz3NZiikSma564NcexTVkbk5bsZeMWB3+oWDBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBDoWpCRs2064iTVyEvjpXg9gDB/Y/86kLRp6IqmPjFH71oslQ674PK3SfO1jpJJRyJ/61zrdoef+jaK0eEvvJIW70o=]
|
||||||
8
hieradata/roles/infra/storage/vault.yaml
Normal file
8
hieradata/roles/infra/storage/vault.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
profiles::vault::server::members_role: roles::infra::storage::vault
|
||||||
|
profiles::vault::server::members_lookup: true
|
||||||
|
profiles::vault::server::data_dir: /data/vault
|
||||||
|
profiles::vault::server::primary_datacenter: 'au-drw1'
|
||||||
|
profiles::vault::server::manage_storage_dir: true
|
||||||
|
profiles::vault::server::tls_disable: false
|
||||||
|
vault::download_url: http://repos.main.unkin.net/unkin/8/x86_64/os/Archives/vault_1.15.5_linux_amd64.zip
|
||||||
@ -24,7 +24,7 @@ class profiles::pki::puppetcerts {
|
|||||||
ensure => 'file',
|
ensure => 'file',
|
||||||
owner => 'root',
|
owner => 'root',
|
||||||
group => 'root',
|
group => 'root',
|
||||||
mode => '0600',
|
mode => '0644',
|
||||||
source => "/etc/puppetlabs/puppet/ssl/private_keys/${facts['networking']['fqdn']}.pem",
|
source => "/etc/puppetlabs/puppet/ssl/private_keys/${facts['networking']['fqdn']}.pem",
|
||||||
require => File['/etc/pki/tls/puppet'],
|
require => File['/etc/pki/tls/puppet'],
|
||||||
}
|
}
|
||||||
|
|||||||
90
site/profiles/manifests/vault/server.pp
Normal file
90
site/profiles/manifests/vault/server.pp
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# profiles::vault::server
|
||||||
|
class profiles::vault::server (
|
||||||
|
Boolean $members_lookup = false,
|
||||||
|
String $members_role = undef,
|
||||||
|
Array $vault_servers = [],
|
||||||
|
Enum[
|
||||||
|
'archive',
|
||||||
|
'repo'
|
||||||
|
] $install_method = 'archive',
|
||||||
|
Boolean $tls_disable = false,
|
||||||
|
Stdlib::Port $client_port = 8200,
|
||||||
|
Stdlib::Port $cluster_port = 8201,
|
||||||
|
Boolean $manage_storage_dir = false,
|
||||||
|
Stdlib::Absolutepath $data_dir = '/opt/vault',
|
||||||
|
Stdlib::Absolutepath $bin_dir = '/usr/bin',
|
||||||
|
){
|
||||||
|
|
||||||
|
# use puppet certs as base
|
||||||
|
include profiles::pki::puppetcerts
|
||||||
|
|
||||||
|
# set a datacentre/cluster name
|
||||||
|
$vault_cluster = "${::facts['country']}-${::facts['region']}"
|
||||||
|
|
||||||
|
# if lookup is enabled, find all the hosts in the specified role and create the servers_array
|
||||||
|
if $members_lookup {
|
||||||
|
|
||||||
|
# check that the role is also set
|
||||||
|
unless !($members_role == undef) {
|
||||||
|
fail("members_role must be provided for ${title} when members_lookup is True")
|
||||||
|
}
|
||||||
|
|
||||||
|
# if it is, find hosts, sort them so they dont cause changes every run
|
||||||
|
$servers_array = sort(query_nodes("enc_role='${members_role}' and region='${::facts['region']}'", 'networking.fqdn'))
|
||||||
|
|
||||||
|
# else use provided array from params
|
||||||
|
}else{
|
||||||
|
$servers_array = $vault_servers
|
||||||
|
}
|
||||||
|
|
||||||
|
# set http scheme
|
||||||
|
$http_scheme = $tls_disable ? {
|
||||||
|
true => 'http',
|
||||||
|
false => 'https'
|
||||||
|
}
|
||||||
|
|
||||||
|
# create vault urls
|
||||||
|
$server_urls = $servers_array.map |$fqdn| {
|
||||||
|
{
|
||||||
|
leader_api_addr => "${http_scheme}://${fqdn}:${client_port}",
|
||||||
|
leader_client_cert_file => "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.crt",
|
||||||
|
leader_client_key_file => "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.key",
|
||||||
|
leader_ca_cert_file => '/etc/pki/tls/puppet/ca.pem',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class { 'vault':
|
||||||
|
install_method => $install_method,
|
||||||
|
manage_storage_dir => $manage_storage_dir,
|
||||||
|
enable_ui => true,
|
||||||
|
storage => {
|
||||||
|
raft => {
|
||||||
|
node_id => $::facts['networking']['fqdn'],
|
||||||
|
path => $data_dir,
|
||||||
|
retry_join => $server_urls,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
api_addr => "${http_scheme}://${::facts['networking']['fqdn']}:${client_port}",
|
||||||
|
extra_config => {
|
||||||
|
cluster_addr => "${http_scheme}://${::facts['networking']['fqdn']}:${cluster_port}",
|
||||||
|
},
|
||||||
|
listener => [
|
||||||
|
{
|
||||||
|
tcp => {
|
||||||
|
address => "127.0.0.1:${client_port}",
|
||||||
|
cluster_address => "127.0.0.1:${cluster_port}",
|
||||||
|
tls_disable => true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tcp => {
|
||||||
|
address => "${::facts['networking']['ip']}:${client_port}",
|
||||||
|
cluster_address => "${::facts['networking']['ip']}:${cluster_port}",
|
||||||
|
tls_disable => $tls_disable,
|
||||||
|
tls_cert_file => "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.crt",
|
||||||
|
tls_key_file => "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.key",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
37
site/profiles/manifests/vault/unseal.pp
Normal file
37
site/profiles/manifests/vault/unseal.pp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# profiles::vault::unseal
|
||||||
|
class profiles::vault::unseal (
|
||||||
|
Array[String] $unseal_keys = lookup('vault::unseal_keys', Array[String], 'first', []),
|
||||||
|
Variant[
|
||||||
|
Stdlib::HTTPSUrl,
|
||||||
|
Stdlib::HTTPUrl
|
||||||
|
] $vault_address = 'http://127.0.0.1:8200',
|
||||||
|
){
|
||||||
|
|
||||||
|
# deploy the unseal keys file
|
||||||
|
file { '/etc/vault/unseal_keys':
|
||||||
|
ensure => file,
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
mode => '0600',
|
||||||
|
content => Sensitive(template('profiles/vault/unseal_keys.erb')),
|
||||||
|
require => Class['vault'],
|
||||||
|
}
|
||||||
|
|
||||||
|
# deploy the unseal script
|
||||||
|
file { '/usr/local/bin/vault-unseal.sh':
|
||||||
|
ensure => file,
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
mode => '0750',
|
||||||
|
content => template('profiles/vault/vault_unseal.sh.erb'),
|
||||||
|
}
|
||||||
|
|
||||||
|
# create systemd service unit
|
||||||
|
systemd::unit_file { 'vault-unseal.service':
|
||||||
|
content => template('profiles/vault/vault-unseal.service.erb'),
|
||||||
|
active => true,
|
||||||
|
enable => true,
|
||||||
|
require => File['/usr/local/bin/vault-unseal.sh'],
|
||||||
|
subscribe => Service['vault'],
|
||||||
|
}
|
||||||
|
}
|
||||||
3
site/profiles/templates/vault/unseal_keys.erb
Normal file
3
site/profiles/templates/vault/unseal_keys.erb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<% @unseal_keys.each do |key| -%>
|
||||||
|
<%= key %>
|
||||||
|
<% end -%>
|
||||||
14
site/profiles/templates/vault/vault-unseal.service.erb
Normal file
14
site/profiles/templates/vault/vault-unseal.service.erb
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Unseal Vault Service
|
||||||
|
After=vault.service network.target
|
||||||
|
Requires=vault.service
|
||||||
|
PartOf=vault.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/vault-unseal.sh
|
||||||
|
RemainAfterExit=yes
|
||||||
|
User=root
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
23
site/profiles/templates/vault/vault_unseal.sh.erb
Normal file
23
site/profiles/templates/vault/vault_unseal.sh.erb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Script to unseal Vault
|
||||||
|
|
||||||
|
VAULT_ADDR='<%= @vault_address %>'
|
||||||
|
UNSEAL_KEYS_FILE='/etc/vault/unseal_keys'
|
||||||
|
|
||||||
|
# Check if Vault is sealed
|
||||||
|
is_sealed=$(curl -s ${VAULT_ADDR}/v1/sys/seal-status | jq -r '.sealed')
|
||||||
|
if [ "$is_sealed" != "true" ]; then
|
||||||
|
echo "Vault is already unsealed."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Retrieve unseal keys from plaintext file
|
||||||
|
unseal_keys=$(cat "$UNSEAL_KEYS_FILE")
|
||||||
|
|
||||||
|
# Loop through the unseal keys and use them to unseal Vault
|
||||||
|
for key in $unseal_keys; do
|
||||||
|
curl --request PUT --data '{"key": "'$key'"}' $VAULT_ADDR/v1/sys/unseal
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Vault has been unsealed."
|
||||||
@ -2,4 +2,7 @@
|
|||||||
class roles::infra::storage::vault {
|
class roles::infra::storage::vault {
|
||||||
include profiles::defaults
|
include profiles::defaults
|
||||||
include profiles::base
|
include profiles::base
|
||||||
|
include profiles::base::datavol
|
||||||
|
include profiles::vault::server
|
||||||
|
include profiles::vault::unseal
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user