예제 #1
0
def _check_fortify(path):
    """Fortify Source - This introduces support for
    detecting buffer overflows in various functions that perform
    operations on memory and strings. The indicator for this is
    symbols such as __sprintf_chk rather then __sprintf. To compile
    an executable with fortify source enabled:
        $ gcc foo.c -D_FORTIFY_SOURCE=2 -O2
    """
    libc = _find_used_libc(path)
    if not libc:
        logger.debug('Unable to determine location of libc')
        return (False, Result.CONF_GUESS)

    fortified = set([])
    for addr, sym, name in _symbols_in_dynsym(libc):
        if sym in (b'T', b'i') and name.endswith(b'_chk'):
            fortified.add(name)
    plain = set(name[2:-4] for name in fortified)

    symbols = set([name for addr, sym, name in _symbols_in_dynsym(path)])
    if len(symbols.intersection(fortified)) > 0:
        return (True, Result.CONF_SURE)

    # if there are no functions to fortify, treat it the same as fortified
    if len(symbols.intersection(plain)) == 0:
        return (True, Result.CONF_SURE)

    # there may be a situation where a function is used on a buffer of unknown
    # size and cannot be fortified - or it may be just not fortified
    return (False, Result.CONF_GUESS)
예제 #2
0
def test_IPC_host():
    logger.debug("Testing if the container is running in user namespace.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '{{ .Id }}: IpcMode={{ .HostConfig.Devices }}'

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(
                ['docker', 'inspect', '--format', testcmd, container_id])

            if 'host' in test:
                notes = ("Container " + str(container_id) + " is "
                         "sharing IPC namespace with the container. ")
                result = TestResult(Result.FAIL, notes)
            else:
                result = TestResult(Result.PASS)

            results.add_result(check, result)
    return results
예제 #3
0
def _extract_symbols(cmd):
    """Helper function to reduce code duplication. Only difference
    in output of commands comes from the way the 'nm' command
    is run.

    :param cmd: The way to invoke 'nm' command.
    :returns: Generated symbols resulting from nm invocation.
    """
    try:
        entries = _safe_exec(cmd)
        for entry in entries.split(b'\n'):
            try:
                values = entry.strip().split(b' ')
                # handle case:
                #                  U __sprintf_chk@@GLIBC_2.3.4
                if len(values) == 2:
                    sym_addr = None
                    sym_type, sym_name = values
                # otherwise expect:
                # 00000000004004b0 T main
                else:
                    sym_addr, sym_type, sym_name = entry.split(b' ')

                yield (sym_addr, sym_type, sym_name.split(b'@@')[0])
            except ValueError as err:
                logger.debug('Unexpected output [ %s ]', entry.strip())

    except subprocess.CalledProcessError as err:
        logger.debug(err)
예제 #4
0
def test_ulimit_default_override():
    logger.debug("Testing if the container is running in user namespace.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '{{ .Id }}: Ulimits={{ .HostConfig.Ulimits }}'

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(
                ['docker', 'inspect', '--format', testcmd, container_id])

            if '<no value>' in test:
                result = TestResult(Result.PASS)
            else:
                notes = ("Container " + str(container_id) + " is "
                         "running with default ulimits in place. ")
                result = TestResult(Result.FAIL, notes)

            results.add_result(check, result)
    return results
예제 #5
0
def test_read_only_root_fs():
    logger.debug("Testing if the container is running in user namespace.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '{{ .Id }}: ReadonlyRootfs={{ .HostConfig.ReadonlyRootfs }}'

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(['docker',
                                            'inspect',
                                            '--format',
                                            testcmd,
                                            container_id])

            if 'false' in test:
                result = TestResult(Result.PASS)
            else:
                notes = ("Container " + str(container_id) + " has a file "
                         "system with permissions that are not read only.")
                result = TestResult(Result.FAIL, notes)
            results.add_result(check, result)
    return results
예제 #6
0
def test_read_only_root_fs():
    logger.debug("Testing if the container is running in user namespace.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '{{ .Id }}: ReadonlyRootfs={{ .HostConfig.ReadonlyRootfs }}'

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(
                ['docker', 'inspect', '--format', testcmd, container_id])

            if 'false' in test:
                result = TestResult(Result.PASS)
            else:
                notes = ("Container " + str(container_id) + " has a file "
                         "system with permissions that are not read only.")
                result = TestResult(Result.FAIL, notes)
            results.add_result(check, result)
    return results
예제 #7
0
def test_docker_pid_mode():
    logger.debug("Testing if the container is running in user namespace.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '{{ .Id }}: PidMode={{ .HostConfig.PidMode }}'

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(['docker',
                                            'inspect',
                                            '--format',
                                            testcmd,
                                            container_id])

            if 'host' in test:
                notes = ("Container " + str(container_id) + " is sharing "
                         "host process namespaces.")
                result = TestResult(Result.FAIL, notes)
            else:
                result = TestResult(Result.PASS)

            results.add_result(check, result)
    return results
예제 #8
0
def test_docker_privilege():
    logger.debug("Testing if the container is running in user namespace.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '{{ .Id }}: {{.HostConfig.Privileged }}'

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(['docker',
                                            'inspect',
                                            '--format',
                                            testcmd,
                                            container_id])

            entry = test.split(':')

            if 'false' in entry:
                result = TestResult(Result.PASS)
            else:
                notes = ("Container " + str(container_id) + " is running with "
                         "privileged flags set to true.")
                result = TestResult(Result.FAIL, notes)
            results.add_result(check, result)
    return results
예제 #9
0
def test_mount_sensitive_directories():
    logger.debug("Testing if the container is running in user namespace.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '{{ .Id }}: Volumes={{ .Volumes }} VolumesRW={{ .VolumesRW }}'

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(['docker',
                                            'inspect',
                                            '--format',
                                            testcmd,
                                            container_id])

            if ':true' in test:
                notes = ("Container " + str(container_id) + " has "
                         "sensitive host system directories " +
                         "mounted.")
                result = TestResult(Result.FAIL, notes)
            else:
                result = TestResult(Result.PASS)

            results.add_result(check, result)
    return results
예제 #10
0
def test_docker_privilege():
    logger.debug("Testing if the container is running in user namespace.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '{{ .Id }}: {{.HostConfig.Privileged }}'

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(
                ['docker', 'inspect', '--format', testcmd, container_id])

            entry = test.split(':')

            if 'false' in entry:
                result = TestResult(Result.PASS)
            else:
                notes = ("Container " + str(container_id) + " is running with "
                         "privileged flags set to true.")
                result = TestResult(Result.FAIL, notes)
            results.add_result(check, result)
    return results
예제 #11
0
def test_log_level():
    logger.debug("Checking the Docker log level.")
    reason = "No Docker containers found."

    result = None

    # if --log-level is set in ps, else find config file and check there
    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if '--log-level=info' in entry:
            result = TestResult(Result.PASS)

        elif '--log-level=debug' in entry:
            reason = ("It is not recommended to run Docker in production "
                      "in debug mode.")
            result = TestResult(Result.FAIL, reason)

        else:
            notes = "Recommended Docker log level is 'info'."
            result = TestResult(Result.PASS, notes)

    return result
예제 #12
0
def _extract_symbols(cmd):
    """Helper function to reduce code duplication. Only difference
    in output of commands comes from the way the 'nm' command
    is run.

    :param cmd: The way to invoke 'nm' command.
    :returns: Generated symbols resulting from nm invocation.
    """
    try:
        entries = _safe_exec(cmd)
        for entry in entries.split(b'\n'):
            try:
                values = entry.strip().split(b' ')
                # handle case:
                #                  U __sprintf_chk@@GLIBC_2.3.4
                if len(values) == 2:
                    sym_addr = None
                    sym_type, sym_name = values
                # otherwise expect:
                # 00000000004004b0 T main
                else:
                    sym_addr, sym_type, sym_name = entry.split(b' ')

                yield (sym_addr, sym_type, sym_name.split(b'@@')[0])
            except ValueError as err:
                logger.debug('Unexpected output [ %s ]', entry.strip())

    except subprocess.CalledProcessError as err:
        logger.debug(err)
예제 #13
0
def test_list_installed_packages():
    logger.debug("Listing installed packages.")
    notes = ""

    containers = _get_docker_ps()
    if not containers:
        reason = "No Docker containers found."
        return TestResult(Result.SKIP, reason)

    for line in containers:
        container_id = line.split(' ')

    for instance in container_id[0]:
        flavor = subprocess.check_output(['docker',
                                          'exec',
                                          instance,
                                          'cat',
                                          '/etc/issue'])
        if 'RH' in flavor:
            notes = subprocess.check_output(['docker',
                                             'exec',
                                             instance,
                                             'rpm',
                                             '-qa']).split('\n')
        elif 'DEB' in flavor:
            notes = subprocess.check_output(['docker',
                                             'exec',
                                             instance,
                                             'dpkg',
                                             '-l']).split('\n')
        else:
            reason = "Host is not RedHat or Debian family."
            return TestResult(Result.SKIP, reason)

    return TestResult(Result.PASS, notes)
예제 #14
0
def test_ulimit_default_override():
    logger.debug("Testing if the container is running in user namespace.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '{{ .Id }}: Ulimits={{ .HostConfig.Ulimits }}'

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(['docker',
                                            'inspect',
                                            '--format',
                                            testcmd,
                                            container_id])

            if '<no value>' in test:
                result = TestResult(Result.PASS)
            else:
                notes = ("Container " + str(container_id) + " is "
                         "running with default ulimits in place. ")
                result = TestResult(Result.FAIL, notes)

            results.add_result(check, result)
    return results
예제 #15
0
def test_log_level():
    logger.debug("Checking the Docker log level.")
    reason = "No Docker containers found."

    result = None

    # if --log-level is set in ps, else find config file and check there
    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if '--log-level=info' in entry:
            result = TestResult(Result.PASS)

        elif '--log-level=debug' in entry:
            reason = ("It is not recommended to run Docker in production "
                      "in debug mode.")
            result = TestResult(Result.FAIL, reason)

        else:
            notes = "Recommended Docker log level is 'info'."
            result = TestResult(Result.PASS, notes)

    return result
예제 #16
0
def test_mount_sensitive_directories():
    logger.debug("Testing if the container is running in user namespace.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '{{ .Id }}: Volumes={{ .Volumes }} VolumesRW={{ .VolumesRW }}'

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(
                ['docker', 'inspect', '--format', testcmd, container_id])

            if ':true' in test:
                notes = ("Container " + str(container_id) + " has "
                         "sensitive host system directories " + "mounted.")
                result = TestResult(Result.FAIL, notes)
            else:
                result = TestResult(Result.PASS)

            results.add_result(check, result)
    return results
예제 #17
0
def test_list_installed_packages():
    logger.debug("Listing installed packages.")
    notes = ""

    containers = _get_docker_ps()
    if not containers:
        reason = "No Docker containers found."
        return TestResult(Result.SKIP, reason)

    for line in containers:
        container_id = line.split(' ')

    for instance in container_id[0]:
        flavor = subprocess.check_output(
            ['docker', 'exec', instance, 'cat', '/etc/issue'])
        if 'RH' in flavor:
            notes = subprocess.check_output(
                ['docker', 'exec', instance, 'rpm', '-qa']).split('\n')
        elif 'DEB' in flavor:
            notes = subprocess.check_output(
                ['docker', 'exec', instance, 'dpkg', '-l']).split('\n')
        else:
            reason = "Host is not RedHat or Debian family."
            return TestResult(Result.SKIP, reason)

    return TestResult(Result.PASS, notes)
예제 #18
0
def _check_fortify(path):
    """Fortify Source - This introduces support for
    detecting buffer overflows in various functions that perform
    operations on memory and strings. The indicator for this is
    symbols such as __sprintf_chk rather then __sprintf. To compile
    an executable with fortify source enabled:
        $ gcc foo.c -D_FORTIFY_SOURCE=2 -O2
    """
    libc = _find_used_libc(path)
    if not libc:
        logger.debug('Unable to determine location of libc')
        return (False, Result.CONF_GUESS)

    fortified = set([])
    for addr, sym, name in _symbols_in_dynsym(libc):
        if sym in (b'T', b'i') and name.endswith(b'_chk'):
            fortified.add(name)
    plain = set(name[2:-4] for name in fortified)

    symbols = set([name for addr, sym, name in _symbols_in_dynsym(path)])
    if len(symbols.intersection(fortified)) > 0:
        return (True, Result.CONF_SURE)

    # if there are no functions to fortify, treat it the same as fortified
    if len(symbols.intersection(plain)) == 0:
        return (True, Result.CONF_SURE)

    # there may be a situation where a function is used on a buffer of unknown
    # size and cannot be fortified - or it may be just not fortified
    return (False, Result.CONF_GUESS)
예제 #19
0
def test_restart_policy():
    logger.debug("Testing if the container is running in user namespace.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '''{{ .Id }}: RestartPolicyName={{ .HostConfig.RestartPolicy.Name }}
    MaximumRetryCount={{ .HostConfig.RestartPolicy.MaximumRetryCount }}'''

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(['docker',
                                            'inspect',
                                            '--format',
                                            testcmd,
                                            container_id])
            try:
                entry = test.split(':')
                r = entry[1].split('=')
                restart_policy = r[1].split(" ")
                max_retry = r[2]
                policy = str(restart_policy[0])

            except IndexError:
                notes = ("Container: " + str(container_id) + "returns "
                         "a malformed restart policy value.")
                result = TestResult(Result.SKIP, notes)
            else:
                if 'no' in policy or policy == " ":
                    result = TestResult(Result.PASS)
                elif policy is None:
                    result = TestResult(Result.PASS)
                elif policy == 'always':
                    notes = ("Container " + str(container_id) + " will always "
                             "restart regardless of max retry count. This is "
                             " not recommended.")
                    result = TestResult(Result.FAIL, notes)
                elif policy == 'on-failure':
                    if int(max_retry) <= 5:
                        result = TestResult(Result.PASS)
                    else:
                        notes = ("Container " + str(container_id) + " max "
                                 "retry count set to a non-compliant level.")
                        result = TestResult(Result.FAIL, notes)
                else:
                    notes = ("Cannot test. Container " + str(container_id) +
                             " settings not returning an expected value.")
                    result = TestResult(Result.SKIP, notes)
                results.add_result(check, result)
    return results
예제 #20
0
def test_restart_policy():
    logger.debug("Testing if the container is running in user namespace.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '''{{ .Id }}: RestartPolicyName={{ .HostConfig.RestartPolicy.Name }}
    MaximumRetryCount={{ .HostConfig.RestartPolicy.MaximumRetryCount }}'''

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(
                ['docker', 'inspect', '--format', testcmd, container_id])
            try:
                entry = test.split(':')
                r = entry[1].split('=')
                restart_policy = r[1].split(" ")
                max_retry = r[2]
                policy = str(restart_policy[0])

            except IndexError:
                notes = ("Container: " + str(container_id) + "returns "
                         "a malformed restart policy value.")
                result = TestResult(Result.SKIP, notes)
            else:
                if 'no' in policy or policy == " ":
                    result = TestResult(Result.PASS)
                elif policy is None:
                    result = TestResult(Result.PASS)
                elif policy == 'always':
                    notes = ("Container " + str(container_id) + " will always "
                             "restart regardless of max retry count. This is "
                             " not recommended.")
                    result = TestResult(Result.FAIL, notes)
                elif policy == 'on-failure':
                    if int(max_retry) <= 5:
                        result = TestResult(Result.PASS)
                    else:
                        notes = ("Container " + str(container_id) + " max "
                                 "retry count set to a non-compliant level.")
                        result = TestResult(Result.FAIL, notes)
                else:
                    notes = ("Cannot test. Container " + str(container_id) +
                             " settings not returning an expected value.")
                    result = TestResult(Result.SKIP, notes)
                results.add_result(check, result)
    return results
예제 #21
0
def test_devmem():
    # initial configurations
    reason = " "
    logger.debug("Attempting to validate /dev/mem protection.")
    result = Result.FAIL  # set fail by default?

    # check kernel config - CONFIG_STRICT_DEVMEM=y
    try:
        devmem_val = utils.kconfig_option('CONFIG_STRICT_DEVMEM')

        if devmem_val == 'y':
            reason = "/dev/mem protection is enabled."
            logger.debug(reason)
            result = Result.PASS
        elif devmem_val == 'n':
            reason = "/dev/mem protection is not enabled."
            logger.debug(reason)
            result = Result.FAIL
        else:
            result = Result.SKIP
            reason = "Cannot find the kernel config or option"

    except IOError as e:
        reason = "Error opening /proc/config.gz."
        logger.debug("Unable to open /proc/config.gz.\n"
                     "    Exception information: [ {} ]".format(e))
        result = Result.SKIP

    return TestResult(result, reason)
예제 #22
0
def test_storage_driver():
    logger.debug("Checking storage driver.")
    notes = "No Docker containers found."

    driver = _parse_colon_delim(list, key='Storage Driver')

    if driver:
        if 'aufs' in driver:
            notes = "Storage driver set to insecure aufs."
            return TestResult(Result.FAIL, notes)
        else:
            return TestResult(Result.PASS)
    else:
        # empty driver, odd failure
        return TestResult(Result.SKIP, notes)
예제 #23
0
def test_storage_driver():
    logger.debug("Checking storage driver.")
    notes = "No Docker containers found."

    driver = _parse_colon_delim(list, key='Storage Driver')

    if driver:
        if 'aufs' in driver:
            notes = "Storage driver set to insecure aufs."
            return TestResult(Result.FAIL, notes)
        else:
            return TestResult(Result.PASS)
    else:
        # empty driver, odd failure
        return TestResult(Result.SKIP, notes)
예제 #24
0
def test_traffic():
    logger.debug("Testing for restricted traffic between containers.")

    dockers = _get_main_docker_processes()
    if not dockers:
        return TestResult(Result.SKIP, "Docker is not running.")

    results = GroupTestResult()
    for pid, cmdline in dockers:
        if '--icc=false' in cmdline:
            results.add_result("pid %s" % pid, TestResult(Result.PASS))
        else:
            reason = "Direct communication between containers is enabled."
            results.add_result("pid %s" % pid, TestResult(Result.FAIL, reason))

    return results
예제 #25
0
def test_cpu_priority():
    logger.debug("Testing if the container has memory limitations.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '{{ .Id }}: CpuShares={{ .Config.CpuShares }}'

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(['docker',
                                            'inspect',
                                            '--format',
                                            testcmd,
                                            container_id])
            cpu_test = test.split(':')
            try:
                cpu_return = cpu_test[1].strip('\n')
            except IndexError:
                notes = ("Container: " + str(container_id) + "returns "
                         "a malformed CPU share value.")
                result = TestResult(Result.SKIP, notes)
            else:
                if '<no value>' not in cpu_return:
                    notes = ("Container " + str(container_id) + " is running "
                             "with no value given for CPU share limitations.")
                    result = TestResult(Result.FAIL, notes)
                elif not cpu_return:
                    notes = ("Container " + str(container_id) + " is running "
                             "with no value given for CPU share limitations.")
                    result = TestResult(Result.SKIP, notes)
                elif int(cpu_return) == 0 or int(cpu_return) == 1024:
                    notes = ("Container " + str(container_id) + " do not have "
                             "CPU shares in place.")
                    result = TestResult(Result.FAIL, notes)
                else:
                    result = TestResult(Result.PASS)
            results.add_result(check, result)
    return results
예제 #26
0
def test_storage_driver():
    logger.debug("Checking storage driver.")

    info = _get_docker_info()
    if not info:
        return TestResult(Result.SKIP, "Cannot get docker info.")
    driver = [l for l in info.splitlines() if l.startswith(b'Storage Driver:')]

    if driver:
        if b'aufs' in driver[0]:
            notes = "Storage driver set to insecure aufs."
            return TestResult(Result.FAIL, notes)
        else:
            return TestResult(Result.PASS)
    else:
        # empty driver, odd failure
        return TestResult(Result.SKIP, "Cannot find storage driver")
예제 #27
0
def test_iptables():
    logger.debug("Checking the firewall settings.")

    dockers = _get_main_docker_processes()
    if not dockers:
        return TestResult(Result.SKIP, "Docker is not running.")

    results = GroupTestResult()
    for pid, cmdline in dockers:
        if '--iptables=false' in cmdline:
            reason = ("The iptables firewall is enabled on a per-container "
                      "basis and will need to be maintained by the user.")
            results.add_result("pid %s" % pid, TestResult(Result.FAIL, reason))
        else:
            results.add_result("pid %s" % pid, TestResult(Result.PASS))

    return results
예제 #28
0
def test_insecure_registries():
    logger.debug("Testing for insecure registries.")

    dockers = _get_main_docker_processes()
    if not dockers:
        return TestResult(Result.SKIP, "Docker is not running.")

    results = GroupTestResult()
    for pid, cmdline in dockers:
        if '--insecure-registry' in cmdline:
            reason = ("A registry was specified with the --insecure-registry "
                      "flag.")
            results.add_result("pid %s" % pid, TestResult(Result.FAIL, reason))
        else:
            results.add_result("pid %s" % pid, TestResult(Result.PASS))

    return results
예제 #29
0
def test_memory_limit():
    logger.debug("Testing if the container has memory limitations.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(['docker',
                                            'inspect',
                                            '--format',
                                            '{{.ID}}:{{.Config.Memory}}',
                                            container_id])
            mem_test = test.split(':')
            try:
                memory = mem_test[1].strip('\n')
            except IndexError:
                notes = ("Container: " + str(container_id) + "returns "
                         "a malformed memory value.")
                result = TestResult(Result.SKIP, notes)
            else:
                if memory == '<no value>':
                    notes = ("Container " + str(container_id) + " is running "
                             "with no value given for memory limitations.")
                    result = TestResult(Result.FAIL, notes)
                elif memory is None:
                    notes = ("Container " + str(container_id) + " is running "
                             "without memory limitations.")
                    result = TestResult(Result.FAIL, notes)
                elif int(memory) <= 0:
                    notes = ("Container " + str(container_id) + " is running "
                             "without memory limitations.")
                    result = TestResult(Result.FAIL, notes)
                else:
                    result = TestResult(Result.PASS)
            results.add_result(check, result)
    return results
예제 #30
0
def test_iptables():
    logger.debug("Checking the firewall settings.")
    reason = "No Docker containers found."

    result = None

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")
    for entry in docker_ps:
        if '--iptables=false' in entry:
            result = TestResult(Result.PASS)
        else:
            reason = ("The iptables firewall is enabled on a per-container "
                      "basis and will need to be maintained by the user.")
            result = TestResult(Result.FAIL, reason)

    return result
예제 #31
0
def test_traffic():
    logger.debug("Testing for restricted traffic between containers.")
    reason = "No Docker containers found."

    result = None

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if '--icc=false' in entry:
            result = TestResult(Result.PASS)
        else:
            reason = "Direct communication between containers is enabled."
            result = TestResult(Result.FAIL, reason)

    return result
예제 #32
0
def test_no_lxc():
    logger.debug("Testing if the container is running in LXC memory.")
    reason = "No Docker containers found."

    result = None

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if 'lxc' in entry:
            reason = "LXC in ps output."
            result = TestResult(Result.FAIL, reason)
        else:
            result = TestResult(Result.PASS)

    return result
예제 #33
0
def test_no_lxc():
    logger.debug("Testing if the container is running in LXC memory.")
    reason = "No Docker containers found."

    docker_ps = _get_main_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    results = GroupTestResult()

    for pid, cmdline in docker_ps:
        if b'lxc' in cmdline:
            reason = "LXC in ps output."
            results.add_result("pid %s" % pid, TestResult(Result.FAIL, reason))
        else:
            results.add_result("pid %s" % pid, TestResult(Result.PASS))

    return results
예제 #34
0
def test_traffic():
    logger.debug("Testing for restricted traffic between containers.")
    reason = "No Docker containers found."

    result = None

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if '--icc=false' in entry:
            result = TestResult(Result.PASS)
        else:
            reason = "Direct communication between containers is enabled."
            result = TestResult(Result.FAIL, reason)

    return result
예제 #35
0
def test_iptables():
    logger.debug("Checking the firewall settings.")
    reason = "No Docker containers found."

    result = None

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")
    for entry in docker_ps:
        if '--iptables=false' in entry:
            result = TestResult(Result.PASS)
        else:
            reason = ("The iptables firewall is enabled on a per-container "
                      "basis and will need to be maintained by the user.")
            result = TestResult(Result.FAIL, reason)

    return result
예제 #36
0
def test_no_lxc():
    logger.debug("Testing if the container is running in LXC memory.")
    reason = "No Docker containers found."

    result = None

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if 'lxc' in entry:
            reason = "LXC in ps output."
            result = TestResult(Result.FAIL, reason)
        else:
            result = TestResult(Result.PASS)

    return result
예제 #37
0
def test_privilege_port_mapping():
    logger.debug("Testing if the container has memory limitations.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(['docker',
                                            'port',
                                            container_id])
            pn = test.split(':')
            try:
                port_number = str(pn[1])
            except IndexError:
                notes = ("Container: " + str(container_id) + "returns "
                         "a malformed port number value.")
                result = TestResult(Result.SKIP, notes)
            else:
                if int(port_number) <= 1024:
                    notes = ("Container " + str(container_id) + " is running "
                             "privileged port number - " + str(port_number) +
                             ".")
                    result = TestResult(Result.FAIL, notes)
                elif port_number == '':
                    notes = ("Container " + str(container_id) + " does not"
                             "have a port number assigned.")
                    result = TestResult(Result.FAIL, notes)
                elif port_number is None:
                    notes = ("Container " + str(container_id) + " does not"
                             "have a port number assigned.")
                    result = TestResult(Result.FAIL, notes)
                else:
                    result = TestResult(Result.PASS)
            results.add_result(check, result)
    return results
예제 #38
0
def test_cpu_priority():
    logger.debug("Testing if the container has memory limitations.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    testcmd = '{{ .Id }}: CpuShares={{ .Config.CpuShares }}'

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(
                ['docker', 'inspect', '--format', testcmd, container_id])
            cpu_test = test.split(':')
            try:
                cpu_return = cpu_test[1].strip('\n')
            except IndexError:
                notes = ("Container: " + str(container_id) + "returns "
                         "a malformed CPU share value.")
                result = TestResult(Result.SKIP, notes)
            else:
                if '<no value>' not in cpu_return:
                    notes = ("Container " + str(container_id) + " is running "
                             "with no value given for CPU share limitations.")
                    result = TestResult(Result.FAIL, notes)
                elif not cpu_return:
                    notes = ("Container " + str(container_id) + " is running "
                             "with no value given for CPU share limitations.")
                    result = TestResult(Result.SKIP, notes)
                elif int(cpu_return) == 0 or int(cpu_return) == 1024:
                    notes = ("Container " + str(container_id) + " do not have "
                             "CPU shares in place.")
                    result = TestResult(Result.FAIL, notes)
                else:
                    result = TestResult(Result.PASS)
            results.add_result(check, result)
    return results
예제 #39
0
def test_memory_limit():
    logger.debug("Testing if the container has memory limitations.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output([
                'docker', 'inspect', '--format', '{{.ID}}:{{.Config.Memory}}',
                container_id
            ])
            mem_test = test.split(':')
            try:
                memory = mem_test[1].strip('\n')
            except IndexError:
                notes = ("Container: " + str(container_id) + "returns "
                         "a malformed memory value.")
                result = TestResult(Result.SKIP, notes)
            else:
                if memory == '<no value>':
                    notes = ("Container " + str(container_id) + " is running "
                             "with no value given for memory limitations.")
                    result = TestResult(Result.FAIL, notes)
                elif memory is None:
                    notes = ("Container " + str(container_id) + " is running "
                             "without memory limitations.")
                    result = TestResult(Result.FAIL, notes)
                elif int(memory) <= 0:
                    notes = ("Container " + str(container_id) + " is running "
                             "without memory limitations.")
                    result = TestResult(Result.FAIL, notes)
                else:
                    result = TestResult(Result.PASS)
            results.add_result(check, result)
    return results
예제 #40
0
def test_port_binding():
    logger.debug("Testing for insecure registries.")
    reason = "No Docker containers found."

    result = None

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if '-H' in entry:
            reason = ("A container is binding to a specific interface "
                      "or port.")
            result = TestResult(Result.FAIL, reason)
        else:
            result = TestResult(Result.PASS)

    return result
예제 #41
0
def test_secure_communication():
    # TODO: check if there is a 'well known' HDP container that either
    # acts as an intermediate CA (for --tlscacert option), or a server
    # that clients connect to securely (for --tlscert and tlskey), and
    # if so, break them into separate tests for better profile coverage

    logger.debug("Testing for insecure registries.")
    reason = "No Docker containers found."

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if '--tlsverify' in entry:
            if '--tlscert' in entry:
                if '--tlskey' in entry:
                    if '--tlscacert' in entry:
                        reason = ("Container set to validate certificates, "
                                  "has both certificate and key in place, "
                                  "and can act as an intermediate CA.")
                        logger.info(reason)
                    else:
                        reason = ("No CA certificate, container cannot act "
                                  "as intermediate CA.")
                        logger.info(reason)
                else:
                    reason = ("A public Certificate exists, but key does not."
                              " Communciation unable to be decrypted.")
                    logger.info(reason)

            else:
                reason = ("No certificate available, container will only be"
                          " able to act as client and accept server cert.")

        else:
            reason = "Docker is not configured to validate certificates."
            result = TestResult(Result.FAIL, reason)
            return result

    result = TestResult(Result.PASS)

    return result
예제 #42
0
def test_insecure_registries():
    logger.debug("Testing for insecure registries.")
    reason = "No Docker containers found."

    result = None

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if '--insecure-registry' in entry:
            reason = ("A registry was specified with the --insecure-registry "
                      "flag.")
            result = TestResult(Result.FAIL, reason)
        else:
            result = TestResult(Result.PASS)

    return result
예제 #43
0
def test_insecure_registries():
    logger.debug("Testing for insecure registries.")
    reason = "No Docker containers found."

    result = None

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if '--insecure-registry' in entry:
            reason = ("A registry was specified with the --insecure-registry "
                      "flag.")
            result = TestResult(Result.FAIL, reason)
        else:
            result = TestResult(Result.PASS)

    return result
예제 #44
0
def test_port_binding():
    logger.debug("Testing for insecure registries.")
    reason = "No Docker containers found."

    result = None

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if '-H' in entry:
            reason = ("A container is binding to a specific interface "
                      "or port.")
            result = TestResult(Result.FAIL, reason)
        else:
            result = TestResult(Result.PASS)

    return result
예제 #45
0
def test_secure_communication():
    # TODO: check if there is a 'well known' HDP container that either
    # acts as an intermediate CA (for --tlscacert option), or a server
    # that clients connect to securely (for --tlscert and tlskey), and
    # if so, break them into separate tests for better profile coverage

    logger.debug("Testing for insecure registries.")
    reason = "No Docker containers found."

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if '--tlsverify' in entry:
            if '--tlscert' in entry:
                if '--tlskey' in entry:
                    if '--tlscacert' in entry:
                        reason = ("Container set to validate certificates, "
                                  "has both certificate and key in place, "
                                  "and can act as an intermediate CA.")
                        logger.info(reason)
                    else:
                        reason = ("No CA certificate, container cannot act "
                                  "as intermediate CA.")
                        logger.info(reason)
                else:
                    reason = ("A public Certificate exists, but key does not."
                              " Communciation unable to be decrypted.")
                    logger.info(reason)

            else:
                reason = ("No certificate available, container will only be"
                          " able to act as client and accept server cert.")

        else:
            reason = "Docker is not configured to validate certificates."
            result = TestResult(Result.FAIL, reason)
            return result

    result = TestResult(Result.PASS)

    return result
예제 #46
0
def test_privilege_port_mapping():
    logger.debug("Testing if the container has memory limitations.")
    notes = "No Docker containers found or docker is not running."

    results = GroupTestResult()

    containers = _get_docker_container()

    if not containers:
        return TestResult(Result.SKIP, notes)

    for container_id in containers:
        if container_id == '':
            pass
        else:
            check = "Checking container: " + str(container_id)
            test = subprocess.check_output(['docker', 'port', container_id])
            pn = test.split(':')
            try:
                port_number = str(pn[1])
            except IndexError:
                notes = ("Container: " + str(container_id) + "returns "
                         "a malformed port number value.")
                result = TestResult(Result.SKIP, notes)
            else:
                if int(port_number) <= 1024:
                    notes = ("Container " + str(container_id) + " is running "
                             "privileged port number - " + str(port_number) +
                             ".")
                    result = TestResult(Result.FAIL, notes)
                elif port_number == '':
                    notes = ("Container " + str(container_id) + " does not"
                             "have a port number assigned.")
                    result = TestResult(Result.FAIL, notes)
                elif port_number is None:
                    notes = ("Container " + str(container_id) + " does not"
                             "have a port number assigned.")
                    result = TestResult(Result.FAIL, notes)
                else:
                    result = TestResult(Result.PASS)
            results.add_result(check, result)
    return results
예제 #47
0
def test_docker_daemon():
    logger.debug("Checking auditing on the Docker daemon.")
    note = "Test is invalid for newer kernels."

    kernel = tuple(int(x) for x in os.uname()[2].split('.')[:2])
    if kernel >= (3, 12):
        return TestResult(Result.SKIP, note)

    try:
        subprocess.check_output(['which', 'auditctl'])
    except subprocess.CalledProcessError:
        note = "The auditctl command is not installed."
        return TestResult(Result.SKIP, note)

    audit = subprocess.check_output(['auditctl', '-l'])
    if b'/usr/bin/docker' in audit:
        return TestResult(Result.PASS)
    else:
        note = "/usr/bin/docker is not being tracked in auditctl."
        return TestResult(Result.FAIL, note)
예제 #48
0
def test_shellshock(config):
    logger.debug("Testing shell for 'shellshock/bashbug' vulnerability.")

    try:
        cmd = config['exploit_command']
    except KeyError:
        logger.error("Can't find exploit command for shellshock test")
    else:

        p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
        stdout, stderr = p.communicate()

        if b'vulnerable' in stdout:
            reason = "System is vulnerable to Shellshock/Bashbug."
            logger.info(reason)
            result = Result.FAIL
        else:
            reason = "System is not vulnerable to Shellshock/Bashbug."
            logger.info(reason)
            result = Result.PASS
        return TestResult(result, reason)
예제 #49
0
def test_shellshock(config):
    logger.debug("Testing shell for 'shellshock/bashbug' vulnerability.")

    try:
        cmd = config['exploit_command']
    except KeyError:
        logger.error("Can't find exploit command for shellshock test")
    else:

        p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
        stdout, stderr = p.communicate()

        if b'vulnerable' in stdout:
            reason = "System is vulnerable to Shellshock/Bashbug."
            logger.info(reason)
            result = Result.FAIL
        else:
            reason = "System is not vulnerable to Shellshock/Bashbug."
            logger.info(reason)
            result = Result.PASS
        return TestResult(result, reason)
예제 #50
0
def test_certs():
    logger.debug("Testing bundled certificate validity & expiration.")

    certList = []
    certStore = '/etc/ssl/certs'
    result = None
    notes = ""

    # use utils to get list of certificates
    certList = utils.get_files_list_from_dir(certStore)

    if certList is None:
        notes = "/etc/ssl/certs is empty, please check on-system certificates."
        logger.debug(notes)
        result = Result.SKIP
        return TestResult(result, notes)

    for cert in certList:
        try:
            p = Popen(['openssl', 'verify', cert], stdout=PIPE, shell=False)
            stdout = p.communicate()
            if b"OK" in stdout[0]:
                logger.debug("Certificate verification success for: %s", cert)
                if result is None:
                    result = Result.PASS
            else:
                result = Result.FAIL
                if notes is "":
                    notes += "Error validating certificate: " + cert
                else:
                    notes += ", " + cert
                logger.debug("Certificate verification failure for: %s", cert)

        except ValueError:
            logger.exception("Error running 'openssl verify %s'", cert)
            result = Result.SKIP

    logger.debug("Completed on-system certificate validation tests.")
    return TestResult(result, notes)
예제 #51
0
def test_certs():
    logger.debug("Testing bundled certificate validity & expiration.")

    certList = []
    certStore = '/etc/ssl/certs'
    result = None
    notes = ""

    # use utils to get list of certificates
    certList = utils.get_files_list_from_dir(certStore)

    if certList is None:
        notes = "/etc/ssl/certs is empty, please check on-system certificates."
        logger.debug(notes)
        result = Result.SKIP
        return TestResult(result, notes)

    for cert in certList:
        try:
            p = Popen(['openssl', 'verify', cert], stdout=PIPE, shell=False)
            stdout = p.communicate()
            if b"OK" in stdout[0]:
                logger.debug("Certificate verification success for: %s", cert)
                if result is None:
                    result = Result.PASS
            else:
                result = Result.FAIL
                if notes is "":
                    notes += "Error validating certificate: " + cert
                else:
                    notes += ", " + cert
                logger.debug("Certificate verification failure for: %s", cert)

        except ValueError:
            logger.exception("Error running 'openssl verify %s'", cert)
            result = Result.SKIP

    logger.debug("Completed on-system certificate validation tests.")
    return TestResult(result, notes)
예제 #52
0
def test_docker_daemon():
    logger.debug("Checking auditing on the Docker daemon.")
    note = "Test is invalid for newer kernels."

    kernel = os.uname()[2].split('.')
    major_version = kernel[0]
    minor_version = int(kernel[1])
    if "3" in major_version:
        if minor_version >= 12:
            return TestResult(Result.SKIP, note)

    try:
        subprocess.check_output(['which', 'auditctl'])
    except OSError:
        note = "The auditctl command is not installed."
        return TestResult(Result.SKIP, note)

    audit = subprocess.check_output(['auditctl', '-l'])
    if '/usr/bin/docker' in audit:
        return TestResult(Result.PASS)
    else:
        note = "/usr/bin/docker is not being tracked in auditctl."
        return TestResult(Result.FAIL, note)
예제 #53
0
def test_log_level():
    logger.debug("Checking the Docker log level.")

    # if --log-level is set in ps, else find config file and check there
    dockers = _get_main_docker_processes()
    if not dockers:
        return TestResult(Result.SKIP, "Docker is not running.")

    results = GroupTestResult()
    for pid, cmdline in dockers:
        if '--log-level=info' in cmdline:
            results.add_result("pid %s" % pid, TestResult(Result.PASS))

        elif '--log-level=debug' in cmdline:
            reason = ("It is not recommended to run Docker in production "
                      "in debug mode.")
            results.add_result("pid %s" % pid, TestResult(Result.FAIL, reason))

        else:
            notes = "Recommended Docker log level is 'info'."
            results.add_result("pid %s" % pid, TestResult(Result.PASS, notes))

    return results
예제 #54
0
def test_user_owned():
    logger.debug("Testing if the container is running in user namespace.")
    reason = "No Docker containers found."

    containers = _get_docker_ps()
    if not containers:
        return TestResult(Result.SKIP, reason)

    for line in containers:
        container_id = line.split(' ')

    for instance in container_id[0]:
        results = subprocess.check_output(['docker',
                                           'inspect',
                                           '--format',
                                           '{{.ID}}:{{.Config.User}}',
                                           instance])
        container_id = results.split(':')
        if container_id[1] is None:
            reason = ("Container " + str(container_id[0]) + " is running in "
                      "root namespace.")
            return TestResult(Result.FAIL, reason)
        else:
            return TestResult(Result.PASS)
예제 #55
0
def test_apparmor():
    """Uses return from apparmor_status to check installation and level
    at which AppArmor is monitoring.

    :returns: A TestResult object containing the result and notes
    explaining why it did not pass.
    """

    # initial configurations
    return_result = None
    logger.debug("Attempting to validate AppArmor is installed.")

    # check
    try:
        cmd = 'apparmor_status'
        p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
        stdout, stderr = p.communicate()

        if b'apparmor_status: command not found' in stderr:
            reason = "AppArmor is not installed."
            logger.debug(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        # enforcing check, no /'s = no directories
        elif b"//" not in stdout:
            reason = "AppArmor has no modules loaded."
            logger.info(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        elif b"//" in stdout:
            reason = "AppArmor is installed and policy is loaded."
            logger.info(reason)
            return_result = TestResult(Result.PASS)
        else:
            # wth?
            logger.debug("Unexpected error while looking for AppArmor: "
                         "    Standard Output from sestatus command: [%s]"
                         "    Standard Error from sestatus command: [%s]",
                         stdout, stderr)
            return_result = TestResult(Result.SKIP, notes="Unexpected error.")

    except EnvironmentError as e:
        logger.debug("Unexpected error running apparmor_status: [%s]", e)
        return_result = TestResult(Result.SKIP, notes="Unexpected error.")

    return return_result
예제 #56
0
def _get_login_defs_config():
    config = {}

    try:
        with open('/etc/login.defs', 'r') as f:
            for line in f:
                line = line.strip()

                if not line:
                    continue
                if line.startswith('#'):
                    continue

                try:
                    key, val = line.split()
                    config[key] = val
                except ValueError:
                    logger.debug("could not parse '%s'", line)
                    continue
    except EnvironmentError:
        logger.warning("cannot read the login.defs config")
        return None

    return config
예제 #57
0
def test_selinux():
    """Uses return from sestatus command to ensure SELinux is installed

    :returns: A TestResult object containing the result and, on failure,
    notes explaining why it did not pass.
    """

    # logger
    return_result = None
    logger.debug("Attempting to validate SELinux is installed.")

    # check
    try:
        # if sestatus_return is stdout:
        cmd = 'sestatus'
        p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
        stdout, stderr = p.communicate()

        if b'sestatus: not found' in stderr:
            reason = "SELinux is not installed."
            logger.info(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        elif b'disabled' in stdout:
            reason = "SELinux is disabled."
            logger.info(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        elif b'permissive' in stdout:
            reason = "SELinux is permissive (disabled but logging)."
            logger.info(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        elif b'enforcing' in stdout:
            reason = "SELinux is installed and enforcing."
            logger.info(reason)
            return_result = TestResult(Result.PASS)

        else:
            # wth?
            logger.debug("Unexpected error while looking for SELinux: "
                         "    Standard Output from sestatus command: [%s]"
                         "    Standard Error from sestatus command: [%s]",
                         stdout, stderr)
            return_result = TestResult(Result.SKIP, notes="Unexpected error.")

    except EnvironmentError as e:
        # log no selinux
        logger.debug("Unexpected error running sestatus: [{}]".format(e))
        return_result = TestResult(Result.SKIP, notes="Unexpected error.")

    return return_result