From d73b92dba8730923fc550663ccbdd15b7374f7e6 Mon Sep 17 00:00:00 2001 From: Nicolas Truyens Date: Mon, 22 Mar 2021 16:52:50 +0100 Subject: [PATCH] New option: puppetdb_ssl_crl The CRL file is required by newer version of Puppet(Server)(DB). --- doc/configuration-puppetdb.md | 2 ++ doc/optionsref.md | 14 +++++++++++ examples/octocatalog-diff.cfg.rb | 9 ++++++++ lib/octocatalog-diff/catalog-util/builddir.rb | 16 +++++++++++++ .../cli/options/puppetdb_ssl_crl.rb | 16 +++++++++++++ lib/octocatalog-diff/puppetdb.rb | 1 + .../fixtures/ssl/generated/crl.pem | 17 ++++++++++++++ .../tests/catalog-util/builddir_spec.rb | 23 ++++++++++++++++++- .../cli/options/puppetdb_ssl_crl_spec.rb | 18 +++++++++++++++ 9 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 lib/octocatalog-diff/cli/options/puppetdb_ssl_crl.rb create mode 100644 spec/octocatalog-diff/fixtures/ssl/generated/crl.pem create mode 100644 spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_crl_spec.rb diff --git a/doc/configuration-puppetdb.md b/doc/configuration-puppetdb.md index 0a2f63ee..d46023ed 100644 --- a/doc/configuration-puppetdb.md +++ b/doc/configuration-puppetdb.md @@ -32,6 +32,7 @@ The following settings can be used in a [configuration file](/doc/configuration. | --- | --- | | `settings[:puppetdb_url]` | PuppetDB URL settings. If this is a string, it will set a single PuppetDB URL. If it is an array, it will set multiple URLs, which will be tried in a random order until one responds. | | `settings[:puppetdb_ssl_ca]` | Path to the certificate of the CA that signed PuppetDB's certificate. This file should contain only the public certificate, so it is safe to distribute to developer workstations or CI environments. | +| `settings[:puppetdb_ssl_crl]` | Path to the Certificate Revocation List provided by Puppetserver. | `settings[:puppetdb_ssl_client_cert]` | TEXT of the certificate of the client SSL keypair used to authenticate to PuppetDB. Note: This variable is not set to a file path, which means you will likely want to use `File.read(...)` if you are configuring this to be read from a file. | | `settings[:puppetdb_ssl_client_key]` | TEXT of the private key of the client SSL keypair used to authenticate to PuppetDB. Note: This variable is not set to a file path, which means you will likely want to use means you will likely want to use `File.read(...)` if you are configuring this to be read from a file. | | `settings[:puppetdb_ssl_client_pem]` | Concatenation of the text of `puppetdb_ssl_client_key` and `puppetdb_ssl_client_cert` as previously described. This is a good alternative if your certificate chain is complex and it's easier just to put everything in a single place. Note: this option is second in precedence; if `settings[:puppetdb_ssl_client_cert]` and `settings[:puppetdb_ssl_client_key]` are both set, this will be ignored. | @@ -46,6 +47,7 @@ The following arguments can be used on the command line. | --- | --- | | --puppetdb-url https://puppetdb.example.net:8081 | PuppetDB URL. The argument should match the `server_urls` configuration setting as described previously. Please note that only one URL is supported via the command line method, so if you have multiple `server_urls` URLs specified, you can only choose one. To use multiple URLs for failover purposes, please configure via configuration files. | | --puppetdb-ssl-ca FILENAME | Path to the certificate of the CA that signed PuppetDB's certificate. This file should contain only the public certificate, so it is safe to distribute to developer workstations or CI environments. | +| --puppetdb-ssl-crl FILENAME | Path to the Certificate Revocation List of the CA that signed PuppetDB's certificate. | | --puppetdb-ssl-client-cert FILENAME | Path to the certificate of the client SSL keypair. | | --puppetdb-ssl-client-key FILENAME | Path to the private key of the client SSL keypair. | | --puppetdb-ssl-client-password PASSWORD_STRING | Plain text string containing the password to unlock the private key. For keys generated by the Puppet Master CA, this is not required. | diff --git a/doc/optionsref.md b/doc/optionsref.md index 963919ca..d231cef1 100644 --- a/doc/optionsref.md +++ b/doc/optionsref.md @@ -106,6 +106,7 @@ Usage: octocatalog-diff [command line options] --puppetdb-token-file PATH Path containing token for PuppetDB API, relative or absolute --puppetdb-url URL PuppetDB base URL --puppetdb-ssl-ca FILENAME CA certificate that signed the PuppetDB certificate + --puppetdb-ssl-crl FILENAME Certificate Revocation List of the CA that signed PuppetDB's certificate. --puppetdb-ssl-client-cert FILENAME SSL client certificate to connect to PuppetDB --puppetdb-ssl-client-key FILENAME @@ -1440,6 +1441,19 @@ matches the name you are using to connecting. (puppetdb_ssl_crl.rb) + + +
--puppetdb-ssl-client-cert FILENAME
diff --git a/examples/octocatalog-diff.cfg.rb b/examples/octocatalog-diff.cfg.rb index 63550e83..021be879 100755 --- a/examples/octocatalog-diff.cfg.rb +++ b/examples/octocatalog-diff.cfg.rb @@ -92,10 +92,19 @@ def self.config # If you don't specify this, SSL will still work, but the tool won't verify the certificate # of the puppetdb server it's connecting to. # More: https://github.com/github/octocatalog-diff/blob/master/doc/configuration-puppetdb.md + # ############################################################################################## # settings[:puppetdb_ssl_ca] = '/etc/puppetlabs/puppet/ssl/certs/ca.pem' + ############################################################################################## + # puppetdb_ssl_crl + # Certificate Revocation List provided by Puppetserver. You can specify an absolute path starting with `/`, or a relative path. + # + ############################################################################################## + + # settings[:puppetdb_ssl_crl] = '/etc/puppetlabs/puppet/ssl/crl.pem' + ############################################################################################## # puppetdb_ssl_client_key # puppetdb_ssl_client_password diff --git a/lib/octocatalog-diff/catalog-util/builddir.rb b/lib/octocatalog-diff/catalog-util/builddir.rb index d4106adb..67c43cc6 100644 --- a/lib/octocatalog-diff/catalog-util/builddir.rb +++ b/lib/octocatalog-diff/catalog-util/builddir.rb @@ -33,6 +33,7 @@ class BuildDir # :hiera_path [String] relative path to hiera data files (mutually exclusive with :hiera_path_strip) # :hiera_path_strip [String] string to strip off the beginning of :datadir # :puppetdb_ssl_ca [String] Path to SSL CA certificate + # :puppetdb_ssl_crl [String] Path to Certificate Revocation List # :puppetdb_ssl_client_key [String] String representation of SSL client key # :puppetdb_ssl_client_cert [String] String representation of SSL client certificate # :puppetdb_ssl_client_password [String] Password to unlock SSL private key @@ -273,6 +274,9 @@ def install_ssl(logger, options) # SSL CA provided? install_ssl_ca(logger, options) if options[:puppetdb_ssl_ca] + + # SSL CRL provided? + install_ssl_crl(logger, options) if options[:puppetdb_ssl_crl] end private @@ -360,6 +364,18 @@ def install_ssl_ca(logger, options) logger.debug "Installed CA certificate in #{ca_outfile}" end + # Install SSL Certificate Revocation List + # @param logger [Logger] Logger object + # @param options [Hash] Options hash + def install_ssl_crl(logger, options) + crl_file = options[:puppetdb_ssl_crl] + raise Errno::ENOENT, 'SSL CRL file does not exist' unless File.file?(crl_file) + crl_content = File.read(crl_file) + crl_outfile = File.join(@tempdir, 'var', 'ssl', 'crl.pem') + File.open(crl_outfile, 'w') { |f| f.write(crl_content) } + logger.debug "Installed Certificate Revocation List in #{crl_outfile}" + end + # Install SSL keypair for client certificate authentication # @param logger [Logger] Logger object # @param options [Hash] Options hash diff --git a/lib/octocatalog-diff/cli/options/puppetdb_ssl_crl.rb b/lib/octocatalog-diff/cli/options/puppetdb_ssl_crl.rb new file mode 100644 index 00000000..a2b0d49e --- /dev/null +++ b/lib/octocatalog-diff/cli/options/puppetdb_ssl_crl.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Specify the Certificate Revocation List for PuppetDB SSL. +# @param parser [OptionParser object] The OptionParser argument +# @param options [Hash] Options hash being constructed; this is modified in this method. +OctocatalogDiff::Cli::Options::Option.newoption(:puppetdb_ssl_crl) do + has_weight 310 + order_within_weight 11 + + def parse(parser, options) + parser.on('--puppetdb-ssl-crl FILENAME', 'Certificate Revocation List provided by the Puppetserver') do |x| + raise Errno::ENOENT, "--puppetdb-ssl-crl #{x} does not point to a valid file" unless File.file?(x) + options[:puppetdb_ssl_crl] = x + end + end +end diff --git a/lib/octocatalog-diff/puppetdb.rb b/lib/octocatalog-diff/puppetdb.rb index f0b360eb..e9bda1ba 100644 --- a/lib/octocatalog-diff/puppetdb.rb +++ b/lib/octocatalog-diff/puppetdb.rb @@ -37,6 +37,7 @@ class PuppetDB # @param :puppetdb_port [Integer] Port number, defaults to 8080 (non-SSL) or 8081 (SSL) # @param :puppetdb_ssl [Boolean] defaults to true, because you should use SSL # @param :puppetdb_ssl_ca [String] Path to file containing CA certificate + # @param :puppetdb_ssl_crl [String] Path to file containing CRL file # @param :puppetdb_ssl_verify [Boolean] Override the CA verification setting guessed from parameters # @param :puppetdb_ssl_client_pem [String] PEM-encoded client key and certificate # @param :puppetdb_ssl_client_p12 [String] pkcs12-encoded client key and certificate diff --git a/spec/octocatalog-diff/fixtures/ssl/generated/crl.pem b/spec/octocatalog-diff/fixtures/ssl/generated/crl.pem new file mode 100644 index 00000000..b1a77ebc --- /dev/null +++ b/spec/octocatalog-diff/fixtures/ssl/generated/crl.pem @@ -0,0 +1,17 @@ +-----BEGIN X509 CRL----- +MIICozCBjAIBATANBgkqhkiG9w0BAQsFADApMScwJQYDVQQDDB5QdXBwZXQgUm9v +dCBDQTogMzdiZjgzODVkMzdiNjMXDTIxMDMwOTE0MTY1M1oXDTM2MDMwNjE0MTcw +MVqgLzAtMB8GA1UdIwQYMBaAFEUp1Q73gDQrV1ayViXRzlDq6nbBMAoGA1UdFAQD +AgEAMA0GCSqGSIb3DQEBCwUAA4ICAQBx3Nb48rbfgu2yYB2g/EClor/neBjk31s9 +zOVwJMbje6qNMFdMeQjvbNtofBzh/2+AMv6KZuq9DNUthM+TkgiRWhSDf/5XWRph +BDC6r21DFdM8qaVsAt08u4qwlX3n+V0iOwfmeClv6EredC1ASbu91Nbk7RFQDBYh +HeviHy0SQXEEf5DdOvAMmTvnHHMVjM9rPS7ZtsyubDouLBVFFfNlOBZdzAqHHvTb +412ZzdQOcBsQ4+W6R3QqyNT3zMJVCG4+X3IBamtxMccEwvg1160wqb3CGtL+8IRK +2f+KzZStqupRVyvtKU1P6NegwtrMznJOLdmXbA96MbHlLwQQrO8Pngz0QXqAWGvR +idOgjOHJzrOkPtzyu7teHaCy/BHptwKi9zuyGoP9Q3k+qGxEFjvT3VyV+JJ3PtMQ +EO6DEnPZSa77BcQ0+PQsCVN320hadt5R1zERp6isgaPR9/VRfyqos5OjY3gFxM9j +pOYBCwRC32FotsCI5xwWxkaZk5L8gNbb9yCqFCixuNKd25Vsc/Ntij+XZquEpdst +t1GZ9/QQFvaEkU2VQcD37Q9H4TvSVuw90MgcYConwTqOsnOag9hftyqnR5QERMzk +mIWg3G31Yyu+BteM6cc4/uZ+WHXNZQNLv7osJT7yLTVm3PGedC1aqSfppzsMmr86 +vJiaDpccRw== +-----END X509 CRL----- diff --git a/spec/octocatalog-diff/tests/catalog-util/builddir_spec.rb b/spec/octocatalog-diff/tests/catalog-util/builddir_spec.rb index 49aa6b90..6e1a32ca 100644 --- a/spec/octocatalog-diff/tests/catalog-util/builddir_spec.rb +++ b/spec/octocatalog-diff/tests/catalog-util/builddir_spec.rb @@ -857,9 +857,15 @@ end let(:ca) { OctocatalogDiff::Spec.fixture_path('ssl/generated/ca.crt') } + let(:crl) { OctocatalogDiff::Spec.fixture_path('ssl/generated/crl.pem') } let(:cert) { File.read(OctocatalogDiff::Spec.fixture_path('ssl/generated/client.crt')) } let(:key) { File.read(OctocatalogDiff::Spec.fixture_path('ssl/generated/client.key')) } - let(:ssl_opts) { { puppetdb_ssl_ca: ca, puppetdb_ssl_client_cert: cert, puppetdb_ssl_client_key: key } } + let(:ssl_opts) do + { + puppetdb_ssl_ca: ca, puppetdb_ssl_crl: crl, + puppetdb_ssl_client_cert: cert, puppetdb_ssl_client_key: key + } + end let(:password) { 'password' } it 'should create directories when SSL setup is provided' do @@ -885,6 +891,13 @@ end.to raise_error(Errno::ENOENT, /SSL CA file does not exist/) end + it 'should error when CRL is specified but does not exist' do + opts = default_opts.merge(puppetdb_ssl_ca: ca, puppetdb_ssl_crl: 'asldfjasdflkasdfj') + expect do + OctocatalogDiff::CatalogUtil::BuildDir.new(opts, @logger) + end.to raise_error(Errno::ENOENT, /SSL CRL file does not exist/) + end + it 'should install the CA file in a known place' do opts = default_opts.merge(puppetdb_ssl_ca: ca) testobj = OctocatalogDiff::CatalogUtil::BuildDir.new(opts, @logger) @@ -893,6 +906,14 @@ expect(File.read(resultfile)).to eq(File.read(ca)) end + it 'should install the CRL file in a known place' do + opts = default_opts.merge(puppetdb_ssl_ca: ca, puppetdb_ssl_crl: crl) + testobj = OctocatalogDiff::CatalogUtil::BuildDir.new(opts, @logger) + resultfile = File.join(testobj.tempdir, 'var', 'ssl', 'crl.pem') + expect(File.file?(resultfile)).to eq(true) + expect(File.read(resultfile)).to eq(File.read(crl)) + end + it 'should install the client certificate in a known place' do opts = default_opts.merge(ssl_opts) testobj = OctocatalogDiff::CatalogUtil::BuildDir.new(opts, @logger) diff --git a/spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_crl_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_crl_spec.rb new file mode 100644 index 00000000..5e7bf3c8 --- /dev/null +++ b/spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_crl_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require_relative '../options_helper' + +describe OctocatalogDiff::Cli::Options do + describe '#opt_puppetdb_ssl_crl' do + it 'should handle --puppetdb-ssl-crl with a valid file' do + result = run_optparse(['--puppetdb-ssl-crl', OctocatalogDiff::Spec.fixture_path('ssl/generated/crl.pem')]) + expect(result[:puppetdb_ssl_crl]).to eq(OctocatalogDiff::Spec.fixture_path('ssl/generated/crl.pem')) + end + + it 'should error when ssl crl file is not found' do + expect do + run_optparse(['--puppetdb-ssl-crl', OctocatalogDiff::Spec.fixture_path('ssl/generated/caasdfadfs.crt')]) + end.to raise_error(Errno::ENOENT) + end + end +end