for filename in args.filename_list: # If directory specified, scan all files in that dir if os.path.isdir(filename): filename = os.path.join(filename, '*') # Expand wildcards for filename in glob.glob(filename): # Only operate on .tf if not filename.endswith('.tf'): continue print("Checking {}".format(filename)) findings = validate_file(filename) if args.config: try: parliament.override_config(args.config) except FileNotFoundError as e: if args.config_is_optional: print("Config file {} not found. Ignoring.".format( args.config)) else: raise e filtered_findings = [] for finding in findings: finding = parliament.enhance_finding(finding) if not is_finding_filtered(finding): filtered_findings.append(finding) if len(filtered_findings) > 0: print(f"{bcolors.FAIL}{filename}{bcolors.ENDC}") for f in filtered_findings:
def main(): parser = argparse.ArgumentParser() parser.add_argument( "--aws-managed-policies", help= "This is used with the policies directory of https://github.com/SummitRoute/aws_managed_policies", type=str, ) parser.add_argument( "--auth-details-file", help= 'Provide the path to a file returned by "aws iam get-account-authorization-details"', type=str, ) parser.add_argument( "--string", help= 'Provide a string such as \'{"Version": "2012-10-17","Statement": {"Effect": "Allow","Action": ["s3:GetObject", "s3:PutBucketPolicy"],"Resource": ["arn:aws:s3:::bucket1", "arn:aws:s3:::bucket2/*"]}}\'', type=str, ) parser.add_argument("--file", help="Provide a policy in a file", type=str) parser.add_argument("--directory", help="Provide a path to directory with policy files", type=str) parser.add_argument( "--include_policy_extension", help= 'Policy file extension to scan for in directory mode (ex. ".json")', default="json", type=str, ) parser.add_argument( "--exclude_pattern", help='File name regex pattern to exclude (ex. ".*venv.*")', type=str, ) parser.add_argument("--minimal", help="Minimal output", default=False, action="store_true") parser.add_argument("--json", help="json output", default=False, action="store_true") parser.add_argument( "--minimum_severity", help= "Minimum severity to display. Options: CRITICAL, HIGH, MEDIUM, LOW, INFO", default="LOW", choices=["CRITICAL", "HIGH", "MEDIUM", "LOW", "INFO"], ) parser.add_argument( "--private_auditors", help= "Directory of the private auditors. Defaults to looking in private_auditors in the same directory as the iam_definition.json file.", default=None, ) parser.add_argument("--config", help="Custom config file for over-riding values", type=str) parser.add_argument( "--include-community-auditors", help="Use this flag to enable community-provided auditors", default=None, action="store_true", ) parser.add_argument( "-v", "--verbose", help="Increase output verbosity", action="store_true", default=False, ) parser.add_argument( "--version", action="version", version="%(prog)s {version}".format(version=__version__), ) args = parser.parse_args() log_level = logging.ERROR log_format = "%(message)s" # We want to silence dependencies logging.getLogger("botocore").setLevel(logging.CRITICAL) logging.getLogger("boto3").setLevel(logging.CRITICAL) logging.getLogger("urllib3").setLevel(logging.CRITICAL) if args.verbose: log_level = logging.INFO log_format = "%(message)s" logging.basicConfig(level=log_level, stream=sys.stderr, format=log_format) if args.private_auditors is not None and "." in args.private_auditors: raise Exception( "The path to the private_auditors must not have periods") if args.minimal and args.json: raise Exception("You cannot choose both minimal and json output") # Change the exit status if there are errors exit_status = 0 findings = [] if args.aws_managed_policies: file_paths = find_files(directory=args.aws_managed_policies) for file_path in file_paths: with open(file_path) as f: contents = f.read() policy_file_json = json.loads(contents) policy_string = json.dumps( policy_file_json["PolicyVersion"]["Document"]) policy = analyze_policy_string( policy_string, file_path, private_auditors_custom_path=args.private_auditors, include_community_auditors=args.include_community_auditors, ) findings.extend(policy.findings) elif args.auth_details_file: with open(args.auth_details_file) as f: contents = f.read() auth_details_json = json.loads(contents) for policy in auth_details_json["Policies"]: # Ignore AWS defined policies if "arn:aws:iam::aws:" not in policy["Arn"]: continue # Ignore AWS Service-linked roles if (policy["Path"] == "/service-role/" or policy["Path"] == "/aws-service-role/" or policy["PolicyName"].startswith("AWSServiceRoleFor") or policy["PolicyName"].endswith("ServiceRolePolicy") or policy["PolicyName"].endswith( "ServiceLinkedRolePolicy")): continue for version in policy["PolicyVersionList"]: if not version["IsDefaultVersion"]: continue policy = analyze_policy_string( json.dumps(version["Document"]), policy["Arn"], ) findings.extend(policy.findings) # Review the inline policies on Users, Roles, and Groups for user in auth_details_json["UserDetailList"]: for policy in user.get("UserPolicyList", []): policy = analyze_policy_string( json.dumps(policy["PolicyDocument"]), user["Arn"], private_auditors_custom_path=args.private_auditors, include_community_auditors=args. include_community_auditors, ) findings.extend(policy.findings) for role in auth_details_json["RoleDetailList"]: for policy in role.get("RolePolicyList", []): policy = analyze_policy_string( json.dumps(policy["PolicyDocument"]), role["Arn"], private_auditors_custom_path=args.private_auditors, include_community_auditors=args. include_community_auditors, ) findings.extend(policy.findings) for group in auth_details_json["GroupDetailList"]: for policy in group.get("GroupPolicyList", []): policy = analyze_policy_string( json.dumps(policy["PolicyDocument"]), group["Arn"], private_auditors_custom_path=args.private_auditors, include_community_auditors=args. include_community_auditors, ) findings.extend(policy.findings) elif args.string: policy = analyze_policy_string( args.string, private_auditors_custom_path=args.private_auditors, include_community_auditors=args.include_community_auditors, ) findings.extend(policy.findings) elif args.file: with open(args.file) as f: contents = f.read() policy = analyze_policy_string( contents, args.file, private_auditors_custom_path=args.private_auditors, include_community_auditors=args.include_community_auditors, ) findings.extend(policy.findings) elif args.directory: file_paths = find_files( directory=args.directory, exclude_pattern=args.exclude_pattern, policy_extension=args.include_policy_extension, ) for file_path in file_paths: with open(file_path) as f: contents = f.read() policy = analyze_policy_string( contents, file_path, private_auditors_custom_path=args.private_auditors, include_community_auditors=args.include_community_auditors, ) findings.extend(policy.findings) else: parser.print_help() exit(-1) filtered_findings = [] override_config(args.config) if args.include_community_auditors: community_auditors_directory = "community_auditors" community_auditors_override_file = (Path(abspath(__file__)).parent / community_auditors_directory / "config_override.yaml") override_config(community_auditors_override_file) for finding in findings: finding = enhance_finding(finding) if not is_finding_filtered(finding, args.minimum_severity): filtered_findings.append(finding) if len(filtered_findings) == 0: # Return with exit code 0 if no findings return for finding in filtered_findings: print_finding(finding, args.minimal, args.json) # There were findings, so return with a non-zero exit code exit(1)
def main(): parser = argparse.ArgumentParser() parser.add_argument( "--aws-managed-policies", help= "This is used with the policies directory of https://github.com/SummitRoute/aws_managed_policies", type=str, ) parser.add_argument( "--auth-details-file", help= 'Provide the path to a file returned by "aws iam get-account-authorization-details"', type=str, ) parser.add_argument( "--string", help= 'Provide a string such as \'{"Version": "2012-10-17","Statement": {"Effect": "Allow","Action": ["s3:GetObject", "s3:PutBucketPolicy"],"Resource": ["arn:aws:s3:::bucket1", "arn:aws:s3:::bucket2/*"]}}\'', type=str, ) parser.add_argument("--file", help="Provide a policy in a file", type=str) parser.add_argument("--minimal", help="Minimal output", default=False, action="store_true") parser.add_argument("--json", help="json output", default=False, action="store_true") parser.add_argument( "--minimum_severity", help= "Minimum severity to display. Options: CRITICAL, HIGH, MEDIUM, LOW, INFO", default="LOW", ) parser.add_argument( "--private_auditors", help= "Directory of the private auditors. Defaults to looking in private_auditors in the same directory as the iam_definition.json file.", default=None, ) parser.add_argument("--config", help="Custom config file for over-riding values", type=str) args = parser.parse_args() if args.private_auditors is not None and "." in args.private_auditors: raise Exception( "The path to the private_auditors must not have periods") if args.minimal and args.json: raise Exception("You cannot choose both minimal and json output") # Change the exit status if there are errors exit_status = 0 findings = [] if args.aws_managed_policies: filenames = [ f for f in listdir(args.aws_managed_policies) if isfile(join(args.aws_managed_policies, f)) ] for filename in filenames: filepath = join(args.aws_managed_policies, filename) with open(filepath) as f: contents = f.read() policy_file_json = json.loads(contents) policy_string = json.dumps( policy_file_json["PolicyVersion"]["Document"]) policy = analyze_policy_string( policy_string, filepath, private_auditors_custom_path=args.private_auditors, ) findings.extend(policy.findings) elif args.auth_details_file: with open(args.auth_details_file) as f: contents = f.read() auth_details_json = json.loads(contents) for policy in auth_details_json["Policies"]: # Ignore AWS defined policies if "arn:aws:iam::aws:" not in policy["Arn"]: continue for version in policy["PolicyVersionList"]: if not version["IsDefaultVersion"]: continue policy = analyze_policy_string( json.dumps(version["Document"]), policy["Arn"], ) findings.extend(policy.findings) # Review the inline policies on Users, Roles, and Groups for user in auth_details_json["UserDetailList"]: for policy in user.get("UserPolicyList", []): policy = analyze_policy_string( json.dumps(version["Document"]), user["Arn"], private_auditors_custom_path=args.private_auditors, ) findings.extend(policy.findings) for role in auth_details_json["RoleDetailList"]: for policy in role.get("RolePolicyList", []): policy = analyze_policy_string( json.dumps(version["Document"]), role["Arn"], private_auditors_custom_path=args.private_auditors, ) findings.extend(policy.findings) for group in auth_details_json["GroupDetailList"]: for policy in group.get("GroupPolicyList", []): policy = analyze_policy_string( json.dumps(version["Document"]), group["Arn"], private_auditors_custom_path=args.private_auditors, ) findings.extend(policy.findings) elif args.string: policy = analyze_policy_string( args.string, private_auditors_custom_path=args.private_auditors) findings.extend(policy.findings) elif args.file: with open(args.file) as f: contents = f.read() policy = analyze_policy_string( contents, args.file, private_auditors_custom_path=args.private_auditors) findings.extend(policy.findings) else: parser.print_help() exit(-1) filtered_findings = [] override_config(args.config) for finding in findings: finding = enhance_finding(finding) if not is_finding_filtered(finding, args.minimum_severity): filtered_findings.append(finding) if len(filtered_findings) == 0: # Return with exit code 0 if no findings return for finding in filtered_findings: print_finding(finding, args.minimal, args.json) # There were findings, so return with a non-zero exit code exit(1)