From 8598d81bb1a18589127b25ba7156986f719c14d1 Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 26 Aug 2018 14:15:55 +0200 Subject: [PATCH 01/32] [wip] Standardize ssh config --- data/hooks/conf_regen/03-ssh | 2 +- locales/en.json | 6 ++++++ src/yunohost/tools.py | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index a469b7a66..e3e03877e 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -7,7 +7,7 @@ do_pre_regen() { cd /usr/share/yunohost/templates/ssh - # only overwrite SSH configuration on an ISO installation + # Don't overwrite configuration if from_script if [[ ! -f /etc/yunohost/from_script ]]; then # do not listen to IPv6 if unavailable [[ -f /proc/net/if_inet6 ]] \ diff --git a/locales/en.json b/locales/en.json index 6ce22ca80..d63fc4a69 100644 --- a/locales/en.json +++ b/locales/en.json @@ -292,6 +292,12 @@ "migration_0005_not_enough_space": "Not enough space is available in {path} to run the migration right now :(.", "migration_0006_disclaimer": "Yunohost now expects admin and root passwords to be synchronized. By running this migration, your root password is going to be replaced by the admin password.", "migration_0006_done": "Your root password have been replaced by your admin password.", + "migration_0007_general_warning": "To ensure a global security of your server, YunoHost recommends to let it manage the SSH configuration of your server. Your current SSH configuration differs from common default configuration. If you let YunoHost reconfigure it, the way to access with SSH to your server could change after this migration:", + "migration_0007_port": "- you will have to connect using port 22 instead of your custom SSH port. Feel free to reconfigure it", + "migration_0007_root": "- you will not be able to connect with root user, instead you will have to use admin user.", + "migration_0007_dsa": "- you might need to invalidate a warning and to recheck fingerprint of your server, because DSA key will be disabled.", + "migration_0007_risk": "If you agree to let YunoHost replace your configuration and change the way to access your server, make the migration else skip it.", + "migration_0007_no_risk": "No major change in the way has been found, but it's difficult to be sure. If you agree to let YunoHost replace your configuration and change the way to access your server, make the migration else skip it.", "migrations_backward": "Migrating backward.", "migrations_bad_value_for_target": "Invalid number for target argument, available migrations numbers are 0 or {}", "migrations_cant_reach_migration_file": "Can't access migrations files at path %s", diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 271947b3d..a0549321a 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -440,6 +440,12 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False, service_start("yunohost-firewall") service_regen_conf(force=True) + + # Restore specific ssh conf + bkp_sshd_conf = '/etc/ssh/sshd_config.to_restore' + if os.path.exists(bkp_sshd_conf): + os.rename(bkp_sshd_conf, '/etc/ssh/sshd_config') + logger.success(m18n.n('yunohost_configured')) logger.warning(m18n.n('recommend_to_add_first_user')) From 7f3a35dac0bd33a15247ca3df866551953d9a39c Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 26 Aug 2018 14:38:46 +0200 Subject: [PATCH 02/32] [enh] Don't change ssh conf if not specified directly --- src/yunohost/service.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/yunohost/service.py b/src/yunohost/service.py index 5b7680a80..9ab301933 100644 --- a/src/yunohost/service.py +++ b/src/yunohost/service.py @@ -39,8 +39,8 @@ from moulinette import m18n from moulinette.core import MoulinetteError from moulinette.utils import log, filesystem -from yunohost.hook import hook_callback from yunohost.log import is_unit_operation +from yunohost.hook import hook_callback, hook_list BASE_CONF_PATH = '/home/yunohost.conf' BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, 'backup') @@ -422,6 +422,12 @@ def service_regen_conf(operation_logger, names=[], with_diff=False, force=False, # return the arguments to pass to the script return pre_args + [service_pending_path, ] + # Don't regen SSH if not specifically specified + if not names: + names = hook_list('conf_regen', list_by='name', + show_info=False)['hooks'] + names.remove('ssh') + pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call) # Update the services name From f0d0a715869af02b2d0594265d04c6c6efe37ba2 Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 26 Aug 2018 14:54:07 +0200 Subject: [PATCH 03/32] [wip] Ask user for keeping or not sshd config --- .../0006_manage_sshd_config.py | 56 ++++++++++++++ .../data_migrations/0007_reset_sshd_config.py | 77 +++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 src/yunohost/data_migrations/0006_manage_sshd_config.py create mode 100644 src/yunohost/data_migrations/0007_reset_sshd_config.py diff --git a/src/yunohost/data_migrations/0006_manage_sshd_config.py b/src/yunohost/data_migrations/0006_manage_sshd_config.py new file mode 100644 index 000000000..413c3fefe --- /dev/null +++ b/src/yunohost/data_migrations/0006_manage_sshd_config.py @@ -0,0 +1,56 @@ +import subprocess +import os + +from shutil import copyfile + +from moulinette import m18n +from moulinette.core import MoulinetteError +from moulinette.utils.log import getActionLogger + +from yunohost.tools import Migration +from yunohost.service import service_regen_conf, _get_conf_hashes, + _calculate_hash + +logger = getActionLogger('yunohost.migration') + + +class MyMigration(Migration): + """ + Ensure SSH conf is managed by YunoHost, reapply initial change and setup an + extension dir + """ + + def migrate(self): + + # Create sshd_config.d dir + if not os.path.exists('/etc/ssh/sshd_config.d'): + mkdir('/etc/ssh/sshd_config.d', '0755', uid='root', gid='root') + + # Manage SSHd in all case + if os.path.exists('/etc/yunohost/from_script'): + rm('/etc/yunohost/from_script') + copyfile('/etc/ssh/sshd_config', '/etc/ssh/sshd_config.restore') + service_regen_conf(names=['ssh'], force=True) + os.rename('/etc/ssh/sshd_config.restore', '/etc/ssh/sshd_config') + + # If custom conf, add 'Include' instruction + ynh_hash = _get_conf_hashes('ssh')['/etc/ssh/sshd_config'] + current_hash = _calculate_hash('/etc/ssh/sshd_config') + if ynh_hash == current_hash: + return + + add_include = False + include_rgx = r'^[ \t]*Include[ \t]+sshd_config\.d/\*[ \t]*(?:#.*)?$' + for line in open('/etc/ssh/sshd_config'): + if re.match(root_rgx, line) is not None: + add_include = True + break + + if add_include: + with open("/etc/ssh/sshd_config", "a") as conf: + conf.write('Include sshd_config.d/*') + + def backward(self): + + raise MoulinetteError(m18n.n("migration_0006_backward_impossible")) + diff --git a/src/yunohost/data_migrations/0007_reset_sshd_config.py b/src/yunohost/data_migrations/0007_reset_sshd_config.py new file mode 100644 index 000000000..701b60e3c --- /dev/null +++ b/src/yunohost/data_migrations/0007_reset_sshd_config.py @@ -0,0 +1,77 @@ +import subprocess +import os + +from shutil import copyfile + +from moulinette import m18n +from moulinette.core import MoulinetteError +from moulinette.utils.log import getActionLogger + +from yunohost.tools import Migration +from yunohost.service import service_regen_conf + +logger = getActionLogger('yunohost.migration') + + +class MyMigration(Migration): + "Reset SSH conf to the YunoHost one" + + mode = "manual" + + def migrate(self): + service_regen_conf(names=['ssh'], force=True) + + def backward(self): + + raise MoulinetteError(m18n.n("migration_0007_backward_impossible")) + + @property + def disclaimer(self): + + # Avoid having a super long disclaimer + ynh_hash = _get_conf_hashes('ssh')['/etc/ssh/sshd_config'] + current_hash = _calculate_hash('/etc/ssh/sshd_config') + if ynh_hash == current_hash: + return None + + # Detect major risk to migrate to the new configuration + dsa = False + port_rgx = r'^[ \t]*Port[ \t]+(\d+)[ \t]*(?:#.*)?$' + root_rgx = r'^[ \t]*PermitRootLogin[ \t]([\w-]*)[ \t]*(?:#.*)?$' + dsa_rgx = r'^[ \t]*HostKey[ \t]+/etc/ssh/ssh_host_dsa_key[ \t]*(?:#.*)?$' + for line in open('/etc/ssh/sshd_config'): + + ports = re.findall(port_rgx, line) + + root_login = re.match(root_rgx, line) + if root_login is not None: + root_login = root_login.group(1) + + if not dsa and re.match(dsa_rgx, line): + dsa = True + + if len(ports) == 0: + ports = ['22'] + + port = ports != ['22'] + + root_user = root_login in ['yes'] + + # Build message + message = m18n.n("migration_0007_general_warning") + + if port: + message += "\n\n" + m18n.n("migration_0007_port") + + if root_user: + message += "\n\n" + m18n.n("migration_0007_root") + + if dsa: + message += "\n\n" + m18n.n("migration_0007_dsa") + + if port or root_user or dsa: + message += "\n\n" + m18n.n("migration_0007_risk") + else: + message += "\n\n" + m18n.n("migration_0007_no_risk") + + return message From c2b225d3765938a5d4536badbdb1700ee1064801 Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 26 Aug 2018 19:57:48 +0200 Subject: [PATCH 04/32] [fix] A lot of bug on the wip work on sshd migration --- data/templates/ssh/sshd_config | 2 ++ locales/en.json | 2 ++ .../0006_manage_sshd_config.py | 13 +++++--- .../data_migrations/0007_reset_sshd_config.py | 32 ++++++++++++------- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index 8c5a7fb95..b79ffd3bf 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -94,3 +94,5 @@ Match User sftpusers AllowTcpForwarding no GatewayPorts no X11Forwarding no + +Include sshd_config.d/* diff --git a/locales/en.json b/locales/en.json index d63fc4a69..94e8a6384 100644 --- a/locales/en.json +++ b/locales/en.json @@ -274,6 +274,8 @@ "migration_description_0004_php5_to_php7_pools": "Reconfigure the PHP pools to use PHP 7 instead of 5", "migration_description_0005_postgresql_9p4_to_9p6": "Migrate databases from postgresql 9.4 to 9.6", "migration_description_0006_sync_admin_and_root_passwords": "Synchronize admin and root passwords", + "migration_description_0006_manage_sshd_config": "Manage SSH conf in a better way", + "migration_description_0007_reset_sshd_config": "Reset SSH conf to the YunoHost default conf", "migration_0003_backward_impossible": "The stretch migration cannot be reverted.", "migration_0003_start": "Starting migration to Stretch. The logs will be available in {logfile}.", "migration_0003_patching_sources_list": "Patching the sources.lists ...", diff --git a/src/yunohost/data_migrations/0006_manage_sshd_config.py b/src/yunohost/data_migrations/0006_manage_sshd_config.py index 413c3fefe..d4740192e 100644 --- a/src/yunohost/data_migrations/0006_manage_sshd_config.py +++ b/src/yunohost/data_migrations/0006_manage_sshd_config.py @@ -1,15 +1,17 @@ import subprocess import os +import re from shutil import copyfile from moulinette import m18n from moulinette.core import MoulinetteError from moulinette.utils.log import getActionLogger +from moulinette.utils.filesystem import mkdir, rm from yunohost.tools import Migration -from yunohost.service import service_regen_conf, _get_conf_hashes, - _calculate_hash +from yunohost.service import service_regen_conf, _get_conf_hashes, \ + _calculate_hash, _run_service_command logger = getActionLogger('yunohost.migration') @@ -24,7 +26,7 @@ class MyMigration(Migration): # Create sshd_config.d dir if not os.path.exists('/etc/ssh/sshd_config.d'): - mkdir('/etc/ssh/sshd_config.d', '0755', uid='root', gid='root') + mkdir('/etc/ssh/sshd_config.d', 0755, uid='root', gid='root') # Manage SSHd in all case if os.path.exists('/etc/yunohost/from_script'): @@ -42,7 +44,7 @@ class MyMigration(Migration): add_include = False include_rgx = r'^[ \t]*Include[ \t]+sshd_config\.d/\*[ \t]*(?:#.*)?$' for line in open('/etc/ssh/sshd_config'): - if re.match(root_rgx, line) is not None: + if re.match(include_rgx, line) is not None: add_include = True break @@ -50,6 +52,9 @@ class MyMigration(Migration): with open("/etc/ssh/sshd_config", "a") as conf: conf.write('Include sshd_config.d/*') + if not _run_service_command('restart', 'ssh'): + self.backward() + def backward(self): raise MoulinetteError(m18n.n("migration_0006_backward_impossible")) diff --git a/src/yunohost/data_migrations/0007_reset_sshd_config.py b/src/yunohost/data_migrations/0007_reset_sshd_config.py index 701b60e3c..a9fb9fa14 100644 --- a/src/yunohost/data_migrations/0007_reset_sshd_config.py +++ b/src/yunohost/data_migrations/0007_reset_sshd_config.py @@ -1,5 +1,6 @@ import subprocess import os +import re from shutil import copyfile @@ -8,7 +9,7 @@ from moulinette.core import MoulinetteError from moulinette.utils.log import getActionLogger from yunohost.tools import Migration -from yunohost.service import service_regen_conf +from yunohost.service import service_regen_conf, _get_conf_hashes, _calculate_hash logger = getActionLogger('yunohost.migration') @@ -16,8 +17,6 @@ logger = getActionLogger('yunohost.migration') class MyMigration(Migration): "Reset SSH conf to the YunoHost one" - mode = "manual" - def migrate(self): service_regen_conf(names=['ssh'], force=True) @@ -26,26 +25,37 @@ class MyMigration(Migration): raise MoulinetteError(m18n.n("migration_0007_backward_impossible")) @property - def disclaimer(self): + def mode(self): # Avoid having a super long disclaimer - ynh_hash = _get_conf_hashes('ssh')['/etc/ssh/sshd_config'] + ynh_hash = _get_conf_hashes('ssh') + if '/etc/ssh/sshd_config' in ynh_hash: + ynh_hash = ynh_hash['/etc/ssh/sshd_config'] current_hash = _calculate_hash('/etc/ssh/sshd_config') if ynh_hash == current_hash: + return "auto" + + return "manual" + + + @property + def disclaimer(self): + + if self.mode == "auto": return None # Detect major risk to migrate to the new configuration dsa = False + ports = [] + root_login = [] port_rgx = r'^[ \t]*Port[ \t]+(\d+)[ \t]*(?:#.*)?$' - root_rgx = r'^[ \t]*PermitRootLogin[ \t]([\w-]*)[ \t]*(?:#.*)?$' + root_rgx = r'^[ \t]*PermitRootLogin[ \t]([^# \t]*)[ \t]*(?:#.*)?$' dsa_rgx = r'^[ \t]*HostKey[ \t]+/etc/ssh/ssh_host_dsa_key[ \t]*(?:#.*)?$' for line in open('/etc/ssh/sshd_config'): - ports = re.findall(port_rgx, line) + ports = ports + re.findall(port_rgx, line) - root_login = re.match(root_rgx, line) - if root_login is not None: - root_login = root_login.group(1) + root_login = root_login + re.findall(root_rgx, line) if not dsa and re.match(dsa_rgx, line): dsa = True @@ -55,7 +65,7 @@ class MyMigration(Migration): port = ports != ['22'] - root_user = root_login in ['yes'] + root_user = root_login and root_login[-1] != 'no' # Build message message = m18n.n("migration_0007_general_warning") From 4e92a36322dae60021738c0d5ef71e67247a45a8 Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 26 Aug 2018 20:20:35 +0200 Subject: [PATCH 05/32] [fix] Backward if can't restart --- locales/en.json | 2 ++ .../0006_manage_sshd_config.py | 33 +++++++++++-------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/locales/en.json b/locales/en.json index 94e8a6384..df69ca1a4 100644 --- a/locales/en.json +++ b/locales/en.json @@ -294,6 +294,8 @@ "migration_0005_not_enough_space": "Not enough space is available in {path} to run the migration right now :(.", "migration_0006_disclaimer": "Yunohost now expects admin and root passwords to be synchronized. By running this migration, your root password is going to be replaced by the admin password.", "migration_0006_done": "Your root password have been replaced by your admin password.", + "migration_0006_cancelled": "YunoHost has failed to improve the way your ssh conf is managed.", + "migration_0006_cannot_restart": "SSH can't be restarted after we tried to cancel the migration 6.", "migration_0007_general_warning": "To ensure a global security of your server, YunoHost recommends to let it manage the SSH configuration of your server. Your current SSH configuration differs from common default configuration. If you let YunoHost reconfigure it, the way to access with SSH to your server could change after this migration:", "migration_0007_port": "- you will have to connect using port 22 instead of your custom SSH port. Feel free to reconfigure it", "migration_0007_root": "- you will not be able to connect with root user, instead you will have to use admin user.", diff --git a/src/yunohost/data_migrations/0006_manage_sshd_config.py b/src/yunohost/data_migrations/0006_manage_sshd_config.py index d4740192e..cd9204846 100644 --- a/src/yunohost/data_migrations/0006_manage_sshd_config.py +++ b/src/yunohost/data_migrations/0006_manage_sshd_config.py @@ -31,31 +31,36 @@ class MyMigration(Migration): # Manage SSHd in all case if os.path.exists('/etc/yunohost/from_script'): rm('/etc/yunohost/from_script') - copyfile('/etc/ssh/sshd_config', '/etc/ssh/sshd_config.restore') + copyfile('/etc/ssh/sshd_config', '/etc/ssh/sshd_config.bkp') service_regen_conf(names=['ssh'], force=True) - os.rename('/etc/ssh/sshd_config.restore', '/etc/ssh/sshd_config') + copyfile('/etc/ssh/sshd_config.bkp', '/etc/ssh/sshd_config') # If custom conf, add 'Include' instruction ynh_hash = _get_conf_hashes('ssh')['/etc/ssh/sshd_config'] current_hash = _calculate_hash('/etc/ssh/sshd_config') - if ynh_hash == current_hash: - return + if ynh_hash != current_hash: - add_include = False - include_rgx = r'^[ \t]*Include[ \t]+sshd_config\.d/\*[ \t]*(?:#.*)?$' - for line in open('/etc/ssh/sshd_config'): - if re.match(include_rgx, line) is not None: - add_include = True - break + add_include = False + include_rgx = r'^[ \t]*Include[ \t]+sshd_config\.d/\*[ \t]*(?:#.*)?$' + for line in open('/etc/ssh/sshd_config'): + if re.match(include_rgx, line) is not None: + add_include = True + break - if add_include: - with open("/etc/ssh/sshd_config", "a") as conf: - conf.write('Include sshd_config.d/*') + if add_include: + with open("/etc/ssh/sshd_config", "a") as conf: + conf.write('Include sshd_config.d/*') + # Restart ssh and backward if it fail if not _run_service_command('restart', 'ssh'): self.backward() + raise MoulinetteError(m18n.n("migration_0006_cancel")) + def backward(self): + # We don't backward completely but it should be enough - raise MoulinetteError(m18n.n("migration_0006_backward_impossible")) + copyfile('/etc/ssh/sshd_config.bkp', '/etc/ssh/sshd_config') + if not _run_service_command('restart', 'ssh'): + raise MoulinetteError(m18n.n("migration_0006_cannot_restart")) From 4602439c013d9db6f9a92f34899788fab0df9f56 Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 26 Aug 2018 20:29:11 +0200 Subject: [PATCH 06/32] [fix] Pep8 and define SSHD_CONF --- .../0006_manage_sshd_config.py | 25 +++++++++---------- .../data_migrations/0007_reset_sshd_config.py | 8 ++---- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/yunohost/data_migrations/0006_manage_sshd_config.py b/src/yunohost/data_migrations/0006_manage_sshd_config.py index cd9204846..4af486b6e 100644 --- a/src/yunohost/data_migrations/0006_manage_sshd_config.py +++ b/src/yunohost/data_migrations/0006_manage_sshd_config.py @@ -1,4 +1,3 @@ -import subprocess import os import re @@ -15,6 +14,8 @@ from yunohost.service import service_regen_conf, _get_conf_hashes, \ logger = getActionLogger('yunohost.migration') +SSHD_CONF = '/etc/ssh/sshd_config' + class MyMigration(Migration): """ @@ -25,30 +26,30 @@ class MyMigration(Migration): def migrate(self): # Create sshd_config.d dir - if not os.path.exists('/etc/ssh/sshd_config.d'): - mkdir('/etc/ssh/sshd_config.d', 0755, uid='root', gid='root') + if not os.path.exists(SSHD_CONF + '.d'): + mkdir(SSHD_CONF + '.d', 0755, uid='root', gid='root') # Manage SSHd in all case if os.path.exists('/etc/yunohost/from_script'): rm('/etc/yunohost/from_script') - copyfile('/etc/ssh/sshd_config', '/etc/ssh/sshd_config.bkp') + copyfile(SSHD_CONF, '/etc/ssh/sshd_config.bkp') service_regen_conf(names=['ssh'], force=True) - copyfile('/etc/ssh/sshd_config.bkp', '/etc/ssh/sshd_config') + copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF) # If custom conf, add 'Include' instruction - ynh_hash = _get_conf_hashes('ssh')['/etc/ssh/sshd_config'] - current_hash = _calculate_hash('/etc/ssh/sshd_config') + ynh_hash = _get_conf_hashes('ssh')[SSHD_CONF] + current_hash = _calculate_hash(SSHD_CONF) + include_rgx = r'^[ \t]*Include[ \t]+sshd_config\.d/\*[ \t]*(?:#.*)?$' if ynh_hash != current_hash: add_include = False - include_rgx = r'^[ \t]*Include[ \t]+sshd_config\.d/\*[ \t]*(?:#.*)?$' - for line in open('/etc/ssh/sshd_config'): + for line in open(SSHD_CONF): if re.match(include_rgx, line) is not None: add_include = True break if add_include: - with open("/etc/ssh/sshd_config", "a") as conf: + with open(SSHD_CONF, "a") as conf: conf.write('Include sshd_config.d/*') # Restart ssh and backward if it fail @@ -56,11 +57,9 @@ class MyMigration(Migration): self.backward() raise MoulinetteError(m18n.n("migration_0006_cancel")) - def backward(self): # We don't backward completely but it should be enough - copyfile('/etc/ssh/sshd_config.bkp', '/etc/ssh/sshd_config') + copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF) if not _run_service_command('restart', 'ssh'): raise MoulinetteError(m18n.n("migration_0006_cannot_restart")) - diff --git a/src/yunohost/data_migrations/0007_reset_sshd_config.py b/src/yunohost/data_migrations/0007_reset_sshd_config.py index a9fb9fa14..5a097968d 100644 --- a/src/yunohost/data_migrations/0007_reset_sshd_config.py +++ b/src/yunohost/data_migrations/0007_reset_sshd_config.py @@ -1,15 +1,12 @@ -import subprocess -import os import re -from shutil import copyfile - from moulinette import m18n from moulinette.core import MoulinetteError from moulinette.utils.log import getActionLogger from yunohost.tools import Migration -from yunohost.service import service_regen_conf, _get_conf_hashes, _calculate_hash +from yunohost.service import service_regen_conf, _get_conf_hashes, \ + _calculate_hash logger = getActionLogger('yunohost.migration') @@ -37,7 +34,6 @@ class MyMigration(Migration): return "manual" - @property def disclaimer(self): From 8e0086d49397e701efbbc2ec4f31ab044b8e5920 Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 26 Aug 2018 23:40:26 +0200 Subject: [PATCH 07/32] [fix] Allow user to trigger the moment when they remove dsa --- data/hooks/conf_regen/03-ssh | 5 +++++ data/templates/ssh/sshd_config | 8 +++----- .../data_migrations/0006_manage_sshd_config.py | 11 +++++++++++ .../data_migrations/0007_reset_sshd_config.py | 7 +++++-- src/yunohost/settings.py | 1 + 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index e3e03877e..563394d40 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -13,6 +13,11 @@ do_pre_regen() { [[ -f /proc/net/if_inet6 ]] \ || sed -i "s/ListenAddress ::/#ListenAddress ::/g" sshd_config + # Add DSA HostKey to let user remove it with migration 7 + if [[ "$(yunohost settings 'service.ssh._deprecated_dsa_hostkey')" == "True" ]]; then + sed -i '/HostKey \/etc\/ssh\/ssh_host_rsa_key/a HostKey /etc/ssh/ssh_host_dsa_key' sshd_config + fi + install -D -m 644 sshd_config "${pending_dir}/etc/ssh/sshd_config" fi } diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index b79ffd3bf..66aacc5f0 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -9,14 +9,12 @@ ListenAddress 0.0.0.0 Protocol 2 # HostKeys for protocol version 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 + #Privilege Separation is turned on for security UsePrivilegeSeparation yes -# Lifetime and size of ephemeral version 1 server key -KeyRegenerationInterval 3600 -ServerKeyBits 768 - # Logging SyslogFacility AUTH LogLevel INFO diff --git a/src/yunohost/data_migrations/0006_manage_sshd_config.py b/src/yunohost/data_migrations/0006_manage_sshd_config.py index 4af486b6e..13b0bbadf 100644 --- a/src/yunohost/data_migrations/0006_manage_sshd_config.py +++ b/src/yunohost/data_migrations/0006_manage_sshd_config.py @@ -11,6 +11,7 @@ from moulinette.utils.filesystem import mkdir, rm from yunohost.tools import Migration from yunohost.service import service_regen_conf, _get_conf_hashes, \ _calculate_hash, _run_service_command +from yunohost.settings import settings_set logger = getActionLogger('yunohost.migration') @@ -25,6 +26,16 @@ class MyMigration(Migration): def migrate(self): + # Check if deprecated DSA Host Key is in config + dsa_rgx = r'^[ \t]*HostKey[ \t]+/etc/ssh/ssh_host_dsa_key[ \t]*(?:#.*)?$' + dsa = False + for line in open(SSHD_CONF): + if re.match(dsa_rgx, line) is not None: + dsa = True + break + if dsa: + settings_set("service.ssh._deprecated_dsa_hostkey", True) + # Create sshd_config.d dir if not os.path.exists(SSHD_CONF + '.d'): mkdir(SSHD_CONF + '.d', 0755, uid='root', gid='root') diff --git a/src/yunohost/data_migrations/0007_reset_sshd_config.py b/src/yunohost/data_migrations/0007_reset_sshd_config.py index 5a097968d..af8f83ce7 100644 --- a/src/yunohost/data_migrations/0007_reset_sshd_config.py +++ b/src/yunohost/data_migrations/0007_reset_sshd_config.py @@ -7,6 +7,7 @@ from moulinette.utils.log import getActionLogger from yunohost.tools import Migration from yunohost.service import service_regen_conf, _get_conf_hashes, \ _calculate_hash +from yunohost.settings import settings_set, settings_get logger = getActionLogger('yunohost.migration') @@ -15,6 +16,7 @@ class MyMigration(Migration): "Reset SSH conf to the YunoHost one" def migrate(self): + settings_set("service.ssh._deprecated_dsa_hostkey", False) service_regen_conf(names=['ssh'], force=True) def backward(self): @@ -29,7 +31,8 @@ class MyMigration(Migration): if '/etc/ssh/sshd_config' in ynh_hash: ynh_hash = ynh_hash['/etc/ssh/sshd_config'] current_hash = _calculate_hash('/etc/ssh/sshd_config') - if ynh_hash == current_hash: + dsa = settings_get("service.ssh._deprecated_dsa_hostkey") + if ynh_hash == current_hash and not dsa: return "auto" return "manual" @@ -53,7 +56,7 @@ class MyMigration(Migration): root_login = root_login + re.findall(root_rgx, line) - if not dsa and re.match(dsa_rgx, line): + if not dsa and re.match(dsa_rgx, line) is not None: dsa = True if len(ports) == 0: diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py index d2526316e..1539435c6 100644 --- a/src/yunohost/settings.py +++ b/src/yunohost/settings.py @@ -39,6 +39,7 @@ DEFAULTS = OrderedDict([ # -1 disabled, 0 alert if listed, 1 8-letter, 2 normal, 3 strong, 4 strongest ("security.password.admin.strength", {"type": "int", "default": 1}), ("security.password.user.strength", {"type": "int", "default": 1}), + ("service.ssh._deprecated_dsa_hostkey", {"type": "bool", "default": False}), ]) From b5896e88c3db60569233da8628b38dc81e7d8cd4 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Sat, 15 Sep 2018 15:14:51 +0200 Subject: [PATCH 08/32] [enh] Display only used fingerprint in bootprompt --- bin/yunoprompt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/yunoprompt b/bin/yunoprompt index 2705dbcdc..41fb83899 100755 --- a/bin/yunoprompt +++ b/bin/yunoprompt @@ -5,7 +5,7 @@ ip=$(hostname --all-ip-address) # Fetch SSH fingerprints i=0 -for key in /etc/ssh/ssh_host_*_key.pub ; do +for key in /etc/ssh/ssh_host_{rsa,ecdsa,ed25519}_key.pub ; do output=$(ssh-keygen -l -f $key) fingerprint[$i]=" - $(echo $output | cut -d' ' -f2) $(echo $output| cut -d' ' -f4)" i=$(($i + 1)) From b4e72173cd4b076ceb36d1513e0278ffcce0af72 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Sat, 15 Sep 2018 15:24:03 +0200 Subject: [PATCH 09/32] [fix] If some ssh keys are missing --- bin/yunoprompt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/yunoprompt b/bin/yunoprompt index 41fb83899..a86d29558 100755 --- a/bin/yunoprompt +++ b/bin/yunoprompt @@ -5,7 +5,7 @@ ip=$(hostname --all-ip-address) # Fetch SSH fingerprints i=0 -for key in /etc/ssh/ssh_host_{rsa,ecdsa,ed25519}_key.pub ; do +for key in /etc/ssh/ssh_host_{rsa,ecdsa,ed25519}_key.pub 2> /dev/null ; do output=$(ssh-keygen -l -f $key) fingerprint[$i]=" - $(echo $output | cut -d' ' -f2) $(echo $output| cut -d' ' -f4)" i=$(($i + 1)) From 07e5ead0382bb8cb6066801a08451f6bde17f2fd Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Sun, 16 Sep 2018 18:37:43 +0200 Subject: [PATCH 10/32] [fix] Sometimes I need to sleep --- bin/yunoprompt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/yunoprompt b/bin/yunoprompt index a86d29558..bca5c2cb3 100755 --- a/bin/yunoprompt +++ b/bin/yunoprompt @@ -5,7 +5,7 @@ ip=$(hostname --all-ip-address) # Fetch SSH fingerprints i=0 -for key in /etc/ssh/ssh_host_{rsa,ecdsa,ed25519}_key.pub 2> /dev/null ; do +for key in $(ls /etc/ssh/ssh_host_{rsa,ecdsa,ed25519}_key.pub 2> /dev/null) ; do output=$(ssh-keygen -l -f $key) fingerprint[$i]=" - $(echo $output | cut -d' ' -f2) $(echo $output| cut -d' ' -f4)" i=$(($i + 1)) From 31c8b88f4470aca75afd5bb5f9f720da2cddbeae Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 21 Sep 2018 15:57:59 +0000 Subject: [PATCH 11/32] Wordin --- locales/en.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/locales/en.json b/locales/en.json index df69ca1a4..a206b9fb8 100644 --- a/locales/en.json +++ b/locales/en.json @@ -294,14 +294,14 @@ "migration_0005_not_enough_space": "Not enough space is available in {path} to run the migration right now :(.", "migration_0006_disclaimer": "Yunohost now expects admin and root passwords to be synchronized. By running this migration, your root password is going to be replaced by the admin password.", "migration_0006_done": "Your root password have been replaced by your admin password.", - "migration_0006_cancelled": "YunoHost has failed to improve the way your ssh conf is managed.", - "migration_0006_cannot_restart": "SSH can't be restarted after we tried to cancel the migration 6.", - "migration_0007_general_warning": "To ensure a global security of your server, YunoHost recommends to let it manage the SSH configuration of your server. Your current SSH configuration differs from common default configuration. If you let YunoHost reconfigure it, the way to access with SSH to your server could change after this migration:", - "migration_0007_port": "- you will have to connect using port 22 instead of your custom SSH port. Feel free to reconfigure it", - "migration_0007_root": "- you will not be able to connect with root user, instead you will have to use admin user.", - "migration_0007_dsa": "- you might need to invalidate a warning and to recheck fingerprint of your server, because DSA key will be disabled.", - "migration_0007_risk": "If you agree to let YunoHost replace your configuration and change the way to access your server, make the migration else skip it.", - "migration_0007_no_risk": "No major change in the way has been found, but it's difficult to be sure. If you agree to let YunoHost replace your configuration and change the way to access your server, make the migration else skip it.", + "migration_0006_cancelled": "YunoHost has failed to improve the way your SSH conf is managed.", + "migration_0006_cannot_restart": "SSH can't be restarted after trying to cancel migration number 6.", + "migration_0007_general_warning": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH configuration differs from the recommended configuration. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change in the following way:", + "migration_0007_port": " - you will have to connect using port 22 instead of your current custom SSH port. Feel free to reconfigure it ;", + "migration_0007_root": " - you will not be able to connect with root user, instead you will have to use the admin user ;", + "migration_0007_dsa": " - you might need to invalidate a warning and to recheck the fingerprint of your server, because DSA key will be disabled ;", + "migration_0007_risk": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration though it is not recommended.", + "migration_0007_no_risk": "No major risk has been indentified about overriding your SSH configuration - but it's difficult to be sure. If you agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration though it is not recommended.", "migrations_backward": "Migrating backward.", "migrations_bad_value_for_target": "Invalid number for target argument, available migrations numbers are 0 or {}", "migrations_cant_reach_migration_file": "Can't access migrations files at path %s", From 68906a1e982adb9785d521c4d3ff21a47dd99d6a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 25 Oct 2018 22:16:36 +0200 Subject: [PATCH 12/32] Improve comments --- .../0006_manage_sshd_config.py | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/yunohost/data_migrations/0006_manage_sshd_config.py b/src/yunohost/data_migrations/0006_manage_sshd_config.py index 13b0bbadf..68ee020fd 100644 --- a/src/yunohost/data_migrations/0006_manage_sshd_config.py +++ b/src/yunohost/data_migrations/0006_manage_sshd_config.py @@ -20,8 +20,14 @@ SSHD_CONF = '/etc/ssh/sshd_config' class MyMigration(Migration): """ - Ensure SSH conf is managed by YunoHost, reapply initial change and setup an - extension dir + This is an automatic migration, that ensure SSH conf is managed by YunoHost + (even if the "from_script" flag is present) + + If the from_script flag exists, then we keep the current SSH conf such that it + will appear as "manually modified" to the regenconf. + + The admin can then choose in the next migration (manual, thi time) wether or + not to actually use the recommended configuration. """ def migrate(self): @@ -40,25 +46,34 @@ class MyMigration(Migration): if not os.path.exists(SSHD_CONF + '.d'): mkdir(SSHD_CONF + '.d', 0755, uid='root', gid='root') - # Manage SSHd in all case + # Here, we make it so that /etc/ssh/sshd_config is managed + # by the regen conf (in particular in the case where the + # from_script flag is present - in which case it was *not* + # managed by the regenconf) + # But because we can't be sure the user wants to use the + # recommended conf, we backup then restore the /etc/ssh/sshd_config + # right after the regenconf, such that it will appear as + # "manually modified". if os.path.exists('/etc/yunohost/from_script'): rm('/etc/yunohost/from_script') copyfile(SSHD_CONF, '/etc/ssh/sshd_config.bkp') service_regen_conf(names=['ssh'], force=True) copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF) - # If custom conf, add 'Include' instruction + # If we detect the conf as manually modified ynh_hash = _get_conf_hashes('ssh')[SSHD_CONF] current_hash = _calculate_hash(SSHD_CONF) - include_rgx = r'^[ \t]*Include[ \t]+sshd_config\.d/\*[ \t]*(?:#.*)?$' if ynh_hash != current_hash: + # And if there's not already an "Include ssh_config.d/*" directive + include_rgx = r'^[ \t]*Include[ \t]+sshd_config\.d/\*[ \t]*(?:#.*)?$' add_include = False for line in open(SSHD_CONF): if re.match(include_rgx, line) is not None: add_include = True break + # We add an "Include sshd_config.d/*" directive if add_include: with open(SSHD_CONF, "a") as conf: conf.write('Include sshd_config.d/*') @@ -69,8 +84,8 @@ class MyMigration(Migration): raise MoulinetteError(m18n.n("migration_0006_cancel")) def backward(self): - # We don't backward completely but it should be enough + # We don't backward completely but it should be enough copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF) if not _run_service_command('restart', 'ssh'): raise MoulinetteError(m18n.n("migration_0006_cannot_restart")) From 7b6bf6f4b890f8f1b1303f691258ea290f6bc278 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 25 Oct 2018 20:27:24 +0000 Subject: [PATCH 13/32] Missing 'get' --- data/hooks/conf_regen/03-ssh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index 563394d40..2c9261193 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -14,7 +14,7 @@ do_pre_regen() { || sed -i "s/ListenAddress ::/#ListenAddress ::/g" sshd_config # Add DSA HostKey to let user remove it with migration 7 - if [[ "$(yunohost settings 'service.ssh._deprecated_dsa_hostkey')" == "True" ]]; then + if [[ "$(yunohost settings get 'service.ssh._deprecated_dsa_hostkey')" == "True" ]]; then sed -i '/HostKey \/etc\/ssh\/ssh_host_rsa_key/a HostKey /etc/ssh/ssh_host_dsa_key' sshd_config fi From e8393a3d26777bdce09ffb77efb06ba6e8fcb754 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 25 Oct 2018 20:47:47 +0000 Subject: [PATCH 14/32] Improve comments, naming and descriptions --- locales/en.json | 4 ++-- ...006_ssh_conf_managed_by_yunohost_step1.py} | 12 +++++++---- ...007_ssh_conf_managed_by_yunohost_step2.py} | 21 ++++++++++++++++--- 3 files changed, 28 insertions(+), 9 deletions(-) rename src/yunohost/data_migrations/{0006_manage_sshd_config.py => 0006_ssh_conf_managed_by_yunohost_step1.py} (86%) rename src/yunohost/data_migrations/{0007_reset_sshd_config.py => 0007_ssh_conf_managed_by_yunohost_step2.py} (76%) diff --git a/locales/en.json b/locales/en.json index a206b9fb8..803d5c937 100644 --- a/locales/en.json +++ b/locales/en.json @@ -274,8 +274,8 @@ "migration_description_0004_php5_to_php7_pools": "Reconfigure the PHP pools to use PHP 7 instead of 5", "migration_description_0005_postgresql_9p4_to_9p6": "Migrate databases from postgresql 9.4 to 9.6", "migration_description_0006_sync_admin_and_root_passwords": "Synchronize admin and root passwords", - "migration_description_0006_manage_sshd_config": "Manage SSH conf in a better way", - "migration_description_0007_reset_sshd_config": "Reset SSH conf to the YunoHost default conf", + "migration_description_0006_ssh_conf_managed_by_yunohost_step1": "Let the SSH configuration be managed by YunoHost (step 1, automatic)", + "migration_description_0007_ssh_conf_managed_by_yunohost_step2": "Let the SSH configuration be managed by YunoHost (step 2, manual)", "migration_0003_backward_impossible": "The stretch migration cannot be reverted.", "migration_0003_start": "Starting migration to Stretch. The logs will be available in {logfile}.", "migration_0003_patching_sources_list": "Patching the sources.lists ...", diff --git a/src/yunohost/data_migrations/0006_manage_sshd_config.py b/src/yunohost/data_migrations/0006_ssh_conf_managed_by_yunohost_step1.py similarity index 86% rename from src/yunohost/data_migrations/0006_manage_sshd_config.py rename to src/yunohost/data_migrations/0006_ssh_conf_managed_by_yunohost_step1.py index 68ee020fd..c3a503492 100644 --- a/src/yunohost/data_migrations/0006_manage_sshd_config.py +++ b/src/yunohost/data_migrations/0006_ssh_conf_managed_by_yunohost_step1.py @@ -20,14 +20,18 @@ SSHD_CONF = '/etc/ssh/sshd_config' class MyMigration(Migration): """ - This is an automatic migration, that ensure SSH conf is managed by YunoHost - (even if the "from_script" flag is present) + This is the first step of a couple of migrations that ensure SSH conf is + managed by YunoHost (even if the "from_script" flag is present, which was + previously preventing it from being managed by YunoHost) + The goal of this first (automatic) migration is to make sure that the + sshd_config is managed by the regen-conf mechanism. + If the from_script flag exists, then we keep the current SSH conf such that it will appear as "manually modified" to the regenconf. - The admin can then choose in the next migration (manual, thi time) wether or - not to actually use the recommended configuration. + In step 2 (manual), the admin will be able to choose wether or not to actually + use the recommended configuration, with an appropriate disclaimer. """ def migrate(self): diff --git a/src/yunohost/data_migrations/0007_reset_sshd_config.py b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py similarity index 76% rename from src/yunohost/data_migrations/0007_reset_sshd_config.py rename to src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py index af8f83ce7..10e319b2d 100644 --- a/src/yunohost/data_migrations/0007_reset_sshd_config.py +++ b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py @@ -13,7 +13,18 @@ logger = getActionLogger('yunohost.migration') class MyMigration(Migration): - "Reset SSH conf to the YunoHost one" + """ + In this second step, the admin is asked if it's okay to use + the recommended SSH configuration - which also implies + disabling deprecated DSA key. + + This has important implications in the way the user may connect + to its server (key change, and a spooky warning might be given + by SSH later) + + A disclaimer explaining the various things to be aware of is + shown - and the user may also choose to skip this migration. + """ def migrate(self): settings_set("service.ssh._deprecated_dsa_hostkey", False) @@ -26,7 +37,10 @@ class MyMigration(Migration): @property def mode(self): - # Avoid having a super long disclaimer + # If the conf is already up to date + # and no DSA key is used, then we're good to go + # and the migration can be done automatically + # (basically nothing shall change) ynh_hash = _get_conf_hashes('ssh') if '/etc/ssh/sshd_config' in ynh_hash: ynh_hash = ynh_hash['/etc/ssh/sshd_config'] @@ -43,7 +57,8 @@ class MyMigration(Migration): if self.mode == "auto": return None - # Detect major risk to migrate to the new configuration + # Detect key things to be aware of before enabling the + # recommended configuration dsa = False ports = [] root_login = [] From 6145199564728e6e6a53b73a3131caf5377599d9 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 25 Oct 2018 21:16:51 +0000 Subject: [PATCH 15/32] Improve semantic / simplify a few things --- locales/en.json | 10 ++--- ...0007_ssh_conf_managed_by_yunohost_step2.py | 37 ++++++++----------- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/locales/en.json b/locales/en.json index 803d5c937..54792a827 100644 --- a/locales/en.json +++ b/locales/en.json @@ -296,12 +296,12 @@ "migration_0006_done": "Your root password have been replaced by your admin password.", "migration_0006_cancelled": "YunoHost has failed to improve the way your SSH conf is managed.", "migration_0006_cannot_restart": "SSH can't be restarted after trying to cancel migration number 6.", - "migration_0007_general_warning": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH configuration differs from the recommended configuration. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change in the following way:", + "migration_0007_general_disclaimer": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH configuration differs from the recommended configuration. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change in the following way:", "migration_0007_port": " - you will have to connect using port 22 instead of your current custom SSH port. Feel free to reconfigure it ;", - "migration_0007_root": " - you will not be able to connect with root user, instead you will have to use the admin user ;", - "migration_0007_dsa": " - you might need to invalidate a warning and to recheck the fingerprint of your server, because DSA key will be disabled ;", - "migration_0007_risk": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration though it is not recommended.", - "migration_0007_no_risk": "No major risk has been indentified about overriding your SSH configuration - but it's difficult to be sure. If you agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration though it is not recommended.", + "migration_0007_root": " - you will not be able to connect as root through SSH. Instead you should use the admin user ;", + "migration_0007_dsa": " - the DSA key will be disabled. Hence, you might need to invalidate a warning from your SSH client, and recheck the fingerprint of your server ;", + "migration_0007_warning": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.", + "migration_0007_no_warning": "No major risk has been indentified about overriding your SSH configuration - but we can't be absolutely sure ;) ! If you agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.", "migrations_backward": "Migrating backward.", "migrations_bad_value_for_target": "Invalid number for target argument, available migrations numbers are 0 or {}", "migrations_cant_reach_migration_file": "Can't access migrations files at path %s", diff --git a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py index 10e319b2d..c6355ac61 100644 --- a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py +++ b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py @@ -11,6 +11,7 @@ from yunohost.settings import settings_set, settings_get logger = getActionLogger('yunohost.migration') +SSHD_CONF = '/etc/ssh/sshd_config' class MyMigration(Migration): """ @@ -41,10 +42,8 @@ class MyMigration(Migration): # and no DSA key is used, then we're good to go # and the migration can be done automatically # (basically nothing shall change) - ynh_hash = _get_conf_hashes('ssh') - if '/etc/ssh/sshd_config' in ynh_hash: - ynh_hash = ynh_hash['/etc/ssh/sshd_config'] - current_hash = _calculate_hash('/etc/ssh/sshd_config') + ynh_hash = _get_conf_hashes('ssh').get(SSHD_CONF, None) + current_hash = _calculate_hash(SSHD_CONF) dsa = settings_get("service.ssh._deprecated_dsa_hostkey") if ynh_hash == current_hash and not dsa: return "auto" @@ -59,43 +58,39 @@ class MyMigration(Migration): # Detect key things to be aware of before enabling the # recommended configuration - dsa = False + dsa_key_enabled = False ports = [] root_login = [] port_rgx = r'^[ \t]*Port[ \t]+(\d+)[ \t]*(?:#.*)?$' root_rgx = r'^[ \t]*PermitRootLogin[ \t]([^# \t]*)[ \t]*(?:#.*)?$' dsa_rgx = r'^[ \t]*HostKey[ \t]+/etc/ssh/ssh_host_dsa_key[ \t]*(?:#.*)?$' - for line in open('/etc/ssh/sshd_config'): + for line in open(SSHD_CONF): ports = ports + re.findall(port_rgx, line) root_login = root_login + re.findall(root_rgx, line) - if not dsa and re.match(dsa_rgx, line) is not None: - dsa = True + if not dsa_key_enabled and re.match(dsa_rgx, line) is not None: + dsa_key_enabled = True - if len(ports) == 0: - ports = ['22'] - - port = ports != ['22'] - - root_user = root_login and root_login[-1] != 'no' + custom_port = ports != ['22'] and ports != [] + root_login_enabled = root_login and root_login[-1] != 'no' # Build message - message = m18n.n("migration_0007_general_warning") + message = m18n.n("migration_0007_general_disclaimer") - if port: + if custom_port: message += "\n\n" + m18n.n("migration_0007_port") - if root_user: + if root_login_enabled: message += "\n\n" + m18n.n("migration_0007_root") - if dsa: + if dsa_key_enabled: message += "\n\n" + m18n.n("migration_0007_dsa") - if port or root_user or dsa: - message += "\n\n" + m18n.n("migration_0007_risk") + if custom_port or root_login_enabled or dsa_key_enabled: + message += "\n\n" + m18n.n("migration_0007_warning") else: - message += "\n\n" + m18n.n("migration_0007_no_risk") + message += "\n\n" + m18n.n("migration_0007_no_warning") return message From 2aa0d2b55bb35c92cce3ba49d0cc217f8e765236 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 25 Oct 2018 23:30:34 +0200 Subject: [PATCH 16/32] Spooky warning is spooky --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 54792a827..53250b0b1 100644 --- a/locales/en.json +++ b/locales/en.json @@ -299,7 +299,7 @@ "migration_0007_general_disclaimer": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH configuration differs from the recommended configuration. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change in the following way:", "migration_0007_port": " - you will have to connect using port 22 instead of your current custom SSH port. Feel free to reconfigure it ;", "migration_0007_root": " - you will not be able to connect as root through SSH. Instead you should use the admin user ;", - "migration_0007_dsa": " - the DSA key will be disabled. Hence, you might need to invalidate a warning from your SSH client, and recheck the fingerprint of your server ;", + "migration_0007_dsa": " - the DSA key will be disabled. Hence, you might need to invalidate a spooky warning from your SSH client, and recheck the fingerprint of your server ;", "migration_0007_warning": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.", "migration_0007_no_warning": "No major risk has been indentified about overriding your SSH configuration - but we can't be absolutely sure ;) ! If you agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.", "migrations_backward": "Migrating backward.", From e596758184204d095da220f5ad20147e6a06160d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 25 Oct 2018 23:34:39 +0200 Subject: [PATCH 17/32] Add a comment about /etc/ssh/sshd_config.to_restor --- src/yunohost/tools.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index a0549321a..678049900 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -442,6 +442,11 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False, service_regen_conf(force=True) # Restore specific ssh conf + # c.f. the install script and in particular + # https://github.com/YunoHost/install_script/pull/50 + # The user can now choose during the install to keep + # the initial, existing sshd configuration + # instead of YunoHost's recommended conf bkp_sshd_conf = '/etc/ssh/sshd_config.to_restore' if os.path.exists(bkp_sshd_conf): os.rename(bkp_sshd_conf, '/etc/ssh/sshd_config') From 325678f541d40d833675823aa7de27bcad338bb9 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 27 Nov 2018 23:55:15 +0100 Subject: [PATCH 18/32] More explicit name for setting --- data/hooks/conf_regen/03-ssh | 4 ++-- .../0006_ssh_conf_managed_by_yunohost_step1.py | 10 +++++----- .../0007_ssh_conf_managed_by_yunohost_step2.py | 4 ++-- src/yunohost/settings.py | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index 2c9261193..37b92e3fe 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -13,8 +13,8 @@ do_pre_regen() { [[ -f /proc/net/if_inet6 ]] \ || sed -i "s/ListenAddress ::/#ListenAddress ::/g" sshd_config - # Add DSA HostKey to let user remove it with migration 7 - if [[ "$(yunohost settings get 'service.ssh._deprecated_dsa_hostkey')" == "True" ]]; then + # Support legacy setting (this setting might be disabled by a user during a migration) + if [[ "$(yunohost settings get 'service.ssh.allow_deprecated_dsa_hostkey')" == "True" ]]; then sed -i '/HostKey \/etc\/ssh\/ssh_host_rsa_key/a HostKey /etc/ssh/ssh_host_dsa_key' sshd_config fi diff --git a/src/yunohost/data_migrations/0006_ssh_conf_managed_by_yunohost_step1.py b/src/yunohost/data_migrations/0006_ssh_conf_managed_by_yunohost_step1.py index c3a503492..751f56fac 100644 --- a/src/yunohost/data_migrations/0006_ssh_conf_managed_by_yunohost_step1.py +++ b/src/yunohost/data_migrations/0006_ssh_conf_managed_by_yunohost_step1.py @@ -23,13 +23,13 @@ class MyMigration(Migration): This is the first step of a couple of migrations that ensure SSH conf is managed by YunoHost (even if the "from_script" flag is present, which was previously preventing it from being managed by YunoHost) - + The goal of this first (automatic) migration is to make sure that the sshd_config is managed by the regen-conf mechanism. If the from_script flag exists, then we keep the current SSH conf such that it will appear as "manually modified" to the regenconf. - + In step 2 (manual), the admin will be able to choose wether or not to actually use the recommended configuration, with an appropriate disclaimer. """ @@ -44,15 +44,15 @@ class MyMigration(Migration): dsa = True break if dsa: - settings_set("service.ssh._deprecated_dsa_hostkey", True) + settings_set("service.ssh.allow_deprecated_dsa_hostkey", True) # Create sshd_config.d dir if not os.path.exists(SSHD_CONF + '.d'): mkdir(SSHD_CONF + '.d', 0755, uid='root', gid='root') # Here, we make it so that /etc/ssh/sshd_config is managed - # by the regen conf (in particular in the case where the - # from_script flag is present - in which case it was *not* + # by the regen conf (in particular in the case where the + # from_script flag is present - in which case it was *not* # managed by the regenconf) # But because we can't be sure the user wants to use the # recommended conf, we backup then restore the /etc/ssh/sshd_config diff --git a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py index c6355ac61..20267d9e8 100644 --- a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py +++ b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py @@ -28,7 +28,7 @@ class MyMigration(Migration): """ def migrate(self): - settings_set("service.ssh._deprecated_dsa_hostkey", False) + settings_set("service.ssh.allow_deprecated_dsa_hostkey", False) service_regen_conf(names=['ssh'], force=True) def backward(self): @@ -44,7 +44,7 @@ class MyMigration(Migration): # (basically nothing shall change) ynh_hash = _get_conf_hashes('ssh').get(SSHD_CONF, None) current_hash = _calculate_hash(SSHD_CONF) - dsa = settings_get("service.ssh._deprecated_dsa_hostkey") + dsa = settings_get("service.ssh.allow_deprecated_dsa_hostkey") if ynh_hash == current_hash and not dsa: return "auto" diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py index 1539435c6..391893b4e 100644 --- a/src/yunohost/settings.py +++ b/src/yunohost/settings.py @@ -39,7 +39,7 @@ DEFAULTS = OrderedDict([ # -1 disabled, 0 alert if listed, 1 8-letter, 2 normal, 3 strong, 4 strongest ("security.password.admin.strength", {"type": "int", "default": 1}), ("security.password.user.strength", {"type": "int", "default": 1}), - ("service.ssh._deprecated_dsa_hostkey", {"type": "bool", "default": False}), + ("service.ssh.allow_deprecated_dsa_hostkey", {"type": "bool", "default": False}), ]) From 23893c43b3431b0fc5094f7b1a2521187243810a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 28 Nov 2018 00:08:53 +0100 Subject: [PATCH 19/32] Increment migrations number --- locales/en.json | 20 +++++++++---------- ...007_ssh_conf_managed_by_yunohost_step1.py} | 4 ++-- ...008_ssh_conf_managed_by_yunohost_step2.py} | 14 ++++++------- 3 files changed, 19 insertions(+), 19 deletions(-) rename src/yunohost/data_migrations/{0006_ssh_conf_managed_by_yunohost_step1.py => 0007_ssh_conf_managed_by_yunohost_step1.py} (96%) rename src/yunohost/data_migrations/{0007_ssh_conf_managed_by_yunohost_step2.py => 0008_ssh_conf_managed_by_yunohost_step2.py} (86%) diff --git a/locales/en.json b/locales/en.json index 53250b0b1..e657d38d1 100644 --- a/locales/en.json +++ b/locales/en.json @@ -274,8 +274,8 @@ "migration_description_0004_php5_to_php7_pools": "Reconfigure the PHP pools to use PHP 7 instead of 5", "migration_description_0005_postgresql_9p4_to_9p6": "Migrate databases from postgresql 9.4 to 9.6", "migration_description_0006_sync_admin_and_root_passwords": "Synchronize admin and root passwords", - "migration_description_0006_ssh_conf_managed_by_yunohost_step1": "Let the SSH configuration be managed by YunoHost (step 1, automatic)", - "migration_description_0007_ssh_conf_managed_by_yunohost_step2": "Let the SSH configuration be managed by YunoHost (step 2, manual)", + "migration_description_0007_ssh_conf_managed_by_yunohost_step1": "Let the SSH configuration be managed by YunoHost (step 1, automatic)", + "migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Let the SSH configuration be managed by YunoHost (step 2, manual)", "migration_0003_backward_impossible": "The stretch migration cannot be reverted.", "migration_0003_start": "Starting migration to Stretch. The logs will be available in {logfile}.", "migration_0003_patching_sources_list": "Patching the sources.lists ...", @@ -294,14 +294,14 @@ "migration_0005_not_enough_space": "Not enough space is available in {path} to run the migration right now :(.", "migration_0006_disclaimer": "Yunohost now expects admin and root passwords to be synchronized. By running this migration, your root password is going to be replaced by the admin password.", "migration_0006_done": "Your root password have been replaced by your admin password.", - "migration_0006_cancelled": "YunoHost has failed to improve the way your SSH conf is managed.", - "migration_0006_cannot_restart": "SSH can't be restarted after trying to cancel migration number 6.", - "migration_0007_general_disclaimer": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH configuration differs from the recommended configuration. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change in the following way:", - "migration_0007_port": " - you will have to connect using port 22 instead of your current custom SSH port. Feel free to reconfigure it ;", - "migration_0007_root": " - you will not be able to connect as root through SSH. Instead you should use the admin user ;", - "migration_0007_dsa": " - the DSA key will be disabled. Hence, you might need to invalidate a spooky warning from your SSH client, and recheck the fingerprint of your server ;", - "migration_0007_warning": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.", - "migration_0007_no_warning": "No major risk has been indentified about overriding your SSH configuration - but we can't be absolutely sure ;) ! If you agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.", + "migration_0007_cancelled": "YunoHost has failed to improve the way your SSH conf is managed.", + "migration_0007_cannot_restart": "SSH can't be restarted after trying to cancel migration number 6.", + "migration_0008_general_disclaimer": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH configuration differs from the recommended configuration. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change in the following way:", + "migration_0008_port": " - you will have to connect using port 22 instead of your current custom SSH port. Feel free to reconfigure it ;", + "migration_0008_root": " - you will not be able to connect as root through SSH. Instead you should use the admin user ;", + "migration_0008_dsa": " - the DSA key will be disabled. Hence, you might need to invalidate a spooky warning from your SSH client, and recheck the fingerprint of your server ;", + "migration_0008_warning": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.", + "migration_0008_no_warning": "No major risk has been indentified about overriding your SSH configuration - but we can't be absolutely sure ;) ! If you agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.", "migrations_backward": "Migrating backward.", "migrations_bad_value_for_target": "Invalid number for target argument, available migrations numbers are 0 or {}", "migrations_cant_reach_migration_file": "Can't access migrations files at path %s", diff --git a/src/yunohost/data_migrations/0006_ssh_conf_managed_by_yunohost_step1.py b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py similarity index 96% rename from src/yunohost/data_migrations/0006_ssh_conf_managed_by_yunohost_step1.py rename to src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py index 751f56fac..82d1fc634 100644 --- a/src/yunohost/data_migrations/0006_ssh_conf_managed_by_yunohost_step1.py +++ b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py @@ -85,11 +85,11 @@ class MyMigration(Migration): # Restart ssh and backward if it fail if not _run_service_command('restart', 'ssh'): self.backward() - raise MoulinetteError(m18n.n("migration_0006_cancel")) + raise MoulinetteError(m18n.n("migration_0007_cancel")) def backward(self): # We don't backward completely but it should be enough copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF) if not _run_service_command('restart', 'ssh'): - raise MoulinetteError(m18n.n("migration_0006_cannot_restart")) + raise MoulinetteError(m18n.n("migration_0007_cannot_restart")) diff --git a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py b/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py similarity index 86% rename from src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py rename to src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py index 20267d9e8..c53154192 100644 --- a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step2.py +++ b/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py @@ -33,7 +33,7 @@ class MyMigration(Migration): def backward(self): - raise MoulinetteError(m18n.n("migration_0007_backward_impossible")) + raise MoulinetteError(m18n.n("migration_0008_backward_impossible")) @property def mode(self): @@ -77,20 +77,20 @@ class MyMigration(Migration): root_login_enabled = root_login and root_login[-1] != 'no' # Build message - message = m18n.n("migration_0007_general_disclaimer") + message = m18n.n("migration_0008_general_disclaimer") if custom_port: - message += "\n\n" + m18n.n("migration_0007_port") + message += "\n\n" + m18n.n("migration_0008_port") if root_login_enabled: - message += "\n\n" + m18n.n("migration_0007_root") + message += "\n\n" + m18n.n("migration_0008_root") if dsa_key_enabled: - message += "\n\n" + m18n.n("migration_0007_dsa") + message += "\n\n" + m18n.n("migration_0008_dsa") if custom_port or root_login_enabled or dsa_key_enabled: - message += "\n\n" + m18n.n("migration_0007_warning") + message += "\n\n" + m18n.n("migration_0008_warning") else: - message += "\n\n" + m18n.n("migration_0007_no_warning") + message += "\n\n" + m18n.n("migration_0008_no_warning") return message From fad4ff090a9f58ed2864097c1c49f192e67c9ba8 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 28 Nov 2018 00:26:25 +0100 Subject: [PATCH 20/32] Use templating for more robustness about which SSH keys are enabled --- data/hooks/conf_regen/03-ssh | 8 ++++++-- data/templates/ssh/sshd_config | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index 37b92e3fe..74064a631 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -2,6 +2,8 @@ set -e +. /usr/share/yunohost/helpers.d/utils + do_pre_regen() { pending_dir=$1 @@ -14,11 +16,13 @@ do_pre_regen() { || sed -i "s/ListenAddress ::/#ListenAddress ::/g" sshd_config # Support legacy setting (this setting might be disabled by a user during a migration) + ssh_keys=$(ls /etc/ssh/ssh_host_{rsa,ecdsa,ed25519}_key 2>/dev/null) if [[ "$(yunohost settings get 'service.ssh.allow_deprecated_dsa_hostkey')" == "True" ]]; then - sed -i '/HostKey \/etc\/ssh\/ssh_host_rsa_key/a HostKey /etc/ssh/ssh_host_dsa_key' sshd_config + ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null)" fi - install -D -m 644 sshd_config "${pending_dir}/etc/ssh/sshd_config" + export $ssh_keys + ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config" fi } diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index 66aacc5f0..36bd9167d 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -8,9 +8,9 @@ ListenAddress :: ListenAddress 0.0.0.0 Protocol 2 # HostKeys for protocol version 2 -HostKey /etc/ssh/ssh_host_rsa_key -HostKey /etc/ssh/ssh_host_ecdsa_key -HostKey /etc/ssh/ssh_host_ed25519_key +{% for key in ssh_keys %} +HostKey {{ key }} +{% endfor %} #Privilege Separation is turned on for security UsePrivilegeSeparation yes From 3d81f032e9aba1d4b2155c8b74300b9bf0d307c0 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 28 Nov 2018 17:50:20 +0000 Subject: [PATCH 21/32] Fixes following tests (some sshd_config options do not exists or are deprecated) --- data/helpers.d/utils | 1 + data/hooks/conf_regen/03-ssh | 2 +- data/templates/ssh/sshd_config | 21 +++++++------------ ...0007_ssh_conf_managed_by_yunohost_step1.py | 2 +- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/data/helpers.d/utils b/data/helpers.d/utils index eef9f2a8e..b280c3b21 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -272,6 +272,7 @@ ynh_local_curl () { ynh_render_template() { local template_path=$1 local output_path=$2 + mkdir -p "$(dirname $output_path)" # Taken from https://stackoverflow.com/a/35009576 python2.7 -c 'import os, sys, jinja2; sys.stdout.write( jinja2.Template(sys.stdin.read() diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index 74064a631..a9ed0ee48 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -21,7 +21,7 @@ do_pre_regen() { ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null)" fi - export $ssh_keys + export ssh_keys ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config" fi } diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index 36bd9167d..ed9a3136e 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -1,16 +1,14 @@ -# Package generated configuration file -# See the sshd_config(5) manpage for details +# This configuration has been automatically generated +# by YunoHost -# What ports, IPs and protocols we listen for +Protocol 2 Port 22 -# Use these options to restrict which interfaces/protocols sshd will bind to + ListenAddress :: ListenAddress 0.0.0.0 -Protocol 2 -# HostKeys for protocol version 2 -{% for key in ssh_keys %} -HostKey {{ key }} -{% endfor %} + +{% for key in ssh_keys.split() %} +HostKey {{ key }}{% endfor %} #Privilege Separation is turned on for security UsePrivilegeSeparation yes @@ -24,14 +22,11 @@ LoginGraceTime 120 PermitRootLogin no StrictModes yes -RSAAuthentication yes PubkeyAuthentication yes #AuthorizedKeysFile %h/.ssh/authorized_keys # Don't read the user's ~/.rhosts and ~/.shosts files IgnoreRhosts yes -# For this to work you will also need host keys in /etc/ssh_known_hosts -RhostsRSAAuthentication no # similar for protocol version 2 HostbasedAuthentication no # Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication @@ -92,5 +87,3 @@ Match User sftpusers AllowTcpForwarding no GatewayPorts no X11Forwarding no - -Include sshd_config.d/* diff --git a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py index 82d1fc634..95e67894c 100644 --- a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py +++ b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py @@ -65,7 +65,7 @@ class MyMigration(Migration): copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF) # If we detect the conf as manually modified - ynh_hash = _get_conf_hashes('ssh')[SSHD_CONF] + ynh_hash = _get_conf_hashes('ssh').get(SSHD_CONF, None) current_hash = _calculate_hash(SSHD_CONF) if ynh_hash != current_hash: From f295c83fd3cd50f8c96e156e4a9267fc1f21be45 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 28 Nov 2018 18:59:34 +0000 Subject: [PATCH 22/32] Order of keys matter, ed25519 is recommended --- bin/yunoprompt | 2 +- data/hooks/conf_regen/03-ssh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/yunoprompt b/bin/yunoprompt index bca5c2cb3..2b2a6cfb2 100755 --- a/bin/yunoprompt +++ b/bin/yunoprompt @@ -5,7 +5,7 @@ ip=$(hostname --all-ip-address) # Fetch SSH fingerprints i=0 -for key in $(ls /etc/ssh/ssh_host_{rsa,ecdsa,ed25519}_key.pub 2> /dev/null) ; do +for key in $(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key.pub 2> /dev/null) ; do output=$(ssh-keygen -l -f $key) fingerprint[$i]=" - $(echo $output | cut -d' ' -f2) $(echo $output| cut -d' ' -f4)" i=$(($i + 1)) diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index a9ed0ee48..e60b3022f 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -16,7 +16,7 @@ do_pre_regen() { || sed -i "s/ListenAddress ::/#ListenAddress ::/g" sshd_config # Support legacy setting (this setting might be disabled by a user during a migration) - ssh_keys=$(ls /etc/ssh/ssh_host_{rsa,ecdsa,ed25519}_key 2>/dev/null) + ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2>/dev/null) if [[ "$(yunohost settings get 'service.ssh.allow_deprecated_dsa_hostkey')" == "True" ]]; then ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null)" fi From 25efab7f2a91243ef55438fc76cd2deb13fec3dd Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 28 Nov 2018 19:45:19 +0000 Subject: [PATCH 23/32] We can't have include blocks in sshd_config :| --- .../0007_ssh_conf_managed_by_yunohost_step1.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py index 95e67894c..73cb162b6 100644 --- a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py +++ b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py @@ -64,24 +64,6 @@ class MyMigration(Migration): service_regen_conf(names=['ssh'], force=True) copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF) - # If we detect the conf as manually modified - ynh_hash = _get_conf_hashes('ssh').get(SSHD_CONF, None) - current_hash = _calculate_hash(SSHD_CONF) - if ynh_hash != current_hash: - - # And if there's not already an "Include ssh_config.d/*" directive - include_rgx = r'^[ \t]*Include[ \t]+sshd_config\.d/\*[ \t]*(?:#.*)?$' - add_include = False - for line in open(SSHD_CONF): - if re.match(include_rgx, line) is not None: - add_include = True - break - - # We add an "Include sshd_config.d/*" directive - if add_include: - with open(SSHD_CONF, "a") as conf: - conf.write('Include sshd_config.d/*') - # Restart ssh and backward if it fail if not _run_service_command('restart', 'ssh'): self.backward() From 6a812190c5ffaae014229088b85217a064a379fa Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 28 Nov 2018 20:27:42 +0000 Subject: [PATCH 24/32] Enforce permissions for /etc/ssh/sshd_config --- data/hooks/conf_regen/03-ssh | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index e60b3022f..dac21b19b 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -15,8 +15,9 @@ do_pre_regen() { [[ -f /proc/net/if_inet6 ]] \ || sed -i "s/ListenAddress ::/#ListenAddress ::/g" sshd_config - # Support legacy setting (this setting might be disabled by a user during a migration) ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2>/dev/null) + + # Support legacy setting (this setting might be disabled by a user during a migration) if [[ "$(yunohost settings get 'service.ssh.allow_deprecated_dsa_hostkey')" == "True" ]]; then ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null)" fi @@ -27,12 +28,15 @@ do_pre_regen() { } do_post_regen() { - regen_conf_files=$1 - - if [[ ! -f /etc/yunohost/from_script ]]; then - [[ -z "$regen_conf_files" ]] \ - || sudo service ssh restart - fi + regen_conf_files=$1 + if [[ ! -f /etc/yunohost/from_script ]]; then + if [[ -n "$regen_conf_files" ]]; + then + sudo service ssh restart + chown root:root "/etc/ssh/sshd_config" + chmod 644 "/etc/ssh/sshd_config" + fi + fi } FORCE=${2:-0} From 4db65682eb468edc81ae043f2da03909437f557d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 28 Nov 2018 20:42:39 +0000 Subject: [PATCH 25/32] Fix IPv6 handling in ssh regen conf script --- data/hooks/conf_regen/03-ssh | 5 +++-- data/templates/ssh/sshd_config | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index dac21b19b..271ad9bb8 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -11,9 +11,9 @@ do_pre_regen() { # Don't overwrite configuration if from_script if [[ ! -f /etc/yunohost/from_script ]]; then + # do not listen to IPv6 if unavailable - [[ -f /proc/net/if_inet6 ]] \ - || sed -i "s/ListenAddress ::/#ListenAddress ::/g" sshd_config + [[ -f /proc/net/if_inet6 ]] && ipv6_enabled=true || ipv6_enabled=false ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2>/dev/null) @@ -23,6 +23,7 @@ do_pre_regen() { fi export ssh_keys + export ipv6_enabled ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config" fi } diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index ed9a3136e..9d6c078b9 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -4,7 +4,7 @@ Protocol 2 Port 22 -ListenAddress :: +{% if ipv6_enabled == "true" %}ListenAddress ::{% endif %} ListenAddress 0.0.0.0 {% for key in ssh_keys.split() %} From 0576b17442282867a6b011a41cdaf7bcfafaaad3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 28 Nov 2018 21:03:28 +0000 Subject: [PATCH 26/32] Simplify code / indentation levels --- data/hooks/conf_regen/03-ssh | 53 ++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index 271ad9bb8..76fab7cd4 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -5,39 +5,44 @@ set -e . /usr/share/yunohost/helpers.d/utils do_pre_regen() { - pending_dir=$1 + pending_dir=$1 - cd /usr/share/yunohost/templates/ssh + # If the (legacy) 'from_script' flag is here, + # we won't touch anything in the ssh config. + [[ ! -f /etc/yunohost/from_script ]] || return - # Don't overwrite configuration if from_script - if [[ ! -f /etc/yunohost/from_script ]]; then + cd /usr/share/yunohost/templates/ssh - # do not listen to IPv6 if unavailable - [[ -f /proc/net/if_inet6 ]] && ipv6_enabled=true || ipv6_enabled=false + # do not listen to IPv6 if unavailable + [[ -f /proc/net/if_inet6 ]] && ipv6_enabled=true || ipv6_enabled=false - ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2>/dev/null) + ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2>/dev/null) - # Support legacy setting (this setting might be disabled by a user during a migration) - if [[ "$(yunohost settings get 'service.ssh.allow_deprecated_dsa_hostkey')" == "True" ]]; then - ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null)" - fi + # Support legacy setting (this setting might be disabled by a user during a migration) + if [[ "$(yunohost settings get 'service.ssh.allow_deprecated_dsa_hostkey')" == "True" ]]; then + ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null)" + fi - export ssh_keys - export ipv6_enabled - ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config" - fi + export ssh_keys + export ipv6_enabled + ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config" } do_post_regen() { - regen_conf_files=$1 - if [[ ! -f /etc/yunohost/from_script ]]; then - if [[ -n "$regen_conf_files" ]]; - then - sudo service ssh restart - chown root:root "/etc/ssh/sshd_config" - chmod 644 "/etc/ssh/sshd_config" - fi - fi + regen_conf_files=$1 + + # If the (legacy) 'from_script' flag is here, + # we won't touch anything in the ssh config. + [[ ! -f /etc/yunohost/from_script ]] || return + + # If no file changed, there's nothing to do + [[ -n "$regen_conf_files" ]] || return + + # Enforce permissions for /etc/ssh/sshd_config + chown root:root "/etc/ssh/sshd_config" + chmod 644 "/etc/ssh/sshd_config" + + systemctl restart ssh } FORCE=${2:-0} From 90e542a9315115f1f7489bbf704433e722ee18dc Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 28 Nov 2018 21:30:26 +0000 Subject: [PATCH 27/32] Allow root login on local networks --- data/templates/ssh/sshd_config | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index 9d6c078b9..cfc101ffa 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -87,3 +87,11 @@ Match User sftpusers AllowTcpForwarding no GatewayPorts no X11Forwarding no + +# root login is allowed on local networks +# It's meant to be a backup solution in case LDAP is down and +# user admin can't be used... +# If the server is a VPS, it's expected that the owner of the +# server has access to a web console through which to log in. +Match Address 192.168.0.0/16,10.0.0.0/16 + PermitRootLogin yes From 847d18293a6c375d062f342425a34d05c62bbd22 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Fri, 30 Nov 2018 15:47:42 +0100 Subject: [PATCH 28/32] [enh] Add other private ip network and link local --- data/templates/ssh/sshd_config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index cfc101ffa..360920751 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -93,5 +93,5 @@ Match User sftpusers # user admin can't be used... # If the server is a VPS, it's expected that the owner of the # server has access to a web console through which to log in. -Match Address 192.168.0.0/16,10.0.0.0/16 +Match Address 192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,169.254.0.0/16,fe80::/10,fd00::/8 PermitRootLogin yes From 447372d07c88172309e122116b5f4086fba82a3e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 3 Dec 2018 17:03:22 +0100 Subject: [PATCH 29/32] [enh] Clean + harden sshd config using Mozilla recommendation (#590) * Clean sshd_config + harden using Mozilla recommendation * Order of keys matter, ed25519 is recommended --- data/hooks/conf_regen/03-ssh | 8 ++- data/templates/ssh/sshd_config | 101 +++++++++++++-------------------- 2 files changed, 48 insertions(+), 61 deletions(-) diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index 76fab7cd4..dafa4327e 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -12,10 +12,16 @@ do_pre_regen() { [[ ! -f /etc/yunohost/from_script ]] || return cd /usr/share/yunohost/templates/ssh - + # do not listen to IPv6 if unavailable [[ -f /proc/net/if_inet6 ]] && ipv6_enabled=true || ipv6_enabled=false + # Support legacy setting (this setting might be disabled by a user during a migration) + ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2>/dev/null) + if [[ "$(yunohost settings get 'service.ssh.allow_deprecated_dsa_hostkey')" == "True" ]]; then + ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null)" + fi + ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2>/dev/null) # Support legacy setting (this setting might be disabled by a user during a migration) diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index 360920751..ed870e5dc 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -10,77 +10,58 @@ ListenAddress 0.0.0.0 {% for key in ssh_keys.split() %} HostKey {{ key }}{% endfor %} -#Privilege Separation is turned on for security -UsePrivilegeSeparation yes +# ############################################## +# Stuff recommended by Mozilla "modern" compat' +# https://infosec.mozilla.org/guidelines/openssh +# ############################################## -# Logging +# Keys, ciphers and MACS +KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 +Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr +MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com + +# Use kernel sandbox mechanisms where possible in unprivileged processes +UsePrivilegeSeparation sandbox + +# LogLevel VERBOSE logs user's key fingerprint on login. +# Needed to have a clear audit track of which key was using to log in. SyslogFacility AUTH -LogLevel INFO +LogLevel VERBOSE + +# ####################### +# Authentication settings +# ####################### + +# Comment from Mozilla about the motivation behind disabling root login +# +# Root login is not allowed for auditing reasons. This is because it's difficult to track which process belongs to which root user: +# +# On Linux, user sessions are tracking using a kernel-side session id, however, this session id is not recorded by OpenSSH. +# Additionally, only tools such as systemd and auditd record the process session id. +# On other OSes, the user session id is not necessarily recorded at all kernel-side. +# Using regular users in combination with /bin/su or /usr/bin/sudo ensure a clear audit track. -# Authentication: LoginGraceTime 120 PermitRootLogin no StrictModes yes - PubkeyAuthentication yes -#AuthorizedKeysFile %h/.ssh/authorized_keys - -# Don't read the user's ~/.rhosts and ~/.shosts files -IgnoreRhosts yes -# similar for protocol version 2 -HostbasedAuthentication no -# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication -#IgnoreUserKnownHosts yes - -# To enable empty passwords, change to yes (NOT RECOMMENDED) PermitEmptyPasswords no - -# Change to yes to enable challenge-response passwords (beware issues with -# some PAM modules and threads) ChallengeResponseAuthentication no - -# Change to no to disable tunnelled clear text passwords -#PasswordAuthentication yes - -# Kerberos options -#KerberosAuthentication no -#KerberosGetAFSToken no -#KerberosOrLocalPasswd yes -#KerberosTicketCleanup yes - -# GSSAPI options -#GSSAPIAuthentication no -#GSSAPICleanupCredentials yes - -X11Forwarding yes -X11DisplayOffset 10 -PrintMotd no -PrintLastLog yes -TCPKeepAlive yes -#UseLogin no - -# keep ssh sessions fresh -ClientAliveInterval 60 - -#MaxStartups 10:30:60 -Banner /etc/issue.net - -# Allow client to pass locale environment variables -AcceptEnv LANG LC_* - -Subsystem sftp internal-sftp - -# Set this to 'yes' to enable PAM authentication, account processing, -# and session processing. If this is enabled, PAM authentication will -# be allowed through the ChallengeResponseAuthentication and -# PasswordAuthentication. Depending on your PAM configuration, -# PAM authentication via ChallengeResponseAuthentication may bypass -# the setting of "PermitRootLogin without-password". -# If you just want the PAM account and session checks to run without -# PAM authentication, then enable this but set PasswordAuthentication -# and ChallengeResponseAuthentication to 'no'. UsePAM yes +# Change to no to disable tunnelled clear text passwords +# (i.e. everybody will need to authenticate using ssh keys) +#PasswordAuthentication yes + +# Post-login stuff +Banner /etc/issue.net +PrintMotd no +PrintLastLog yes +ClientAliveInterval 60 +AcceptEnv LANG LC_* + +# SFTP stuff +Subsystem sftp internal-sftp Match User sftpusers ForceCommand internal-sftp ChrootDirectory /home/%u From 4f05cd5b2b2f12fddf67712c3c263c89fbf4678a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 3 Dec 2018 16:56:28 +0000 Subject: [PATCH 30/32] Uh for some reason we need to return *0* explicitly --- data/hooks/conf_regen/03-ssh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index dafa4327e..34cb441b4 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -9,7 +9,7 @@ do_pre_regen() { # If the (legacy) 'from_script' flag is here, # we won't touch anything in the ssh config. - [[ ! -f /etc/yunohost/from_script ]] || return + [[ ! -f /etc/yunohost/from_script ]] || return 0 cd /usr/share/yunohost/templates/ssh @@ -39,10 +39,10 @@ do_post_regen() { # If the (legacy) 'from_script' flag is here, # we won't touch anything in the ssh config. - [[ ! -f /etc/yunohost/from_script ]] || return + [[ ! -f /etc/yunohost/from_script ]] || return 0 # If no file changed, there's nothing to do - [[ -n "$regen_conf_files" ]] || return + [[ -n "$regen_conf_files" ]] || return 0 # Enforce permissions for /etc/ssh/sshd_config chown root:root "/etc/ssh/sshd_config" From e871ff3b20307069ccc28eede7bb31e1f91561aa Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 3 Dec 2018 17:04:43 +0000 Subject: [PATCH 31/32] Semantics --- src/yunohost/tools.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 678049900..c5b35a6b5 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -441,15 +441,18 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False, service_regen_conf(force=True) - # Restore specific ssh conf - # c.f. the install script and in particular + # Restore original ssh conf, as chosen by the + # admin during the initial install + # + # c.f. the install script and in particular # https://github.com/YunoHost/install_script/pull/50 # The user can now choose during the install to keep # the initial, existing sshd configuration # instead of YunoHost's recommended conf - bkp_sshd_conf = '/etc/ssh/sshd_config.to_restore' - if os.path.exists(bkp_sshd_conf): - os.rename(bkp_sshd_conf, '/etc/ssh/sshd_config') + # + original_sshd_conf = '/etc/ssh/sshd_config.before_yunohost' + if os.path.exists(original_sshd_conf): + os.rename(original_sshd_conf, '/etc/ssh/sshd_config') logger.success(m18n.n('yunohost_configured')) From 3949333599dfcad37799c83e6765b4f75a56bf02 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 3 Dec 2018 17:56:01 +0000 Subject: [PATCH 32/32] We need to explicitly ask for the ssh conf to be generated --- src/yunohost/tools.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index c5b35a6b5..6810e5397 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -453,6 +453,10 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False, original_sshd_conf = '/etc/ssh/sshd_config.before_yunohost' if os.path.exists(original_sshd_conf): os.rename(original_sshd_conf, '/etc/ssh/sshd_config') + else: + # We need to explicitly ask the regen conf to regen ssh + # (by default, i.e. first argument = None, it won't because it's too touchy) + service_regen_conf(names=["ssh"], force=True) logger.success(m18n.n('yunohost_configured'))