From 734fcb8cf43dd1e9ac327a7389cc9ba0ce19e0cf Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Sun, 20 Sep 2026 23:32:16 +1000 Subject: [PATCH] Trust the estate CA when fetching ENC facts (#529) Facter runs under Puppet's vendored Ruby, which reads its own bundled CA file and never the system trust store. The ENC fact now fetches over HTTPS, so every node fails certificate verification and falls back to its cached value. - set ca_file on the request to the vaultca anchor bundle - keep VERIFY_PEER on, and fall through to the existing cache path when the anchor is absent Reviewed-on: https://git.unkin.net/unkin/puppet-prod/pulls/529 Co-authored-by: unkin-agent Co-committed-by: unkin-agent --- modules/libs/lib/facter/enc_direct_facts.rb | 23 ++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/modules/libs/lib/facter/enc_direct_facts.rb b/modules/libs/lib/facter/enc_direct_facts.rb index bf0fed4..7fde380 100644 --- a/modules/libs/lib/facter/enc_direct_facts.rb +++ b/modules/libs/lib/facter/enc_direct_facts.rb @@ -3,6 +3,7 @@ require 'facter' require 'yaml' require 'net/http' +require 'openssl' require 'uri' require 'fileutils' @@ -10,6 +11,13 @@ require 'fileutils' module EncapiENC CACHE_FILE = '/var/cache/puppet_enc.yaml' CACHE_TTL = 7 * 24 * 60 * 60 # 7 days in seconds + # Facter runs under Puppet's vendored ruby, whose OpenSSL trusts only + # /opt/puppetlabs/puppet/ssl/cert.pem and never the system trust store, so the + # estate CA anchor profiles::pki::vaultca installs has to be named explicitly. + CA_BUNDLE_PATHS = [ + '/etc/pki/ca-trust/source/anchors/vaultcaroot.pem', + '/usr/local/share/ca-certificates/vaultcaroot.pem' + ].freeze @enc_data = nil # In-memory cache for the ENC response def self.read_cache @@ -29,9 +37,22 @@ module EncapiENC File.write(CACHE_FILE, cache_data.to_yaml) end + def self.ca_bundle + CA_BUNDLE_PATHS.find { |path| File.exist?(path) } + end + + def self.http_client(uri) + client = Net::HTTP.new(uri.host, uri.port) + client.use_ssl = true + client.verify_mode = OpenSSL::SSL::VERIFY_PEER + bundle = ca_bundle + client.ca_file = bundle if bundle + client + end + def self.fetch_from_encapi uri = URI("https://encapi.k8s.syd1.au.unkin.net/cblr/svc/op/puppet/hostname/#{Facter.value(:fqdn) || Facter.value(:hostname)}") - response = Net::HTTP.get_response(uri) + response = http_client(uri).request(Net::HTTP::Get.new(uri)) raise "Failed to fetch ENC data. HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)