From e30a7a6cebce788bca90a22693ef514fd76f153b Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 11 May 2018 17:19:29 +0200 Subject: T631: Rewrite SSH configuration as XML interface definition --- Makefile | 3 + interface-definitions/ssh.xml | 183 +++++++++++++++++++++++++++++++++++++++ src/conf-mode/vyos-config-ssh.py | 67 ++++++++++++++ 3 files changed, 253 insertions(+) create mode 100644 interface-definitions/ssh.xml create mode 100755 src/conf-mode/vyos-config-ssh.py diff --git a/Makefile b/Makefile index ee89a5608..d194b44e4 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,9 @@ interface_definitions: sed -i '/^type: txt/d' $(TMPL_DIR)/system/ntp/server/node.tag/noselect/node.def sed -i '/^type: txt/d' $(TMPL_DIR)/system/ntp/server/node.tag/preempt/node.def sed -i '/^type: txt/d' $(TMPL_DIR)/system/ntp/server/node.tag/prefer/node.def + sed -i '/^type: txt/d' $(TMPL_DIR)/service/ssh/allow-root/node.def + sed -i '/^type: txt/d' $(TMPL_DIR)/service/ssh/disable-host-validation/node.def + sed -i '/^type: txt/d' $(TMPL_DIR)/service/ssh/disable-password-authentication/node.def .PHONY: all all: interface_definitions diff --git a/interface-definitions/ssh.xml b/interface-definitions/ssh.xml new file mode 100644 index 000000000..9965dd69e --- /dev/null +++ b/interface-definitions/ssh.xml @@ -0,0 +1,183 @@ + + + + + + + + + + Secure SHell (SSH) protocol + 500 + + + + + SSH user/group access controls + + + + + Configure sshd_config access control for allowed groups + + + + + Configure sshd_config access control for allowed users + + + + + Configure sshd_config access control for disallowed groups + + + + + Configure sshd_config access control for disallowed users + + + + + + + Enable root login over ssh + + + + + Allowed ciphers + + chacha20-poly1305@openssh.com + ChaCha20 Poly1305 + + + 3des-cbc + 3DES CBC (weak) + + + aes128-cbc + AES 128 CBC + + + aes192-cbc + AES 192 CBC + + + aes256-cbc + AES 256 CBC + + + aes128-ctr + AES 128 CTR + + + aes192-ctr + AES 192 CTR + + + aes256-ctr + AES 256 CTR + + + arcfour128 + AC4 128 (broken) + + + arcfour256 + AC4 256 (broken) + + + arcfour + AC4 (broken) + + + blowfish-cbc + Blowfish CBC + + + cast128-cbc + CAST 128 CBC + + + + + + Don't validate the remote host name with DNS + + + + + Don't allow unknown user to login with password + + + + + Key exchange algorithms + + + + + + + + Local addresses SSH service should listen on + + ipv4 + IP address to listen for incoming connections + + + ipv6 + IPv6 address to listen for incoming connections + + ipv4,ipv6 + + + + + + Log level + + QUIET + stay silent + + + FATAL + log fatals only + + + ERROR + log errors and fatals only + + + INFO + default log level + + + VERBOSE + enable logging of failed login attempts + + + + + + Allowed message authentication algorithms + + + + + + + + Port for SSH service + + u32:1-65535 + Numeric IP port + + u32 + + + + + + + diff --git a/src/conf-mode/vyos-config-ssh.py b/src/conf-mode/vyos-config-ssh.py new file mode 100755 index 000000000..e91e829b2 --- /dev/null +++ b/src/conf-mode/vyos-config-ssh.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2018 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 time + +from vyos.config import Config +from vyos.util import ConfigError + +config_file = r'/etc/ssh/sshd_config' + +def get_config(): + ssh = {} + conf = Config() + conf.set_level('service ssh') + if not conf.exists(''): + return ssh + + return ssh + +def verify(ssh): + return None + +def generate(ssh): + config_header = '### Autogenerated by vyos-config-ssh.py on {tm} ###\n'.format(tm=time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())) + + # write new configuration file + f = open(config_file, 'w') + f.write(config_header) + f.write('\n') + f.close() + return None + +def apply(ssh): + if len(ssh) == 0: + cmd = "sudo systemctl stop ssh" + else: + cmd = "sudo systemctl start ssh" + + os.system(cmd) + return None + +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 From 0a8021c21eb918cc2c31d7d922b6428017b341c0 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 12 May 2018 11:58:55 +0200 Subject: T631: use completionHelp for SSH rather then valueHelp SSH is already probed for some possible values. ALso use completionHelp for available ciphers. In addition drop 'perl' from helper script in favor of 'tr'. --- interface-definitions/ssh.xml | 59 ++++--------------------------------------- 1 file changed, 5 insertions(+), 54 deletions(-) diff --git a/interface-definitions/ssh.xml b/interface-definitions/ssh.xml index 9965dd69e..5b9368360 100644 --- a/interface-definitions/ssh.xml +++ b/interface-definitions/ssh.xml @@ -46,58 +46,9 @@ Allowed ciphers - - chacha20-poly1305@openssh.com - ChaCha20 Poly1305 - - - 3des-cbc - 3DES CBC (weak) - - - aes128-cbc - AES 128 CBC - - - aes192-cbc - AES 192 CBC - - - aes256-cbc - AES 256 CBC - - - aes128-ctr - AES 128 CTR - - - aes192-ctr - AES 192 CTR - - - aes256-ctr - AES 256 CTR - - - arcfour128 - AC4 128 (broken) - - - arcfour256 - AC4 256 (broken) - - - arcfour - AC4 (broken) - - - blowfish-cbc - Blowfish CBC - - - cast128-cbc - CAST 128 CBC - + + + @@ -114,7 +65,7 @@ Key exchange algorithms - + @@ -162,7 +113,7 @@ Allowed message authentication algorithms - + -- cgit v1.2.3 From 018cf55955a470724753be099641863f8441654a Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 12 May 2018 12:29:52 +0200 Subject: T631: first full generated config file with XML and Python --- src/conf-mode/vyos-config-ssh.py | 163 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 3 deletions(-) diff --git a/src/conf-mode/vyos-config-ssh.py b/src/conf-mode/vyos-config-ssh.py index e91e829b2..be7af64be 100755 --- a/src/conf-mode/vyos-config-ssh.py +++ b/src/conf-mode/vyos-config-ssh.py @@ -32,6 +32,69 @@ def get_config(): if not conf.exists(''): return ssh + if conf.exists('access-control allow'): + ssh.setdefault('allowed-users', []) + allow_user = [] + allow_user = conf.return_values('access-control allow user') + for user in allow_user: + ssh['allowed-users'].append(user) + + ssh.setdefault('allowed-groups', []) + allow_group = [] + allow_group = conf.return_values('access-control allow group') + for group in allow_group: + ssh['allowed-groups'].append(group) + + if conf.exists('access-control deny'): + ssh.setdefault('deny-users', []) + deny_user = [] + deny_user = conf.return_values('access-control deny user') + for user in deny_user: + ssh['deny-users'].append(user) + + ssh.setdefault('deny-groups', []) + deny_group = [] + deny_group = conf.return_values('access-control deny group') + for group in deny_group: + ssh['deny-groups'].append(group) + + if conf.exists('allow-root'): + ssh.setdefault('allow-root', True) + + if conf.exists('ciphers'): + ciphers = conf.return_value('ciphers') + ssh.setdefault('ciphers', ciphers) + + if conf.exists('disable-host-validation'): + ssh.setdefault('disable-host-validation', True) + + if conf.exists('disable-password-authentication'): + ssh.setdefault('disable-password-authentication', True) + + if conf.exists('key-exchange'): + kex = conf.return_value('key-exchange') + ssh.setdefault('key-exchange', kex) + + if conf.exists('listen-address'): + ssh.setdefault('listen-address', []) + addresses = [] + addresses = conf.return_values('listen-address') + for addr in addresses: + ssh['listen-address'].append(addr) + + if conf.exists('loglevel'): + level = conf.return_value('loglevel') + ssh.setdefault('loglevel', level) + + if conf.exists('mac'): + mac = conf.return_value('mac') + ssh.setdefault('mac', mac) + + if conf.exists('port'): + port = conf.return_value('port') + ssh.setdefault('port', port) + + print(ssh) return ssh def verify(ssh): @@ -44,14 +107,108 @@ def generate(ssh): f = open(config_file, 'w') f.write(config_header) f.write('\n') + + if 'port' in ssh.keys(): + f.write('Port {0}\n'.format(ssh['port'])) + else: + f.write('Port 22\n') + + f.write('Protocol 2\n') + f.write('HostKey /etc/ssh/ssh_host_rsa_key\n') + f.write('HostKey /etc/ssh/ssh_host_dsa_key\n') + f.write('HostKey /etc/ssh/ssh_host_ecdsa_key\n') + f.write('HostKey /etc/ssh/ssh_host_ed25519_key\n') + f.write('UsePrivilegeSeparation yes\n') + f.write('\n') + f.write('KeyRegenerationInterval 3600\n') + f.write('ServerKeyBits 1024\n') + f.write('\n') + f.write('SyslogFacility AUTH\n') + + if 'loglevel' in ssh.keys(): + f.write('LogLevel {0}\n'.format(ssh['loglevel'])) + else: + f.write('LogLevel INFO\n') + + f.write('\n') + f.write('LoginGraceTime 120\n') + + if 'allow-root' in ssh.keys(): + f.write('PermitRootLogin yes\n') + else: + f.write('PermitRootLogin no\n') + + f.write('StrictModes yes\n') + f.write('\n') + f.write('RSAAuthentication yes\n') + f.write('PubkeyAuthentication yes\n') + f.write('\n') + f.write('IgnoreRhosts yes\n') + f.write('RhostsRSAAuthentication no\n') + f.write('HostbasedAuthentication no\n') + f.write('\n') + f.write('PermitEmptyPasswords no\n') + f.write('\n') + f.write('ChallengeResponseAuthentication no\n') + f.write('\n') + + if 'disable-password-authentication' in ssh.keys(): + f.write('PasswordAuthentication no\n') + else: + f.write('PasswordAuthentication yes\n') + + f.write('\n') + f.write('X11Forwarding yes\n') + f.write('X11DisplayOffset 10\n') + f.write('PrintMotd no\n') + f.write('PrintLastLog yes\n') + f.write('TCPKeepAlive yes\n') + f.write('\n') + f.write('Banner /etc/issue.net\n') + f.write('\n') + f.write('Subsystem sftp /usr/lib/openssh/sftp-server\n') + f.write('\n') + f.write('UsePAM yes\n') + f.write('HostKey /etc/ssh/ssh_host_key\n') + + if 'disable-host-validation' in ssh.keys(): + f.write('UseDNS no\n') + else: + f.write('UseDNS yes\n') + + if 'listen-address' in ssh.keys(): + for addr in ssh['listen-address']: + f.write('ListenAddress {0}\n'.format(addr)) + + if 'ciphers' in ssh.keys(): + f.write('Ciphers {0}\n'.format(ssh['ciphers'])) + + if 'key-exchange' in ssh.keys(): + f.write('KexAlgorithms {0}\n'.format(ssh['key-exchange'])) + + if 'mac' in ssh.keys(): + f.write('MACs {0}\n'.format(ssh['mac'])) + + if 'allowed-users' in ssh.keys(): + print('AllowUsers {0}\n'.format(' '.join(str(usr) for usr in ssh['allowed-users']))) + + if 'allowed-groups' in ssh.keys(): + print('AllowGroups {0}\n'.format(' '.join(str(grp) for grp in ssh['allowed-groups']))) + + if 'deny-users' in ssh.keys(): + print('DenyUsers {0}\n'.format(' '.join(str(usr) for usr in ssh['deny-users']))) + + if 'deny-groups' in ssh.keys(): + print('DenyGroups {0}\n'.format(' '.join(str(grp) for grp in ssh['deny-groups']))) + f.close() return None def apply(ssh): - if len(ssh) == 0: - cmd = "sudo systemctl stop ssh" + if 'port' in ssh.keys(): + cmd = "sudo systemctl restart ssh" else: - cmd = "sudo systemctl start ssh" + cmd = "sudo systemctl stop ssh" os.system(cmd) return None -- cgit v1.2.3 From d06ca97a71dd2cf282a281ac2053ac488a84153e Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 12 May 2018 19:03:24 +0200 Subject: T631: refactor SSH script and switch to jinja2 --- src/conf-mode/vyos-config-ssh.py | 357 +++++++++++++++++++++++---------------- 1 file changed, 213 insertions(+), 144 deletions(-) diff --git a/src/conf-mode/vyos-config-ssh.py b/src/conf-mode/vyos-config-ssh.py index be7af64be..6a520fc2c 100755 --- a/src/conf-mode/vyos-config-ssh.py +++ b/src/conf-mode/vyos-config-ssh.py @@ -18,75 +18,230 @@ import sys import os -import time + +import jinja2 from vyos.config import Config from vyos.util import ConfigError config_file = r'/etc/ssh/sshd_config' +# Please be careful if you edit the template. +config_tmpl = """ + +### Autogenerated by vyos-config-ssh.py ### + +# Non-configurable defaults +Protocol 2 +HostKey /etc/ssh/ssh_host_rsa_key +HostKey /etc/ssh/ssh_host_dsa_key +HostKey /etc/ssh/ssh_host_ecdsa_key +HostKey /etc/ssh/ssh_host_ed25519_key +UsePrivilegeSeparation yes +KeyRegenerationInterval 3600 +ServerKeyBits 1024 +SyslogFacility AUTH +LoginGraceTime 120 +StrictModes yes +RSAAuthentication yes +PubkeyAuthentication yes +IgnoreRhosts yes +RhostsRSAAuthentication no +HostbasedAuthentication no +PermitEmptyPasswords no +ChallengeResponseAuthentication no +X11Forwarding yes +X11DisplayOffset 10 +PrintMotd no +PrintLastLog yes +TCPKeepAlive yes +Banner /etc/issue.net +Subsystem sftp /usr/lib/openssh/sftp-server +UsePAM yes +HostKey /etc/ssh/ssh_host_key + +# Specifies whether sshd should look up the remote host name, +# and to check that the resolved host name for the remote IP +# address maps back to the very same IP address. +UseDNS {{ host_validation }} + +# Specifies the port number that sshd listens on. The default is 22. +# Multiple options of this type are permitted. +Port {{ port }} + +# Gives the verbosity level that is used when logging messages from sshd +LogLevel {{ log_level }} + +# Specifies whether root can log in using ssh +PermitRootLogin {{ allow_root }} + +# Specifies whether password authentication is allowed +PasswordAuthentication {{ password_authentication }} + +{% if listen_on -%} +# Specifies the local addresses sshd should listen on +{% for a in listen_on -%} +ListenAddress {{ a }} +{% endfor -%} +{% endif %} + +{% if ciphers -%} +# Specifies the ciphers allowed. Multiple ciphers must be comma-separated. +# +# NOTE: As of now, there is no 'multi' node for 'ciphers', thus we have only one :/ +Ciphers {{ ciphers }} +{% endif %} + +{% if mac -%} +# Specifies the available MAC (message authentication code) algorithms. The MAC +# algorithm is used for data integrity protection. Multiple algorithms must be +# comma-separated. +# +# NOTE: As of now, there is no 'multi' node for 'mac', thus we have only one :/ +MACs {{ mac }} +{% endif %} + +{% if key_exchange -%} +# Specifies the available KEX (Key Exchange) algorithms. Multiple algorithms must +# be comma-separated. +# +# NOTE: As of now, there is no 'multi' node for 'key-exchange', thus we have only one :/ +KexAlgorithms {{ key_exchange }} +{% endif %} + +{% if allow_users -%} +# This keyword can be followed by a list of user name patterns, separated by spaces. +# If specified, login is allowed only for user names that match one of the patterns. +# Only user names are valid, a numerical user ID is not recognized. +AllowUsers {{ allow_users | join(" ") }} +{% endif %} + +{% if allow_groups -%} +# This keyword can be followed by a list of group name patterns, separated by spaces. +# If specified, login is allowed only for users whose primary group or supplementary +# group list matches one of the patterns. Only group names are valid, a numerical group +# ID is not recognized. +AllowGroups {{ allow_groups | join(" ") }} +{% endif %} + +{% if deny_users -%} +# This keyword can be followed by a list of user name patterns, separated by spaces. +# Login is disallowed for user names that match one of the patterns. Only user names +# are valid, a numerical user ID is not recognized. +DenyUsers {{ deny_users | join(" ") }} +{% endif %} + +{% if deny_groups -%} +# This keyword can be followed by a list of group name patterns, separated by spaces. +# Login is disallowed for users whose primary group or supplementary group list matches +# one of the patterns. Only group names are valid, a numerical group ID is not recognized. +DenyGroups {{ deny_groups | join(" ") }} +{% endif %} +""" + +default_config_data = { + 'port' : '22', + 'log_level': 'INFO', + 'allow_root': 'no', + 'password_authentication': 'yes', + 'host_validation': 'yes' +} + def get_config(): - ssh = {} + ssh = default_config_data conf = Config() - conf.set_level('service ssh') - if not conf.exists(''): - return ssh - - if conf.exists('access-control allow'): - ssh.setdefault('allowed-users', []) - allow_user = [] - allow_user = conf.return_values('access-control allow user') - for user in allow_user: - ssh['allowed-users'].append(user) - - ssh.setdefault('allowed-groups', []) - allow_group = [] - allow_group = conf.return_values('access-control allow group') - for group in allow_group: - ssh['allowed-groups'].append(group) - - if conf.exists('access-control deny'): - ssh.setdefault('deny-users', []) - deny_user = [] - deny_user = conf.return_values('access-control deny user') - for user in deny_user: - ssh['deny-users'].append(user) - - ssh.setdefault('deny-groups', []) - deny_group = [] - deny_group = conf.return_values('access-control deny group') - for group in deny_group: - ssh['deny-groups'].append(group) + if not conf.exists('service ssh'): + return None + else: + conf.set_level('service ssh') + + if conf.exists('access-control allow-users'): + # Retrieve ',' separated list for allowed users and convert it to a list. + # The current VyOS CLI implementation should be improved to rather use multi nodes + # instead of a ',' separated input. + allow_user = conf.return_value('access-control allow-users') + tmp = allow_user.split(',') + users = [] + for u in tmp: + users.append(u) + + ssh.setdefault('allow_users', users) + + if conf.exists('access-control allow-groups'): + # Retrieve ',' separated list for allowed groups and convert it to a list. + # The current VyOS CLI implementation should be improved to rather use multi nodes + # instead of a ',' separated input. + allow_group = conf.return_value('access-control allow-groups') + tmp = allow_group.split(',') + groups = [] + for g in tmp: + groups.append(g) + + ssh.setdefault('allow_groups', groups) + + if conf.exists('access-control deny-groups'): + # Retrieve ',' separated list for denied users and convert it to a list. + # The current VyOS CLI implementation should be improved to rather use multi nodes + # instead of a ',' separated input. + deny_user = conf.return_value('access-control deny-users') + tmp = deny_user.split(',') + users = [] + for u in tmp: + users.append(u) + + ssh.setdefault('deny_users', users) + + if conf.exists('access-control deny-groups'): + # Retrieve ',' separated list for denied groups and convert it to a list. + # The current VyOS CLI implementation should be improved to rather use multi nodes + # instead of a ',' separated input. + deny_group = conf.return_value('access-control deny-groups') + tmp = deny_group.split(',') + groups = [] + for g in tmp: + groups.append(g) + + ssh.setdefault('deny_groups', groups) if conf.exists('allow-root'): - ssh.setdefault('allow-root', True) + ssh['allow-root'] = 'yes' if conf.exists('ciphers'): + # TODO: OpenSSH supports having multiple Ciphers configured. VyOS CLI + # yet has no multi node for this. See T632 in phabricator. ciphers = conf.return_value('ciphers') ssh.setdefault('ciphers', ciphers) if conf.exists('disable-host-validation'): - ssh.setdefault('disable-host-validation', True) + ssh['host_validation'] = 'no' if conf.exists('disable-password-authentication'): - ssh.setdefault('disable-password-authentication', True) + ssh['password_authentication'] = 'no' if conf.exists('key-exchange'): + # TODO: OpenSSH supports having multiple KEYX methods configured. VyOS CLI + # yet has no multi node for this. See T632 in phabricator. kex = conf.return_value('key-exchange') - ssh.setdefault('key-exchange', kex) + ssh.setdefault('key_exchange', kex) if conf.exists('listen-address'): - ssh.setdefault('listen-address', []) - addresses = [] + # We can listen on both IPv4 and IPv6 addresses + # Maybe there could be a check in the future if the configured IP address + # is configured on this system at all? addresses = conf.return_values('listen-address') + listen = [] + for addr in addresses: - ssh['listen-address'].append(addr) + listen.append(addr) + + ssh.setdefault('listen_on', listen) if conf.exists('loglevel'): - level = conf.return_value('loglevel') - ssh.setdefault('loglevel', level) + ssh['log_level'] = conf.return_value('loglevel') if conf.exists('mac'): + # TODO: OpenSSH supports having multiple MACs configured. VyOS CLI + # yet has no multi node for this. See T632 in phabricator. mac = conf.return_value('mac') ssh.setdefault('mac', mac) @@ -94,123 +249,37 @@ def get_config(): port = conf.return_value('port') ssh.setdefault('port', port) - print(ssh) return ssh def verify(ssh): - return None - -def generate(ssh): - config_header = '### Autogenerated by vyos-config-ssh.py on {tm} ###\n'.format(tm=time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())) - - # write new configuration file - f = open(config_file, 'w') - f.write(config_header) - f.write('\n') - - if 'port' in ssh.keys(): - f.write('Port {0}\n'.format(ssh['port'])) - else: - f.write('Port 22\n') - - f.write('Protocol 2\n') - f.write('HostKey /etc/ssh/ssh_host_rsa_key\n') - f.write('HostKey /etc/ssh/ssh_host_dsa_key\n') - f.write('HostKey /etc/ssh/ssh_host_ecdsa_key\n') - f.write('HostKey /etc/ssh/ssh_host_ed25519_key\n') - f.write('UsePrivilegeSeparation yes\n') - f.write('\n') - f.write('KeyRegenerationInterval 3600\n') - f.write('ServerKeyBits 1024\n') - f.write('\n') - f.write('SyslogFacility AUTH\n') + if ssh is None: + return None if 'loglevel' in ssh.keys(): - f.write('LogLevel {0}\n'.format(ssh['loglevel'])) - else: - f.write('LogLevel INFO\n') - - f.write('\n') - f.write('LoginGraceTime 120\n') - - if 'allow-root' in ssh.keys(): - f.write('PermitRootLogin yes\n') - else: - f.write('PermitRootLogin no\n') - - f.write('StrictModes yes\n') - f.write('\n') - f.write('RSAAuthentication yes\n') - f.write('PubkeyAuthentication yes\n') - f.write('\n') - f.write('IgnoreRhosts yes\n') - f.write('RhostsRSAAuthentication no\n') - f.write('HostbasedAuthentication no\n') - f.write('\n') - f.write('PermitEmptyPasswords no\n') - f.write('\n') - f.write('ChallengeResponseAuthentication no\n') - f.write('\n') - - if 'disable-password-authentication' in ssh.keys(): - f.write('PasswordAuthentication no\n') - else: - f.write('PasswordAuthentication yes\n') - - f.write('\n') - f.write('X11Forwarding yes\n') - f.write('X11DisplayOffset 10\n') - f.write('PrintMotd no\n') - f.write('PrintLastLog yes\n') - f.write('TCPKeepAlive yes\n') - f.write('\n') - f.write('Banner /etc/issue.net\n') - f.write('\n') - f.write('Subsystem sftp /usr/lib/openssh/sftp-server\n') - f.write('\n') - f.write('UsePAM yes\n') - f.write('HostKey /etc/ssh/ssh_host_key\n') - - if 'disable-host-validation' in ssh.keys(): - f.write('UseDNS no\n') - else: - f.write('UseDNS yes\n') - - if 'listen-address' in ssh.keys(): - for addr in ssh['listen-address']: - f.write('ListenAddress {0}\n'.format(addr)) + allowed_loglevel = 'QUIET, FATAL, ERROR, INFO, VERBOSE' + if not ssh['loglevel'] in allowed_loglevel: + raise ConfigError('loglevel must be one of "{0}"\n'.format(allowed_loglevel)) - if 'ciphers' in ssh.keys(): - f.write('Ciphers {0}\n'.format(ssh['ciphers'])) - - if 'key-exchange' in ssh.keys(): - f.write('KexAlgorithms {0}\n'.format(ssh['key-exchange'])) - - if 'mac' in ssh.keys(): - f.write('MACs {0}\n'.format(ssh['mac'])) - - if 'allowed-users' in ssh.keys(): - print('AllowUsers {0}\n'.format(' '.join(str(usr) for usr in ssh['allowed-users']))) - - if 'allowed-groups' in ssh.keys(): - print('AllowGroups {0}\n'.format(' '.join(str(grp) for grp in ssh['allowed-groups']))) - - if 'deny-users' in ssh.keys(): - print('DenyUsers {0}\n'.format(' '.join(str(usr) for usr in ssh['deny-users']))) + return None - if 'deny-groups' in ssh.keys(): - print('DenyGroups {0}\n'.format(' '.join(str(grp) for grp in ssh['deny-groups']))) +def generate(ssh): + if ssh is None: + return None - f.close() + tmpl = jinja2.Template(config_tmpl) + config_text = tmpl.render(ssh) + with open(config_file, 'w') as f: + f.write(config_text) return None def apply(ssh): - if 'port' in ssh.keys(): - cmd = "sudo systemctl restart ssh" + if ssh is not None and 'port' in ssh.keys(): + os.system("sudo systemctl restart ssh") else: - cmd = "sudo systemctl stop ssh" + # SSH access is removed in the commit + os.system("sudo systemctl stop ssh") + os.unlink(config_file) - os.system(cmd) return None if __name__ == '__main__': -- cgit v1.2.3 From a20634014490f2b3053f0b7176f98f39a4f72e9e Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 13 May 2018 13:41:12 +0200 Subject: T631: improve help for access-control --- interface-definitions/ssh.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface-definitions/ssh.xml b/interface-definitions/ssh.xml index 5b9368360..5ccd3006f 100644 --- a/interface-definitions/ssh.xml +++ b/interface-definitions/ssh.xml @@ -13,7 +13,7 @@ - SSH user/group access controls + SSH user/group access controls. Directives are processed in this: deny-users, allow-users, deny-groups and allow-groups -- cgit v1.2.3 From 3249bc34e9897fbb6b7cfb83e655a5b7c9d9ddcf Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 13 May 2018 14:16:13 +0200 Subject: T631: small bugfix in config parsind for deny-users --- src/conf-mode/vyos-config-ssh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conf-mode/vyos-config-ssh.py b/src/conf-mode/vyos-config-ssh.py index 6a520fc2c..1605dcd74 100755 --- a/src/conf-mode/vyos-config-ssh.py +++ b/src/conf-mode/vyos-config-ssh.py @@ -179,7 +179,7 @@ def get_config(): ssh.setdefault('allow_groups', groups) - if conf.exists('access-control deny-groups'): + if conf.exists('access-control deny-users'): # Retrieve ',' separated list for denied users and convert it to a list. # The current VyOS CLI implementation should be improved to rather use multi nodes # instead of a ',' separated input. -- cgit v1.2.3