Skip to content
Snippets Groups Projects
Verified Commit 4119ad46 authored by Varac's avatar Varac
Browse files

Test certs with openssl and requests

We now add the letsencrypt staging CA bundle to the trust store
and validate certs against it.

Closes #132
parent d324ada1
No related branches found
No related tags found
No related merge requests found
......@@ -8,6 +8,18 @@ Specify host manually:
py.test -v --hosts='ssh://root@varac-oas.openappstack.net'
Run cert test manually using the ansible inventory file:
OAS_DOMAIN='varac-oas.openappstack.net' py.test -v -m 'certs' \
--connection=ansible \
--ansible-inventory=../ansible/inventory.yml \
--hosts='ansible://*'
Run cert test manually against a different cluster, not configured in any
ansible inventory file:
OAS_DOMAIN='varac-oas.openappstack.net' py.test -v -m 'certs'
# Issues
- Default ssh backend is `paramiko`, which doesn't work oout of the
......
-----BEGIN CERTIFICATE-----
MIIEqzCCApOgAwIBAgIRAIvhKg5ZRO08VGQx8JdhT+UwDQYJKoZIhvcNAQELBQAw
GjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMB4XDTE2MDUyMzIyMDc1OVoXDTM2
MDUyMzIyMDc1OVowIjEgMB4GA1UEAwwXRmFrZSBMRSBJbnRlcm1lZGlhdGUgWDEw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtWKySDn7rWZc5ggjz3ZB0
8jO4xti3uzINfD5sQ7Lj7hzetUT+wQob+iXSZkhnvx+IvdbXF5/yt8aWPpUKnPym
oLxsYiI5gQBLxNDzIec0OIaflWqAr29m7J8+NNtApEN8nZFnf3bhehZW7AxmS1m0
ZnSsdHw0Fw+bgixPg2MQ9k9oefFeqa+7Kqdlz5bbrUYV2volxhDFtnI4Mh8BiWCN
xDH1Hizq+GKCcHsinDZWurCqder/afJBnQs+SBSL6MVApHt+d35zjBD92fO2Je56
dhMfzCgOKXeJ340WhW3TjD1zqLZXeaCyUNRnfOmWZV8nEhtHOFbUCU7r/KkjMZO9
AgMBAAGjgeMwgeAwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw
HQYDVR0OBBYEFMDMA0a5WCDMXHJw8+EuyyCm9Wg6MHoGCCsGAQUFBwEBBG4wbDA0
BggrBgEFBQcwAYYoaHR0cDovL29jc3Auc3RnLXJvb3QteDEubGV0c2VuY3J5cHQu
b3JnLzA0BggrBgEFBQcwAoYoaHR0cDovL2NlcnQuc3RnLXJvb3QteDEubGV0c2Vu
Y3J5cHQub3JnLzAfBgNVHSMEGDAWgBTBJnSkikSg5vogKNhcI5pFiBh54DANBgkq
hkiG9w0BAQsFAAOCAgEABYSu4Il+fI0MYU42OTmEj+1HqQ5DvyAeyCA6sGuZdwjF
UGeVOv3NnLyfofuUOjEbY5irFCDtnv+0ckukUZN9lz4Q2YjWGUpW4TTu3ieTsaC9
AFvCSgNHJyWSVtWvB5XDxsqawl1KzHzzwr132bF2rtGtazSqVqK9E07sGHMCf+zp
DQVDVVGtqZPHwX3KqUtefE621b8RI6VCl4oD30Olf8pjuzG4JKBFRFclzLRjo/h7
IkkfjZ8wDa7faOjVXx6n+eUQ29cIMCzr8/rNWHS9pYGGQKJiY2xmVC9h12H99Xyf
zWE9vb5zKP3MVG6neX1hSdo7PEAb9fqRhHkqVsqUvJlIRmvXvVKTwNCP3eCjRCCI
PTAvjV+4ni786iXwwFYNz8l3PmPLCyQXWGohnJ8iBm+5nk7O2ynaPVW0U2W+pt2w
SVuvdDM5zGv2f9ltNWUiYZHJ1mmO97jSY/6YfdOUH66iRtQtDkHBRdkNBsMbD+Em
2TgBldtHNSJBfB3pm9FblgOcJ0FSWcUDWJ7vO0+NTXlgrRofRT6pVywzxVo6dND0
WzYlTWeUVsO40xJqhgUQRER9YLOLxJ0O6C8i0xFxAMKOtSdodMB3RIwt7RFQ0uyt
n5Z5MqkYhlMI3J1tPRTp1nEt9fyGspBOO05gi148Qasp+3N+svqKomoQglNoAxU=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFATCCAumgAwIBAgIRAKc9ZKBASymy5TLOEp57N98wDQYJKoZIhvcNAQELBQAw
GjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMB4XDTE2MDMyMzIyNTM0NloXDTM2
MDMyMzIyNTM0NlowGjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMIICIjANBgkq
hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA+pYHvQw5iU3v2b3iNuYNKYgsWD6KU7aJ
diddtZQxSWYzUI3U0I1UsRPTxnhTifs/M9NW4ZlV13ZfB7APwC8oqKOIiwo7IwlP
xg0VKgyz+kT8RJfYr66PPIYP0fpTeu42LpMJ+CKo9sbpgVNDZN2z/qiXrRNX/VtG
TkPV7a44fZ5bHHVruAxvDnylpQxJobtCBWlJSsbIRGFHMc2z88eUz9NmIOWUKGGj
EmP76x8OfRHpIpuxRSCjn0+i9+hR2siIOpcMOGd+40uVJxbRRP5ZXnUFa2fF5FWd
O0u0RPI8HON0ovhrwPJY+4eWKkQzyC611oLPYGQ4EbifRsTsCxUZqyUuStGyp8oa
aoSKfF6X0+KzGgwwnrjRTUpIl19A92KR0Noo6h622OX+4sZiO/JQdkuX5w/HupK0
A0M0WSMCvU6GOhjGotmh2VTEJwHHY4+TUk0iQYRtv1crONklyZoAQPD76hCrC8Cr
IbgsZLfTMC8TWUoMbyUDgvgYkHKMoPm0VGVVuwpRKJxv7+2wXO+pivrrUl2Q9fPe
Kk055nJLMV9yPUdig8othUKrRfSxli946AEV1eEOhxddfEwBE3Lt2xn0hhiIedbb
Ftf/5kEWFZkXyUmMJK8Ra76Kus2ABueUVEcZ48hrRr1Hf1N9n59VbTUaXgeiZA50
qXf2bymE6F8CAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB
Af8wHQYDVR0OBBYEFMEmdKSKRKDm+iAo2FwjmkWIGHngMA0GCSqGSIb3DQEBCwUA
A4ICAQBCPw74M9X/Xx04K1VAES3ypgQYH5bf9FXVDrwhRFSVckria/7dMzoF5wln
uq9NGsjkkkDg17AohcQdr8alH4LvPdxpKr3BjpvEcmbqF8xH+MbbeUEnmbSfLI8H
sefuhXF9AF/9iYvpVNC8FmJ0OhiVv13VgMQw0CRKkbtjZBf8xaEhq/YqxWVsgOjm
dm5CAQ2X0aX7502x8wYRgMnZhA5goC1zVWBVAi8yhhmlhhoDUfg17cXkmaJC5pDd
oenZ9NVhW8eDb03MFCrWNvIh89DDeCGWuWfDltDq0n3owyL0IeSn7RfpSclpxVmV
/53jkYjwIgxIG7Gsv0LKMbsf6QdBcTjhvfZyMIpBRkTe3zuHd2feKzY9lEkbRvRQ
zbh4Ps5YBnG6CKJPTbe2hfi3nhnw/MyEmF3zb0hzvLWNrR9XW3ibb2oL3424XOwc
VjrTSCLzO9Rv6s5wi03qoWvKAQQAElqTYRHhynJ3w6wuvKYF5zcZF3MDnrVGLbh1
Q9ePRFBCiXOQ6wPLoUhrrbZ8LpFUFYDXHMtYM7P9sc9IAWoONXREJaO08zgFtMp4
8iyIYUyQAbsvx8oD2M8kRvrIRSrRJSl6L957b4AFiLIQ/GgV2curs0jje7Edx34c
idWw1VrejtwclobqNMVtG3EiPUIpJGpbMcJgbiLSmKkrvQtGng==
-----END CERTIFICATE-----
#!/usr/bin/env python3
"""Validates remote TLS certs."""
import pycurl
import certifi
from io import BytesIO
import os
import pytest
import requests
import socket
import shutil
import sys
from OpenSSL import SSL
def add_custom_cert_authorities(ca_file: str,
custom_ca_files: list,
destination_file: str =
'/tmp/custom_ca_bundle.crt'):
"""Concanates existing cert bundle with custom CAs."""
destination = open(destination_file, 'wb')
shutil.copyfileobj(open(ca_file, 'rb'), destination)
for custom_ca_file in custom_ca_files:
shutil.copyfileobj(open(custom_ca_file, 'rb'), destination)
destination.close()
def check_cert_url(url: str):
print('Testing URL: ', url)
buffer = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, url)
c.setopt(c.WRITEDATA, buffer)
c.setopt(c.CAINFO, certifi.where())
c.setopt(c.VERBOSE, True)
def fetch_certs(domain: str, port: int = 443):
"""Fetches cert fom given domain."""
s = socket.socket()
context = SSL.Context(SSL.TLSv1_2_METHOD)
conn = SSL.Connection(context, s)
conn.set_tlsext_host_name(domain.encode('utf-8'))
certs = []
try:
c.perform()
valid_cert = True
except pycurl.error as e:
valid_cert = False
print('Cert error!')
if e.args[0] == pycurl.E_COULDNT_CONNECT and c.exception:
print(c.exception)
else:
print(e)
c.close()
conn.connect((domain, port))
except socket.gaierror as e:
print('socket.gaierror: {0}'.format(str(e)))
sys.exit(1)
conn.do_handshake()
try:
certs = conn.get_peer_cert_chain()
except SSL.Error as e:
print('SSL Error: {0}'.format(str(e)))
sys.exit(1)
return certs
def inspect_certs(certs: list):
"""Show CN and issuer CN of cert list."""
return valid_cert
for cert in certs:
subject = cert.get_subject()
cn = subject.CN
issuer = cert.get_issuer().CN
# issued_by = issuer.CN
print('CN: {0} (Issuer: {1})'.format(cn, issuer))
def valid_cert(domain: str, ca_file: str = '/tmp/custom_ca_bundle.crt'):
"""Validate cert of given domain against a ca_file bundle."""
url = 'https://' + domain
print('Validating cert from {0} ...'.format(url))
inspect_certs(fetch_certs(domain))
try:
requests.get(url, verify=ca_file)
except requests.exceptions.SSLError as ex:
print('SSL Verification Error %s' % ex)
return False
print('Successfully Verified SSL Cert.\n')
return True
@pytest.mark.certs
def test_cert_validation(host):
domain = os.environ.get("OAS_DOMAIN")
assert domain, "Please export OAS_DOMAIN as environment variable."
# Check traefik cert
assert check_cert_url('https://traefi.%s/' % domain)
add_custom_cert_authorities(certifi.where(),
['pytest/le-staging-bundle.pem'])
# Check nextcloud cert
assert valid_cert('files.%s' % domain)
if __name__ == "__main__":
test_cert_validation('')
ansible>=2.7.0
behave-webdriver>=0.2.2
certifi>=2019.3.9
# Needed for ansible k8s resource
openshift>=0.8.6
psutil>=5.5.0
pycurl>=7.43.0.2
pyopenssl>=19.0.0
pytest>=4.3.0
requests>=2.19.1
tabulate>=0.8.3
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment