mirror of
https://github.com/usnistgov/macos_security.git
synced 2026-03-19 23:12:15 +00:00
Merge branch 'dev_mont_omg' into monterey
This commit is contained in:
@@ -7,6 +7,7 @@ authors: |
|
||||
|Dan Brodjieski|National Aeronautics and Space Administration
|
||||
|Allen Golbig|Jamf
|
||||
|===
|
||||
parent_values: recommended
|
||||
profile:
|
||||
- section: "authentication"
|
||||
rules:
|
||||
|
||||
@@ -7,6 +7,7 @@ authors: |
|
||||
|Dan Brodjieski|National Aeronautics and Space Administration
|
||||
|Allen Golbig|Jamf
|
||||
|===
|
||||
parent_values: recommended
|
||||
profile:
|
||||
- section: "authentication"
|
||||
rules:
|
||||
|
||||
@@ -7,6 +7,7 @@ authors: |
|
||||
|Dan Brodjieski|National Aeronautics and Space Administration
|
||||
|Allen Golbig|Jamf
|
||||
|===
|
||||
parent_values: recommended
|
||||
profile:
|
||||
- section: "authentication"
|
||||
rules:
|
||||
|
||||
@@ -7,6 +7,7 @@ authors: |
|
||||
|Dan Brodjieski|National Aeronautics and Space Administration
|
||||
|Allen Golbig|Jamf
|
||||
|===
|
||||
parent_values: recommended
|
||||
profile:
|
||||
- section: "authentication"
|
||||
rules:
|
||||
|
||||
@@ -7,6 +7,7 @@ authors: |
|
||||
|Allen Golbig|Jamf
|
||||
|Bob Gendler|National Institute of Standards and Technology
|
||||
|===
|
||||
parent_values: stig
|
||||
profile:
|
||||
- section: "authentication"
|
||||
rules:
|
||||
|
||||
@@ -7,6 +7,7 @@ authors: |
|
||||
|Dan Brodjieski|National Aeronautics and Space Administration
|
||||
|Allen Golbig|Jamf
|
||||
|===
|
||||
parent_values: recommended
|
||||
profile:
|
||||
- section: "authentication"
|
||||
rules:
|
||||
|
||||
@@ -8,6 +8,7 @@ authors: |
|
||||
|Ron Colvin|Center for Internet Security
|
||||
|Allen Golbig|Jamf
|
||||
|===
|
||||
parent_values: cis_lvl1
|
||||
profile:
|
||||
- section: "auditing"
|
||||
rules:
|
||||
|
||||
@@ -8,6 +8,7 @@ authors: |
|
||||
|Ron Colvin|Center for Internet Security
|
||||
|Allen Golbig|Jamf
|
||||
|===
|
||||
parent_values: cis_lvl2
|
||||
profile:
|
||||
- section: "auditing"
|
||||
rules:
|
||||
|
||||
@@ -9,6 +9,7 @@ authors: |
|
||||
|Dan Brodjieski|National Aeronautics and Space Administration
|
||||
|Allen Golbig|Jamf
|
||||
|===
|
||||
parent_values: recommended
|
||||
profile:
|
||||
- section: "authentication"
|
||||
rules:
|
||||
|
||||
@@ -30,7 +30,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Percentage of free space."
|
||||
default: 25
|
||||
recommended: 25
|
||||
stig: 25
|
||||
tags:
|
||||
- 800-53r5_high
|
||||
|
||||
@@ -38,7 +38,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "See man audit_control for possible values."
|
||||
default: 7d
|
||||
recommended: 7d
|
||||
stig: 7d
|
||||
cis_lvl1: 60d or 1G
|
||||
cis_lvl2: 60d or 1G
|
||||
|
||||
@@ -40,7 +40,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of days."
|
||||
default: 365
|
||||
recommended: 365
|
||||
cis_lvl1: 365
|
||||
cis_lvl2: 365
|
||||
tags:
|
||||
|
||||
@@ -10,10 +10,7 @@ check: |
|
||||
result:
|
||||
string: "false"
|
||||
fix: |
|
||||
[source,bash]
|
||||
----
|
||||
This is implemented by a Configuration Profile.
|
||||
----
|
||||
references:
|
||||
cce:
|
||||
- CCE-91108-1
|
||||
|
||||
@@ -56,7 +56,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Organization's Policy Text"
|
||||
default: |-
|
||||
recommended: |-
|
||||
You are accessing a U.S. Government information system, which includes: 1) this computer, 2) this computer network, 3) all Government-furnished computers connected to this network, and 4) all Government-furnished devices and storage media attached to this network or to a computer on this network. You understand and consent to the following: you may access this information system for authorized use only; unauthorized use of the system is prohibited and subject to criminal and civil penalties; you have no reasonable expectation of privacy regarding any communication or data transiting or stored on this information system at any time and for any lawful Government purpose, the Government may monitor, intercept, audit, and search and seize any communication or data transiting or stored on this information system; and any communications or data transiting or stored on this information system may be disclosed or used for any lawful Government purpose. This information system may contain Controlled Unclassified Information (CUI) that is subject to safeguarding or dissemination controls in accordance with law, regulation, or Government-wide policy. Accessing and using this system indicates your understanding of this warning.
|
||||
stig: |-
|
||||
You are accessing a U.S. Government (USG) Information System (IS) that is provided for USG-authorized use only. By using this IS (which includes any device attached to this IS), you consent to the following conditions:
|
||||
|
||||
@@ -36,7 +36,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Organization's Policy Text"
|
||||
default: |-
|
||||
recommended: |-
|
||||
You are accessing a U.S. Government (USG) Information System (IS) that is provided for USG-authorized use only. By using this IS (which includes any device attached to this IS), you consent to the following conditions:
|
||||
-The USG routinely intercepts and monitors communications on this IS for purposes including, but not limited to, penetration testing, COMSEC monitoring, network operations and defense, personnel misconduct (PM), law enforcement (LE), and counterintelligence (CI) investigations.
|
||||
-At any time, the USG may inspect and seize data stored on this IS.
|
||||
|
||||
@@ -46,7 +46,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of seconds."
|
||||
default: 0
|
||||
recommended: 0
|
||||
tags:
|
||||
- 800-53r5_moderate
|
||||
- 800-53r5_high
|
||||
|
||||
@@ -49,7 +49,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of seconds."
|
||||
default: 900
|
||||
recommended: 900
|
||||
tags:
|
||||
- 800-53r5_moderate
|
||||
- 800-53r5_high
|
||||
|
||||
@@ -32,7 +32,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of seconds."
|
||||
default: 0
|
||||
recommended: 0
|
||||
stig: 0
|
||||
tags:
|
||||
- 800-53r5_moderate
|
||||
|
||||
@@ -35,7 +35,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of seconds."
|
||||
default: 900
|
||||
recommended: 900
|
||||
stig: 900
|
||||
tags:
|
||||
- 800-53r5_moderate
|
||||
|
||||
@@ -32,7 +32,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of seconds."
|
||||
default: 30
|
||||
recommended: 30
|
||||
stig: 30
|
||||
tags:
|
||||
- stig
|
||||
|
||||
@@ -34,7 +34,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of minutes."
|
||||
default: 0
|
||||
recommended: 0
|
||||
cis_lvl1: 0
|
||||
cis_lvl2: 0
|
||||
tags:
|
||||
|
||||
@@ -59,7 +59,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of days."
|
||||
default: 35
|
||||
recommended: 35
|
||||
tags:
|
||||
- 800-171
|
||||
- cnssi-1253
|
||||
|
||||
@@ -37,7 +37,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of failed attempts."
|
||||
default: 3
|
||||
recommended: 3
|
||||
stig: 3
|
||||
cis_lvl1: 5
|
||||
cis_lvl2: 5
|
||||
|
||||
@@ -37,7 +37,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of minutes."
|
||||
default: 15
|
||||
recommended: 15
|
||||
stig: 15
|
||||
tags:
|
||||
- 800-171
|
||||
|
||||
@@ -44,7 +44,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of previous passwords."
|
||||
default: 5
|
||||
recommended: 5
|
||||
stig: 5
|
||||
cis_lvl1: 15
|
||||
cis_lvl2: 15
|
||||
|
||||
@@ -45,7 +45,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of days."
|
||||
default: 60
|
||||
recommended: 60
|
||||
stig: 60
|
||||
tags:
|
||||
- 800-171
|
||||
|
||||
@@ -45,7 +45,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Minimum password length."
|
||||
default: 15
|
||||
recommended: 15
|
||||
stig: 15
|
||||
cis_lvl1: 15
|
||||
cis_lvl2: 15
|
||||
|
||||
@@ -63,7 +63,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of hours."
|
||||
default: 24
|
||||
recommended: 24
|
||||
tags:
|
||||
- 800-171
|
||||
- cnssi-1253
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
id: supplemental_cis_manual
|
||||
title: " CIS Manual Recommendations"
|
||||
title: "CIS Manual Recommendations"
|
||||
discussion: |
|
||||
List of CIS recommendations that are manual check in the CIS macOS Benchmark.
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Organization's approved message."
|
||||
default: Center for Internet Security Test Message
|
||||
recommended: Center for Internet Security Test Message
|
||||
cis_lvl1: Center for Internet Security Test Message
|
||||
cis_lvl2: Center for Internet Security Test Message
|
||||
tags:
|
||||
|
||||
@@ -44,7 +44,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of seconds."
|
||||
default: 5
|
||||
recommended: 5
|
||||
stig: 5
|
||||
cis_lvl1: 5
|
||||
cis_lvl2: 5
|
||||
|
||||
@@ -45,7 +45,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Number of seconds."
|
||||
default: 1200
|
||||
recommended: 1200
|
||||
stig: 900
|
||||
cis_lvl1: 1200
|
||||
cis_lvl2: 1200
|
||||
@@ -61,6 +61,7 @@ tags:
|
||||
- cis_lvl2
|
||||
- cisv8
|
||||
- stig
|
||||
- test
|
||||
severity: "medium"
|
||||
mobileconfig: true
|
||||
mobileconfig_info:
|
||||
|
||||
@@ -40,7 +40,7 @@ macOS:
|
||||
- "12.0"
|
||||
odv:
|
||||
hint: "Name of timeserver(s) separated by commas."
|
||||
default: "time-a.nist.gov,time-b.nist.gov"
|
||||
recommended: "time-a.nist.gov,time-b.nist.gov"
|
||||
stig: "time-a.nist.gov,time-b.nist.gov"
|
||||
cis_lvl1: "time.apple.com"
|
||||
cis_lvl2: "time.apple.com"
|
||||
|
||||
@@ -212,7 +212,7 @@ def available_tags(all_rules):
|
||||
print(tag)
|
||||
return
|
||||
|
||||
def output_baseline(rules, os, keyword):
|
||||
def output_baseline(rules, os, keyword, benchmark="recommended"):
|
||||
inherent_rules = []
|
||||
permanent_rules = []
|
||||
na_rules = []
|
||||
@@ -240,6 +240,7 @@ def output_baseline(rules, os, keyword):
|
||||
output_text = f'title: "macOS {os}: Security Configuration - {keyword}"\n'
|
||||
output_text += f'description: |\n This guide describes the actions to take when securing a macOS {os} system against the {keyword} baseline.\n'
|
||||
output_text += f'authors: |\n |===\n |Name|Organization\n |===\n'
|
||||
output_text += f'parent_values: "{benchmark}"\n'
|
||||
output_text += 'profile:\n'
|
||||
|
||||
# sort the rules
|
||||
@@ -345,19 +346,16 @@ def sanitised_input(prompt, type_=None, range_=None, default_=None):
|
||||
else:
|
||||
return ui
|
||||
|
||||
def odv_query(rules, keyword):
|
||||
def odv_query(rules, benchmark):
|
||||
print("The inclusion of any given rule is a risk-based-decision (RBD). While each rule is mapped to an 800-53 control, deploying it in your organization should be part of the decision-making process. \nYou will be prompted to include each rule, and for those with specific organizational defined values (ODV), you will be prompted for those as well.\n")
|
||||
|
||||
_established_benchmarks = ['stig', 'cis_lvl1', 'cis_lvl2']
|
||||
if any(bm in keyword for bm in _established_benchmarks):
|
||||
if not benchmark == "recommended":
|
||||
print(f"WARNING: You are attempting to tailor an already established benchmark. Excluding rules or modifying ODVs may not meet the compliance of the established benchmark.\n")
|
||||
benchmark = keyword
|
||||
else:
|
||||
benchmark = "default"
|
||||
|
||||
|
||||
included_rules = []
|
||||
queried_rule_ids = []
|
||||
|
||||
include_all = False
|
||||
|
||||
for rule in rules:
|
||||
get_odv = False
|
||||
@@ -366,30 +364,38 @@ def odv_query(rules, keyword):
|
||||
if any(tag in rule.rule_tags for tag in _always_include):
|
||||
#print(f"Including rule {rule.rule_id} by default")
|
||||
include = "Y"
|
||||
elif include_all:
|
||||
include = "Y"
|
||||
get_odv = True
|
||||
queried_rule_ids.append(rule.rule_id)
|
||||
remove_odv_custom_rule(rule)
|
||||
else:
|
||||
if rule.rule_id not in queried_rule_ids:
|
||||
include = sanitised_input(f"Would you like to include the rule for \"{rule.rule_id}\" in your benchmark? [Y/n]: ", str.lower, range_=('y', 'n'), default_="y")
|
||||
include = sanitised_input(f"Would you like to include the rule for \"{rule.rule_id}\" in your benchmark? [Y/n/all]: ", str.lower, range_=('y', 'n', 'all'), default_="y")
|
||||
queried_rule_ids.append(rule.rule_id)
|
||||
get_odv = True
|
||||
# remove custom ODVs if there, they will be re-written if needed
|
||||
remove_odv_custom_rule(rule)
|
||||
if include.upper() == "ALL":
|
||||
include_all = True
|
||||
include = "y"
|
||||
if include.upper() == "Y":
|
||||
included_rules.append(rule)
|
||||
if rule.rule_odv == "missing":
|
||||
continue
|
||||
elif get_odv:
|
||||
if benchmark == "default":
|
||||
if benchmark == "recommended":
|
||||
print(f'{rule.rule_odv["hint"]}')
|
||||
if isinstance(rule.rule_odv["default"], int):
|
||||
odv = sanitised_input(f'Enter the ODV for \"{rule.rule_id}\" or press Enter for the default value ({rule.rule_odv["default"]}): ', int, default_=rule.rule_odv["default"])
|
||||
elif isinstance(rule.rule_odv["default"], bool):
|
||||
odv = sanitised_input(f'Enter the ODV for \"{rule.rule_id}\" or press Enter for the default value ({rule.rule_odv["default"]}): ', bool, default_=rule.rule_odv["default"])
|
||||
if isinstance(rule.rule_odv["recommended"], int):
|
||||
odv = sanitised_input(f'Enter the ODV for \"{rule.rule_id}\" or press Enter for the recommended value ({rule.rule_odv["recommended"]}): ', int, default_=rule.rule_odv["recommended"])
|
||||
elif isinstance(rule.rule_odv["recommended"], bool):
|
||||
odv = sanitised_input(f'Enter the ODV for \"{rule.rule_id}\" or press Enter for the recommended value ({rule.rule_odv["recommended"]}): ', bool, default_=rule.rule_odv["recommended"])
|
||||
else:
|
||||
odv = sanitised_input(f'Enter the ODV for \"{rule.rule_id}\" or press Enter for the default value ({rule.rule_odv["default"]}): ', str, default_=rule.rule_odv["default"])
|
||||
if odv and odv != rule.rule_odv["default"]:
|
||||
odv = sanitised_input(f'Enter the ODV for \"{rule.rule_id}\" or press Enter for the recommended value ({rule.rule_odv["recommended"]}): ', str, default_=rule.rule_odv["recommended"])
|
||||
if odv and odv != rule.rule_odv["recommended"]:
|
||||
write_odv_custom_rule(rule, odv)
|
||||
else:
|
||||
print(f'{rule.rule_odv["hint"]}')
|
||||
print(f'\nODV value: {rule.rule_odv["hint"]}')
|
||||
if isinstance(rule.rule_odv[benchmark], int):
|
||||
odv = sanitised_input(f'Enter the ODV for \"{rule.rule_id}\" or press Enter for the default value ({rule.rule_odv[benchmark]}): ', int, default_=rule.rule_odv[benchmark])
|
||||
elif isinstance(rule.rule_odv[benchmark], bool):
|
||||
@@ -467,10 +473,17 @@ def main():
|
||||
print("No rules found for the keyword provided, please verify from the following list:")
|
||||
available_tags(all_rules)
|
||||
elif args.tailor:
|
||||
_established_benchmarks = ['stig', 'cis_lvl1', 'cis_lvl2']
|
||||
if any(bm in args.keyword for bm in _established_benchmarks):
|
||||
benchmark = args.keyword
|
||||
else:
|
||||
benchmark = "recommended"
|
||||
# prompt for name of benchmark to be used for filename
|
||||
tailored_filename = sanitised_input(f'Enter a name for your tailored benchmark or press Enter for the default value ({args.keyword}): ', str, default_=args.keyword)
|
||||
# prompt for inclusion, add ODV
|
||||
odv_baseline_rules = odv_query(found_rules, args.keyword)
|
||||
baseline_output_file = open(f"{build_path}/{args.keyword}.yaml", 'w')
|
||||
baseline_output_file.write(output_baseline(odv_baseline_rules, version_yaml["os"], args.keyword))
|
||||
odv_baseline_rules = odv_query(found_rules, benchmark)
|
||||
baseline_output_file = open(f"{build_path}/{tailored_filename}.yaml", 'w')
|
||||
baseline_output_file.write(output_baseline(odv_baseline_rules, version_yaml["os"], args.keyword, benchmark))
|
||||
else:
|
||||
baseline_output_file = open(f"{build_path}/{args.keyword}.yaml", 'w')
|
||||
baseline_output_file.write(output_baseline(found_rules, version_yaml["os"], args.keyword))
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
# filename: generate_guidance.py
|
||||
# description: Process a given baseline, and output guidance files
|
||||
import types
|
||||
import sys
|
||||
import os.path
|
||||
import plistlib
|
||||
from unittest import result
|
||||
import xlwt
|
||||
import io
|
||||
import glob
|
||||
import os
|
||||
import yaml
|
||||
@@ -20,7 +17,6 @@ from xlwt import Workbook
|
||||
from string import Template
|
||||
from itertools import groupby
|
||||
from uuid import uuid4
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
class MacSecurityRule():
|
||||
@@ -283,7 +279,7 @@ class PayloadDict:
|
||||
"""
|
||||
output_file_path = output_path.name
|
||||
preferences_path = os.path.dirname(output_file_path)
|
||||
|
||||
|
||||
|
||||
settings_dict = {}
|
||||
for i in self.data['PayloadContent']:
|
||||
@@ -302,7 +298,7 @@ class PayloadDict:
|
||||
for setting in value['Forced']:
|
||||
for key, value in setting['mcx_preference_settings'].items():
|
||||
settings_dict[key] = value
|
||||
|
||||
|
||||
#preferences_output_path = open(preferences_output_file, 'wb')
|
||||
plistlib.dump(settings_dict, fp)
|
||||
print(f"Settings plist written to {preferences_output_file}")
|
||||
@@ -321,10 +317,10 @@ class PayloadDict:
|
||||
for key,value in i.items():
|
||||
if not key.startswith("Payload"):
|
||||
settings_dict[key] = value
|
||||
|
||||
|
||||
plistlib.dump(settings_dict, output_path)
|
||||
print(f"Settings plist written to {output_path.name}")
|
||||
|
||||
|
||||
|
||||
def makeNewUUID():
|
||||
return str(uuid4())
|
||||
@@ -368,7 +364,7 @@ def generate_profiles(baseline_name, build_path, parent_dir, baseline_yaml, sign
|
||||
except OSError:
|
||||
print("Creation of the directory %s failed" %
|
||||
unsigned_mobileconfig_output_path)
|
||||
|
||||
|
||||
if signing:
|
||||
signed_mobileconfig_output_path = os.path.join(
|
||||
f'{build_path}', 'mobileconfigs', 'signed')
|
||||
@@ -406,7 +402,7 @@ def generate_profiles(baseline_name, build_path, parent_dir, baseline_yaml, sign
|
||||
|
||||
#for rule in glob.glob('../rules/*/{}.yaml'.format(profile_rule)) + glob.glob('../custom/rules/**/{}.yaml'.format(profile_rule),recursive=True):
|
||||
rule_yaml = get_rule_yaml(rule, custom)
|
||||
|
||||
|
||||
if rule_yaml['mobileconfig']:
|
||||
for payload_type, info in rule_yaml['mobileconfig_info'].items():
|
||||
valid = True
|
||||
@@ -432,7 +428,7 @@ def generate_profiles(baseline_name, build_path, parent_dir, baseline_yaml, sign
|
||||
profile_errors.append(rule)
|
||||
logging.debug(e)
|
||||
valid = False
|
||||
|
||||
|
||||
if valid:
|
||||
if payload_type == "com.apple.systemuiserver":
|
||||
for setting_key, setting_value in info['mount-controls'].items():
|
||||
@@ -486,7 +482,7 @@ def generate_profiles(baseline_name, build_path, parent_dir, baseline_yaml, sign
|
||||
displayname=displayname,
|
||||
description=description)
|
||||
|
||||
|
||||
|
||||
|
||||
if payload == "com.apple.ManagedClient.preferences":
|
||||
for item in settings:
|
||||
@@ -515,13 +511,13 @@ def generate_profiles(baseline_name, build_path, parent_dir, baseline_yaml, sign
|
||||
newProfile.finalizeAndSave(config_file)
|
||||
newProfile.finalizeAndSavePlist(settings_config_file)
|
||||
config_file.close()
|
||||
|
||||
|
||||
print(f"""
|
||||
CAUTION: These configuration profiles are intended for evaluation in a TEST
|
||||
environment. Certain configuration profiles (Smartcards), when applied could
|
||||
leave a system in a state where a user can no longer login with a password.
|
||||
environment. Certain configuration profiles (Smartcards), when applied could
|
||||
leave a system in a state where a user can no longer login with a password.
|
||||
Please use caution when applying configuration settings to a system.
|
||||
|
||||
|
||||
NOTE: If an MDM is already being leveraged, many of these profile settings may
|
||||
be available through the vendor.
|
||||
""")
|
||||
@@ -529,7 +525,7 @@ def generate_profiles(baseline_name, build_path, parent_dir, baseline_yaml, sign
|
||||
def default_audit_plist(baseline_name, build_path, baseline_yaml):
|
||||
""""Generate the default audit plist file to define exemptions
|
||||
"""
|
||||
|
||||
|
||||
# Output folder
|
||||
plist_output_path = os.path.join(
|
||||
f'{build_path}', 'preferences')
|
||||
@@ -552,7 +548,7 @@ def default_audit_plist(baseline_name, build_path, baseline_yaml):
|
||||
if profile_rule.startswith("supplemental"):
|
||||
continue
|
||||
plist_dict[profile_rule] = { "exempt": False }
|
||||
|
||||
|
||||
plistlib.dump(plist_dict, plist_file)
|
||||
|
||||
|
||||
@@ -571,7 +567,7 @@ def generate_script(baseline_name, build_path, baseline_yaml, reference):
|
||||
|
||||
## This script will attempt to audit all of the settings based on the installed profile.
|
||||
|
||||
## This script is provided as-is and should be fully tested on a system that is not in a production environment.
|
||||
## This script is provided as-is and should be fully tested on a system that is not in a production environment.
|
||||
|
||||
################### Variables ###################
|
||||
|
||||
@@ -635,9 +631,9 @@ ask() {{
|
||||
fi
|
||||
|
||||
# Ask the question - use /dev/tty in case stdin is redirected from somewhere else
|
||||
/usr/bin/printf "${{YELLOW}} $1 [$prompt] ${{STD}}"
|
||||
printf "${{YELLOW}} $1 [$prompt] ${{STD}}"
|
||||
read REPLY
|
||||
|
||||
|
||||
# Default?
|
||||
if [ -z "$REPLY" ]; then
|
||||
REPLY=$default
|
||||
@@ -655,7 +651,7 @@ ask() {{
|
||||
# function to display menus
|
||||
show_menus() {{
|
||||
/usr/bin/clear
|
||||
/bin/echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
/bin/echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
/bin/echo " M A I N - M E N U"
|
||||
/bin/echo " macOS Security Compliance Tool"
|
||||
/bin/echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
@@ -685,7 +681,7 @@ compliance_count(){{
|
||||
non_compliant=0
|
||||
|
||||
results=$(/usr/libexec/PlistBuddy -c "Print" /Library/Preferences/org.{baseline_name}.audit.plist)
|
||||
|
||||
|
||||
while IFS= read -r line; do
|
||||
if [[ "$line" =~ "finding = false" ]]; then
|
||||
compliant=$((compliant+1))
|
||||
@@ -694,8 +690,8 @@ compliance_count(){{
|
||||
non_compliant=$((non_compliant+1))
|
||||
fi
|
||||
done <<< "$results"
|
||||
|
||||
# Enable output of just the compliant or non-compliant numbers.
|
||||
|
||||
# Enable output of just the compliant or non-compliant numbers.
|
||||
if [[ $1 = "compliant" ]]
|
||||
then
|
||||
/bin/echo $compliant
|
||||
@@ -713,18 +709,18 @@ generate_report(){{
|
||||
count=($(compliance_count))
|
||||
compliant=${{count[1]}}
|
||||
non_compliant=${{count[2]}}
|
||||
|
||||
|
||||
total=$((non_compliant + compliant))
|
||||
percentage=$(printf %.2f $(( compliant * 100. / total )) )
|
||||
/bin/echo
|
||||
/bin/echo "Number of tests passed: ${{GREEN}}$compliant${{STD}}"
|
||||
/bin/echo "Number of test FAILED: ${{RED}}$non_compliant${{STD}}"
|
||||
/bin/echo "You are ${{YELLOW}}$percentage%${{STD}} percent compliant!"
|
||||
echo "Number of tests passed: ${{GREEN}}$compliant${{STD}}"
|
||||
echo "Number of test FAILED: ${{RED}}$non_compliant${{STD}}"
|
||||
echo "You are ${{YELLOW}}$percentage%${{STD}} percent compliant!"
|
||||
pause
|
||||
}}
|
||||
|
||||
view_report(){{
|
||||
|
||||
|
||||
if [[ $lastComplianceScan == "No scans have been run" ]];then
|
||||
/bin/echo "no report to run, please run new scan"
|
||||
pause
|
||||
@@ -738,7 +734,7 @@ generate_stats(){{
|
||||
count=($(compliance_count))
|
||||
compliant=${{count[1]}}
|
||||
non_compliant=${{count[2]}}
|
||||
|
||||
|
||||
total=$((non_compliant + compliant))
|
||||
percentage=$(printf %.2f $(( compliant * 100. / total )) )
|
||||
/bin/echo "PASSED: $compliant FAILED: $non_compliant, $percentage percent compliant!"
|
||||
@@ -773,22 +769,22 @@ fi
|
||||
logging.debug(f"{rule}")
|
||||
|
||||
rule_yaml = get_rule_yaml(rule, custom)
|
||||
|
||||
|
||||
|
||||
if rule_yaml['id'].startswith("supplemental"):
|
||||
continue
|
||||
|
||||
|
||||
arch=""
|
||||
if "tags" in rule_yaml:
|
||||
try:
|
||||
if "manual" in rule_yaml['tags']:
|
||||
continue
|
||||
if "arm64" in rule_yaml['tags']:
|
||||
arch="arm64"
|
||||
elif "i386" in rule_yaml['tags']:
|
||||
arch="i386"
|
||||
else:
|
||||
arch=""
|
||||
|
||||
except:
|
||||
pass
|
||||
|
||||
# grab the 800-53 controls
|
||||
try:
|
||||
rule_yaml['references']['800-53r5']
|
||||
@@ -796,14 +792,14 @@ fi
|
||||
nist_80053r5 = 'N/A'
|
||||
else:
|
||||
nist_80053r5 = rule_yaml['references']['800-53r5']
|
||||
|
||||
|
||||
if reference == "default":
|
||||
log_reference_id = [rule_yaml['id']]
|
||||
else:
|
||||
try:
|
||||
try:
|
||||
rule_yaml['references'][reference]
|
||||
except KeyError:
|
||||
try:
|
||||
try:
|
||||
rule_yaml['references']['custom'][reference]
|
||||
except KeyError:
|
||||
log_reference_id = [rule_yaml['id']]
|
||||
@@ -817,8 +813,8 @@ fi
|
||||
log_reference_id = rule_yaml['references'][reference] + [rule_yaml['id']]
|
||||
else:
|
||||
log_reference_id = [rule_yaml['references'][reference]] + [rule_yaml['id']]
|
||||
|
||||
|
||||
|
||||
|
||||
# group the controls
|
||||
if not nist_80053r5 == "N/A":
|
||||
nist_80053r5.sort()
|
||||
@@ -865,16 +861,16 @@ if [[ "$arch" == "$rule_arch" ]] || [[ -z "$rule_arch" ]]; then
|
||||
# check to see if rule is exempt
|
||||
unset exempt
|
||||
unset exempt_reason
|
||||
|
||||
|
||||
exempt=$(/usr/bin/osascript -l JavaScript << EOS 2>/dev/null
|
||||
ObjC.unwrap($.NSUserDefaults.alloc.initWithSuiteName('org.{7}.audit').objectForKey('{0}'))["exempt"]
|
||||
ObjC.unwrap($.NSUserDefaults.alloc.initWithSuiteName('org.{7}.audit').objectForKey('{0}'))["exempt"]
|
||||
EOS
|
||||
)
|
||||
exempt_reason=$(/usr/bin/osascript -l JavaScript << EOS 2>/dev/null
|
||||
ObjC.unwrap($.NSUserDefaults.alloc.initWithSuiteName('org.{7}.audit').objectForKey('{0}'))["exempt_reason"]
|
||||
ObjC.unwrap($.NSUserDefaults.alloc.initWithSuiteName('org.{7}.audit').objectForKey('{0}'))["exempt_reason"]
|
||||
EOS
|
||||
)
|
||||
|
||||
|
||||
if [[ $result_value == "{4}" ]]; then
|
||||
/bin/echo "$(date -u) {5} passed (Result: $result_value, Expected: "{3}")" | /usr/bin/tee -a "$audit_log"
|
||||
/usr/bin/defaults write "$audit_plist" {0} -dict-add finding -bool NO
|
||||
@@ -891,8 +887,8 @@ EOS
|
||||
/bin/sleep 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
else
|
||||
/bin/echo "$(date -u) {5} does not apply to this architechture" | tee -a "$audit_log"
|
||||
/usr/bin/defaults write "$audit_plist" {0} -dict-add finding -bool NO
|
||||
@@ -922,12 +918,12 @@ unset exempt
|
||||
unset exempt_reason
|
||||
|
||||
exempt=$(/usr/bin/osascript -l JavaScript << EOS 2>/dev/null
|
||||
ObjC.unwrap($.NSUserDefaults.alloc.initWithSuiteName('org.{baseline_name}.audit').objectForKey('{rule_yaml['id']}'))["exempt"]
|
||||
ObjC.unwrap($.NSUserDefaults.alloc.initWithSuiteName('org.{baseline_name}.audit').objectForKey('{rule_yaml['id']}'))["exempt"]
|
||||
EOS
|
||||
)
|
||||
|
||||
exempt_reason=$(/usr/bin/osascript -l JavaScript << EOS 2>/dev/null
|
||||
ObjC.unwrap($.NSUserDefaults.alloc.initWithSuiteName('org.{baseline_name}.audit').objectForKey('{rule_yaml['id']}'))["exempt_reason"]
|
||||
ObjC.unwrap($.NSUserDefaults.alloc.initWithSuiteName('org.{baseline_name}.audit').objectForKey('{rule_yaml['id']}'))["exempt_reason"]
|
||||
EOS
|
||||
)
|
||||
|
||||
@@ -969,7 +965,7 @@ if [[ ! -e "$audit_plist" ]]; then
|
||||
pause
|
||||
show_menus
|
||||
read_options
|
||||
else
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -986,7 +982,7 @@ fi
|
||||
# append to existing logfile
|
||||
/bin/echo "$(date -u) Beginning remediation of non-compliant settings" >> "$audit_log"
|
||||
|
||||
# run mcxrefresh
|
||||
# run mcxrefresh
|
||||
/usr/bin/mcxrefresh -u $CURR_USER_UID
|
||||
|
||||
|
||||
@@ -1000,16 +996,12 @@ fi
|
||||
|
||||
zparseopts -D -E -check=check -fix=fix -stats=stats -compliant=compliant -non_compliant=non_compliant
|
||||
|
||||
if [[ $check ]];then
|
||||
run_scan
|
||||
elif [[ $fix ]];then
|
||||
run_fix
|
||||
elif [[ $stats ]];then
|
||||
generate_stats
|
||||
elif [[ $compliant ]];then
|
||||
compliance_count "compliant"
|
||||
elif [[ $non_compliant ]];then
|
||||
compliance_count "non-compliant"
|
||||
if [[ $check ]] || [[ $fix ]] || [[ $stats ]] || [[ $compliant ]] || [[ $non_compliant ]]; then
|
||||
if [[ $fix ]]; then run_fix; fi
|
||||
if [[ $check ]]; then run_scan; fi
|
||||
if [[ $stats ]];then generate_stats; fi
|
||||
if [[ $compliant ]];then compliance_count "compliant"; fi
|
||||
if [[ $non_compliant ]];then compliance_count "non-compliant"; fi
|
||||
else
|
||||
while true; do
|
||||
show_menus
|
||||
@@ -1033,19 +1025,19 @@ fi
|
||||
#fix_script_file.close()
|
||||
compliance_script_file.close()
|
||||
|
||||
def fill_in_odv(resulting_yaml, baseline_name):
|
||||
def fill_in_odv(resulting_yaml, parent_values):
|
||||
fields_to_process = ['title', 'discussion', 'check', 'fix']
|
||||
_has_odv = False
|
||||
if "odv" in resulting_yaml:
|
||||
try:
|
||||
odv = str(resulting_yaml['odv'][baseline_name])
|
||||
odv = str(resulting_yaml['odv'][parent_values])
|
||||
_has_odv = True
|
||||
except KeyError:
|
||||
try:
|
||||
odv = str(resulting_yaml['odv']['custom'])
|
||||
_has_odv = True
|
||||
except KeyError:
|
||||
odv = str(resulting_yaml['odv']['default'])
|
||||
odv = str(resulting_yaml['odv']['recommended'])
|
||||
_has_odv = True
|
||||
else:
|
||||
pass
|
||||
@@ -1054,23 +1046,25 @@ def fill_in_odv(resulting_yaml, baseline_name):
|
||||
for field in fields_to_process:
|
||||
if "$ODV" in resulting_yaml[field]:
|
||||
resulting_yaml[field]=resulting_yaml[field].replace("$ODV", odv)
|
||||
|
||||
|
||||
for result_value in resulting_yaml['result']:
|
||||
resulting_yaml['result'][result_value] = odv
|
||||
|
||||
if "$ODV" in str(resulting_yaml['result'][result_value]):
|
||||
resulting_yaml['result'][result_value] = odv
|
||||
|
||||
if resulting_yaml['mobileconfig_info']:
|
||||
for mobileconfig_type in resulting_yaml['mobileconfig_info']:
|
||||
if isinstance(resulting_yaml['mobileconfig_info'][mobileconfig_type], dict):
|
||||
for mobileconfig_value in resulting_yaml['mobileconfig_info'][mobileconfig_type]:
|
||||
resulting_yaml['mobileconfig_info'][mobileconfig_type][mobileconfig_value] = odv
|
||||
|
||||
|
||||
|
||||
|
||||
def get_rule_yaml(rule_file, custom=False, baseline_name=""):
|
||||
if "$ODV" in str(resulting_yaml['mobileconfig_info'][mobileconfig_type][mobileconfig_value]):
|
||||
resulting_yaml['mobileconfig_info'][mobileconfig_type][mobileconfig_value] = odv
|
||||
|
||||
|
||||
|
||||
|
||||
def get_rule_yaml(rule_file, custom=False, parent_values="recommended"):
|
||||
""" Takes a rule file, checks for a custom version, and returns the yaml for the rule
|
||||
"""
|
||||
global resulting_yaml
|
||||
global resulting_yaml
|
||||
resulting_yaml = {}
|
||||
names = [os.path.basename(x) for x in glob.glob('../custom/rules/**/*.yaml', recursive=True)]
|
||||
file_name = os.path.basename(rule_file)
|
||||
@@ -1086,14 +1080,14 @@ def get_rule_yaml(rule_file, custom=False, baseline_name=""):
|
||||
else:
|
||||
with open(rule_file) as r:
|
||||
rule_yaml = yaml.load(r, Loader=yaml.SafeLoader)
|
||||
|
||||
|
||||
try:
|
||||
og_rule_path = glob.glob('../rules/**/{}'.format(file_name), recursive=True)[0]
|
||||
except IndexError:
|
||||
#assume this is a completely new rule
|
||||
og_rule_path = glob.glob('../custom/rules/**/{}'.format(file_name), recursive=True)[0]
|
||||
resulting_yaml['customized'] = ["customized rule"]
|
||||
|
||||
|
||||
# get original/default rule yaml for comparison
|
||||
with open(og_rule_path) as og:
|
||||
og_rule_yaml = yaml.load(og, Loader=yaml.SafeLoader)
|
||||
@@ -1115,7 +1109,7 @@ def get_rule_yaml(rule_file, custom=False, baseline_name=""):
|
||||
resulting_yaml['references'][ref] = rule_yaml['references'][ref]
|
||||
except KeyError:
|
||||
resulting_yaml['references'][ref] = og_rule_yaml['references'][ref]
|
||||
try:
|
||||
try:
|
||||
if "custom" in rule_yaml['references']:
|
||||
resulting_yaml['references']['custom'] = rule_yaml['references']['custom']
|
||||
if 'customized' in resulting_yaml:
|
||||
@@ -1127,14 +1121,16 @@ def get_rule_yaml(rule_file, custom=False, baseline_name=""):
|
||||
pass
|
||||
elif yaml_field == "tags":
|
||||
# try to concatenate tags from both original yaml and custom yaml
|
||||
if "tags" in rule_yaml:
|
||||
try:
|
||||
if og_rule_yaml["tags"] == rule_yaml["tags"]:
|
||||
#print("using default data in yaml field {}".format("tags"))
|
||||
resulting_yaml['tags'] = og_rule_yaml['tags']
|
||||
#print("using default data in yaml field {}".format("tags"))
|
||||
resulting_yaml['tags'] = og_rule_yaml['tags']
|
||||
else:
|
||||
#print("Found custom tags... concatenating them")
|
||||
resulting_yaml['tags'] = og_rule_yaml['tags'] + rule_yaml['tags']
|
||||
else:
|
||||
except KeyError:
|
||||
resulting_yaml['tags'] = og_rule_yaml['tags']
|
||||
else:
|
||||
try:
|
||||
if og_rule_yaml[yaml_field] == rule_yaml[yaml_field]:
|
||||
#print("using default data in yaml field {}".format(yaml_field))
|
||||
@@ -1148,8 +1144,8 @@ def get_rule_yaml(rule_file, custom=False, baseline_name=""):
|
||||
resulting_yaml['customized'] = ["customized {}".format(yaml_field)]
|
||||
except KeyError:
|
||||
resulting_yaml[yaml_field] = og_rule_yaml[yaml_field]
|
||||
|
||||
fill_in_odv(resulting_yaml, baseline_name)
|
||||
|
||||
fill_in_odv(resulting_yaml, parent_values)
|
||||
|
||||
return resulting_yaml
|
||||
|
||||
@@ -1190,7 +1186,7 @@ def generate_xls(baseline_name, build_path, baseline_yaml):
|
||||
sheet1.write(0, 10, "SRG", headers)
|
||||
sheet1.write(0, 11, "DISA STIG", headers)
|
||||
sheet1.write(0, 12, "CIS Benchmark", headers)
|
||||
sheet1.write(0, 13, "CIS v8", headers)
|
||||
sheet1.write(0, 13, "CIS v8", headers)
|
||||
sheet1.write(0, 14, "CCI", headers)
|
||||
sheet1.write(0, 15, "Modifed Rule", headers)
|
||||
sheet1.set_panes_frozen(True)
|
||||
@@ -1201,7 +1197,7 @@ def generate_xls(baseline_name, build_path, baseline_yaml):
|
||||
for rule in baseline_rules:
|
||||
if rule.rule_id.startswith("supplemental") or rule.rule_id.startswith("srg"):
|
||||
continue
|
||||
|
||||
|
||||
sheet1.write(counter, 0, rule.rule_cce, top)
|
||||
sheet1.col(0).width = 256 * 15
|
||||
sheet1.write(counter, 1, rule.rule_id, top)
|
||||
@@ -1298,12 +1294,12 @@ def generate_xls(baseline_name, build_path, baseline_yaml):
|
||||
if title not in custom_ref_column:
|
||||
custom_ref_column[title] = column_counter
|
||||
column_counter = column_counter + 1
|
||||
sheet1.write(0, custom_ref_column[title], title, headers)
|
||||
sheet1.write(0, custom_ref_column[title], title, headers)
|
||||
sheet1.col(custom_ref_column[title]).width = 512 * 25
|
||||
added_ref = (str(ref)).strip('[]\'')
|
||||
added_ref = added_ref.replace(", ", "\n").replace("\'", "")
|
||||
sheet1.write(counter, custom_ref_column[title], added_ref, topWrap)
|
||||
|
||||
|
||||
|
||||
tall_style = xlwt.easyxf('font:height 640;') # 36pt
|
||||
|
||||
@@ -1426,7 +1422,7 @@ def is_asciidoctor_installed():
|
||||
cmd = "which asciidoctor"
|
||||
process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
|
||||
output, error = process.communicate()
|
||||
|
||||
|
||||
# return path to asciidoctor
|
||||
return output.decode("utf-8").strip()
|
||||
|
||||
@@ -1447,7 +1443,7 @@ def verify_signing_hash(hash):
|
||||
with tempfile.NamedTemporaryFile(mode="w") as in_file:
|
||||
unsigned_tmp_file_path=in_file.name
|
||||
in_file.write("temporary file for signing")
|
||||
|
||||
|
||||
cmd = f"security cms -S -Z {hash} -i {unsigned_tmp_file_path}"
|
||||
FNULL = open(os.devnull, 'w')
|
||||
process = subprocess.Popen(cmd.split(), stdout=FNULL, stderr=FNULL)
|
||||
@@ -1456,7 +1452,7 @@ def verify_signing_hash(hash):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def sign_config_profile(in_file, out_file, hash):
|
||||
"""Signs the configuration profile using the identity associated with the provided hash
|
||||
"""
|
||||
@@ -1539,28 +1535,32 @@ def main():
|
||||
log_reference = args.reference
|
||||
else:
|
||||
log_reference = "default"
|
||||
use_custom_reference = False
|
||||
use_custom_reference = False
|
||||
|
||||
except IOError as msg:
|
||||
parser.error(str(msg))
|
||||
|
||||
|
||||
|
||||
baseline_yaml = yaml.load(args.baseline, Loader=yaml.SafeLoader)
|
||||
try:
|
||||
parent_values = baseline_yaml['parent_values']
|
||||
except KeyError:
|
||||
parent_values = "recommended"
|
||||
version_file = os.path.join(parent_dir, "VERSION.yaml")
|
||||
with open(version_file) as r:
|
||||
version_yaml = yaml.load(r, Loader=yaml.SafeLoader)
|
||||
|
||||
adoc_templates = [ "adoc_rule",
|
||||
"adoc_supplemental",
|
||||
"adoc_rule_no_setting",
|
||||
adoc_templates = [ "adoc_rule",
|
||||
"adoc_supplemental",
|
||||
"adoc_rule_no_setting",
|
||||
"adoc_rule_custom_refs",
|
||||
"adoc_section",
|
||||
"adoc_header",
|
||||
"adoc_footer",
|
||||
"adoc_section",
|
||||
"adoc_header",
|
||||
"adoc_footer",
|
||||
"adoc_foreword",
|
||||
"adoc_scope",
|
||||
"adoc_authors",
|
||||
"adoc_acronyms",
|
||||
"adoc_scope",
|
||||
"adoc_authors",
|
||||
"adoc_acronyms",
|
||||
"adoc_additional_docs"
|
||||
]
|
||||
adoc_templates_dict = {}
|
||||
@@ -1572,7 +1572,7 @@ def main():
|
||||
adoc_templates_dict[template] = f"../custom/templates/{template}.adoc"
|
||||
else:
|
||||
adoc_templates_dict[template] = f"../templates/{template}.adoc"
|
||||
|
||||
|
||||
# check for custom PDF theme (must have theme in the name and end with .yml)
|
||||
pdf_theme="mscp-theme.yml"
|
||||
themes = glob.glob('../custom/templates/*theme*.yml')
|
||||
@@ -1581,7 +1581,7 @@ def main():
|
||||
elif len(themes) == 1 :
|
||||
print(f"Found custom PDF theme: {themes[0]}")
|
||||
pdf_theme = themes[0]
|
||||
|
||||
|
||||
|
||||
|
||||
# Setup AsciiDoc templates
|
||||
@@ -1593,7 +1593,7 @@ def main():
|
||||
|
||||
with open(adoc_templates_dict['adoc_rule_no_setting']) as adoc_rule_no_setting_file:
|
||||
adoc_rule_no_setting_template = Template(adoc_rule_no_setting_file.read())
|
||||
|
||||
|
||||
with open(adoc_templates_dict['adoc_rule_custom_refs']) as adoc_rule_custom_refs_file:
|
||||
adoc_rule_custom_refs_template = Template(adoc_rule_custom_refs_file.read())
|
||||
|
||||
@@ -1605,13 +1605,13 @@ def main():
|
||||
|
||||
with open(adoc_templates_dict['adoc_footer']) as adoc_footer_file:
|
||||
adoc_footer_template = Template(adoc_footer_file.read())
|
||||
|
||||
|
||||
with open(adoc_templates_dict['adoc_foreword']) as adoc_foreword_file:
|
||||
adoc_foreword_template = adoc_foreword_file.read() + "\n"
|
||||
|
||||
with open(adoc_templates_dict['adoc_scope']) as adoc_scope_file:
|
||||
adoc_scope_template = Template(adoc_scope_file.read() +"\n")
|
||||
|
||||
|
||||
with open(adoc_templates_dict['adoc_authors']) as adoc_authors_file:
|
||||
adoc_authors_template = Template(adoc_authors_file.read() + "\n")
|
||||
|
||||
@@ -1636,7 +1636,7 @@ def main():
|
||||
adoc_171_show=":show_171:"
|
||||
else:
|
||||
adoc_171_show=":show_171!:"
|
||||
|
||||
|
||||
if args.gary:
|
||||
adoc_tag_show=":show_tags:"
|
||||
adoc_STIG_show=":show_STIG:"
|
||||
@@ -1683,7 +1683,7 @@ def main():
|
||||
adoc_output_file.write(adoc_acronyms_template)
|
||||
adoc_output_file.write(adoc_additional_docs_template)
|
||||
|
||||
|
||||
|
||||
|
||||
# Create sections and rules
|
||||
for sections in baseline_yaml['profile']:
|
||||
@@ -1730,8 +1730,8 @@ def main():
|
||||
else:
|
||||
rule_location = rule_path[0]
|
||||
custom=False
|
||||
|
||||
rule_yaml = get_rule_yaml(rule_location, custom, baseline_name)
|
||||
|
||||
rule_yaml = get_rule_yaml(rule_location, custom, parent_values)
|
||||
|
||||
# Determine if the references exist and set accordingly
|
||||
try:
|
||||
@@ -1754,7 +1754,7 @@ def main():
|
||||
nist_80053r5 = 'N/A'
|
||||
else:
|
||||
nist_80053r5 = rule_yaml['references']['800-53r5']
|
||||
|
||||
|
||||
try:
|
||||
rule_yaml['references']['800-171r2']
|
||||
except KeyError:
|
||||
@@ -1908,16 +1908,16 @@ def main():
|
||||
# Output footer
|
||||
adoc_output_file.write(footer_adoc)
|
||||
adoc_output_file.close()
|
||||
|
||||
|
||||
if args.profiles:
|
||||
print("Generating configuration profiles...")
|
||||
generate_profiles(baseline_name, build_path, parent_dir, baseline_yaml, signing, args.hash)
|
||||
|
||||
|
||||
if args.script:
|
||||
print("Generating compliance script...")
|
||||
generate_script(baseline_name, build_path, baseline_yaml, log_reference)
|
||||
default_audit_plist(baseline_name, build_path, baseline_yaml)
|
||||
|
||||
|
||||
if args.xls:
|
||||
print('Generating excel document...')
|
||||
generate_xls(baseline_name, build_path, baseline_yaml)
|
||||
@@ -1930,7 +1930,7 @@ def main():
|
||||
process.communicate()
|
||||
else:
|
||||
print("If you would like to generate the HTML file from the AsciiDoc file, install the ruby gem for asciidoctor")
|
||||
|
||||
|
||||
asciidoctorPDF_path = is_asciidoctor_pdf_installed()
|
||||
|
||||
# Don't create PDF if we are generating SCAP
|
||||
|
||||
@@ -184,9 +184,9 @@ def generate_scap(all_rules, all_baselines, args):
|
||||
loop = 1
|
||||
if "odv" in og_rule_yaml:
|
||||
loop = len(og_rule_yaml['odv'])
|
||||
if args.baseline:
|
||||
loop = 1
|
||||
|
||||
if args.baseline != "None":
|
||||
loop = 1
|
||||
|
||||
for a in range(0, loop):
|
||||
|
||||
@@ -196,7 +196,7 @@ def generate_scap(all_rules, all_baselines, args):
|
||||
|
||||
odv_label = list(rule_yaml['odv'].keys())[a]
|
||||
|
||||
if args.baseline:
|
||||
if args.baseline != "None":
|
||||
odv_label = args.baseline
|
||||
|
||||
if odv_label == "hint":
|
||||
@@ -219,24 +219,24 @@ def generate_scap(all_rules, all_baselines, args):
|
||||
for mobileconfig_type in rule_yaml['mobileconfig_info']:
|
||||
if isinstance(rule_yaml['mobileconfig_info'][mobileconfig_type], dict):
|
||||
for mobileconfig_value in rule_yaml['mobileconfig_info'][mobileconfig_type]:
|
||||
if "$ODV" == rule_yaml['mobileconfig_info'][mobileconfig_type][mobileconfig_value]:
|
||||
rule_yaml['mobileconfig_info'][mobileconfig_type][mobileconfig_value] = rule_yaml['mobileconfig_info'][mobileconfig_type][mobileconfig_value].replace("$ODV",odv_value)
|
||||
if "$ODV" in str(resulting_yaml['mobileconfig_info'][mobileconfig_type][mobileconfig_value]):
|
||||
resulting_yaml['mobileconfig_info'][mobileconfig_type][mobileconfig_value] = rule_yaml['mobileconfig_info'][mobileconfig_type][mobileconfig_value].replace("$ODV",odv_value)
|
||||
|
||||
except:
|
||||
odv_label = "default"
|
||||
odv_label = "recommended"
|
||||
|
||||
for baseline in all_baselines:
|
||||
found_rules = []
|
||||
for tag in rule_yaml['tags']:
|
||||
if tag == baseline:
|
||||
if odv_label != "default" and odv_label == tag:
|
||||
if odv_label != "recommended" and odv_label == tag or odv_label == "custom":
|
||||
|
||||
if baseline in generated_baselines:
|
||||
generated_baselines[baseline].append(rule_yaml['id'] + "_" + odv_label)
|
||||
else:
|
||||
generated_baselines[baseline] = [rule_yaml['id'] + "_" + odv_label]
|
||||
continue
|
||||
elif odv_label == "default":
|
||||
elif odv_label == "recommended" or odv_label == "custom":
|
||||
|
||||
if "odv" in rule_yaml:
|
||||
if baseline not in rule_yaml['odv']:
|
||||
@@ -2707,10 +2707,16 @@ def get_rule_yaml(rule_file, custom=False, baseline_name=""):
|
||||
except:
|
||||
pass
|
||||
elif yaml_field == "tags":
|
||||
if og_rule_yaml["tags"] == rule_yaml["tags"]:
|
||||
# try to concatenate tags from both original yaml and custom yaml
|
||||
try:
|
||||
if og_rule_yaml["tags"] == rule_yaml["tags"]:
|
||||
#print("using default data in yaml field {}".format("tags"))
|
||||
resulting_yaml['tags'] = og_rule_yaml['tags']
|
||||
else:
|
||||
#print("Found custom tags... concatenating them")
|
||||
resulting_yaml['tags'] = og_rule_yaml['tags'] + rule_yaml['tags']
|
||||
except KeyError:
|
||||
resulting_yaml['tags'] = og_rule_yaml['tags']
|
||||
else:
|
||||
resulting_yaml['tags'] = og_rule_yaml['tags'] + rule_yaml['tags']
|
||||
else:
|
||||
try:
|
||||
if og_rule_yaml[yaml_field] == rule_yaml[yaml_field]:
|
||||
|
||||
Reference in New Issue
Block a user