diff --git a/hardening.yaml b/hardening.yaml index 314bb385..e591e509 100644 --- a/hardening.yaml +++ b/hardening.yaml @@ -3,3 +3,6 @@ ssh: server: use_pam: 'yes' # juju requires this +apache: + hardening: + modules_to_disable: ['status'] diff --git a/hooks/charmhelpers/contrib/hardening/audits/apache.py b/hooks/charmhelpers/contrib/hardening/audits/apache.py index d812948a..d32bf44e 100644 --- a/hooks/charmhelpers/contrib/hardening/audits/apache.py +++ b/hooks/charmhelpers/contrib/hardening/audits/apache.py @@ -70,12 +70,12 @@ class DisabledModuleAudit(BaseAudit): """Returns the modules which are enabled in Apache.""" output = subprocess.check_output(['apache2ctl', '-M']) modules = [] - for line in output.strip().split(): + for line in output.splitlines(): # Each line of the enabled module output looks like: # module_name (static|shared) # Plus a header line at the top of the output which is stripped # out by the regex. - matcher = re.search(r'^ (\S*)', line) + matcher = re.search(r'^ (\S*)_module (\S*)', line) if matcher: modules.append(matcher.group(1)) return modules diff --git a/hooks/charmhelpers/core/hookenv.py b/hooks/charmhelpers/core/hookenv.py index 12f37b28..899722fd 100644 --- a/hooks/charmhelpers/core/hookenv.py +++ b/hooks/charmhelpers/core/hookenv.py @@ -218,6 +218,8 @@ def principal_unit(): for rid in relation_ids(reltype): for unit in related_units(rid): md = _metadata_unit(unit) + if not md: + continue subordinate = md.pop('subordinate', None) if not subordinate: return unit @@ -511,7 +513,10 @@ def _metadata_unit(unit): """ basedir = os.sep.join(charm_dir().split(os.sep)[:-2]) unitdir = 'unit-{}'.format(unit.replace(os.sep, '-')) - with open(os.path.join(basedir, unitdir, 'charm', 'metadata.yaml')) as md: + joineddir = os.path.join(basedir, unitdir, 'charm', 'metadata.yaml') + if not os.path.exists(joineddir): + return None + with open(joineddir) as md: return yaml.safe_load(md) diff --git a/tests/basic_deployment.py b/tests/basic_deployment.py index 1e0955a9..44fdec66 100644 --- a/tests/basic_deployment.py +++ b/tests/basic_deployment.py @@ -18,6 +18,7 @@ import amulet import os import urllib2 import yaml +import time from charmhelpers.contrib.openstack.amulet.deployment import ( OpenStackAmuletDeployment @@ -234,6 +235,29 @@ class OpenstackDashboardBasicDeployment(OpenStackAmuletDeployment): msg = "Dashboard frontpage check failed" amulet.raise_status(amulet.FAIL, msg=msg) + def test_404_connection(self): + """Verify the apache status module gets disabled when + hardening apache.""" + + u.log.debug('Checking apache mod_status gets disabled.') + unit = self.openstack_dashboard_sentry + dashboard_relation = unit.relation('identity-service', + 'keystone:identity-service') + dashboard_ip = dashboard_relation['private-address'] + + u.log.debug('Enabling hardening for apache...') + self.d.configure('openstack-dashboard', {'harden': 'apache'}) + time.sleep(5) # wait for hook to run + self.d.sentry.wait() # wait for hook to finish + + try: + urllib2.urlopen('http://%s/server-status' % (dashboard_ip)) + except urllib2.HTTPError as e: + if e.code == 404: + return + msg = "Apache mod_status check failed." + amulet.raise_status(amulet.FAIL, msg=msg) + def test_900_restart_on_config_change(self): """Verify that the specified services are restarted when the config is changed.""" diff --git a/tests/charmhelpers/core/hookenv.py b/tests/charmhelpers/core/hookenv.py index 12f37b28..899722fd 100644 --- a/tests/charmhelpers/core/hookenv.py +++ b/tests/charmhelpers/core/hookenv.py @@ -218,6 +218,8 @@ def principal_unit(): for rid in relation_ids(reltype): for unit in related_units(rid): md = _metadata_unit(unit) + if not md: + continue subordinate = md.pop('subordinate', None) if not subordinate: return unit @@ -511,7 +513,10 @@ def _metadata_unit(unit): """ basedir = os.sep.join(charm_dir().split(os.sep)[:-2]) unitdir = 'unit-{}'.format(unit.replace(os.sep, '-')) - with open(os.path.join(basedir, unitdir, 'charm', 'metadata.yaml')) as md: + joineddir = os.path.join(basedir, unitdir, 'charm', 'metadata.yaml') + if not os.path.exists(joineddir): + return None + with open(joineddir) as md: return yaml.safe_load(md)