Add option to create selfsigned certs to AppMgr

This commit is contained in:
Disassembler 2018-09-03 15:57:47 +02:00
parent ae70b53074
commit bc1994c31b
Signed by: Disassembler
GPG Key ID: 524BD33A0EE29499
6 changed files with 35 additions and 19 deletions

View File

@ -33,14 +33,6 @@ cp ${SOURCE_DIR}/etc/conf.d/consolefont /etc/conf.d/consolefont
# Configure NTP client
cp ${SOURCE_DIR}/etc/conf.d/ntpd /etc/conf.d/ntpd
# Create a self-signed certificate
mkdir /etc/ssl/private
openssl req -x509 -new -out /etc/ssl/certs/services.pem -keyout /etc/ssl/private/services.key -nodes -days 7305 -subj "/CN=spotter.vm"
chmod 640 /etc/ssl/private/services.key
# Configure nginx
cp ${SOURCE_DIR}/etc/nginx/nginx.conf /etc/nginx/nginx.conf
# Download and configure acme.sh
mkdir /etc/acme.sh.d
wget https://raw.githubusercontent.com/Neilpang/acme.sh/master/acme.sh -O /usr/bin/acme.sh
@ -53,6 +45,12 @@ rc-update -u
cp -r ${SOURCE_DIR}/srv/spotter /srv/spotter
ln -s /srv/spotter/cli.py /usr/bin/spotter-appmgr
# Create a self-signed certificate
spotter-appmgr create-selfsigned
# Configure nginx
cp ${SOURCE_DIR}/etc/nginx/nginx.conf /etc/nginx/nginx.conf
# Configure services
for SERVICE in consolefont crond nginx ntpd sshd spotter-appmgr swap; do
rc-update add ${SERVICE} boot

View File

@ -21,8 +21,8 @@ http {
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
ssl_certificate /etc/ssl/certs/services.pem;
ssl_certificate_key /etc/ssl/private/services.key;
ssl_certificate /etc/ssl/services.pem;
ssl_certificate_key /etc/ssl/services.key;
ssl_session_cache shared:SSL:1m;
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';

View File

@ -15,8 +15,9 @@ CONF_FILE = '/srv/spotter/config.json'
ISSUE_FILE = '/etc/issue'
NGINX_DIR = '/etc/nginx/conf.d'
ACME_CRON = '/etc/periodic/daily/acme-sh'
CERT_PUB_FILE = '/etc/ssl/certs/services.pem'
CERT_KEY_FILE = '/etc/ssl/private/services.key'
CERT_PUB_FILE = '/etc/ssl/services.pem'
CERT_KEY_FILE = '/etc/ssl/services.key'
CERT_SAN_FILE = '/etc/ssl/san.cnf'
NGINX_TEMPLATE = '''server {{
listen [::]:{port} ssl http2;
@ -113,6 +114,14 @@ ACME_CRON_TEMPLATE = '''#!/bin/sh
[ -x /usr/bin/acme.sh ] && /usr/bin/acme.sh --cron >/dev/null
'''
CERT_SAN = '''[ req ]
distinguished_name = dn
x509_extensions = ext
[ dn ]
[ ext ]
subjectAltName=DNS:{domain},DNS:*.{domain}"
'''
class AppMgr:
def __init__(self):
# Load JSON configuration
@ -288,6 +297,13 @@ class AppMgr:
# Save config to file
self.save_conf()
def create_selfsigned(self):
# Create selfsigned certificate with wildcard alternative subject name
with open(os.path.join(CERT_SAN_FILE), 'w') as f:
f.write(CERT_SAN.format(domain=self.domain))
subprocess.run(['openssl', 'req', '-config', CERT_SAN_FILE, '-x509', '-new', '-out', CERT_PUB_FILE, '-keyout', CERT_KEY_FILE, '-nodes', '-days', '7305', '-subj', '/CN={}'.format(self.domain)], check=True)
os.chmod(CERT_KEY_FILE, 0o640)
def request_cert(self):
# Remove all possible conflicting certificates requested in the past
certs = [i for i in os.listdir('/etc/acme.sh.d') if i not in ('account.conf', 'ca', 'http.header')]

View File

@ -101,8 +101,8 @@ def reload_nginx():
def restart_nginx():
restart_service('nginx')
def get_cert_info():
data = ssl._ssl._test_decode_cert('/etc/ssl/certs/services.pem')
def get_cert_info(cert):
data = ssl._ssl._test_decode_cert(cert)
data['subject'] = dict(data['subject'][i][0] for i in range(len(data['subject'])))
data['issuer'] = dict(data['issuer'][i][0] for i in range(len(data['issuer'])))
return data

View File

@ -10,7 +10,7 @@ from werkzeug.wrappers import Request, Response
from werkzeug.wsgi import ClosingIterator
from jinja2 import Environment, FileSystemLoader
from . import AppMgr
from . import AppMgr, CERT_PUB_FILE
from . import tools
from .validator import InvalidValueException
from .wsgilang import WSGILang
@ -107,9 +107,6 @@ class WSGIApp(object):
def portal_view(self, request):
# Default view. If domain is set to the default dummy domain, redirects to first-run setup instead.
if request.mgr.domain == 'spotter.vm':
request.session['admin'] = True
return redirect('/setup-host')
if request.session['admin']:
return self.render_template('portal-admin.html', request)
return self.render_template('portal-user.html', request)
@ -121,7 +118,7 @@ class WSGIApp(object):
in_ipv4 = tools.get_local_ipv4()
in_ipv6 = tools.get_local_ipv6()
is_letsencrypt = os.path.exists('/etc/periodic/daily/acme-sh')
cert_info = tools.get_cert_info()
cert_info = tools.get_cert_info(CERT_PUB_FILE)
return self.render_template('setup-host.html', request, ex_ipv4=ex_ipv4, ex_ipv6=ex_ipv6, in_ipv4=in_ipv4, in_ipv6=in_ipv6, is_letsencrypt=is_letsencrypt, cert_info=cert_info)
def setup_apps_view(self, request):

View File

@ -65,6 +65,9 @@ parser_update_common.add_argument('--gmaps-api-key', help='Google Maps API key')
parser_update_password = subparsers.add_parser('update-password', help='Updates password for HDD encryption and WSGI administration interface')
parser_update_password.set_defaults(action='update-password')
parser_create_selfsigned = subparsers.add_parser('create-selfsigned', help='Creates and installs selfsigned certificate for currently set domain')
parser_create_selfsigned.set_defaults(action='create-selfsigned')
parser_request_cert = subparsers.add_parser('request-cert', help='Requests and installs Let\'s Encrypt certificate for currently set domain')
parser_request_cert.set_defaults(action='request-cert')
@ -103,6 +106,8 @@ elif args.action == 'update-password':
oldpassword = getpass.getpass('Old password: ')
newpassword = getpass.getpass('New password: ')
mgr.update_password(oldpassword, newpassword)
elif args.action == 'create-selfsigned':
mgr.create_selfsigned()
elif args.action == 'request-cert':
mgr.request_cert()
elif args.action == 'install-cert':