From 1870a3db38e6469d9216343a4dc180d859651d84 Mon Sep 17 00:00:00 2001
From: sarthurdev <965089+sarthurdev@users.noreply.github.com>
Date: Thu, 22 Jul 2021 12:08:19 +0200
Subject: pki: https: T3642: Migrate HTTPS to use PKI configuration
---
src/conf_mode/https.py | 123 +++++++++++++++++++++++++++++++++----------------
1 file changed, 84 insertions(+), 39 deletions(-)
(limited to 'src/conf_mode/https.py')
diff --git a/src/conf_mode/https.py b/src/conf_mode/https.py
index a6e2d9c8c..be4380462 100755
--- a/src/conf_mode/https.py
+++ b/src/conf_mode/https.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2020 VyOS maintainers and contributors
+# Copyright (C) 2019-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+import os
import sys
from copy import deepcopy
@@ -23,13 +24,17 @@ import vyos.certbot_util
from vyos.config import Config
from vyos import ConfigError
-from vyos.util import call
+from vyos.pki import wrap_certificate
+from vyos.pki import wrap_private_key
from vyos.template import render
+from vyos.util import call
from vyos import airbag
airbag.enable()
config_file = '/etc/nginx/sites-available/default'
+cert_dir = '/etc/ssl/certs'
+key_dir = '/etc/ssl/private'
certbot_dir = vyos.defaults.directories['certbot']
# https config needs to coordinate several subsystems: api, certbot,
@@ -56,12 +61,58 @@ def get_config(config=None):
if not conf.exists('service https'):
return None
+ https = conf.get_config_dict('service https', get_first_key=True)
+
+ if https:
+ https['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'),
+ get_first_key=True, no_tag_node_value_mangle=True)
+
+ return https
+
+def verify(https):
+ if https is None:
+ return None
+
+ if 'certificates' in https:
+ certificates = https['certificates']
+
+ if 'certificate' in certificates:
+ if not https['pki']:
+ raise ConfigError("PKI is not configured")
+
+ cert_name = certificates['certificate']
+
+ if cert_name not in https['pki']['certificate']:
+ raise ConfigError("Invalid certificate on https configuration")
+
+ pki_cert = https['pki']['certificate'][cert_name]
+
+ if 'certificate' not in pki_cert:
+ raise ConfigError("Missing certificate on https configuration")
+
+ if 'private' not in pki_cert or 'key' not in pki_cert['private']:
+ raise ConfigError("Missing certificate private key on https configuration")
+
+ if 'certbot' in https['certificates']:
+ vhost_names = []
+ for vh, vh_conf in https.get('virtual-host', {}).items():
+ vhost_names += vh_conf.get('server-name', [])
+ domains = https['certificates']['certbot'].get('domain-name', [])
+ domains_found = [domain for domain in domains if domain in vhost_names]
+ if not domains_found:
+ raise ConfigError("At least one 'virtual-host server-name' "
+ "matching the 'certbot domain-name' is required.")
+ return None
+
+def generate(https):
+ if https is None:
+ return None
+
server_block_list = []
- https_dict = conf.get_config_dict('service https', get_first_key=True)
# organize by vhosts
- vhost_dict = https_dict.get('virtual-host', {})
+ vhost_dict = https.get('virtual-host', {})
if not vhost_dict:
# no specified virtual hosts (server blocks); use default
@@ -79,18 +130,30 @@ def get_config(config=None):
# get certificate data
- cert_dict = https_dict.get('certificates', {})
+ cert_dict = https.get('certificates', {})
+
+ if 'certificate' in cert_dict:
+ cert_name = cert_dict['certificate']
+ pki_cert = https['pki']['certificate'][cert_name]
+
+ cert_path = os.path.join(cert_dir, f'{cert_name}.pem')
+ key_path = os.path.join(key_dir, f'{cert_name}.pem')
+
+ with open(cert_path, 'w') as f:
+ f.write(wrap_certificate(pki_cert['certificate']))
+
+ with open(key_path, 'w') as f:
+ f.write(wrap_private_key(pki_cert['private']['key']))
- # self-signed certificate
+ vyos_cert_data = {
+ "crt": cert_path,
+ "key": key_path
+ }
- vyos_cert_data = {}
- if 'system-generated-certificate' in list(cert_dict):
- vyos_cert_data = vyos.defaults.vyos_cert_data
- if vyos_cert_data:
for block in server_block_list:
block['vyos_cert'] = vyos_cert_data
- # letsencrypt certificate using certbot
+ # letsencrypt certificate using certbot
certbot = False
cert_domains = cert_dict.get('certbot', {}).get('domain-name', [])
@@ -110,15 +173,15 @@ def get_config(config=None):
api_set = False
api_data = {}
- if 'api' in list(https_dict):
+ if 'api' in list(https):
api_set = True
api_data = vyos.defaults.api_data
- api_settings = https_dict.get('api', {})
+ api_settings = https.get('api', {})
if api_settings:
port = api_settings.get('port', '')
if port:
api_data['port'] = port
- vhosts = https_dict.get('api-restrict', {}).get('virtual-host', [])
+ vhosts = https.get('api-restrict', {}).get('virtual-host', [])
if vhosts:
api_data['vhost'] = vhosts[:]
@@ -132,34 +195,16 @@ def get_config(config=None):
if block['id'] in vhost_list:
block['api'] = api_data
- # return dict for use in template
-
- https = {'server_block_list' : server_block_list,
- 'api_set': api_set,
- 'certbot': certbot}
-
- return https
-
-def verify(https):
- if https is None:
- return None
-
- if https['certbot']:
- for sb in https['server_block_list']:
- if sb['certbot']:
- return None
- raise ConfigError("At least one 'virtual-host server-name' "
- "matching the 'certbot domain-name' is required.")
- return None
-
-def generate(https):
- if https is None:
- return None
-
if 'server_block_list' not in https or not https['server_block_list']:
https['server_block_list'] = [default_server_block]
- render(config_file, 'https/nginx.default.tmpl', https)
+ data = {
+ 'server_block_list': server_block_list,
+ 'api_set': api_set,
+ 'certbot': certbot
+ }
+
+ render(config_file, 'https/nginx.default.tmpl', data)
return None
--
cgit v1.2.3