Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
c6037b1
Add Hashicorp mirror as apt source
willaerk Dec 12, 2024
56598e2
Add vault user and group
willaerk Dec 12, 2024
7eab593
Make terraform use the Hashicorp apt mirror
willaerk Dec 12, 2024
db94cb8
Initial vault profile
willaerk Dec 12, 2024
72528d7
Create basic vault configuration
willaerk Dec 13, 2024
b450f9e
Manage vault user homedir
willaerk Dec 18, 2024
bf24a7f
Add vault GPG key generation
willaerk Dec 18, 2024
e25a49d
Add vault GPG key class to configuration
willaerk Dec 18, 2024
33a0ec1
Add firewall rule when vault is not only listening on 127.0.0.1
willaerk Dec 19, 2024
103c562
Export vault GPG public key after creation
willaerk Dec 19, 2024
f348672
Initialize vault at end of install
willaerk Dec 19, 2024
804c7c1
Add vault seal management to vault profile
willaerk Dec 19, 2024
11fb14d
Unseal vault at vault startup when auto_unseal is true
willaerk Dec 20, 2024
9b00796
Pass auto_unseal to the correct classes
willaerk Dec 20, 2024
a92cea9
Split vault init and seal into separate classes
willaerk Dec 20, 2024
6b72edf
Add scripts to process output of 'vault init' and to unseal vault
willaerk Dec 22, 2024
ef7bce8
Only create Vault GPG key when auto_unseal is set to true
willaerk Dec 22, 2024
bf764bb
Use provided GPG keys to create encrypted unseal keys when initializi…
willaerk Jan 7, 2025
40ab464
Import all GPG keys and provide base64 encoded export
willaerk Jan 7, 2025
a1026f2
Make GPG keys directory configurable
willaerk Jan 7, 2025
7b865b0
Pass GPG keys from main vault class to vault::init
willaerk Jan 7, 2025
91bb59f
Move all parameter validation to main vault profile
willaerk Jan 8, 2025
1c760d8
Gnupg_key resource type requires a short key id
willaerk Jan 8, 2025
b0282a3
Use owner parameter for GPG key and implement vault-process-init script
willaerk Jan 9, 2025
09abcd4
Split vault init output processing into multiple exec resources for c…
willaerk Jan 10, 2025
d5c6a8d
Make GPG keys an array, as the order is important
willaerk Jan 10, 2025
d788065
Use GPG keys array in the main vault profile too
willaerk Jan 10, 2025
07b5392
Specify key fingerprint for GPG key export
willaerk Jan 10, 2025
6d1fdf2
Add Puppet CA certificate to system truststore
willaerk Jan 10, 2025
4141655
Set the VAULT_ADDR environment variable with any Vault deployment
willaerk Jan 10, 2025
391c89f
Merge branch 'main' into feature/OPS-1248
willaerk Jan 13, 2025
7dd2cbc
Use double quotes for string to allow newlines to be interpreted
willaerk Jan 13, 2025
055a8fd
Add vault certificate class
willaerk Jan 13, 2025
6f9ebd7
Add certname parameter to main vault profile
willaerk Jan 13, 2025
713feb3
Only add vault certificate when specified as parameter
willaerk Jan 14, 2025
4e5d8ec
Set correct service address and cert in configuration
willaerk Jan 14, 2025
3662132
Add TLS certicate authentication and key-value secrets engine
willaerk Jan 15, 2025
659e042
Merge branch 'feature/simplify_hiera_config' into feature/OPS-1248
willaerk Jan 17, 2025
c5a580c
Enable lingering for Vault user when auto-unseal is enabled, to allow…
willaerk Jan 17, 2025
fbf30b4
Use 'puppet' path for puppet kv secrets
willaerk Jan 20, 2025
25bec4e
Use puppet_certificate policy name for trusted certificates
willaerk Jan 20, 2025
99ce876
Add vault policy defined type
willaerk Jan 20, 2025
2e57535
Simplify exec condition for cert authentication
willaerk Jan 20, 2025
bc72da6
Add vault policies
willaerk Jan 20, 2025
3a100fd
Add unmodified hiera_vault function from https://github.com/petems/pe…
willaerk Jan 20, 2025
2bcbefe
Credit original source and get rid of code warnings
willaerk Jan 20, 2025
4923ece
Use correct name for puppet certificate vault policy
willaerk Jan 21, 2025
eaa8d3f
Add vault logging to files
willaerk Jan 21, 2025
5f8356d
Add log management to vault configuration template
willaerk Jan 21, 2025
38021b3
Add LVM support to vault profile
willaerk Jan 21, 2025
a53168d
Make sure the vault logfile is available
willaerk Jan 21, 2025
667a434
Move vault::certificate class to main profile to simplify ordering
willaerk Jan 21, 2025
152e97a
Log all requests to Vault
willaerk Jan 24, 2025
7d49c98
Start changes to hiera_vault function
willaerk Jan 24, 2025
015ae4b
Remove caching functionality
willaerk Jan 24, 2025
1eeb03f
No need to check for json gem, as it is already present by default
willaerk Jan 24, 2025
1887fe0
Never continue to other backend if no secret is found
willaerk Jan 24, 2025
79d7352
Move authentication to authenticate method and make configurable
willaerk Jan 24, 2025
b43526f
Always fail when a secret is not found
willaerk Jan 24, 2025
12f25f1
Limit client configuration to required items
willaerk Jan 24, 2025
0353d6a
Start a vault client instance for each lookup
willaerk Jan 24, 2025
1332ea3
Remove unused configuration options
willaerk Jan 24, 2025
f1d58ea
Always return complete secret, let puppet handle the rest
willaerk Jan 24, 2025
69e71c1
Only support kv version 2 mounts
willaerk Jan 24, 2025
c7e4e1d
No need to check for nil value here
willaerk Jan 24, 2025
5b6b38c
Simplify path interpolation for hiera_vault function and add separate…
willaerk Jan 26, 2025
a0ff31e
Add vault gem to puppetserver and export puppet certificate
willaerk Jan 27, 2025
28bcb69
Add vault integration to hiera
willaerk Jan 27, 2025
5c7a4e8
Add vault integration to main puppetserver profile
willaerk Jan 27, 2025
2e3f953
Merge branch 'main' into feature/OPS-1248
willaerk Jan 27, 2025
8e5be75
Add vault backup class
willaerk Jan 28, 2025
b225460
Add vault backup class to main vault profile
willaerk Jan 28, 2025
c053146
Remove duplicate hash key
willaerk Jan 28, 2025
7fe76e7
Spec fixes
willaerk Jan 28, 2025
a242771
Merge branch 'main' into feature/OPS-1248
willaerk Jan 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions files/vault/vault-process-init-output
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

