Skip to content

Commit 3f6ffa8

Browse files
committed
(PUP-7737) Allow http report processor to trust the system CA store
Adds a `Puppet[:report_include_system_store]` setting that defaults to false. If set to true, the "http" report processor will trust the system certificate store when submitting reports to an HTTPS report server. If false, then the processor only trusts the puppet CA. When installed from puppet-agent packages the system store is installed in `/opt/puppetlabs/puppet/ssl/cert*` or on Windows `C:\Program Files\Puppet Labs\Puppet\puppet\ssl\cert*`. Note this change only affects the `http` report processor when running `puppet apply`. A separate change is needed in puppetserver when the "http" processor runs in puppetserver. Skip all of the apply integration tests on jruby, like we do for agent.
1 parent f136aea commit 3f6ffa8

File tree

3 files changed

+67
-3
lines changed

3 files changed

+67
-3
lines changed

lib/puppet/defaults.rb

+10
Original file line numberDiff line numberDiff line change
@@ -1795,6 +1795,16 @@ def self.initialize_default_settings!(settings)
17951795
:type => :boolean,
17961796
:desc => "Whether to send reports after every transaction.",
17971797
},
1798+
:report_include_system_store => {
1799+
:default => false,
1800+
:type => :boolean,
1801+
:desc => "Whether the 'http' report processor should include the system
1802+
certificate store when submitting reports to HTTPS URLs. If false, then
1803+
the 'http' processor will only trust HTTPS report servers whose certificates
1804+
are issued by the puppet CA or one of its intermediate CAs. If true, the
1805+
processor will additionally trust CA certificates in the system's
1806+
certificate store."
1807+
},
17981808
:resubmit_facts => {
17991809
:default => false,
18001810
:type => :boolean,

lib/puppet/reports/http.rb

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def process
2323
options = {
2424
:metric_id => [:puppet, :report, :http],
2525
:body => self.to_yaml,
26+
:include_system_store => Puppet[:report_include_system_store],
2627
}
2728

2829
if url.user && url.password

spec/integration/application/apply_spec.rb

+56-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
require 'puppet_spec/compiler'
44
require 'puppet_spec/https'
55

6-
describe "apply" do
6+
describe "apply", unless: Puppet::Util::Platform.jruby? do
77
include PuppetSpec::Files
88

99
before :each do
@@ -258,7 +258,7 @@ class mod {
258258
expect(@logs.map(&:to_s)).to include(/{environment =>.*/)
259259
end
260260

261-
it "applies a given file even when an ENC is configured", :unless => Puppet::Util::Platform.windows? || RUBY_PLATFORM == 'java' do
261+
it "applies a given file even when an ENC is configured", :unless => Puppet::Util::Platform.windows? || Puppet::Util::Platform.jruby? do
262262
manifest = file_containing("manifest.pp", "notice('specific manifest applied')")
263263
enc = script_containing('enc_script',
264264
:windows => '@echo classes: []' + "\n" + '@echo environment: special',
@@ -379,7 +379,7 @@ def init_cli_args_and_apply_app(args, execute)
379379
# External node script execution will fail, likely due to the tampering
380380
# with the basic file descriptors.
381381
# Workaround: Define a log destination and merely inspect logs.
382-
context "with an ENC", :unless => RUBY_PLATFORM == 'java' do
382+
context "with an ENC" do
383383
let(:logdest) { tmpfile('logdest') }
384384
let(:args) { ['-e', execute, '--logdest', logdest ] }
385385
let(:enc) do
@@ -587,6 +587,14 @@ def bogus()
587587
end
588588

589589
let(:apply) { Puppet::Application[:apply] }
590+
let(:unknown_server) do
591+
unknown_ca_cert = cert_fixture('unknown-ca.pem')
592+
PuppetSpec::HTTPSServer.new(
593+
ca_cert: unknown_ca_cert,
594+
server_cert: cert_fixture('unknown-127.0.0.1.pem'),
595+
server_key: key_fixture('unknown-127.0.0.1-key.pem')
596+
)
597+
end
590598

591599
it 'submits a report via reporturl' do
592600
report = nil
@@ -609,5 +617,50 @@ def bogus()
609617
expect(report.resource_statuses['Notify[hi]']).to be_a(Puppet::Resource::Status)
610618
end
611619
end
620+
621+
it 'rejects an HTTPS report server whose root cert is not the puppet CA' do
622+
unknown_server.start_server do |https_port|
623+
Puppet[:reporturl] = "https://127.0.0.1:#{https_port}/reports/upload"
624+
625+
# processing the report happens after the transaction is finished,
626+
# so we expect exit code 0, with a later failure on stderr
627+
expect {
628+
apply.command_line.args = ['-e', 'notify { "hi": }']
629+
apply.run
630+
}.to exit_with(0)
631+
.and output(/Applied catalog/).to_stdout
632+
.and output(/Report processor failed: certificate verify failed \[self signed certificate in certificate chain for CN=Unknown CA\]/).to_stderr
633+
end
634+
end
635+
636+
it 'accepts an HTTPS report servers whose cert is in the system CA store' do
637+
Puppet[:report_include_system_store] = true
638+
report = nil
639+
640+
response_proc = -> (req, res) {
641+
report = Puppet::Transaction::Report.convert_from(:yaml, req.body)
642+
}
643+
644+
# create a temp cacert bundle
645+
ssl_file = tmpfile('systemstore')
646+
File.write(ssl_file, unknown_server.ca_cert.to_pem)
647+
648+
unknown_server.start_server(response_proc: response_proc) do |https_port|
649+
Puppet[:reporturl] = "https://127.0.0.1:#{https_port}/reports/upload"
650+
651+
# override path to system cacert bundle, this must be done before
652+
# the SSLContext is created and the call to X509::Store.set_default_paths
653+
Puppet::Util.withenv("SSL_CERT_FILE" => ssl_file) do
654+
expect {
655+
apply.command_line.args = ['-e', 'notify { "hi": }']
656+
apply.run
657+
}.to exit_with(0)
658+
.and output(/Applied catalog/).to_stdout
659+
end
660+
661+
expect(report).to be_a(Puppet::Transaction::Report)
662+
expect(report.resource_statuses['Notify[hi]']).to be_a(Puppet::Resource::Status)
663+
end
664+
end
612665
end
613666
end

0 commit comments

Comments
 (0)