#!/usr/bin/env python3 # # Copyright (C) 2019 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 # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # import sys import os from copy import deepcopy import jinja2 import vyos.defaults import vyos.certbot_util from vyos.config import Config from vyos import ConfigError config_file = '/etc/nginx/sites-available/default' # Please be careful if you edit the template. config_tmpl = """ ### Autogenerated by https.py ### # Default server configuration # server { listen 80 default_server; listen [::]:80 default_server; server_name _; return 301 https://$server_name$request_uri; } {% for server in server_block_list %} server { # SSL configuration # {% if server.address == '*' %} listen {{ server.port }} ssl; listen [::]:{{ server.port }} ssl; {% else %} listen {{ server.address }}:{{ server.port }} ssl; {% endif %} {% for name in server.name %} server_name {{ name }}; {% endfor %} {% if server.certbot %} ssl_certificate /etc/letsencrypt/live/{{ server.certbot_dir }}/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/{{ server.certbot_dir }}/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; {% elif server.vyos_cert %} include {{ server.vyos_cert.conf }}; {% else %} # # Self signed certs generated by the ssl-cert package # Don't use them in a production server! # include snippets/snakeoil.conf; {% endif %} # proxy settings for HTTP API, if enabled; 503, if not location ~ /(retrieve|configure|config-file|image|generate|show) { {% if server.api %} proxy_pass http://localhost:{{ server.api.port }}; proxy_buffering off; {% else %} return 503; {% endif %} } error_page 501 502 503 =200 @50*_json; location @50*_json { default_type application/json; return 200 '{"error": "Start service in configuration mode: set service https api"}'; } } {% endfor %} """ default_server_block = { 'address' : '*', 'port' : '443', 'name' : ['_'], 'api' : {}, 'vyos_cert' : {}, 'certbot' : False } def get_config(): server_block_list = [] conf = Config() if not conf.exists('service https'): return None else: conf.set_level('service https') if not conf.exists('virtual-host'): server_block_list.append(default_server_block) else: for vhost in conf.list_nodes('virtual-host'): server_block = deepcopy(default_server_block) if conf.exists(f'virtual-host {vhost} listen-address'): addr = conf.return_value(f'virtual-host {vhost} listen-address') server_block['address'] = addr if conf.exists(f'virtual-host {vhost} listen-port'): port = conf.return_value(f'virtual-host {vhost} listen-port') server_block['port'] = port if conf.exists(f'virtual-host {vhost} server-name'): names = conf.return_values(f'virtual-host {vhost} server-name') server_block['name'] = names[:] server_block_list.append(server_block) vyos_cert_data = {} if conf.exists('certificates system-generated-certificate'): vyos_cert_data = vyos.defaults.vyos_cert_data if vyos_cert_data: for block in server_block_list: block['vyos_cert'] = vyos_cert_data certbot = False certbot_domains = [] if conf.exists('certificates certbot domain-name'): certbot_domains = conf.return_values('certificates certbot domain-name') if certbot_domains: certbot = True for domain in certbot_domains: sub_list = vyos.certbot_util.choose_server_block(server_block_list, domain) if sub_list: for sb in sub_list: sb['certbot'] = True # certbot organizes certificates by first domain sb['certbot_dir'] = certbot_domains[0] api_data = {} if conf.exists('api'): api_data = vyos.defaults.api_data if conf.exists('api port'): port = conf.return_value('api port') api_data['port'] = port if api_data: for block in server_block_list: block['api'] = api_data https = {'server_block_list' : server_block_list, '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] tmpl = jinja2.Template(config_tmpl, trim_blocks=True) config_text = tmpl.render(https) with open(config_file, 'w') as f: f.write(config_text) return None def apply(https): if https is not None: os.system('sudo systemctl restart nginx.service') else: os.system('sudo systemctl stop nginx.service') if __name__ == '__main__': try: c = get_config() verify(c) generate(c) apply(c) except ConfigError as e: print(e) sys.exit(1)