1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
#!/usr/bin/python3
import sys
import os
import argparse
import json
from ssg.build_cpe import ProductCPEs
import ssg.build_profile
import ssg.build_yaml
import ssg.controls
import ssg.environment
import ssg.products
import ssg.rules
import ssg.rule_yaml
import ssg.yaml
import ssg.utils
SSG_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
RULES_JSON = os.path.join(SSG_ROOT, "build", "rule_dirs.json")
BUILD_CONFIG = os.path.join(SSG_ROOT, "build", "build_config.yml")
CONTROLS_DIR = os.path.join(SSG_ROOT, "controls")
def parse_args():
parser = argparse.ArgumentParser(description="Check all rule.yml referenced in a given"
"profile for a required reference identifier")
parser.add_argument("-j", "--json", type=str, action="store",
default=RULES_JSON, help="File to read "
"json output of rule_dir_json from (defaults to "
"build/rule_dirs.json")
parser.add_argument("-c", "--build-config-yaml", default=BUILD_CONFIG,
help="YAML file with information about the build configuration. "
"Defaults to build/build_config.yml")
parser.add_argument("--controls", default=CONTROLS_DIR,
help="Directory that contains control files with policy controls.")
parser.add_argument("-p", "--profiles-root",
help="Override where to look for profile files.")
parser.add_argument("product", type=str,
help="Product to check has required references")
parser.add_argument("profile", type=str, help="Profile to iterate over")
parser.add_argument("reference", type=str,
help="Required reference system to check for")
parser.add_argument("--exclude", "-e", type=str,
help="A comma separated list of rules to be ignored")
return parser.parse_args()
def load(rule_obj, env_yaml=None):
"""
From the given rule_dir object, load the build_yaml.Rule associated with
it.
"""
yaml_file = ssg.rules.get_rule_dir_yaml(rule_obj['dir'])
return ssg.build_yaml.Rule.from_yaml(yaml_file, env_yaml=env_yaml)
def load_for_product(rule_obj, product, env_yaml=None):
"""
From the given rule_dir object, load the build_yaml.Rule associated with
it, normalizing for the given product.
"""
rule = load(rule_obj, env_yaml=env_yaml)
rule.normalize(product)
return rule
def _process_controls_manager(controls_manager, env_yaml, product_yaml, profile, rule_dirs):
product_cpes = ProductCPEs()
product_cpes.load_product_cpes(env_yaml)
product_cpes.load_content_cpes(env_yaml)
if controls_manager:
profile_files = ssg.products.get_profile_files_from_root(env_yaml, product_yaml)
all_profiles = ssg.build_profile.make_name_to_profile_mapping(profile_files, env_yaml,
product_cpes)
profile.resolve(all_profiles, rule_dirs, controls_manager)
def _process_excludes(excludes):
if not excludes or excludes == '':
return list()
result = list()
if ',' not in excludes:
result.append(excludes)
return result
for item in excludes.split(','):
result.append(item.strip())
return result
def reference_check(env_yaml, rule_dirs, profile_path, product, product_yaml, reference,
excludes, controls_manager=None):
profile = ssg.build_yaml.ProfileWithInlinePolicies.from_yaml(profile_path, env_yaml)
_process_controls_manager(controls_manager, env_yaml, product_yaml, profile, rule_dirs)
ok = True
processed_excludes = _process_excludes(excludes)
for rule_id in profile.selected + profile.unselected:
if rule_id not in rule_dirs:
msg = "Unable to find rule in rule_dirs.json: {0}"
msg = msg.format(rule_id)
raise ValueError(msg)
rule = load_for_product(rule_dirs[rule_id], product, env_yaml=env_yaml)
if rule_id in processed_excludes:
continue
if reference not in rule.references:
ok = False
msg = "Rule {0} lacks required reference {1} or {1}@{2}"
msg = msg.format(rule_id, reference, product)
print(msg, file=sys.stderr)
return ok
def main():
args = parse_args()
json_file = open(args.json, 'r')
all_rules = json.load(json_file)
linux_products, other_products = ssg.products.get_all(SSG_ROOT)
all_products = linux_products.union(other_products)
if args.product not in all_products:
msg = "Unknown product {0}: check SSG_ROOT and try again"
msg = msg.format(args.product)
raise ValueError(msg)
product_base = os.path.join(SSG_ROOT, "products", args.product)
product_yaml_path = os.path.join(product_base, "product.yml")
product_yaml = ssg.products.Product(product_yaml_path)
env_yaml = ssg.environment.open_environment(
args.build_config_yaml, product_yaml_path, os.path.join(SSG_ROOT, "product_properties"))
controls_manager = None
if os.path.exists(args.controls):
controls_manager = ssg.controls.ControlsManager(args.controls, env_yaml)
controls_manager.load()
profiles_root = os.path.join(product_base, "profiles")
if args.profiles_root:
profiles_root = args.profiles_root
profile_filename = args.profile + ".profile"
profile_path = os.path.join(profiles_root, profile_filename)
if not os.path.exists(profile_path):
msg = "Unknown profile {0}: check profile, --profiles-root, and try again. "
msg += "Note that the '.profile' suffix shouldn't be included."
msg = msg.format(args.profile)
raise ValueError(msg)
ok = reference_check(env_yaml, all_rules, profile_path, args.product, product_yaml,
args.reference, args.exclude, controls_manager)
if not ok:
sys.exit(1)
if __name__ == "__main__":
main()
|