KEY_OWNERS=${1}
INPUT=$(/usr/bin/cat)

while IFS=',' read -ra OWNER; do
for counter in `/usr/bin/seq 0 $(( ${#OWNER[@]} - 1 ))`; do
owner="${OWNER[${counter}]}"
key=$(/usr/bin/echo ${INPUT} | /usr/bin/jq -r ".unseal_keys_b64[${counter}]")

/usr/bin/echo $(/usr/bin/jq -n --arg key "$owner" --arg value "$key" '{ ($key): ($value) }')
done | /usr/bin/jq -s add
done <<< "${KEY_OWNERS}" | /usr/bin/jq '{ "vault_encrypted_unseal_keys": . }'
5 changes: 5 additions & 0 deletions files/vault/vault-unseal
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

encrypted_unseal_key=$(/usr/bin/cat ${1})

/usr/bin/vault operator unseal -tls-skip-verify $(/usr/bin/echo ${encrypted_unseal_key} | /usr/bin/base64 --decode | /usr/bin/gpg --decrypt --quiet)
8 changes: 8 additions & 0 deletions files/vault/vaultbackup
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

mv /data/backup/vault/current/*.tar.gz /data/backup/vault/archive

tar cvzf /data/backup/vault/current/vault_$(date +%Y.%m.%d.%H%M%S).tar.gz \
/opt/vault \
/home/vault/.vault-token \
/home/vault/encrypted_unseal_key \
156 changes: 156 additions & 0 deletions lib/puppet/functions/hiera_vault.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# Originally copied from Peter Souter hiera_vault repository, licensed under the Apache License, Version 2.0
#
# https://github.com/petems/petems-hiera_vault/blob/master/lib/puppet/functions/hiera_vault.rb

require_relative 'hiera_vault/authentication.rb'

Puppet::Functions.create_function(:hiera_vault) do
begin
require 'vault'
rescue LoadError => _e
raise Puppet::DataBinding::LookupError, "[hiera-vault] Must install vault gem to use hiera-vault backend"
end

dispatch :lookup_key do
param 'Variant[String, Numeric]', :key
param 'Hash', :options
param 'Puppet::LookupContext', :context
end

def lookup_key(key, options, context)
if confine_keys = options['confine_to_keys']
raise ArgumentError, '[hiera-vault] confine_to_keys must be an array' unless confine_keys.is_a?(Array)

begin
confine_keys = confine_keys.map { |r| Regexp.new(r) }
rescue StandardError => e
raise Puppet::DataBinding::LookupError, "[hiera-vault] creating regexp failed with: #{e}"
end

regex_key_match = Regexp.union(confine_keys)

unless key[regex_key_match] == key
context.explain { "[hiera-vault] Skipping hiera_vault backend because key '#{key}' does not match confine_to_keys" }
context.not_found
end
end

if strip_from_keys = options['strip_from_keys']
raise ArgumentError, '[hiera-vault] strip_from_keys must be an array' unless strip_from_keys.is_a?(Array)

strip_from_keys.each do |prefix|
key = key.gsub(Regexp.new(prefix), '')
end
end

vault_get(key, options, context)
end

def vault_get(key, options, context)
hiera_vault_client = Vault::Client.new

begin
hiera_vault_client.configure do |config|
config.address = options['address'] unless options['address'].nil?
config.ssl_verify = options['ssl_verify'] unless options['ssl_verify'].nil?
config.ssl_ca_cert = options['ssl_ca_cert'] if config.respond_to? :ssl_ca_cert
end

context.explain { "[hiera-vault] Using #{options['authentication']['method']} authentication" }
authenticate(options['authentication'], hiera_vault_client, context)

if hiera_vault_client.sys.seal_status.sealed?
raise Puppet::DataBinding::LookupError, "[hiera-vault] vault is sealed"
end

context.explain { "[hiera-vault] Client configured to connect to #{hiera_vault_client.address}" }
rescue StandardError => e
hiera_vault_client.shutdown
raise Puppet::DataBinding::LookupError, "[hiera-vault] Skipping backend. Configuration error: #{e}"
end

answer = nil

# Only kv v2 mounts supported
options['mounts'].each_pair do |mount, paths|
interpolate(context, paths).each do |path|
context.explain { "[hiera-vault] Looking on mount #{mount} in path #{path} for #{key}" }

secret = nil

begin
context.explain { "[hiera-vault] Checking path: #{path} on mount: #{mount}" }
secret = hiera_vault_client.kv(mount).read(File.join(path, key).chomp('/'))
rescue Vault::HTTPConnectionError
msg = "[hiera-vault] Could not connect to read secret: #{path} on mount: #{mount}"
context.explain { msg }
raise Puppet::DataBinding::LookupError, msg
rescue Vault::HTTPError => e
msg = "[hiera-vault] Could not read secret #{path} on mount #{mount}: #{e.errors.join("\n").rstrip}"
context.explain { msg }
raise Puppet::DataBinding::LookupError, msg
end

next if secret.nil?

context.explain { "[hiera-vault] Read secret: #{key}" }
# Turn secret's hash keys into strings allow for nested arrays and hashes
# this enables support for create resources etc
answer = secret.data.inject({}) { |h, (k, v)| h[k.to_s] = stringify_keys v; h }
break
end

break unless answer.nil?
end

raise Puppet::DataBinding::LookupError, "[hiera-vault] Could not find secret #{key}" if answer.nil?

answer = context.not_found if answer.nil?
hiera_vault_client.shutdown

return answer
end

# Stringify key:values so user sees expected results and nested objects
def stringify_keys(value)
case value
when String
value
when Hash
result = {}
value.each_pair { |k, v| result[k.to_s] = stringify_keys v }
result
when Array
value.map { |v| stringify_keys v }
else
value
end
end

def interpolate(context, paths)
allowed_paths = []
paths.each do |path|
path = context.interpolate(path)
# TODO: Unify usage of '/' - File.join seems to be a mistake, since it won't work on Windows
# secret/puppet/scope1,scope2 => [[secret], [puppet], [scope1, scope2]]
segments = path.split('/').map { |segment| segment.split(',') }
allowed_paths += build_paths(segments) unless segments.empty?
end
allowed_paths
end

# [[secret], [puppet], [scope1, scope2]] => ['secret/puppet/scope1', 'secret/puppet/scope2']
def build_paths(segments)
paths = [[]]
segments.each do |segment|
p = paths.dup
paths.clear
segment.each do |option|
p.each do |path|
paths << path + [option]
end
end
end
paths.map { |p| File.join(*p) }
end
end
25 changes: 25 additions & 0 deletions lib/puppet/functions/hiera_vault/authentication.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
def authenticate(options, client, context)
auth_methods = {
'token' => method(:token),
'tls_certificate' => method(:tls)
}

auth_methods[options['method']].(options['config'], client, context)
end

def token(config, client, context)
context.explain { "[hiera-vault] Starting token authentication with config: #{config}" }
client.auth.token(config['token'])
end

def tls(config, client, context)
privatekeydir = Puppet.settings['privatekeydir']
certdir = Puppet.settings['certdir']
certname = config['certname']

privatekey = File.read("#{privatekeydir}/#{certname}.pem")
certificate = File.read("#{certdir}/#{certname}.pem")

context.explain { "[hiera-vault] Starting tls_certificate authentication with config: #{config}" }
client.auth.tls(privatekey + certificate)
end
7 changes: 7 additions & 0 deletions manifests/apt/repositories.pp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,13 @@
repos => 'puppet'
}

@apt::source { 'hashicorp':
location => "https://apt-mirror.publiq.be/hashicorp-${codename}-${environment}",
release => $codename,
architecture => $arch,
repos => 'main'
}

# Project repositories
@apt::source { 'uit-mail-subscriptions':
location => "https://apt.publiq.be/uit-mail-subscriptions-${environment}",
Expand Down
31 changes: 27 additions & 4 deletions manifests/files.pp
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,39 @@

@file { '/data/backup':
ensure => 'directory',
owner => 'root',
group => 'root',
mode => '0755',
owner => 'root',
group => 'root',
mode => '0755',
require => File['/data']
}

@file { '/etc/gcloud':
ensure => 'directory',
ensure => 'directory',
owner => 'root',
group => 'root',
mode => '0755'
}

@file { '/etc/puppetlabs':
ensure => 'directory',
owner => 'root',
group => 'root',
mode => '0755'
}

@file { '/etc/puppetlabs/facter':
ensure => 'directory',
owner => 'root',
group => 'root',
mode => '0755',
require => File['/etc/puppetlabs']
}

@file { '/etc/puppetlabs/facter/facts.d':
ensure => 'directory',
owner => 'root',
group => 'root',
mode => '0755',
require => File['/etc/puppetlabs/facter']
}
}
6 changes: 6 additions & 0 deletions manifests/firewall/rules.pp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@
action => 'accept'
}

@firewall { '400 accept vault traffic':
proto => 'tcp',
dport => '8200',
action => 'accept'
}

@firewall { '500 accept carbon traffic':
proto => 'tcp',
dport => '2003',
Expand Down
5 changes: 5 additions & 0 deletions manifests/groups.pp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@
gid => '457'
}

@group { 'vault':
ensure => 'present',
gid => '458'
}

@group { 'ubuntu':
ensure => 'present',
gid => '1000'
Expand Down
22 changes: 7 additions & 15 deletions manifests/puppet/agent.pp
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@
) inherits ::profiles {

$default_ini_setting_attributes = {
path => '/etc/puppetlabs/puppet/puppet.conf',
notify => Service['puppet']
path => '/etc/puppetlabs/puppet/puppet.conf',
notify => Service['puppet']
}

realize Apt::Source['puppet']

realize File['/etc/puppetlabs']
realize File['/etc/puppetlabs/facter']
realize File['/etc/puppetlabs/facter/facts.d']

package { 'puppet-agent':
ensure => $version,
require => Apt::Source['puppet'],
require => [Apt::Source['puppet'], File['/etc/puppetlabs/facter/facts.d']],
notify => Service['puppet']
}

Expand All @@ -30,18 +34,6 @@
require => Package['puppet-agent']
}

file { 'puppet agent facter datadir':
ensure => 'directory',
path => '/etc/puppetlabs/facter',
require => Package['puppet-agent']
}

file { 'puppet agent facts.d datadir':
ensure => 'directory',
path => '/etc/puppetlabs/facter/facts.d',
require => File['puppet agent facter datadir']
}

if $puppetserver {
ini_setting { 'puppetserver':
ensure => 'present',
Expand Down
11 changes: 11 additions & 0 deletions manifests/puppet/puppetserver.pp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
{ 'name' => 'Per-node data', 'path' => 'nodes/%{::trusted.certname}.yaml' },
{ 'name' => 'Common data', 'path' => 'common.yaml' }
],
Boolean $vault_integration = false,
Optional[String] $vault_address = undef,
Hash $vault_mounts = {},
Boolean $terraform_integration = lookup('data::puppet::terraform_integration', Boolean, 'first', false),
Optional[String] $terraform_bucket = undef,
Boolean $terraform_use_iam_role = true,
Expand Down Expand Up @@ -101,10 +104,18 @@
gpg_key => $eyaml_gpg_key,
lookup_hierarchy => $lookup_hierarchy,
terraform_integration => $terraform_integration,
vault_integration => $vault_integration,
vault_address => $vault_address,
vault_mounts => $vault_mounts,
require => Class['profiles::puppet::puppetserver::install'],
notify => Class['profiles::puppet::puppetserver::service']
}

class { 'profiles::puppet::puppetserver::vault':
before => Class['profiles::puppet::puppetserver::hiera'],
notify => Class['profiles::puppet::puppetserver::service']
}

if $terraform_integration {
class { 'profiles::puppet::puppetserver::terraform':
bucket => $terraform_bucket,
Expand Down
Loading