c9215801f0
This autogenerates the list of ssl domains for the ssl-cert-check tool directly from the letsencrypt list. The first step is the install-certcheck role that replaces the puppet-ssl_cert_check module that does the same. The reason for this is so that during gate testing we can test this on the test bridge.openstack.org server, and avoid adding another node as a requirement for this test. letsencrypt-request-certs is updated to set a fact letsencrypt_certcheck_domains for each host that is generating a certificate. As described in the comments, this defaults to the first host specified for the certificate and the listening port can be indicated (if set, this new port value is stripped when generating certs as is not necessary for certificate generation). The new letsencrypt-config-certcheck role runs and iterates all letsencrypt hosts to build the final list of domains that should be checked. This is then extended with the letsencrypt_certcheck_additional_domains value that covers any hosts using certificates not provisioned by letsencrypt using this mechanism. These additional domains are pre-populated from the openstack.org domains in the extant check file, minus those openstack.org domain certificates we are generating via letsencrypt (see letsencrypt-create-certs/handlers/main.yaml). Additionally, we update some of the certificate variables in host_vars that are listening on port !443. As mentioned, bridge.openstack.org is placed in the new certcheck group for gate testing, so the tool and config file will be deployed to it. For production, cacti is added to the group, which is where the tool currently runs. The extant puppet installation is disabled, pending removal in a follow-on change. Change-Id: Idbe084f13f3684021e8efd9ac69b63fe31484606
164 lines
5.9 KiB
Python
164 lines
5.9 KiB
Python
# Copyright 2019 Red Hat, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import pytest
|
|
|
|
testinfra_hosts = ['adns-letsencrypt.opendev.org',
|
|
'bridge.openstack.org',
|
|
'letsencrypt01.opendev.org',
|
|
'letsencrypt02.opendev.org']
|
|
|
|
|
|
def test_acme_zone(host):
|
|
if host.backend.get_hostname() != 'adns-letsencrypt.opendev.org':
|
|
pytest.skip()
|
|
acme_opendev_zone = host.file('/var/lib/bind/zones/acme.opendev.org/zone.db')
|
|
assert acme_opendev_zone.exists
|
|
|
|
# On our test nodes, unbound is listening on 127.0.0.1:53; this
|
|
# ensures the query hits bind
|
|
query_addr = host.ansible("setup")["ansible_facts"]["ansible_default_ipv4"]["address"]
|
|
cmd = host.run("dig -t txt acme.opendev.org @" + query_addr)
|
|
count = 0
|
|
for line in cmd.stdout.split('\n'):
|
|
if line.startswith('acme.opendev.org. 60 IN TXT'):
|
|
count = count + 1
|
|
if count != 6:
|
|
# NOTE(ianw): I'm sure there's more pytest-y ways to save this
|
|
# for debugging ...
|
|
print(cmd.stdout)
|
|
assert count == 6, "Did not see required number of TXT records!"
|
|
|
|
def test_certs_created(host):
|
|
if host.backend.get_hostname() == 'letsencrypt01.opendev.org':
|
|
domain_one = host.file(
|
|
'/etc/letsencrypt-certs/'
|
|
'letsencrypt01.opendev.org/letsencrypt01.opendev.org.key')
|
|
assert domain_one.exists
|
|
assert domain_one.user == "root"
|
|
assert domain_one.group == "letsencrypt"
|
|
assert domain_one.mode == 0o640
|
|
|
|
cert_one = host.file(
|
|
'/etc/letsencrypt-certs/'
|
|
'letsencrypt01.opendev.org/letsencrypt01.opendev.org.cer')
|
|
assert cert_one.exists
|
|
assert cert_one.user == "root"
|
|
assert cert_one.group == "letsencrypt"
|
|
assert cert_one.mode == 0o640
|
|
|
|
ca_one = host.file(
|
|
'/etc/letsencrypt-certs/'
|
|
'letsencrypt01.opendev.org/ca.cer')
|
|
assert ca_one.exists
|
|
assert ca_one.user == "root"
|
|
assert ca_one.group == "letsencrypt"
|
|
assert ca_one.mode == 0o640
|
|
|
|
domain_two = host.file(
|
|
'/etc/letsencrypt-certs/'
|
|
'someotherservice.opendev.org/someotherservice.opendev.org.key')
|
|
assert domain_two.exists
|
|
assert domain_two.user == "root"
|
|
assert domain_two.group == "letsencrypt"
|
|
assert domain_two.mode == 0o640
|
|
|
|
cert_two = host.file(
|
|
'/etc/letsencrypt-certs/'
|
|
'someotherservice.opendev.org/someotherservice.opendev.org.cer')
|
|
assert cert_two.exists
|
|
assert cert_two.user == "root"
|
|
assert cert_two.group == "letsencrypt"
|
|
assert cert_two.mode == 0o640
|
|
|
|
ca_two = host.file(
|
|
'/etc/letsencrypt-certs/'
|
|
'someotherservice.opendev.org/ca.cer')
|
|
assert ca_one.exists
|
|
assert ca_one.user == "root"
|
|
assert ca_one.group == "letsencrypt"
|
|
assert ca_one.mode == 0o640
|
|
|
|
elif host.backend.get_hostname() == 'letsencrypt02.opendev.org':
|
|
domain_one = host.file(
|
|
'/etc/letsencrypt-certs/'
|
|
'letsencrypt02.opendev.org/letsencrypt02.opendev.org.key')
|
|
assert domain_one.exists
|
|
assert domain_one.user == "root"
|
|
assert domain_one.group == "letsencrypt"
|
|
assert domain_one.mode == 0o640
|
|
|
|
cert_one = host.file(
|
|
'/etc/letsencrypt-certs/'
|
|
'letsencrypt02.opendev.org/letsencrypt02.opendev.org.cer')
|
|
assert cert_one.exists
|
|
assert cert_one.user == "root"
|
|
assert cert_one.group == "letsencrypt"
|
|
assert cert_one.mode == 0o640
|
|
|
|
ca_one = host.file(
|
|
'/etc/letsencrypt-certs/'
|
|
'letsencrypt02.opendev.org/ca.cer')
|
|
assert ca_one.exists
|
|
assert ca_one.user == "root"
|
|
assert ca_one.group == "letsencrypt"
|
|
assert ca_one.mode == 0o640
|
|
|
|
else:
|
|
pytest.skip()
|
|
|
|
def test_updated_handler(host):
|
|
if host.backend.get_hostname() == 'letsencrypt01.opendev.org':
|
|
stamp_file = host.file('/tmp/letsencrypt01-main-service.stamp')
|
|
assert stamp_file.exists
|
|
stamp_file = host.file('/tmp/letsencrypt01-other-service.stamp')
|
|
assert stamp_file.exists
|
|
|
|
elif host.backend.get_hostname() == 'letsencrypt02.opendev.org':
|
|
stamp_file = host.file('/tmp/letsencrypt02-main-service.stamp')
|
|
assert stamp_file.exists
|
|
|
|
else:
|
|
pytest.skip()
|
|
|
|
def test_acme_sh_config(host):
|
|
if not host.backend.get_hostname().startswith('letsencrypt0'):
|
|
pytest.skip()
|
|
|
|
config = host.file('/root/.acme.sh/account.conf')
|
|
assert config.exists
|
|
assert config.contains("^ACCOUNT_EMAIL='le-test@opendev.org'")
|
|
|
|
def test_certcheck_config(host, zuul_data):
|
|
if host.backend.get_hostname() != 'bridge.openstack.org':
|
|
pytest.skip()
|
|
|
|
if zuul_data['extra']['zuul']['job'] != 'system-config-run-letsencrypt':
|
|
pytest.skip()
|
|
|
|
domainlist = host.file('/var/lib/certcheck/ssldomains')
|
|
|
|
# TODO(ianw): figure out a flag or something from the
|
|
# system-config-run-letsencrypt test so that we can assert this
|
|
# file exists only in that case.
|
|
if not domainlist.exists:
|
|
pytest.skip()
|
|
|
|
assert domainlist.exists
|
|
assert domainlist.user == 'certcheck'
|
|
# from variables
|
|
assert domainlist.contains('^letsencrypt01.opendev.org 5000')
|
|
# from extra list; may need to change if list is modified
|
|
assert domainlist.contains('^wiki.openstack.org 443')
|