
Add charmhelpers.contrib.hardening and calls to install, config-changed, upgrade-charm and update-status hooks. Also add new config option to allow one or more hardening modules to be applied at runtime. Change-Id: Icf48829e010d35d7d7a4ccd547eae6a8c511c04e
132 lines
5.0 KiB
Python
132 lines
5.0 KiB
Python
# 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 subprocess
|
|
|
|
from charmhelpers.core.hookenv import (
|
|
log,
|
|
INFO,
|
|
)
|
|
from charmhelpers.contrib.hardening.audits.file import NoSUIDSGIDAudit
|
|
from charmhelpers.contrib.hardening import utils
|
|
|
|
|
|
BLACKLIST = ['/usr/bin/rcp', '/usr/bin/rlogin', '/usr/bin/rsh',
|
|
'/usr/libexec/openssh/ssh-keysign',
|
|
'/usr/lib/openssh/ssh-keysign',
|
|
'/sbin/netreport',
|
|
'/usr/sbin/usernetctl',
|
|
'/usr/sbin/userisdnctl',
|
|
'/usr/sbin/pppd',
|
|
'/usr/bin/lockfile',
|
|
'/usr/bin/mail-lock',
|
|
'/usr/bin/mail-unlock',
|
|
'/usr/bin/mail-touchlock',
|
|
'/usr/bin/dotlockfile',
|
|
'/usr/bin/arping',
|
|
'/usr/sbin/uuidd',
|
|
'/usr/bin/mtr',
|
|
'/usr/lib/evolution/camel-lock-helper-1.2',
|
|
'/usr/lib/pt_chown',
|
|
'/usr/lib/eject/dmcrypt-get-device',
|
|
'/usr/lib/mc/cons.saver']
|
|
|
|
WHITELIST = ['/bin/mount', '/bin/ping', '/bin/su', '/bin/umount',
|
|
'/sbin/pam_timestamp_check', '/sbin/unix_chkpwd', '/usr/bin/at',
|
|
'/usr/bin/gpasswd', '/usr/bin/locate', '/usr/bin/newgrp',
|
|
'/usr/bin/passwd', '/usr/bin/ssh-agent',
|
|
'/usr/libexec/utempter/utempter', '/usr/sbin/lockdev',
|
|
'/usr/sbin/sendmail.sendmail', '/usr/bin/expiry',
|
|
'/bin/ping6', '/usr/bin/traceroute6.iputils',
|
|
'/sbin/mount.nfs', '/sbin/umount.nfs',
|
|
'/sbin/mount.nfs4', '/sbin/umount.nfs4',
|
|
'/usr/bin/crontab',
|
|
'/usr/bin/wall', '/usr/bin/write',
|
|
'/usr/bin/screen',
|
|
'/usr/bin/mlocate',
|
|
'/usr/bin/chage', '/usr/bin/chfn', '/usr/bin/chsh',
|
|
'/bin/fusermount',
|
|
'/usr/bin/pkexec',
|
|
'/usr/bin/sudo', '/usr/bin/sudoedit',
|
|
'/usr/sbin/postdrop', '/usr/sbin/postqueue',
|
|
'/usr/sbin/suexec',
|
|
'/usr/lib/squid/ncsa_auth', '/usr/lib/squid/pam_auth',
|
|
'/usr/kerberos/bin/ksu',
|
|
'/usr/sbin/ccreds_validate',
|
|
'/usr/bin/Xorg',
|
|
'/usr/bin/X',
|
|
'/usr/lib/dbus-1.0/dbus-daemon-launch-helper',
|
|
'/usr/lib/vte/gnome-pty-helper',
|
|
'/usr/lib/libvte9/gnome-pty-helper',
|
|
'/usr/lib/libvte-2.90-9/gnome-pty-helper']
|
|
|
|
|
|
def get_audits():
|
|
"""Get OS hardening suid/sgid audits.
|
|
|
|
:returns: dictionary of audits
|
|
"""
|
|
checks = []
|
|
settings = utils.get_settings('os')
|
|
if not settings['security']['suid_sgid_enforce']:
|
|
log("Skipping suid/sgid hardening", level=INFO)
|
|
return checks
|
|
|
|
# Build the blacklist and whitelist of files for suid/sgid checks.
|
|
# There are a total of 4 lists:
|
|
# 1. the system blacklist
|
|
# 2. the system whitelist
|
|
# 3. the user blacklist
|
|
# 4. the user whitelist
|
|
#
|
|
# The blacklist is the set of paths which should NOT have the suid/sgid bit
|
|
# set and the whitelist is the set of paths which MAY have the suid/sgid
|
|
# bit setl. The user whitelist/blacklist effectively override the system
|
|
# whitelist/blacklist.
|
|
u_b = settings['security']['suid_sgid_blacklist']
|
|
u_w = settings['security']['suid_sgid_whitelist']
|
|
|
|
blacklist = set(BLACKLIST) - set(u_w + u_b)
|
|
whitelist = set(WHITELIST) - set(u_b + u_w)
|
|
|
|
checks.append(NoSUIDSGIDAudit(blacklist))
|
|
|
|
dry_run = settings['security']['suid_sgid_dry_run_on_unknown']
|
|
|
|
if settings['security']['suid_sgid_remove_from_unknown'] or dry_run:
|
|
# If the policy is a dry_run (e.g. complain only) or remove unknown
|
|
# suid/sgid bits then find all of the paths which have the suid/sgid
|
|
# bit set and then remove the whitelisted paths.
|
|
root_path = settings['environment']['root_path']
|
|
unknown_paths = find_paths_with_suid_sgid(root_path) - set(whitelist)
|
|
checks.append(NoSUIDSGIDAudit(unknown_paths, unless=dry_run))
|
|
|
|
return checks
|
|
|
|
|
|
def find_paths_with_suid_sgid(root_path):
|
|
"""Finds all paths/files which have an suid/sgid bit enabled.
|
|
|
|
Starting with the root_path, this will recursively find all paths which
|
|
have an suid or sgid bit set.
|
|
"""
|
|
cmd = ['find', root_path, '-perm', '-4000', '-o', '-perm', '-2000',
|
|
'-type', 'f', '!', '-path', '/proc/*', '-print']
|
|
|
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
out, _ = p.communicate()
|
|
return set(out.split('\n'))
|