1
# Copyright 2016 Canonical Limited.
3
# This file is part of charm-helpers.
5
# charm-helpers is free software: you can redistribute it and/or modify
6
# it under the terms of the GNU Lesser General Public License version 3 as
7
# published by the Free Software Foundation.
9
# charm-helpers is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU Lesser General Public License for more details.
14
# You should have received a copy of the GNU Lesser General Public License
15
# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
20
from six import string_types
22
from charmhelpers.core.hookenv import (
28
from charmhelpers.contrib.hardening.audits import BaseAudit
31
class DisabledModuleAudit(BaseAudit):
32
"""Audits Apache2 modules.
34
Determines if the apache2 modules are enabled. If the modules are enabled
35
then they are removed in the ensure_compliance.
37
def __init__(self, modules):
40
elif isinstance(modules, string_types):
41
self.modules = [modules]
43
self.modules = modules
45
def ensure_compliance(self):
46
"""Ensures that the modules are not loaded."""
51
loaded_modules = self._get_loaded_modules()
52
non_compliant_modules = []
53
for module in self.modules:
54
if module in loaded_modules:
55
log("Module '%s' is enabled but should not be." %
57
non_compliant_modules.append(module)
59
if len(non_compliant_modules) == 0:
62
for module in non_compliant_modules:
63
self._disable_module(module)
64
self._restart_apache()
65
except subprocess.CalledProcessError as e:
66
log('Error occurred auditing apache module compliance. '
67
'This may have been already reported. '
68
'Output is: %s' % e.output, level=ERROR)
71
def _get_loaded_modules():
72
"""Returns the modules which are enabled in Apache."""
73
output = subprocess.check_output(['apache2ctl', '-M'])
75
for line in output.strip().split():
76
# Each line of the enabled module output looks like:
77
# module_name (static|shared)
78
# Plus a header line at the top of the output which is stripped
80
matcher = re.search(r'^ (\S*)', line)
82
modules.append(matcher.group(1))
86
def _disable_module(module):
87
"""Disables the specified module in Apache."""
89
subprocess.check_call(['a2dismod', module])
90
except subprocess.CalledProcessError as e:
91
# Note: catch error here to allow the attempt of disabling
92
# multiple modules in one go rather than failing after the
94
log('Error occurred disabling module %s. '
95
'Output is: %s' % (module, e.output), level=ERROR)
98
def _restart_apache():
99
"""Restarts the apache process"""
100
subprocess.check_output(['service', 'apache2', 'restart'])