Files
WPIQ/wo/core/acme.py

171 lines
7.1 KiB
Python
Raw Normal View History

2019-10-01 15:22:03 +02:00
import csv
2019-09-22 19:30:39 +02:00
import os
import requests
from wo.core.fileutils import WOFileUtils
from wo.core.git import WOGit
from wo.core.logging import Log
from wo.core.shellexec import WOShellExec
2019-10-02 13:13:32 +02:00
from wo.core.variables import WOVar
2019-09-22 19:30:39 +02:00
2019-10-01 17:29:29 +02:00
class WOAcme:
2019-09-22 19:30:39 +02:00
"""Acme.sh utilities for WordOps"""
2019-10-01 15:22:03 +02:00
wo_acme_exec = ("/etc/letsencrypt/acme.sh --config-home "
"'/etc/letsencrypt/config'")
def export_cert(self):
"""Export acme.sh csv certificate list"""
if not WOShellExec.cmd_exec(
2019-10-01 17:29:29 +02:00
self, "{0} ".format(WOAcme.wo_acme_exec) +
2019-10-01 15:22:03 +02:00
"--list --listraw > /var/lib/wo/cert.csv"):
Log.error(self, "Unable to export certs list")
WOFileUtils.chmod(self, '/var/lib/wo/cert.csv', 0o600)
2019-10-01 15:22:03 +02:00
2019-09-23 01:02:44 +02:00
def setupletsencrypt(self, acme_domains, acmedata):
2019-09-30 12:38:28 +02:00
"""Issue SSL certificates with acme.sh"""
2019-09-23 01:02:44 +02:00
all_domains = '\' -d \''.join(acme_domains)
2019-09-22 19:30:39 +02:00
wo_acme_dns = acmedata['acme_dns']
2019-09-30 15:05:07 +02:00
keylenght = acmedata['keylength']
2019-09-22 19:30:39 +02:00
if acmedata['dns'] is True:
acme_mode = "--dns {0}".format(wo_acme_dns)
validation_mode = "DNS mode with {0}".format(wo_acme_dns)
2019-09-24 02:36:46 +02:00
if acmedata['dnsalias'] is True:
acme_mode = acme_mode + \
" --challenge-alias {0}".format(acmedata['acme_alias'])
2019-09-22 19:30:39 +02:00
else:
acme_mode = "-w /var/www/html"
validation_mode = "Webroot challenge"
Log.debug(self, "Validation : Webroot mode")
if not os.path.isdir('/var/www/html/.well-known/acme-challenge'):
WOFileUtils.mkdir(
self, '/var/www/html/.well-known/acme-challenge')
WOFileUtils.chown(
self, '/var/www/html/.well-known', 'www-data', 'www-data',
recursive=True)
WOFileUtils.chmod(self, '/var/www/html/.well-known', 0o750,
recursive=True)
2019-09-22 19:30:39 +02:00
Log.info(self, "Validation mode : {0}".format(validation_mode))
Log.wait(self, "Issuing SSL cert with acme.sh")
2019-09-23 01:16:52 +02:00
if not WOShellExec.cmd_exec(
2019-10-01 17:29:29 +02:00
self, "{0} ".format(WOAcme.wo_acme_exec) +
2019-09-22 19:30:39 +02:00
"--issue -d '{0}' {1} -k {2} -f"
2019-09-23 01:16:52 +02:00
.format(all_domains, acme_mode, keylenght)):
2019-09-22 19:30:39 +02:00
Log.failed(self, "Issuing SSL cert with acme.sh")
if acmedata['dns'] is True:
Log.error(
2019-09-22 19:30:39 +02:00
self, "Please make sure your properly "
"set your DNS API credentials for acme.sh")
return False
2019-09-22 19:30:39 +02:00
else:
Log.error(
self, "Your domain is properly configured "
"but acme.sh was unable to issue certificate.\n"
"You can find more informations in "
"/var/log/wo/wordops.log")
return False
2019-09-23 01:14:59 +02:00
else:
Log.valide(self, "Issuing SSL cert with acme.sh")
return True
2019-09-22 19:30:39 +02:00
def deploycert(self, wo_domain_name):
2019-09-23 01:00:58 +02:00
if not os.path.isfile('/etc/letsencrypt/renewal/{0}_ecc/fullchain.cer'
2019-09-22 19:30:39 +02:00
.format(wo_domain_name)):
Log.error(self, 'Certificate not found. Deployment canceled')
Log.debug(self, "Cert deployment for domain: {0}"
.format(wo_domain_name))
try:
Log.wait(self, "Deploying SSL cert")
if WOShellExec.cmd_exec(
self, "mkdir -p {0}/{1} && {2} --install-cert -d {1} --ecc "
"--cert-file {0}/{1}/cert.pem --key-file {0}/{1}/key.pem "
"--fullchain-file {0}/{1}/fullchain.pem "
"--ca-file {0}/{1}/ca.pem --reloadcmd \"nginx -t && "
"service nginx restart\" "
2019-10-02 13:13:32 +02:00
.format(WOVar.wo_ssl_live,
2019-10-01 17:29:29 +02:00
wo_domain_name, WOAcme.wo_acme_exec)):
2019-09-22 19:30:39 +02:00
Log.valide(self, "Deploying SSL cert")
else:
Log.failed(self, "Deploying SSL cert")
Log.error(self, "Unable to deploy certificate")
if os.path.isdir('/var/www/{0}/conf/nginx'
.format(wo_domain_name)):
sslconf = open("/var/www/{0}/conf/nginx/ssl.conf"
.format(wo_domain_name),
encoding='utf-8', mode='w')
sslconf.write(
"listen 443 ssl http2;\n"
"listen [::]:443 ssl http2;\n"
"ssl_certificate {0}/{1}/fullchain.pem;\n"
"ssl_certificate_key {0}/{1}/key.pem;\n"
"ssl_trusted_certificate {0}/{1}/ca.pem;\n"
"ssl_stapling_verify on;\n"
2019-10-02 13:13:32 +02:00
.format(WOVar.wo_ssl_live, wo_domain_name))
2019-09-22 19:30:39 +02:00
sslconf.close()
if not WOFileUtils.grep(self, '/var/www/22222/conf/nginx/ssl.conf',
'/etc/letsencrypt'):
2019-09-30 12:38:28 +02:00
Log.info(self, "Securing WordOps backend with current cert")
2019-09-22 19:30:39 +02:00
sslconf = open("/var/www/22222/conf/nginx/ssl.conf",
encoding='utf-8', mode='w')
sslconf.write("ssl_certificate {0}/{1}/fullchain.pem;\n"
"ssl_certificate_key {0}/{1}/key.pem;\n"
"ssl_trusted_certificate {0}/{1}/ca.pem;\n"
"ssl_stapling_verify on;\n"
2019-10-02 13:13:32 +02:00
.format(WOVar.wo_ssl_live, wo_domain_name))
2019-09-22 19:30:39 +02:00
sslconf.close()
WOGit.add(self, ["/etc/letsencrypt"],
msg="Adding letsencrypt folder")
except IOError as e:
Log.debug(self, str(e))
Log.debug(self, "Error occured while generating "
"ssl.conf")
2019-10-01 04:08:54 +02:00
return 0
def check_dns(self, acme_domains):
"""Check if a list of domains point to the server IP"""
server_ip = requests.get('http://v4.wordops.eu/').text
for domain in acme_domains:
domain_ip = requests.get('http://v4.wordops.eu/dns/{0}/'
.format(domain)).text
if(not domain_ip == server_ip):
Log.warn(
self, "{0} is not pointing to your server IP"
.format(domain))
Log.error(
self, "You have to add the "
"proper DNS record", False)
return False
else:
Log.debug(self, "DNS record are properly set")
return True
2019-10-01 15:22:03 +02:00
def cert_check(self, wo_domain_name):
"""Check certificate existance with acme.sh and return Boolean"""
2019-10-01 17:29:29 +02:00
WOAcme.export_cert(self)
2019-10-01 15:22:03 +02:00
# define new csv dialect
csv.register_dialect('acmeconf', delimiter='|')
# open file
certfile = open('/var/lib/wo/cert.csv', mode='r', encoding='utf-8')
reader = csv.reader(certfile, 'acmeconf')
for row in reader:
# check if domain exist
if wo_domain_name in row[0]:
# check if cert expiration exist
if not row[3] == '':
cert_exist = True
break
else:
cert_exist = False
certfile.close()
return cert_exist