diff options
Diffstat (limited to 'ansible/roles/certs/files')
-rwxr-xr-x | ansible/roles/certs/files/leforward.py | 68 | ||||
-rw-r--r-- | ansible/roles/certs/files/lets-encrypt-x3-cross-signed.pem | 27 |
2 files changed, 95 insertions, 0 deletions
diff --git a/ansible/roles/certs/files/leforward.py b/ansible/roles/certs/files/leforward.py new file mode 100755 index 0000000..dccbac1 --- /dev/null +++ b/ansible/roles/certs/files/leforward.py | |||
@@ -0,0 +1,68 @@ | |||
1 | #!/usr/bin/env python3 | ||
2 | |||
3 | """ Run a single-purpose HTTP server. | ||
4 | |||
5 | Server takes all GET requests and redirects them to a new host | ||
6 | if the request URI starts with SUBPATH, otherwise returns 404. | ||
7 | |||
8 | Requests are redirected to the URL provided by --baseurl. """ | ||
9 | |||
10 | import socketserver | ||
11 | import http.server | ||
12 | import argparse | ||
13 | import sys | ||
14 | |||
15 | |||
16 | CHALLENGE_HOST = None | ||
17 | SUBPATH = "/.well-known/acme-challenge" | ||
18 | |||
19 | |||
20 | class RedirectChallenges(http.server.BaseHTTPRequestHandler): | ||
21 | def do_GET(self): | ||
22 | if self.path.startswith(SUBPATH): | ||
23 | self.send_response(301) | ||
24 | self.send_header('Location', f"{CHALLENGE_HOST}{self.path}") | ||
25 | else: | ||
26 | self.send_response(404) | ||
27 | |||
28 | self.end_headers() | ||
29 | |||
30 | |||
31 | class ReusableServer(socketserver.TCPServer): | ||
32 | """ Allow TCPServer to reuse host address. | ||
33 | |||
34 | Without setting 'allow_reuse_address', we can get stuck in | ||
35 | TIME_WAIT after being killed and the stale state stops a new | ||
36 | server from attaching to the port.""" | ||
37 | |||
38 | allow_reuse_address = True | ||
39 | |||
40 | |||
41 | if __name__ == "__main__": | ||
42 | parser = argparse.ArgumentParser( | ||
43 | description="Redirect all URIs with matching prefix to another host") | ||
44 | parser.add_argument( | ||
45 | '--baseurl', | ||
46 | dest='baseurl', | ||
47 | required=True, | ||
48 | help="Destination URL for all matching URIs on this server") | ||
49 | |||
50 | args = parser.parse_args() | ||
51 | CHALLENGE_HOST = args.baseurl | ||
52 | |||
53 | if not CHALLENGE_HOST.startswith("http"): | ||
54 | print("Redirect URL must be a full URL starting with http") | ||
55 | sys.exit(1) | ||
56 | |||
57 | # If user gave us a trailing slash URL, remove slash. | ||
58 | if CHALLENGE_HOST[-1] == "/": | ||
59 | CHALLENGE_HOST = CHALLENGE_HOST[:-1] | ||
60 | |||
61 | serverAddress = ('', 80) | ||
62 | |||
63 | # Note: if running remotely by an SSH command, you MUST launch with '-t': | ||
64 | # > ssh -t me@otherhost leforward.py --baseurl http://otherserver.com | ||
65 | # If you omit '-t' the listening server won't terminate when you kill the | ||
66 | # ssh session, which probably isn't what you want. | ||
67 | with ReusableServer(serverAddress, RedirectChallenges) as httpd: | ||
68 | httpd.serve_forever() | ||
diff --git a/ansible/roles/certs/files/lets-encrypt-x3-cross-signed.pem b/ansible/roles/certs/files/lets-encrypt-x3-cross-signed.pem new file mode 100644 index 0000000..0002462 --- /dev/null +++ b/ansible/roles/certs/files/lets-encrypt-x3-cross-signed.pem | |||
@@ -0,0 +1,27 @@ | |||
1 | -----BEGIN CERTIFICATE----- | ||
2 | MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ | ||
3 | MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT | ||
4 | DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow | ||
5 | SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT | ||
6 | GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC | ||
7 | AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF | ||
8 | q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 | ||
9 | SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 | ||
10 | Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA | ||
11 | a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj | ||
12 | /PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T | ||
13 | AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG | ||
14 | CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv | ||
15 | bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k | ||
16 | c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw | ||
17 | VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC | ||
18 | ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz | ||
19 | MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu | ||
20 | Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF | ||
21 | AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo | ||
22 | uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ | ||
23 | wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu | ||
24 | X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG | ||
25 | PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 | ||
26 | KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== | ||
27 | -----END CERTIFICATE----- | ||