Skip to content

Commit 861921e

Browse files
committed
(PUP-11428) Add integration tests
Adds 2 tests for the agent ssl bootstrapping. Also adds pending test for reloading a CRL between runs. It performs an agent run which overwrites the agent's cert and key (to one that is revoked). The second run should then fail, but doesn't currently. We stub the `run_event_loop` to ensure we don't get into an infinite loop.
1 parent 56c91a0 commit 861921e

File tree

3 files changed

+153
-6
lines changed

3 files changed

+153
-6
lines changed

spec/integration/application/agent_spec.rb

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require 'puppet_spec/puppetserver'
44
require 'puppet_spec/compiler'
55
require 'puppet_spec/https'
6+
require 'puppet/application/agent'
67

78
describe "puppet agent", unless: Puppet::Util::Platform.jruby? do
89
include PuppetSpec::Files
@@ -737,4 +738,112 @@ def with_another_agent_running(&block)
737738
end
738739
end
739740
end
741+
742+
context "ssl" do
743+
context "bootstrapping" do
744+
before :each do
745+
# reconfigure ssl to non-existent dir and files to force bootstrapping
746+
dir = tmpdir('ssl')
747+
Puppet[:ssldir] = dir
748+
Puppet[:localcacert] = File.join(dir, 'ca.pem')
749+
Puppet[:hostcrl] = File.join(dir, 'crl.pem')
750+
Puppet[:hostprivkey] = File.join(dir, 'cert.pem')
751+
Puppet[:hostcert] = File.join(dir, 'key.pem')
752+
753+
Puppet[:daemonize] = false
754+
Puppet[:logdest] = 'console'
755+
Puppet[:log_level] = 'info'
756+
end
757+
758+
it "exits if the agent is not allowed to wait" do
759+
Puppet[:waitforcert] = 0
760+
761+
server.start_server do |port|
762+
Puppet[:serverport] = port
763+
expect {
764+
agent.run
765+
}.to exit_with(1)
766+
.and output(%r{Exiting now because the waitforcert setting is set to 0}).to_stdout
767+
.and output(%r{Failed to submit the CSR, HTTP response was 404}).to_stderr
768+
end
769+
end
770+
771+
it "exits if the maxwaitforcert time is exceeded" do
772+
Puppet[:waitforcert] = 1
773+
Puppet[:maxwaitforcert] = 1
774+
775+
server.start_server do |port|
776+
Puppet[:serverport] = port
777+
expect {
778+
agent.run
779+
}.to exit_with(1)
780+
.and output(%r{Couldn't fetch certificate from CA server; you might still need to sign this agent's certificate \(127.0.0.1\). Exiting now because the maxwaitforcert timeout has been exceeded.}).to_stdout
781+
.and output(%r{Failed to submit the CSR, HTTP response was 404}).to_stderr
782+
end
783+
end
784+
end
785+
786+
def copy_fixtures(sources, dest)
787+
ssldir = File.join(PuppetSpec::FIXTURE_DIR, 'ssl')
788+
File.open(dest, 'w') do |f|
789+
sources.each do |s|
790+
f.write(File.read(File.join(ssldir, s)))
791+
end
792+
end
793+
end
794+
795+
it "reloads the CRL between runs" do
796+
Puppet[:localcacert] = ca = tmpfile('ca')
797+
Puppet[:hostcrl] = crl = tmpfile('crl')
798+
Puppet[:hostcert] = cert = tmpfile('cert')
799+
Puppet[:hostprivkey] = key = tmpfile('key')
800+
801+
copy_fixtures(%w[ca.pem intermediate.pem], ca)
802+
copy_fixtures(%w[crl.pem intermediate-crl.pem], crl)
803+
copy_fixtures(%w[127.0.0.1.pem], cert)
804+
copy_fixtures(%w[127.0.0.1-key.pem], key)
805+
806+
revoked = cert_fixture('revoked.pem')
807+
revoked_key = key_fixture('revoked-key.pem')
808+
809+
mounts = {}
810+
mounts[:catalog] = -> (req, res) {
811+
catalog = compile_to_catalog(<<~MANIFEST, node)
812+
file { '#{cert}':
813+
ensure => file,
814+
content => '#{revoked}'
815+
}
816+
file { '#{key}':
817+
ensure => file,
818+
content => '#{revoked_key}'
819+
}
820+
MANIFEST
821+
822+
res.body = formatter.render(catalog)
823+
res['Content-Type'] = formatter.mime
824+
}
825+
826+
server.start_server(mounts: mounts) do |port|
827+
Puppet[:serverport] = port
828+
Puppet[:daemonize] = false
829+
Puppet[:runinterval] = 1
830+
Puppet[:waitforcert] = 1
831+
Puppet[:maxwaitforcert] = 1
832+
833+
# simulate two runs of the agent, then return so we don't infinite loop
834+
allow_any_instance_of(Puppet::Daemon).to receive(:run_event_loop) do |instance|
835+
instance.agent.run(splay: false)
836+
instance.agent.run(splay: false)
837+
end
838+
839+
pending("PUP-11428: the second run should fail due to the revoked client cert")
840+
agent.command_line.args << '--verbose'
841+
expect {
842+
agent.run
843+
}.to exit_with(1)
844+
.and output(%r{Exiting now because the maxwaitforcert timeout has been exceeded}).to_stdout
845+
.and output(%r{Certificate 'CN=revoked' is revoked}).to_stderr
846+
end
847+
end
848+
end
740849
end

spec/lib/puppet_spec/puppetserver.rb

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,40 @@ def do_HEAD request, response
7272
end
7373
end
7474

75+
class CertificateServlet < WEBrick::HTTPServlet::AbstractServlet
76+
def initialize(server, ca_cert)
77+
super(server)
78+
@ca_cert = ca_cert
79+
end
80+
81+
def do_GET request, response
82+
if request.path =~ %r{/puppet-ca/v1/certificate/ca$}
83+
response['Content-Type'] = 'text/plain'
84+
response.body = @ca_cert.to_pem
85+
else
86+
response.status = 404
87+
end
88+
end
89+
end
90+
91+
class CertificateRevocationListServlet < WEBrick::HTTPServlet::AbstractServlet
92+
def initialize(server, crl)
93+
super(server)
94+
@crl = crl
95+
end
96+
97+
def do_GET request, response
98+
response['Content-Type'] = 'text/plain'
99+
response.body = @crl.to_pem
100+
end
101+
end
102+
103+
class CertificateRequestServlet < WEBrick::HTTPServlet::AbstractServlet
104+
def do_PUT request, response
105+
response.status = 404
106+
end
107+
end
108+
75109
def initialize
76110
@ca_cert = cert_fixture('ca.pem')
77111
@ca_crl = crl_fixture('crl.pem')
@@ -125,15 +159,18 @@ def register_mounts(mounts: {})
125159
register_mount('/puppet/v3/static_file_content', mounts[:static_file_content], StaticFileContentServlet)
126160
register_mount('/puppet/v3/report', mounts[:report], ReportServlet)
127161
register_mount('/puppet/v3/file_bucket_file', mounts[:filebucket], FilebucketServlet)
162+
register_mount('/puppet-ca/v1/certificate', mounts[:certificate], CertificateServlet, @ca_cert)
163+
register_mount('/puppet-ca/v1/certificate_revocation_list', mounts[:certificate_revocation_list], CertificateRevocationListServlet, @ca_crl)
164+
register_mount('/puppet-ca/v1/certificate_request', mounts[:certificate_request], CertificateRequestServlet)
128165
end
129166

130-
def register_mount(path, user_proc, default_servlet)
167+
def register_mount(path, user_proc, default_servlet, *args)
131168
handler = if user_proc
132169
WEBrick::HTTPServlet::ProcHandler.new(user_proc)
133170
else
134171
default_servlet
135172
end
136-
@https.mount(path, handler)
173+
@https.mount(path, handler, *args)
137174
end
138175

139176
def upload_directory

tasks/generate_cert_fixtures.rake

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,15 @@ task(:gen_cert_fixtures) do
3737
# | |
3838
# signed.pem | +- /CN=signed
3939
# revoked.pem | +- /CN=revoked
40-
# 127.0.0.1.pem | +- /CN=127.0.0.1 (with dns alt names)
4140
# tampered-cert.pem | +- /CN=signed (with different public key)
4241
# ec.pem | +- /CN=ec (with EC private key)
4342
# oid.pem | +- /CN=oid (with custom oid)
4443
# |
45-
# + /CN=Test CA Agent Subauthority
46-
# | |
47-
# pluto.pem | +- /CN=pluto
44+
# 127.0.0.1.pem +- /CN=127.0.0.1 (with dns alt names)
45+
# |
46+
# intermediate-agent.pem +- /CN=Test CA Agent Subauthority
47+
# | |
48+
# pluto.pem | +- /CN=pluto
4849
# |
4950
# bad-int-basic-constraints.pem +- /CN=Test CA Subauthority (bad isCA constraint)
5051
#

0 commit comments

Comments
 (0)