docker-mailserver/target/bin/acme_extract
Brennan Kinney e807631a76
refactor: acme.json extraction (#2274)
Split into scoped commits with messages if further details are needed, view those via the associated PR :)

**Commit Summary:**

**`check-for-changes.sh`**

- Prevent `SSL_DOMAIN` silently skipping when value has wildcard prefix `*.` (_at least this was known as a bugfix when originally committed in linked PR_).
- Improved inlined docs for maintainers.
- Additional logging for debugging.

**`helper-functions.sh:_extract_certs_from_acme`**:

- Fail if the input arg (_`$CERT_DOMAIN`, aka the FQDN_) provided for extraction is empty.
- Use `$CERT_DOMAIN` in place of `$HOSTNAME` and `$1` for a consistent value (_previously could mismatch, eg with `SSL_DOMAIN` defined_).
- The conditional is now only for handling extraction failure (_key or cert value is missing from extraction_).
- Log an actual warning or success (debug) based on outcome.
- Don't use `SSL_DOMAIN` with wildcard value for the `mkdir` letsencrypt directory name (_wildcard prefix `*.` is first stripped instead_).

**`acme_extract`** (_new python utility for `acme.json` handling_):

- Extracted out into a python script that can be treated as a utility in the `$PATH` like other helper scripts. It can now be used and optionally tested directly instead of via `helper-functions.sh`.
-Made compatible with Python 3, as Python 2 is EOL and no longer in newer versions of Debian.
2021-11-04 09:28:40 +13:00

40 lines
1.7 KiB
Python

#!/usr/bin/env python3
import argparse,json
parser = argparse.ArgumentParser(description='Traefik acme.json key and cert extractor utility.')
parser.add_argument('filepath', metavar='<filepath>', help='Path to acme.json')
parser.add_argument('fqdn', metavar='<FQDN>', help="FQDN to match in a certificates 'main' or 'sans' field")
# Only one of these options can be used at a time, `const` is the key value that will be queried:
key_or_cert = parser.add_mutually_exclusive_group(required=True)
key_or_cert.add_argument('--key', dest='requested', action='store_const', const='key', help='Output the key data to stdout')
key_or_cert.add_argument('--cert', dest='requested', action='store_const', const='certificate', help='Output the cert data to stdout')
args = parser.parse_args()
def has_fqdn(domains, fqdn):
main = domains.get('main', '')
sans = domains.get('sans', [])
return main == fqdn or fqdn in sans
# Searches the acme.json data for the target FQDN,
# upon a match returns the requested key or cert:
def retrieve_data():
with open(args.filepath) as json_file:
acme_data = json.load(json_file)
for key, value in acme_data.items():
try:
certs = value['Certificates'] or []
for cert in certs:
if has_fqdn(cert['domain'], args.fqdn):
return cert[args.requested]
# One of the expected keys is missing.. return an empty result
# Certificates: [{domain: [main, sans], key, certificate}]
except KeyError:
return None
# No match == 'None', we convert to empty string for
# existing error handling by `helper-functions.sh`:
result = retrieve_data() or ''
print(result)