Commit 0418a395 authored by Adrien Dorsaz's avatar Adrien Dorsaz

Merge branch 'v2-csr-argument' into 'v2'

v2: allwo to define CSR file path by argument

See merge request !10
parents e2ddab12 e1f23bea
Pipeline #189 passed with stage
in 14 minutes and 8 seconds
......@@ -269,20 +269,17 @@ def get_crt(config, log=LOGGER):
def main(argv):
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""
This script automates the process of getting a signed TLS certificate
chain from any CA using the ACME protocol and its DNS verification.
It will need to have access to your private ACME account key and dns server
so PLEASE READ THROUGH IT!
It's around 300 lines, so it won't take long.
description="Tiny ACME client to get TLS certificate by responding to DNS challenges.",
epilog="""As the script requires access to your private ACME account key and dns server,
so PLEASE READ THROUGH IT (it's about 300 lines, so it won't take long) !
===Example Usage===
python3 acme_dns_tiny.py ./example.ini > chain.crt
See example.ini file to configure correctly this script.
===================
"""
Example: requests certificate chain and store it in chain.crt
python3 acme_dns_tiny.py ./example.ini > chain.crt
See example.ini file to configure correctly this script."""
)
parser.add_argument("--quiet", action="store_const", const=logging.ERROR, help="suppress output except for errors")
parser.add_argument("--csr", help="specifies CSR file path to use instead of the CSRFile option from the configuration file.")
parser.add_argument("configfile", help="path to your configuration file")
args = parser.parse_args(argv)
......@@ -292,6 +289,9 @@ See example.ini file to configure correctly this script.
"DNS": {"Port": "53"}})
config.read(args.configfile)
if args.csr :
config.set("acmednstiny", "csrfile", args.csr)
if (set(["accountkeyfile", "csrfile", "acmedirectory", "checkchallengedelay"]) - set(config.options("acmednstiny"))
or set(["keyname", "keyvalue", "algorithm"]) - set(config.options("TSIGKeyring"))
or set(["zone", "host", "port"]) - set(config.options("DNS"))):
......
......@@ -2,6 +2,7 @@
# Required readable ACME account key
AccountKeyFile = account.key
# Required readable CSR file
# Note: if you use the "--csr" optional argument, this setting is not read and can be omitted
CSRFile = domain.csr
# Optional ACME directory url
# Default: https://acme-staging-v02.api.letsencrypt.org/directory
......
......@@ -90,8 +90,12 @@ def generate_acme_dns_tiny_config():
config = configparser.ConfigParser()
config.read(goodCName)
goodCNameWithoutCSR = NamedTemporaryFile(delete=False)
config.remove_option("acmednstiny", "CSRFile")
with open(goodCNameWithoutCSR.name, 'w') as configfile:
config.write(configfile)
wildCName = NamedTemporaryFile(delete=False)
config["acmednstiny"]["AccountKeyFile"] = account_key
config["acmednstiny"]["CSRFile"] = wilddomain_csr.name
with open(wildCName.name, 'w') as configfile:
config.write(configfile)
......@@ -103,13 +107,11 @@ def generate_acme_dns_tiny_config():
config["DNS"]["Host"] = DNSHOST
goodSAN = NamedTemporaryFile(delete=False)
config["acmednstiny"]["AccountKeyFile"] = account_key
config["acmednstiny"]["CSRFile"] = san_csr.name
with open(goodSAN.name, 'w') as configfile:
config.write(configfile)
wildSAN = NamedTemporaryFile(delete=False)
config["acmednstiny"]["AccountKeyFile"] = account_key
config["acmednstiny"]["CSRFile"] = wildsan_csr.name
with open(wildSAN.name, 'w') as configfile:
config.write(configfile)
......@@ -139,6 +141,7 @@ def generate_acme_dns_tiny_config():
return {
# configs
"goodCName": goodCName,
"goodCNameWithoutCSR": goodCNameWithoutCSR.name,
"wildCName": wildCName.name,
"dnsHostIP": dnsHostIP.name,
"goodSAN": goodSAN.name,
......@@ -149,6 +152,8 @@ def generate_acme_dns_tiny_config():
"missingDNS": missingDNS.name,
# key (just to simply remove the account from staging server)
"accountkey": account_key,
# CName CSR file to use with goodCNameWithoutCSR
"cnameCSR": domain_csr,
}
# generate two account keys to roll over them
......
......@@ -63,6 +63,19 @@ class TestACMEDNSTiny(unittest.TestCase):
self.assertCertificateChain(certchain)
def test_success_cn_with_csr_option(self):
""" Successfully issue a certificate using CSR option outside from the config file"""
old_stdout = sys.stdout
sys.stdout = StringIO()
acme_dns_tiny.main(["--csr", self.configs['cnameCSR'], self.configs['goodCNameWithoutCSR']])
certchain = sys.stdout.getvalue()
sys.stdout.close()
sys.stdout = old_stdout
self.assertCertificateChain(certchain)
def test_success_wild_cn(self):
""" Successfully issue a certificate via a wildcard common name """
old_stdout = sys.stdout
......@@ -128,6 +141,16 @@ class TestACMEDNSTiny(unittest.TestCase):
self.assertCertificateChain(certchain)
def test_success_cli_with_csr_option(self):
""" Successfully issue a certificate via command line interface using CSR option"""
certout, err = subprocess.Popen([
"python3", "acme_dns_tiny.py", "--csr", self.configs['cnameCSR'], self.configs['goodCNameWithoutCSR']
], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
certchain = certout.decode("utf8")
self.assertCertificateChain(certchain)
def test_weak_key(self):
""" Let's Encrypt rejects weak keys """
self.assertRaisesRegex(ValueError,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment