Add option to create selfsigned certs to AppMgr
This commit is contained in:
parent
ae70b53074
commit
bc1994c31b
14
basic.sh
14
basic.sh
@ -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
|
||||
|
@ -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"';
|
||||
|
@ -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')]
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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':
|
||||
|
Loading…
Reference in New Issue
Block a user