aboutsummaryrefslogtreecommitdiffstats
path: root/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh
diff options
context:
space:
mode:
Diffstat (limited to 'charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh')
-rw-r--r--charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/__init__.py19
-rw-r--r--charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/checks/__init__.py31
-rw-r--r--charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/checks/config.py394
-rw-r--r--charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/templates/__init__.py0
-rw-r--r--charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/templates/ssh_config70
-rw-r--r--charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/templates/sshd_config159
6 files changed, 673 insertions, 0 deletions
diff --git a/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/__init__.py b/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/__init__.py
new file mode 100644
index 0000000..277b8c7
--- /dev/null
+++ b/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/__init__.py
@@ -0,0 +1,19 @@
+# Copyright 2016 Canonical Limited.
+#
+# This file is part of charm-helpers.
+#
+# charm-helpers is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3 as
+# published by the Free Software Foundation.
+#
+# charm-helpers 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
+
+from os import path
+
+TEMPLATES_DIR = path.join(path.dirname(__file__), 'templates')
diff --git a/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/checks/__init__.py b/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/checks/__init__.py
new file mode 100644
index 0000000..b85150d
--- /dev/null
+++ b/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/checks/__init__.py
@@ -0,0 +1,31 @@
+# Copyright 2016 Canonical Limited.
+#
+# This file is part of charm-helpers.
+#
+# charm-helpers is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3 as
+# published by the Free Software Foundation.
+#
+# charm-helpers 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
+
+from charmhelpers.core.hookenv import (
+ log,
+ DEBUG,
+)
+from charmhelpers.contrib.hardening.ssh.checks import config
+
+
+def run_ssh_checks():
+ log("Starting SSH hardening checks.", level=DEBUG)
+ checks = config.get_audits()
+ for check in checks:
+ log("Running '%s' check" % (check.__class__.__name__), level=DEBUG)
+ check.ensure_compliance()
+
+ log("SSH hardening checks complete.", level=DEBUG)
diff --git a/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/checks/config.py b/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/checks/config.py
new file mode 100644
index 0000000..3fb6ae8
--- /dev/null
+++ b/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/checks/config.py
@@ -0,0 +1,394 @@
+# Copyright 2016 Canonical Limited.
+#
+# This file is part of charm-helpers.
+#
+# charm-helpers is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3 as
+# published by the Free Software Foundation.
+#
+# charm-helpers 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+
+from charmhelpers.core.hookenv import (
+ log,
+ DEBUG,
+)
+from charmhelpers.fetch import (
+ apt_install,
+ apt_update,
+)
+from charmhelpers.core.host import lsb_release
+from charmhelpers.contrib.hardening.audits.file import (
+ TemplatedFile,
+ FileContentAudit,
+)
+from charmhelpers.contrib.hardening.ssh import TEMPLATES_DIR
+from charmhelpers.contrib.hardening import utils
+
+
+def get_audits():
+ """Get SSH hardening config audits.
+
+ :returns: dictionary of audits
+ """
+ audits = [SSHConfig(), SSHDConfig(), SSHConfigFileContentAudit(),
+ SSHDConfigFileContentAudit()]
+ return audits
+
+
+class SSHConfigContext(object):
+
+ type = 'client'
+
+ def get_macs(self, allow_weak_mac):
+ if allow_weak_mac:
+ weak_macs = 'weak'
+ else:
+ weak_macs = 'default'
+
+ default = 'hmac-sha2-512,hmac-sha2-256,hmac-ripemd160'
+ macs = {'default': default,
+ 'weak': default + ',hmac-sha1'}
+
+ default = ('hmac-sha2-512-etm@openssh.com,'
+ 'hmac-sha2-256-etm@openssh.com,'
+ 'hmac-ripemd160-etm@openssh.com,umac-128-etm@openssh.com,'
+ 'hmac-sha2-512,hmac-sha2-256,hmac-ripemd160')
+ macs_66 = {'default': default,
+ 'weak': default + ',hmac-sha1'}
+
+ # Use newer ciphers on Ubuntu Trusty and above
+ if lsb_release()['DISTRIB_CODENAME'].lower() >= 'trusty':
+ log("Detected Ubuntu 14.04 or newer, using new macs", level=DEBUG)
+ macs = macs_66
+
+ return macs[weak_macs]
+
+ def get_kexs(self, allow_weak_kex):
+ if allow_weak_kex:
+ weak_kex = 'weak'
+ else:
+ weak_kex = 'default'
+
+ default = 'diffie-hellman-group-exchange-sha256'
+ weak = (default + ',diffie-hellman-group14-sha1,'
+ 'diffie-hellman-group-exchange-sha1,'
+ 'diffie-hellman-group1-sha1')
+ kex = {'default': default,
+ 'weak': weak}
+
+ default = ('curve25519-sha256@libssh.org,'
+ 'diffie-hellman-group-exchange-sha256')
+ weak = (default + ',diffie-hellman-group14-sha1,'
+ 'diffie-hellman-group-exchange-sha1,'
+ 'diffie-hellman-group1-sha1')
+ kex_66 = {'default': default,
+ 'weak': weak}
+
+ # Use newer kex on Ubuntu Trusty and above
+ if lsb_release()['DISTRIB_CODENAME'].lower() >= 'trusty':
+ log('Detected Ubuntu 14.04 or newer, using new key exchange '
+ 'algorithms', level=DEBUG)
+ kex = kex_66
+
+ return kex[weak_kex]
+
+ def get_ciphers(self, cbc_required):
+ if cbc_required:
+ weak_ciphers = 'weak'
+ else:
+ weak_ciphers = 'default'
+
+ default = 'aes256-ctr,aes192-ctr,aes128-ctr'
+ cipher = {'default': default,
+ 'weak': default + 'aes256-cbc,aes192-cbc,aes128-cbc'}
+
+ default = ('chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,'
+ 'aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr')
+ ciphers_66 = {'default': default,
+ 'weak': default + ',aes256-cbc,aes192-cbc,aes128-cbc'}
+
+ # Use newer ciphers on ubuntu Trusty and above
+ if lsb_release()['DISTRIB_CODENAME'].lower() >= 'trusty':
+ log('Detected Ubuntu 14.04 or newer, using new ciphers',
+ level=DEBUG)
+ cipher = ciphers_66
+
+ return cipher[weak_ciphers]
+
+ def __call__(self):
+ settings = utils.get_settings('ssh')
+ if settings['common']['network_ipv6_enable']:
+ addr_family = 'any'
+ else:
+ addr_family = 'inet'
+
+ ctxt = {
+ 'addr_family': addr_family,
+ 'remote_hosts': settings['common']['remote_hosts'],
+ 'password_auth_allowed':
+ settings['client']['password_authentication'],
+ 'ports': settings['common']['ports'],
+ 'ciphers': self.get_ciphers(settings['client']['cbc_required']),
+ 'macs': self.get_macs(settings['client']['weak_hmac']),
+ 'kexs': self.get_kexs(settings['client']['weak_kex']),
+ 'roaming': settings['client']['roaming'],
+ }
+ return ctxt
+
+
+class SSHConfig(TemplatedFile):
+ def __init__(self):
+ path = '/etc/ssh/ssh_config'
+ super(SSHConfig, self).__init__(path=path,
+ template_dir=TEMPLATES_DIR,
+ context=SSHConfigContext(),
+ user='root',
+ group='root',
+ mode=0o0644)
+
+ def pre_write(self):
+ settings = utils.get_settings('ssh')
+ apt_update(fatal=True)
+ apt_install(settings['client']['package'])
+ if not os.path.exists('/etc/ssh'):
+ os.makedir('/etc/ssh')
+ # NOTE: don't recurse
+ utils.ensure_permissions('/etc/ssh', 'root', 'root', 0o0755,
+ maxdepth=0)
+
+ def post_write(self):
+ # NOTE: don't recurse
+ utils.ensure_permissions('/etc/ssh', 'root', 'root', 0o0755,
+ maxdepth=0)
+
+
+class SSHDConfigContext(SSHConfigContext):
+
+ type = 'server'
+
+ def __call__(self):
+ settings = utils.get_settings('ssh')
+ if settings['common']['network_ipv6_enable']:
+ addr_family = 'any'
+ else:
+ addr_family = 'inet'
+
+ ctxt = {
+ 'ssh_ip': settings['server']['listen_to'],
+ 'password_auth_allowed':
+ settings['server']['password_authentication'],
+ 'ports': settings['common']['ports'],
+ 'addr_family': addr_family,
+ 'ciphers': self.get_ciphers(settings['server']['cbc_required']),
+ 'macs': self.get_macs(settings['server']['weak_hmac']),
+ 'kexs': self.get_kexs(settings['server']['weak_kex']),
+ 'host_key_files': settings['server']['host_key_files'],
+ 'allow_root_with_key': settings['server']['allow_root_with_key'],
+ 'password_authentication':
+ settings['server']['password_authentication'],
+ 'use_priv_sep': settings['server']['use_privilege_separation'],
+ 'use_pam': settings['server']['use_pam'],
+ 'allow_x11_forwarding': settings['server']['allow_x11_forwarding'],
+ 'print_motd': settings['server']['print_motd'],
+ 'print_last_log': settings['server']['print_last_log'],
+ 'client_alive_interval':
+ settings['server']['alive_interval'],
+ 'client_alive_count': settings['server']['alive_count'],
+ 'allow_tcp_forwarding': settings['server']['allow_tcp_forwarding'],
+ 'allow_agent_forwarding':
+ settings['server']['allow_agent_forwarding'],
+ 'deny_users': settings['server']['deny_users'],
+ 'allow_users': settings['server']['allow_users'],
+ 'deny_groups': settings['server']['deny_groups'],
+ 'allow_groups': settings['server']['allow_groups'],
+ 'use_dns': settings['server']['use_dns'],
+ 'sftp_enable': settings['server']['sftp_enable'],
+ 'sftp_group': settings['server']['sftp_group'],
+ 'sftp_chroot': settings['server']['sftp_chroot'],
+ 'max_auth_tries': settings['server']['max_auth_tries'],
+ 'max_sessions': settings['server']['max_sessions'],
+ }
+ return ctxt
+
+
+class SSHDConfig(TemplatedFile):
+ def __init__(self):
+ path = '/etc/ssh/sshd_config'
+ super(SSHDConfig, self).__init__(path=path,
+ template_dir=TEMPLATES_DIR,
+ context=SSHDConfigContext(),
+ user='root',
+ group='root',
+ mode=0o0600,
+ service_actions=[{'service': 'ssh',
+ 'actions':
+ ['restart']}])
+
+ def pre_write(self):
+ settings = utils.get_settings('ssh')
+ apt_update(fatal=True)
+ apt_install(settings['server']['package'])
+ if not os.path.exists('/etc/ssh'):
+ os.makedir('/etc/ssh')
+ # NOTE: don't recurse
+ utils.ensure_permissions('/etc/ssh', 'root', 'root', 0o0755,
+ maxdepth=0)
+
+ def post_write(self):
+ # NOTE: don't recurse
+ utils.ensure_permissions('/etc/ssh', 'root', 'root', 0o0755,
+ maxdepth=0)
+
+
+class SSHConfigFileContentAudit(FileContentAudit):
+ def __init__(self):
+ self.path = '/etc/ssh/ssh_config'
+ super(SSHConfigFileContentAudit, self).__init__(self.path, {})
+
+ def is_compliant(self, *args, **kwargs):
+ self.pass_cases = []
+ self.fail_cases = []
+ settings = utils.get_settings('ssh')
+
+ if lsb_release()['DISTRIB_CODENAME'].lower() >= 'trusty':
+ if not settings['server']['weak_hmac']:
+ self.pass_cases.append(r'^MACs.+,hmac-ripemd160$')
+ else:
+ self.pass_cases.append(r'^MACs.+,hmac-sha1$')
+
+ if settings['server']['weak_kex']:
+ self.fail_cases.append(r'^KexAlgorithms\sdiffie-hellman-group-exchange-sha256[,\s]?') # noqa
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group14-sha1[,\s]?') # noqa
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group-exchange-sha1[,\s]?') # noqa
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group1-sha1[,\s]?') # noqa
+ else:
+ self.pass_cases.append(r'^KexAlgorithms.+,diffie-hellman-group-exchange-sha256$') # noqa
+ self.fail_cases.append(r'^KexAlgorithms.*diffie-hellman-group14-sha1[,\s]?') # noqa
+
+ if settings['server']['cbc_required']:
+ self.pass_cases.append(r'^Ciphers\s.*-cbc[,\s]?')
+ self.fail_cases.append(r'^Ciphers\s.*aes128-ctr[,\s]?')
+ self.fail_cases.append(r'^Ciphers\s.*aes192-ctr[,\s]?')
+ self.fail_cases.append(r'^Ciphers\s.*aes256-ctr[,\s]?')
+ else:
+ self.fail_cases.append(r'^Ciphers\s.*-cbc[,\s]?')
+ self.pass_cases.append(r'^Ciphers\schacha20-poly1305@openssh.com,.+') # noqa
+ self.pass_cases.append(r'^Ciphers\s.*aes128-ctr$')
+ self.pass_cases.append(r'^Ciphers\s.*aes192-ctr[,\s]?')
+ self.pass_cases.append(r'^Ciphers\s.*aes256-ctr[,\s]?')
+ else:
+ if not settings['client']['weak_hmac']:
+ self.fail_cases.append(r'^MACs.+,hmac-sha1$')
+ else:
+ self.pass_cases.append(r'^MACs.+,hmac-sha1$')
+
+ if settings['client']['weak_kex']:
+ self.fail_cases.append(r'^KexAlgorithms\sdiffie-hellman-group-exchange-sha256[,\s]?') # noqa
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group14-sha1[,\s]?') # noqa
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group-exchange-sha1[,\s]?') # noqa
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group1-sha1[,\s]?') # noqa
+ else:
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group-exchange-sha256$') # noqa
+ self.fail_cases.append(r'^KexAlgorithms\sdiffie-hellman-group14-sha1[,\s]?') # noqa
+ self.fail_cases.append(r'^KexAlgorithms\sdiffie-hellman-group-exchange-sha1[,\s]?') # noqa
+ self.fail_cases.append(r'^KexAlgorithms\sdiffie-hellman-group1-sha1[,\s]?') # noqa
+
+ if settings['client']['cbc_required']:
+ self.pass_cases.append(r'^Ciphers\s.*-cbc[,\s]?')
+ self.fail_cases.append(r'^Ciphers\s.*aes128-ctr[,\s]?')
+ self.fail_cases.append(r'^Ciphers\s.*aes192-ctr[,\s]?')
+ self.fail_cases.append(r'^Ciphers\s.*aes256-ctr[,\s]?')
+ else:
+ self.fail_cases.append(r'^Ciphers\s.*-cbc[,\s]?')
+ self.pass_cases.append(r'^Ciphers\s.*aes128-ctr[,\s]?')
+ self.pass_cases.append(r'^Ciphers\s.*aes192-ctr[,\s]?')
+ self.pass_cases.append(r'^Ciphers\s.*aes256-ctr[,\s]?')
+
+ if settings['client']['roaming']:
+ self.pass_cases.append(r'^UseRoaming yes$')
+ else:
+ self.fail_cases.append(r'^UseRoaming yes$')
+
+ return super(SSHConfigFileContentAudit, self).is_compliant(*args,
+ **kwargs)
+
+
+class SSHDConfigFileContentAudit(FileContentAudit):
+ def __init__(self):
+ self.path = '/etc/ssh/sshd_config'
+ super(SSHDConfigFileContentAudit, self).__init__(self.path, {})
+
+ def is_compliant(self, *args, **kwargs):
+ self.pass_cases = []
+ self.fail_cases = []
+ settings = utils.get_settings('ssh')
+
+ if lsb_release()['DISTRIB_CODENAME'].lower() >= 'trusty':
+ if not settings['server']['weak_hmac']:
+ self.pass_cases.append(r'^MACs.+,hmac-ripemd160$')
+ else:
+ self.pass_cases.append(r'^MACs.+,hmac-sha1$')
+
+ if settings['server']['weak_kex']:
+ self.fail_cases.append(r'^KexAlgorithms\sdiffie-hellman-group-exchange-sha256[,\s]?') # noqa
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group14-sha1[,\s]?') # noqa
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group-exchange-sha1[,\s]?') # noqa
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group1-sha1[,\s]?') # noqa
+ else:
+ self.pass_cases.append(r'^KexAlgorithms.+,diffie-hellman-group-exchange-sha256$') # noqa
+ self.fail_cases.append(r'^KexAlgorithms.*diffie-hellman-group14-sha1[,\s]?') # noqa
+
+ if settings['server']['cbc_required']:
+ self.pass_cases.append(r'^Ciphers\s.*-cbc[,\s]?')
+ self.fail_cases.append(r'^Ciphers\s.*aes128-ctr[,\s]?')
+ self.fail_cases.append(r'^Ciphers\s.*aes192-ctr[,\s]?')
+ self.fail_cases.append(r'^Ciphers\s.*aes256-ctr[,\s]?')
+ else:
+ self.fail_cases.append(r'^Ciphers\s.*-cbc[,\s]?')
+ self.pass_cases.append(r'^Ciphers\schacha20-poly1305@openssh.com,.+') # noqa
+ self.pass_cases.append(r'^Ciphers\s.*aes128-ctr$')
+ self.pass_cases.append(r'^Ciphers\s.*aes192-ctr[,\s]?')
+ self.pass_cases.append(r'^Ciphers\s.*aes256-ctr[,\s]?')
+ else:
+ if not settings['server']['weak_hmac']:
+ self.pass_cases.append(r'^MACs.+,hmac-ripemd160$')
+ else:
+ self.pass_cases.append(r'^MACs.+,hmac-sha1$')
+
+ if settings['server']['weak_kex']:
+ self.fail_cases.append(r'^KexAlgorithms\sdiffie-hellman-group-exchange-sha256[,\s]?') # noqa
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group14-sha1[,\s]?') # noqa
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group-exchange-sha1[,\s]?') # noqa
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group1-sha1[,\s]?') # noqa
+ else:
+ self.pass_cases.append(r'^KexAlgorithms\sdiffie-hellman-group-exchange-sha256$') # noqa
+ self.fail_cases.append(r'^KexAlgorithms\sdiffie-hellman-group14-sha1[,\s]?') # noqa
+ self.fail_cases.append(r'^KexAlgorithms\sdiffie-hellman-group-exchange-sha1[,\s]?') # noqa
+ self.fail_cases.append(r'^KexAlgorithms\sdiffie-hellman-group1-sha1[,\s]?') # noqa
+
+ if settings['server']['cbc_required']:
+ self.pass_cases.append(r'^Ciphers\s.*-cbc[,\s]?')
+ self.fail_cases.append(r'^Ciphers\s.*aes128-ctr[,\s]?')
+ self.fail_cases.append(r'^Ciphers\s.*aes192-ctr[,\s]?')
+ self.fail_cases.append(r'^Ciphers\s.*aes256-ctr[,\s]?')
+ else:
+ self.fail_cases.append(r'^Ciphers\s.*-cbc[,\s]?')
+ self.pass_cases.append(r'^Ciphers\s.*aes128-ctr[,\s]?')
+ self.pass_cases.append(r'^Ciphers\s.*aes192-ctr[,\s]?')
+ self.pass_cases.append(r'^Ciphers\s.*aes256-ctr[,\s]?')
+
+ if settings['server']['sftp_enable']:
+ self.pass_cases.append(r'^Subsystem\ssftp')
+ else:
+ self.fail_cases.append(r'^Subsystem\ssftp')
+
+ return super(SSHDConfigFileContentAudit, self).is_compliant(*args,
+ **kwargs)
diff --git a/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/templates/__init__.py b/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/templates/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/templates/__init__.py
diff --git a/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/templates/ssh_config b/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/templates/ssh_config
new file mode 100644
index 0000000..9742d8e
--- /dev/null
+++ b/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/templates/ssh_config
@@ -0,0 +1,70 @@
+###############################################################################
+# WARNING: This configuration file is maintained by Juju. Local changes may
+# be overwritten.
+###############################################################################
+# This is the ssh client system-wide configuration file. See
+# ssh_config(5) for more information. This file provides defaults for
+# users, and the values can be changed in per-user configuration files
+# or on the command line.
+
+# Configuration data is parsed as follows:
+# 1. command line options
+# 2. user-specific file
+# 3. system-wide file
+# Any configuration value is only changed the first time it is set.
+# Thus, host-specific definitions should be at the beginning of the
+# configuration file, and defaults at the end.
+
+# Site-wide defaults for some commonly used options. For a comprehensive
+# list of available options, their meanings and defaults, please see the
+# ssh_config(5) man page.
+
+# Restrict the following configuration to be limited to this Host.
+{% if remote_hosts -%}
+Host {{ ' '.join(remote_hosts) }}
+{% endif %}
+ForwardAgent no
+ForwardX11 no
+ForwardX11Trusted yes
+RhostsRSAAuthentication no
+RSAAuthentication yes
+PasswordAuthentication {{ password_auth_allowed }}
+HostbasedAuthentication no
+GSSAPIAuthentication no
+GSSAPIDelegateCredentials no
+GSSAPIKeyExchange no
+GSSAPITrustDNS no
+BatchMode no
+CheckHostIP yes
+AddressFamily {{ addr_family }}
+ConnectTimeout 0
+StrictHostKeyChecking ask
+IdentityFile ~/.ssh/identity
+IdentityFile ~/.ssh/id_rsa
+IdentityFile ~/.ssh/id_dsa
+# The port at the destination should be defined
+{% for port in ports -%}
+Port {{ port }}
+{% endfor %}
+Protocol 2
+Cipher 3des
+{% if ciphers -%}
+Ciphers {{ ciphers }}
+{%- endif %}
+{% if macs -%}
+MACs {{ macs }}
+{%- endif %}
+{% if kexs -%}
+KexAlgorithms {{ kexs }}
+{%- endif %}
+EscapeChar ~
+Tunnel no
+TunnelDevice any:any
+PermitLocalCommand no
+VisualHostKey no
+RekeyLimit 1G 1h
+SendEnv LANG LC_*
+HashKnownHosts yes
+{% if roaming -%}
+UseRoaming {{ roaming }}
+{% endif %}
diff --git a/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/templates/sshd_config b/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/templates/sshd_config
new file mode 100644
index 0000000..5f87298
--- /dev/null
+++ b/charms/trusty/ceilometer/charmhelpers/contrib/hardening/ssh/templates/sshd_config
@@ -0,0 +1,159 @@
+###############################################################################
+# WARNING: This configuration file is maintained by Juju. Local changes may
+# be overwritten.
+###############################################################################
+# Package generated configuration file
+# See the sshd_config(5) manpage for details
+
+# What ports, IPs and protocols we listen for
+{% for port in ports -%}
+Port {{ port }}
+{% endfor -%}
+AddressFamily {{ addr_family }}
+# Use these options to restrict which interfaces/protocols sshd will bind to
+{% if ssh_ip -%}
+{% for ip in ssh_ip -%}
+ListenAddress {{ ip }}
+{% endfor %}
+{%- else -%}
+ListenAddress ::
+ListenAddress 0.0.0.0
+{% endif -%}
+Protocol 2
+{% if ciphers -%}
+Ciphers {{ ciphers }}
+{% endif -%}
+{% if macs -%}
+MACs {{ macs }}
+{% endif -%}
+{% if kexs -%}
+KexAlgorithms {{ kexs }}
+{% endif -%}
+# HostKeys for protocol version 2
+{% for keyfile in host_key_files -%}
+HostKey {{ keyfile }}
+{% endfor -%}
+
+# Privilege Separation is turned on for security
+{% if use_priv_sep -%}
+UsePrivilegeSeparation {{ use_priv_sep }}
+{% endif -%}
+
+# Lifetime and size of ephemeral version 1 server key
+KeyRegenerationInterval 3600
+ServerKeyBits 1024
+
+# Logging
+SyslogFacility AUTH
+LogLevel VERBOSE
+
+# Authentication:
+LoginGraceTime 30s
+{% if allow_root_with_key -%}
+PermitRootLogin without-password
+{% else -%}
+PermitRootLogin no
+{% endif %}
+PermitTunnel no
+PermitUserEnvironment 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
+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 {{ password_authentication }}
+
+# Kerberos options
+KerberosAuthentication no
+KerberosGetAFSToken no
+KerberosOrLocalPasswd no
+KerberosTicketCleanup yes
+
+# GSSAPI options
+GSSAPIAuthentication no
+GSSAPICleanupCredentials yes
+
+X11Forwarding {{ allow_x11_forwarding }}
+X11DisplayOffset 10
+X11UseLocalhost yes
+GatewayPorts no
+PrintMotd {{ print_motd }}
+PrintLastLog {{ print_last_log }}
+TCPKeepAlive no
+UseLogin no
+
+ClientAliveInterval {{ client_alive_interval }}
+ClientAliveCountMax {{ client_alive_count }}
+AllowTcpForwarding {{ allow_tcp_forwarding }}
+AllowAgentForwarding {{ allow_agent_forwarding }}
+
+MaxStartups 10:30:100
+#Banner /etc/issue.net
+
+# Allow client to pass locale environment variables
+AcceptEnv LANG LC_*
+
+# 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 {{ use_pam }}
+
+{% if deny_users -%}
+DenyUsers {{ deny_users }}
+{% endif -%}
+{% if allow_users -%}
+AllowUsers {{ allow_users }}
+{% endif -%}
+{% if deny_groups -%}
+DenyGroups {{ deny_groups }}
+{% endif -%}
+{% if allow_groups -%}
+AllowGroups allow_groups
+{% endif -%}
+UseDNS {{ use_dns }}
+MaxAuthTries {{ max_auth_tries }}
+MaxSessions {{ max_sessions }}
+
+{% if sftp_enable -%}
+# Configuration, in case SFTP is used
+## override default of no subsystems
+## Subsystem sftp /opt/app/openssh5/libexec/sftp-server
+Subsystem sftp internal-sftp -l VERBOSE
+
+## These lines must appear at the *end* of sshd_config
+Match Group {{ sftp_group }}
+ForceCommand internal-sftp -l VERBOSE
+ChrootDirectory {{ sftp_chroot }}
+{% else -%}
+# Configuration, in case SFTP is used
+## override default of no subsystems
+## Subsystem sftp /opt/app/openssh5/libexec/sftp-server
+## These lines must appear at the *end* of sshd_config
+Match Group sftponly
+ForceCommand internal-sftp -l VERBOSE
+ChrootDirectory /sftpchroot/home/%u
+{% endif %}