Browse Source

V2 relying on acme-tiny

master
Bastien 1 year ago
parent
commit
9f4f9b5578
3 changed files with 173 additions and 20 deletions
  1. +9
    -5
      letsencrypt-wrapper-v1.py
  2. +0
    -15
      letsencrypt-wrapper.conf
  3. +164
    -0
      wrapper-v2.py

letsencrypt-wrapper.py → letsencrypt-wrapper-v1.py View File

@ -82,7 +82,13 @@ def create_next_csr(logger, config):
logger.error('%s not writeable' % config['filenames']['next']['csr']['der'])
sys.exit(1)
try:
subprocess.check_call(['bash', '-c', 'openssl req -new -key "' + config['filenames']['next']['key'] + '" -out "' + config['filenames']['next']['csr']['pem'] + '" -subj "' + config['cn'] + '" -reqexts cert -config <(cat /etc/ssl/openssl.cnf <(printf "[ cert ]\nsubjectAltName=DNS:' + config['domain'] + '"))'])
if config['other_domains']:
o = []
for d in config['other_domains'][0].split(','):
o.append('DNS:' + d)
subprocess.check_call(['bash', '-c', 'openssl req -new -key "' + config['filenames']['next']['key'] + '" -out "' + config['filenames']['next']['csr']['pem'] + '" -subj "' + config['cn'] + '" -reqexts cert -config <(cat /etc/ssl/openssl.cnf <(printf "[ cert ]\nsubjectAltName=DNS:' + config['domain'] + ',' + ','.join(o) + '"))'])
else:
subprocess.check_call(['bash', '-c', 'openssl req -new -key "' + config['filenames']['next']['key'] + '" -out "' + config['filenames']['next']['csr']['pem'] + '" -subj "' + config['cn'] + '" -reqexts cert -config <(cat /etc/ssl/openssl.cnf <(printf "[ cert ]\nsubjectAltName=DNS:' + config['domain'] + '"))'])
except subprocess.CalledProcessError as e :
logger.error('next csr creation failed (return %d)' % e.returncode)
sys.exit(1)
@ -285,6 +291,7 @@ if '__main__' == __name__:
parser = argparse.ArgumentParser();
parser.add_argument('--conf', help='set configuration file', dest='conf', metavar='CONFIG_FILE', type=argparse.FileType('r'), nargs=1, required=False, default='/etc/letsencrypt/letsencrypt-wrapper.conf');
parser.add_argument('-d', '--domain', help='set domain', dest='domain', metavar='DOMAIN', type=str, nargs=1, required=True);
parser.add_argument('-e', '--other-domains', help='set other domains', dest='other_domain', metavar='OTHER_DOMAIN', type=str, nargs=1, required=False);
parser.add_argument('-c', '--chain', help='set certification chain', dest='chain', metavar='CHAIN', type=str, nargs=1, required=True);
parser.add_argument('-v', help='set loglevel to debug', dest='verbose', action='store_true');
args = parser.parse_args();
@ -339,6 +346,7 @@ if '__main__' == __name__:
directory = '/etc/letsencrypt/%s/' % args.chain[0]
config = {
'domain': args.domain[0],
'other_domains': args.other_domain,
'chain': args.chain[0],
'directory': directory,
'cn': ('/O=confais.org/CN=%s' % args.domain[0]),
@ -413,10 +421,6 @@ if '__main__' == __name__:
logger.info('move files')
move_files(logger, config)
# generate the next key
logger.info('create the next key')
create_next_key(logger, config)
# generate dh parameters
logger.info('create dh files')
create_dh(logger, config)

+ 0
- 15
letsencrypt-wrapper.conf View File

@ -1,15 +0,0 @@
{
"confais": {
"server": "https://server",
"email": "email@example.com",
"type": "standalone"
},
"letsencrypt": {
"server": "https://server2",
"email": "email@example.com",
"type": "webroot",
"launch-nginx": false,
"webroot-path": "/srv/http"
}
}

+ 164
- 0
wrapper-v2.py View File

@ -0,0 +1,164 @@
#!/usr/bin/python
import os,sys,argparse,subprocess,shutil
import json,base64,binascii
pki_directory = '/etc/pki'
def letsencrypt_key_convert(file):
with open(file) as fp:
pkey=json.load(fp)
def enc(data):
missing_padding = 4 - len(data) % 4
if missing_padding:
data += b'='* missing_padding
return b'0x'+binascii.hexlify(base64.b64decode(data,b'-_')).upper()
for k,v in pkey.items():
if k == 'kty': continue
pkey[k] = enc(v.encode()).decode()
res = "asn1=SEQUENCE:private_key\n[private_key]\nversion=INTEGER:0\n"
res += "n=INTEGER:{}\n".format(pkey[u'n'])
res += "e=INTEGER:{}\n".format(pkey[u'e'])
res += "d=INTEGER:{}\n".format(pkey[u'd'])
res += "p=INTEGER:{}\n".format(pkey[u'p'])
res += "q=INTEGER:{}\n".format(pkey[u'q'])
res += "dp=INTEGER:{}\n".format(pkey[u'dp'])
res += "dq=INTEGER:{}\n".format(pkey[u'dq'])
res += "qi=INTEGER:{}\n".format(pkey[u'qi'])
return res
def pki_directory_migrate():
os.mkdir(pki_directory)
os.mkdir('%s/live' % (pki_directory))
os.mkdir('%s/backups' % (pki_directory))
os.mkdir('%s/accounts' % (pki_directory))
if os.path.isdir('/etc/letsencrypt/letsencrypt/accounts'):
for x in os.listdir('/etc/letsencrypt/letsencrypt/accounts'):
for xx in os.listdir('/etc/letsencrypt/letsencrypt/accounts/%s/directory/' % (x)):
if os.path.isfile('/etc/letsencrypt/letsencrypt/accounts/%s/directory/%s/private_key.json' % (x, xx)):
with open('%s/accounts/%s.tmp' % (pki_directory, x), 'w') as f:
f.write(letsencrypt_key_convert('/etc/letsencrypt/letsencrypt/accounts/%s/directory/%s/private_key.json' % (x, xx)))
subprocess.check_call(['openssl', 'asn1parse', '-noout', '-out', '%s/accounts/%s.der' % (pki_directory, x), '-genconf', '%s/accounts/%s.tmp' % (pki_directory, x)])
subprocess.check_call(['openssl', 'rsa', '-in', '%s/accounts/%s.der' % (pki_directory, x), '-out', '%s/accounts/%s.key' % (pki_directory, x), '-inform', 'der', '-outform', 'pem'])
os.remove('%s/accounts/%s.tmp' % (pki_directory, x))
os.remove('%s/accounts/%s.der' % (pki_directory, x))
os.chmod('%s/accounts/%s.key' % (pki_directory, x), 0o400)
def split_certificate(chain, cert, issuer):
with open(chain, 'r') as chainfile:
with open(cert, 'w') as certfile:
with open(issuer, 'w') as issuerfile:
first=True
for l in chainfile.readlines():
if '\n' == l:
first = False
continue
if first:
certfile.write(l)
else:
issuerfile.write(l)
if '__main__' == __name__:
parser = argparse.ArgumentParser();
parser.add_argument('-d', '--domain', help='set domain', dest='domain', metavar='DOMAIN', type=str, nargs=1, required=True)
parser.add_argument('-e', '--other-domains', help='set other domains', dest='other_domain', metavar='OTHER_DOMAIN', type=str, nargs=1, required=False)
parser.add_argument('-c', help='create pki_directory structure', dest='create', action='store_true')
parser.add_argument('-l', help='letsencrypt signature', dest='letsencrypt', action='store_true')
args = parser.parse_args();
if args.create:
pki_directory_migrate()
sys.exit(0)
if not os.path.isdir(pki_directory):
print('Error: The directory structure does not exists', file=sys.stderr)
sys.exit(1)
# create a temp directory
tmpdir = '%s/tmp' % (pki_directory)
try:
shutil.rmtree(tmpdir)
except:
pass
os.mkdir(tmpdir)
# create the keys
subprocess.check_call(['openssl', 'genrsa', '-out', '%s/key.rsa.pem' % (tmpdir), '2048'])
subprocess.check_call(['openssl', 'ecparam', '-out', '%s/key.ecc.pem' % (tmpdir), '-name', 'prime256v1', '-genkey'])
# create csr
o = ['DNS:%s' % (args.domain[0])]
if args.other_domain:
for d in args.other_domain[0].split(','):
o.append('DNS:%s' % (d))
subprocess.check_call(['bash', '-c', 'openssl req -new -key "%s/key.rsa.pem" -out "%s/csr.rsa.pem" -subj "/O=confais.org/CN=%s" -reqexts cert -config <(cat /etc/ssl/openssl.cnf <(printf "[ cert ]\nsubjectAltName=%s"))' % (tmpdir, tmpdir, args.domain[0], ','.join(o))])
subprocess.check_call(['bash', '-c', 'openssl req -new -key "%s/key.ecc.pem" -out "%s/csr.ecc.pem" -subj "/O=confais.org/CN=%s" -reqexts cert -config <(cat /etc/ssl/openssl.cnf <(printf "[ cert ]\nsubjectAltName=%s"))' % (tmpdir, tmpdir, args.domain[0], ','.join(o))])
# sign the certificate
if args.letsencrypt:
with open('%s/chain.rsa.pem' % (tmpdir), 'w') as chainfile:
subprocess.Popen(['acme-tiny', '--account-key', '%s/accounts/acme-v01.api.letsencrypt.org.key' % (pki_directory), '--csr', '%s/csr.rsa.pem' % (tmpdir), '--acme-dir', '/srv/http/.well-known/acme-challenge/'], stdout=chainfile)
with open('%s/chain.ecc.pem' % (tmpdir), 'w') as chainfile:
subprocess.Popen(['acme-tiny', '--account-key', '%s/accounts/acme-v01.api.letsencrypt.org.key' % (pki_directory), '--csr', '%s/csr.ecc.pem' % (tmpdir), '--acme-dir', '/srv/http/.well-known/acme-challenge/'], stdout=chainfile)
else:
# no letsencrypt signature
input("Copy chain.rsa.pem to continue...")
# split the chain into cert and issuer
split_certificate('%s/chain.rsa.pem' % (tmpdir), '%s/cert.rsa.pem' % (tmpdir), '%s/issuer.rsa.pem' % (tmpdir))
split_certificate('%s/chain.ecc.pem' % (tmpdir), '%s/cert.ecc.pem' % (tmpdir), '%s/issuer.ecc.pem' % (tmpdir))
# certificate transparency
if args.letsencrypt:
subprocess.check_call(['bash', '-c', 'ct-submit ct.googleapis.com/pilot < %s/cert.rsa.pem > %s/ct.rsa.sct'])
subprocess.check_call(['bash', '-c', 'ct-submit ct.googleapis.com/pilot < %s/cert.ecc.pem > %s/ct.ecc.sct'])
# dh parameters
subprocess.check_call(['openssl', 'dhparam', '-dsaparam', '-out', '%s/dh.pem' % (tmpdir), '2048'])
# permissions
os.chmod('%s/key.rsa.pem' % (tmpdir), 0o400)
os.chmod('%s/key.ecc.pem' % (tmpdir), 0o400)
os.chmod('%s/csr.rsa.pem' % (tmpdir), 0o444)
os.chmod('%s/csr.ecc.pem' % (tmpdir), 0o444)
os.chmod('%s/chain.rsa.pem' % (tmpdir), 0o444)
os.chmod('%s/chain.ecc.pem' % (tmpdir), 0o444)
os.chmod('%s/cert.rsa.pem' % (tmpdir), 0o444)
os.chmod('%s/cert.ecc.pem' % (tmpdir), 0o444)
os.chmod('%s/issuer.rsa.pem' % (tmpdir), 0o444)
os.chmod('%s/issuer.ecc.pem' % (tmpdir), 0o444)
if(os.path.isfile('%s/ct.rsa.sct' % (tmpdir))):
os.chmod('%s/ct.rsa.sct' % (tmpdir), 0o444)
os.chmod('%s/ct.ecc.sct' % (tmpdir), 0o444)
os.chmod('%s/dh.pem' % (tmpdir), 0o444)
# move files
try:
shutil.rmtree('%s/backups/%s' % (pki_directory, args.domain[0]))
except:
pass
if os.path.isdir('%s/live/%s' % (pki_directory, args.domain[0])):
shutil.move('%s/live/%s' % (pki_directory, args.domain[0]), '%s/backups/%s' % (pki_directory, args.domain[0]))
shutil.move('%s/tmp/' % (pki_directory), '%s/live/%s' % (pki_directory, args.domain[0]))
# display infos
ret_rsa = subprocess.check_output(['ldns-dane', '-n', '-c', '%s/live/%s/cert.rsa.pem' % (pki_directory, args.domain[0]), 'create', args.domain[0], '443', '3', '1', '2' ])
ret_ecc = subprocess.check_output(['ldns-dane', '-n', '-c', '%s/live/%s/cert.ecc.pem' % (pki_directory, args.domain[0]), 'create', args.domain[0], '443', '3', '1', '2' ])
print('')
print('========')
print('TLSA:')
print(ret_rsa.decode(), end='')
print(ret_ecc.decode())
print('')
ret_rsa = subprocess.check_output(['openssl', 'x509', '-in', '%s/live/%s/cert.rsa.pem' % (pki_directory, args.domain[0]), '-sha1', '-noout', '-fingerprint'])
ret_ecc = subprocess.check_output(['openssl', 'x509', '-in', '%s/live/%s/cert.ecc.pem' % (pki_directory, args.domain[0]), '-sha1', '-noout', '-fingerprint'])
print('SHA1:')
print(ret_rsa.decode(), end='')
print(ret_ecc.decode())
print('')
print('Do not forget to copy files on the frontend reverse proxy!')

Loading…
Cancel
Save