feat: add incus auto-client certificate trust
All checks were successful
Build / precommit (pull_request) Successful in 5m40s
All checks were successful
Build / precommit (pull_request) Successful in 5m40s
- add fact to export vault public cert from agents - add fact to export list of trusted incus client certs - add method for incus clients to export their client cert to be trusted
This commit is contained in:
parent
fac90c66db
commit
e55fd8fbd5
@ -2,6 +2,7 @@
|
|||||||
hiera_include:
|
hiera_include:
|
||||||
- docker
|
- docker
|
||||||
- profiles::gitea::runner
|
- profiles::gitea::runner
|
||||||
|
- incus::client
|
||||||
|
|
||||||
docker::version: latest
|
docker::version: latest
|
||||||
docker::curl_ensure: false
|
docker::curl_ensure: false
|
||||||
|
|||||||
28
modules/incus/lib/facter/incus_trust_list.rb
Normal file
28
modules/incus/lib/facter/incus_trust_list.rb
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# lib/facter/incus_trust_list.rb
|
||||||
|
require 'json'
|
||||||
|
|
||||||
|
Facter.add(:incus_trust_list) do
|
||||||
|
confine do
|
||||||
|
# Only run on systems that have incus installed and running
|
||||||
|
incus_path = Facter::Util::Resolution.which('incus')
|
||||||
|
incus_path && File.exist?('/var/lib/incus/server.key')
|
||||||
|
end
|
||||||
|
|
||||||
|
setcode do
|
||||||
|
incus_path = Facter::Util::Resolution.which('incus')
|
||||||
|
next {} unless incus_path
|
||||||
|
|
||||||
|
begin
|
||||||
|
# Run incus config trust list --format=json
|
||||||
|
trust_output = Facter::Core::Execution.execute("#{incus_path} config trust list --format=json")
|
||||||
|
next {} if trust_output.empty?
|
||||||
|
|
||||||
|
# Parse the JSON output
|
||||||
|
JSON.parse(trust_output)
|
||||||
|
rescue StandardError
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
16
modules/incus/manifests/client.pp
Normal file
16
modules/incus/manifests/client.pp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# incus::client
|
||||||
|
#
|
||||||
|
# This class configures a host as an incus client and exports its certificate
|
||||||
|
# for automatic trust management on incus servers.
|
||||||
|
#
|
||||||
|
class incus::client {
|
||||||
|
|
||||||
|
# Export this client's certificate for collection by incus servers
|
||||||
|
@@incus::client_cert { $facts['networking']['fqdn']:
|
||||||
|
hostname => $facts['networking']['fqdn'],
|
||||||
|
certificate => $facts['vault_cert_content'],
|
||||||
|
fingerprint => $facts['vault_cert_fingerprint'],
|
||||||
|
tag => 'incus_client',
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
41
modules/incus/manifests/client_cert.pp
Normal file
41
modules/incus/manifests/client_cert.pp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Define the exported resource type for incus client certificates
|
||||||
|
define incus::client_cert (
|
||||||
|
String $hostname,
|
||||||
|
Optional[String] $certificate = undef,
|
||||||
|
Optional[String] $fingerprint = undef,
|
||||||
|
) {
|
||||||
|
|
||||||
|
# Only proceed if we have both certificate and fingerprint
|
||||||
|
if $certificate and $fingerprint {
|
||||||
|
|
||||||
|
$trust_list = $facts['incus_trust_list']
|
||||||
|
$existing_client = $trust_list.filter |$client| { $client['name'] == $hostname }
|
||||||
|
|
||||||
|
if $existing_client.empty {
|
||||||
|
# Add new certificate
|
||||||
|
exec { "incus_trust_add_${hostname}":
|
||||||
|
path => ['/bin', '/usr/bin'],
|
||||||
|
command => "echo '${certificate}' > /tmp/${hostname}.crt && \
|
||||||
|
incus config trust add-certificate /tmp/${hostname}.crt --name ${hostname} && \
|
||||||
|
rm -f /tmp/${hostname}.crt",
|
||||||
|
unless => "incus config trust list --format=json | grep '\"name\":\"${hostname}\"'",
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# Check if fingerprints are different
|
||||||
|
$existing_fingerprint = $existing_client[0]['fingerprint']
|
||||||
|
|
||||||
|
if $existing_fingerprint != $fingerprint {
|
||||||
|
# Remove existing and add new certificate only if fingerprints differ
|
||||||
|
exec { "incus_trust_update_${hostname}":
|
||||||
|
path => ['/bin', '/usr/bin'],
|
||||||
|
command => "incus config trust remove ${existing_fingerprint} && \
|
||||||
|
echo '${certificate}' > /tmp/${hostname}.crt && \
|
||||||
|
incus config trust add-certificate /tmp/${hostname}.crt --name ${hostname} && \
|
||||||
|
rm -f /tmp/${hostname}.crt",
|
||||||
|
onlyif => "incus config trust list --format=json | grep '${existing_fingerprint}'",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# If fingerprints match, do nothing (certificate is already correct)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -92,5 +92,10 @@ class incus (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Collect exported client certificates and manage trust
|
||||||
|
Incus::Client_cert <<| tag == 'incus_client' |>> {
|
||||||
|
require => Service['incus'],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
modules/libs/lib/facter/vault_cert_content.rb
Normal file
11
modules/libs/lib/facter/vault_cert_content.rb
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# lib/facter/vault_cert_content.rb
|
||||||
|
|
||||||
|
Facter.add(:vault_cert_content) do
|
||||||
|
confine kernel: 'Linux'
|
||||||
|
setcode do
|
||||||
|
cert_path = '/etc/pki/tls/vault/certificate.crt'
|
||||||
|
File.read(cert_path) if File.exist?(cert_path) && File.readable?(cert_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
23
modules/libs/lib/facter/vault_cert_fingerprint.rb
Normal file
23
modules/libs/lib/facter/vault_cert_fingerprint.rb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# lib/facter/vault_cert_fingerprint.rb
|
||||||
|
|
||||||
|
Facter.add(:vault_cert_fingerprint) do
|
||||||
|
confine kernel: 'Linux'
|
||||||
|
setcode do
|
||||||
|
require 'openssl'
|
||||||
|
require 'digest'
|
||||||
|
|
||||||
|
cert_path = '/etc/pki/tls/vault/certificate.crt'
|
||||||
|
if File.exist?(cert_path) && File.readable?(cert_path)
|
||||||
|
begin
|
||||||
|
cert_content = File.read(cert_path)
|
||||||
|
cert = OpenSSL::X509::Certificate.new(cert_content)
|
||||||
|
# Calculate SHA256 fingerprint like incus does
|
||||||
|
Digest::SHA256.hexdigest(cert.to_der)
|
||||||
|
rescue StandardError
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user