From d56d52990f5b30a1b03b2479767e91aa3aa2cdc5 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Mon, 1 Jul 2019 13:57:52 -0500 Subject: [service https] T1443: add service https and service https api --- debian/rules | 3 + interface-definitions/https.xml | 87 ++++++++++++++++++++++++++ python/vyos/defaults.py | 1 + src/conf_mode/http-api.py | 104 +++++++++++++++++++++++++++++++ src/conf_mode/https.py | 132 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 327 insertions(+) create mode 100644 interface-definitions/https.xml create mode 100755 src/conf_mode/http-api.py create mode 100755 src/conf_mode/https.py diff --git a/debian/rules b/debian/rules index b06117922..952867a76 100755 --- a/debian/rules +++ b/debian/rules @@ -77,3 +77,6 @@ override_dh_auto_install: # Install systemd service units mkdir -p $(DIR)/lib/systemd/system cp -r src/systemd/* $(DIR)/lib/systemd/system + + # Make directory for generated configuration file + mkdir -p $(DIR)/etc/vyos diff --git a/interface-definitions/https.xml b/interface-definitions/https.xml new file mode 100644 index 000000000..828de449c --- /dev/null +++ b/interface-definitions/https.xml @@ -0,0 +1,87 @@ + + + + + + + + HTTPS configuration + 1001 + + + + + Addresses to listen for HTTPS requests + + ipv4 + HTTPS IPv4 address + + + ipv6 + HTTPS IPv6 address + + + + + + + + + + + VyOS HTTP API configuration + 1002 + + + + + Port for HTTP API service + + 1-65535 + Numeric IP port + + + + + + + + + HTTP API keys + + + + + HTTP API id + + + + + HTTP API plaintext key + + + + + + + + + Enforce strict path checking + + + + + + Debug + + + + + + + + + + + + diff --git a/python/vyos/defaults.py b/python/vyos/defaults.py index da363b8e1..f23e15631 100644 --- a/python/vyos/defaults.py +++ b/python/vyos/defaults.py @@ -16,6 +16,7 @@ directories = { "data": "/usr/share/vyos/", + "conf_mode": "/usr/libexec/vyos/conf_mode", "config": "/opt/vyatta/etc/config", "current": "/opt/vyatta/etc/config-migrate/current", "migrate": "/opt/vyatta/etc/config-migrate/migrate", diff --git a/src/conf_mode/http-api.py b/src/conf_mode/http-api.py new file mode 100755 index 000000000..7d618dded --- /dev/null +++ b/src/conf_mode/http-api.py @@ -0,0 +1,104 @@ +#!/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 +import subprocess +import json + +import vyos.defaults +from vyos.config import Config +from vyos import ConfigError + +config_file = '/etc/vyos/http-api.conf' + +default_config_data = { + 'listen_address' : '127.0.0.1', + 'port' : '8080', + 'strict' : 'false', + 'debug' : 'false', + 'api_keys' : [ {"id": "testapp", "key": "qwerty"} ] +} + +vyos_conf_scripts_dir=vyos.defaults.directories['conf_mode'] + +# XXX: this model will need to be extended for tag nodes +dependencies = [ + 'https.py', +] + +def get_config(): + http_api = default_config_data + conf = Config() + if not conf.exists('service https api'): + return None + else: + conf.set_level('service https api') + + if conf.exists('strict'): + http_api['strict'] = 'true' + + if conf.exists('debug'): + http_api['debug'] = 'true' + + if conf.exists('port'): + port = conf.return_value('port') + http_api['port'] = port + + if conf.exists('keys'): + for name in conf.list_nodes('keys id'): + if conf.exists('keys id {0} key'.format(name)): + key = conf.return_value('keys id {0} key'.format(name)) + new_key = { 'id': name, 'key': key } + http_api['api_keys'].append(new_key) + + return http_api + +def verify(http_api): + return None + +def generate(http_api): + if http_api is None: + return None + + with open(config_file, 'w') as f: + json.dump(http_api, f, indent=2) + + return None + +def apply(http_api): + if http_api is not None: + os.system('sudo systemctl restart vyos-http-api.service') + for dep in dependencies: + cmd = '{0}/{1}'.format(vyos_conf_scripts_dir, dep) + try: + subprocess.check_call(cmd, shell=True) + except subprocess.CalledProcessError as err: + raise ConfigError("{}.".format(err)) + else: + os.system('sudo systemctl stop vyos-http-api.service') + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + sys.exit(1) diff --git a/src/conf_mode/https.py b/src/conf_mode/https.py new file mode 100755 index 000000000..dae51dd7d --- /dev/null +++ b/src/conf_mode/https.py @@ -0,0 +1,132 @@ +#!/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 + +import jinja2 + +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 http-api.py ### +# Default server configuration +# +server { + listen 80 default_server; + listen [::]:80 default_server; + server_name _; + return 302 https://$server_name$request_uri; +} + +server { + + # SSL configuration + # + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + # + # Self signed certs generated by the ssl-cert package + # Don't use them in a production server! + # + include snippets/snakeoil.conf; + +{% for l_addr in listen_address %} + server_name {{ l_addr }}; +{% endfor %} + + location / { +{% if api %} + proxy_pass http://localhost:{{ api.port }}; + proxy_buffering off; +{% 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"}'; + } + +} +""" + +default_config_data = { + 'listen_address' : [ '127.0.0.1' ] +} + +default_api_config_data = { + 'port' : '8080', +} + +def get_config(): + https = default_config_data + conf = Config() + if not conf.exists('service https'): + return None + else: + conf.set_level('service https') + + if conf.exists('listen-address'): + addrs = conf.return_values('listen-address') + https['listen_address'] = addrs[:] + + if conf.exists('api'): + https['api'] = default_api_config_data + + if conf.exists('api port'): + port = conf.return_value('api port') + https['api']['port'] = port + + return https + +def verify(https): + return None + +def generate(https): + if https is None: + return None + + 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) -- cgit v1.2.3