diff --git a/README.md b/README.md index ff2b8bf..d72ad18 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ Parses IAM identity-based and resource-based policies from Terraform templates. | --enable-logging | | | Enables log output to stdout | | --ignore-finding | | FINDING_CODE,RESOURCE_NAME,RESOURCE_NAME.FINDING_CODE | Allow validation failures to be ignored. Specify as a comma separated list of findings to be ignored. Can be individual finding codes (e.g. "PASS_ROLE_WITH_STAR_IN_RESOURCE"), a specific resource name (e.g. "MyResource"), or a combination of both separated by a period.(e.g. "MyResource.PASS_ROLE_WITH_STAR_IN_RESOURCE"). Names of finding codes may change in IAM Access Analyzer over time. | --treat-finding-type-as-blocking | | ERROR,SECURITY_WARNING,WARNING,SUGGESTION,NONE | Specify which finding types should be treated as blocking. Other finding types are treated as nonblocking. If the tool detects any blocking finding types, it will exit with a non-zero exit code. If all findings are nonblocking or there are no findings, the tool exits with an exit code of 0. Defaults to "ERROR" and "SECURITY_WARNING". Specify as a comma separated list of finding types that should be blocking. Pass "NONE" to ignore all findings. | +| --treat-finding-code-as-blocking | | | Specify which finding codes should be treated as blocking. Other finding codes are treated as nonblocking. If the tool detects any blocking finding codes, it will exit with a non-zero exit code. If all findings are nonblocking or there are no findings, the tool exits with an exit code of 0. Not set by default. Specify as a comma separated list of finding codes that should be blocking. | | --allow-external-principals | | ACCOUNT,ARN | A comma separated list of external principals that should be ignored. Specify as a comma separated list of a 12 digit AWS account ID, a federated web identity user, a federated SAML user, or an ARN. Specify "*" to allow anonymous access. (e.g. 123456789123,arn:aws:iam::111111111111:role/MyOtherRole,graph.facebook.com) | | --config |Yes | FILE_NAME1, FILE_NAME2, ... | A list of config files for running this script | **check-no-new-access** diff --git a/iam_check/argument_actions.py b/iam_check/argument_actions.py index 6d44f87..f65a9ca 100644 --- a/iam_check/argument_actions.py +++ b/iam_check/argument_actions.py @@ -35,6 +35,37 @@ def __call__(self, _, namespace, values, option_string=None): setattr(namespace, self.dest, findings_to_ignore) +class ParseCodesToBlockFromCLI(argparse.Action): + """ + Parses comma delimited list of codes to block on. This is either a resource name or a finding code name, or + a combination of both in the form MyResource.FindingA + """ + + def __call__(self, _, namespace, values, option_string=None): + values = values.split(',') + + codes_to_block = parse_codes_to_block(values) + + setattr(namespace, self.dest, codes_to_block) + +def parse_codes_to_block(values_as_list): + if values_as_list is None: + return values_as_list + + values_as_list = [value.strip() for value in values_as_list] + + codes_to_block = [] + for value in values_as_list: + if "." in value: + resource_and_code = value.split(".", 1) + # a split must have at least two members of the array, so no need to validate + finding_to_ignore = ResourceAndCodeFindingToBlock(resource_and_code[0], resource_and_code[1]) + else: + finding_to_ignore = ResourceOrCodeFindingToBlock(value) + + codes_to_block.append(finding_to_ignore) + + return codes_to_block def parse_findings_to_ignore(values_as_list): if values_as_list is None: diff --git a/iam_check/iam_check.py b/iam_check/iam_check.py index c19c6fa..6c50dc7 100644 --- a/iam_check/iam_check.py +++ b/iam_check/iam_check.py @@ -98,6 +98,11 @@ def cli_parse_opts(): 'list of finding types that should be blocking. Possible values are "ERROR", ' '"SECURITY_WARNING", "SUGGESTION", and "WARNING". Pass "NONE" to ignore all errors.', default=default_finding_types_that_are_blocking, type=validate_finding_types_from_cli) + validate_parser.add_argument('--treat-finding-code-as-blocking', dest="treat_as_blocking", metavar="ERROR,SECURITY_WARNING", + help='Specify which finding codes should be treated as blocking. Other finding codes are treated ' + 'as non-blocking. Not set by default. Specify as a comma separated ' + 'list of finding codes that should be blocking.', + default=default_finding_codes_that_are_blocking, type=validate_finding_codes_from_cli) validate_parser.add_argument('--allow-external-principals', dest='allowed_external_principals', metavar="ACCOUNT,ARN", help='A comma separated list of external principals that should be ignored. Specify as ' diff --git a/iam_check/lib/reporter.py b/iam_check/lib/reporter.py index 4c69ca0..5002c08 100644 --- a/iam_check/lib/reporter.py +++ b/iam_check/lib/reporter.py @@ -8,6 +8,7 @@ from iam_check.tools import regex_patterns default_finding_types_that_are_blocking = ['ERROR', 'SECURITY_WARNING'] +default_finding_codes_that_are_blocking = [] class Reporter: @@ -15,12 +16,13 @@ class Reporter: Determines what findings should be reported to the end user based on parameters provided when starting validation. """ - def __init__(self, findings_to_ignore, finding_types_that_are_blocking, allowed_external_principals): + def __init__(self, findings_to_ignore, finding_types_that_are_blocking, allowed_external_principals, finding_codes_that_are_blocking=default_finding_codes_that_are_blocking): self.blocking_findings = [] self.nonblocking_findings = [] self.findings_to_ignore = findings_to_ignore self.finding_types_that_are_blocking = finding_types_that_are_blocking self.allowed_external_principals = allowed_external_principals + self.finding_codes_that_are_blocking = finding_codes_that_are_blocking def build_report_from(self, findings): self._filter_overridden_findings(findings) @@ -66,6 +68,8 @@ def _classify_as_blocking_or_non_blocking(self, finding): if finding.findingType.upper() in self.finding_types_that_are_blocking: self.blocking_findings.append(finding) + elif finding.code.upper() in self.finding_codes_that_are_blocking: + self.blocking_findings.append(finding) else: self.nonblocking_findings.append(finding) @@ -84,6 +88,20 @@ def __eq__(self, other): return self.value == other.value +class ResourceOrCodeFindingToBlock: + def __init__(self, value): + self.value = value + + def matches(self, finding): + return finding.resourceName.lower() == self.value.lower() or \ + finding.code.lower() == self.value.lower() + + def __eq__(self, other): + if not isinstance(other, ResourceOrCodeFindingToBlock): + return False + + return self.value == other.value + class ResourceAndCodeFindingToIgnore: def __init__(self, resource_name, code): @@ -182,4 +200,4 @@ def print(self): @staticmethod def _to_json_string(obj): - return json.dumps(obj, default=default_to_json, indent=4) \ No newline at end of file + return json.dumps(obj, default=default_to_json, indent=4) diff --git a/iam_check/parameters.py b/iam_check/parameters.py index 2cd65d1..75e2c96 100644 --- a/iam_check/parameters.py +++ b/iam_check/parameters.py @@ -34,6 +34,16 @@ def validate_finding_types_from_cli(value): return finding_types +def validate_finding_codes_from_cli(value): + """ + Validate that the finding codes provided are valid finding codes. + """ + + finding_codes = value.split(',') + finding_codes = validate_finding_codes(finding_codes) + + return finding_codes + def validate_finding_types(finding_types): if finding_types is None: @@ -46,4 +56,17 @@ def validate_finding_types(finding_types): if finding_type not in ['ERROR', 'SECURITY_WARNING', 'SUGGESTION', 'WARNING', 'NONE']: raise ArgumentTypeError(f"Invalid finding type: {finding_type}.") - return finding_types \ No newline at end of file + return finding_types + +def validate_finding_codes(finding_codes): + if finding_codes is None: + return finding_codes + + finding_codes = [finding_code.strip() for finding_code in finding_codes] + finding_codes = [finding_code.upper() for finding_code in finding_codes] + + # for finding_code in finding_codes: + # if finding_code not in ['ERROR', 'SECURITY_WARNING', 'SUGGESTION', 'WARNING', 'NONE']: + # raise ArgumentTypeError(f"Invalid finding code: {finding_code}.") + + return finding_codes \ No newline at end of file diff --git a/iam_check/test/iam_policy/test_plan.json b/iam_check/test/iam_policy/test_plan.json index 7e6cf6e..f8248a4 100644 --- a/iam_check/test/iam_policy/test_plan.json +++ b/iam_check/test/iam_policy/test_plan.json @@ -1 +1,362 @@ -{"format_version":"1.2","terraform_version":"1.5.7","planned_values":{"root_module":{"resources":[{"address":"aws_iam_policy.demo_policy","mode":"managed","type":"aws_iam_policy","name":"demo_policy","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"description":"This is a demo policy","name":"demo-policy","path":"/","policy":"{\"Statement\":[{\"Action\":\"iam:PassRole\",\"Condition\":{\"StringEquals\":{\"iam:PassedToService\":\"lambda.amazonaws.com\"}},\"Effect\":\"Allow\",\"Resource\":\"arn:aws:iam::123456789012:role/topping-*\",\"Sid\":\"PassExecutionRole\"},{\"Action\":[\"lambda:ListFunctions\",\"lambda:ListEventSourceMappings\",\"lambda:GetAccountSettings\",\"iam:ListRoles\"],\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"ReadOnlyPermissions\"},{\"Action\":[\"lambda:invokeFunction\",\"lambda:UpdateFunctionCode\",\"lambda:ListVersionsByFunction\",\"lambda:ListTags\",\"lambda:ListProvisionedConcurrencyConfigs\",\"lambda:ListAliases\",\"lambda:GetPolicy\",\"lambda:GetFunctionEventInvokeConfig\",\"lambda:GetFunctionCodeSigningConfig\",\"lambda:GetFunction\",\"lambda:CreateFunction\"],\"Effect\":\"Allow\",\"Resource\":\"arn:aws:lambda:us-east-1:123456789012:function:pizza-*\",\"Sid\":\"ViewAndConfigureFunctions\"}],\"Version\":\"2012-10-17\"}","tags":null},"sensitive_values":{"tags_all":{}}}]}},"resource_changes":[{"address":"aws_iam_policy.demo_policy","mode":"managed","type":"aws_iam_policy","name":"demo_policy","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"description":"This is a demo policy","name":"demo-policy","path":"/","policy":"{\"Statement\":[{\"Action\":\"iam:PassRole\",\"Condition\":{\"StringEquals\":{\"iam:PassedToService\":\"lambda.amazonaws.com\"}},\"Effect\":\"Allow\",\"Resource\":\"arn:aws:iam::123456789012:role/topping-*\",\"Sid\":\"PassExecutionRole\"},{\"Action\":[\"lambda:ListFunctions\",\"lambda:ListEventSourceMappings\",\"lambda:GetAccountSettings\",\"iam:ListRoles\"],\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"ReadOnlyPermissions\"},{\"Action\":[\"lambda:invokeFunction\",\"lambda:UpdateFunctionCode\",\"lambda:ListVersionsByFunction\",\"lambda:ListTags\",\"lambda:ListProvisionedConcurrencyConfigs\",\"lambda:ListAliases\",\"lambda:GetPolicy\",\"lambda:GetFunctionEventInvokeConfig\",\"lambda:GetFunctionCodeSigningConfig\",\"lambda:GetFunction\",\"lambda:CreateFunction\"],\"Effect\":\"Allow\",\"Resource\":\"arn:aws:lambda:us-east-1:123456789012:function:pizza-*\",\"Sid\":\"ViewAndConfigureFunctions\"}],\"Version\":\"2012-10-17\"}","tags":null},"after_unknown":{"arn":true,"id":true,"name_prefix":true,"policy_id":true,"tags_all":true},"before_sensitive":false,"after_sensitive":{"tags_all":{}}}}],"prior_state":{"format_version":"1.0","terraform_version":"1.5.7","values":{"root_module":{"resources":[{"address":"data.aws_iam_policy_document.demo_policy","mode":"data","type":"aws_iam_policy_document","name":"demo_policy","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"id":"1993420229","json":"{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"PassExecutionRole\",\n \"Effect\": \"Allow\",\n \"Action\": \"iam:PassRole\",\n \"Resource\": \"arn:aws:iam::123456789012:role/topping-*\",\n \"Condition\": {\n \"StringEquals\": {\n \"iam:PassedToService\": \"lambda.amazonaws.com\"\n }\n }\n },\n {\n \"Sid\": \"ReadOnlyPermissions\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"lambda:ListFunctions\",\n \"lambda:ListEventSourceMappings\",\n \"lambda:GetAccountSettings\",\n \"iam:ListRoles\"\n ],\n \"Resource\": \"*\"\n },\n {\n \"Sid\": \"ViewAndConfigureFunctions\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"lambda:invokeFunction\",\n \"lambda:UpdateFunctionCode\",\n \"lambda:ListVersionsByFunction\",\n \"lambda:ListTags\",\n \"lambda:ListProvisionedConcurrencyConfigs\",\n \"lambda:ListAliases\",\n \"lambda:GetPolicy\",\n \"lambda:GetFunctionEventInvokeConfig\",\n \"lambda:GetFunctionCodeSigningConfig\",\n \"lambda:GetFunction\",\n \"lambda:CreateFunction\"\n ],\n \"Resource\": \"arn:aws:lambda:us-east-1:123456789012:function:pizza-*\"\n }\n ]\n}","override_json":null,"override_policy_documents":null,"policy_id":null,"source_json":null,"source_policy_documents":null,"statement":[{"actions":["iam:PassRole"],"condition":[{"test":"StringEquals","values":["lambda.amazonaws.com"],"variable":"iam:PassedToService"}],"effect":"Allow","not_actions":[],"not_principals":[],"not_resources":[],"principals":[],"resources":["arn:aws:iam::123456789012:role/topping-*"],"sid":"PassExecutionRole"},{"actions":["iam:ListRoles","lambda:GetAccountSettings","lambda:ListEventSourceMappings","lambda:ListFunctions"],"condition":[],"effect":"Allow","not_actions":[],"not_principals":[],"not_resources":[],"principals":[],"resources":["*"],"sid":"ReadOnlyPermissions"},{"actions":["lambda:CreateFunction","lambda:GetFunction","lambda:GetFunctionCodeSigningConfig","lambda:GetFunctionEventInvokeConfig","lambda:GetPolicy","lambda:ListAliases","lambda:ListProvisionedConcurrencyConfigs","lambda:ListTags","lambda:ListVersionsByFunction","lambda:UpdateFunctionCode","lambda:invokeFunction"],"condition":[],"effect":"Allow","not_actions":[],"not_principals":[],"not_resources":[],"principals":[],"resources":["arn:aws:lambda:us-east-1:123456789012:function:pizza-*"],"sid":"ViewAndConfigureFunctions"}],"version":"2012-10-17"},"sensitive_values":{"statement":[{"actions":[false],"condition":[{"values":[false]}],"not_actions":[],"not_principals":[],"not_resources":[],"principals":[],"resources":[false]},{"actions":[false,false,false,false],"condition":[],"not_actions":[],"not_principals":[],"not_resources":[],"principals":[],"resources":[false]},{"actions":[false,false,false,false,false,false,false,false,false,false,false],"condition":[],"not_actions":[],"not_principals":[],"not_resources":[],"principals":[],"resources":[false]}]}}]}}},"configuration":{"provider_config":{"aws":{"name":"aws","full_name":"registry.terraform.io/hashicorp/aws","version_constraint":"~\u003e 4.0","expressions":{"region":{"constant_value":"us-east-1"}}}},"root_module":{"resources":[{"address":"aws_iam_policy.demo_policy","mode":"managed","type":"aws_iam_policy","name":"demo_policy","provider_config_key":"aws","expressions":{"description":{"constant_value":"This is a demo policy"},"name":{"constant_value":"demo-policy"},"policy":{"references":["data.aws_iam_policy_document.demo_policy.json","data.aws_iam_policy_document.demo_policy"]}},"schema_version":0},{"address":"data.aws_iam_policy_document.demo_policy","mode":"data","type":"aws_iam_policy_document","name":"demo_policy","provider_config_key":"aws","expressions":{"statement":[{"actions":{"constant_value":["iam:PassRole"]},"condition":[{"test":{"constant_value":"StringEquals"},"values":{"constant_value":["lambda.amazonaws.com"]},"variable":{"constant_value":"iam:PassedToService"}}],"effect":{"constant_value":"Allow"},"resources":{"constant_value":["arn:aws:iam::123456789012:role/topping-*"]},"sid":{"constant_value":"PassExecutionRole"}},{"actions":{"constant_value":["iam:ListRoles","lambda:GetAccountSettings","lambda:ListEventSourceMappings","lambda:ListFunctions"]},"effect":{"constant_value":"Allow"},"resources":{"constant_value":["*"]},"sid":{"constant_value":"ReadOnlyPermissions"}},{"actions":{"constant_value":["lambda:CreateFunction","lambda:GetFunction","lambda:GetFunctionCodeSigningConfig","lambda:GetFunctionEventInvokeConfig","lambda:GetPolicy","lambda:ListAliases","lambda:ListProvisionedConcurrencyConfigs","lambda:ListTags","lambda:ListVersionsByFunction","lambda:UpdateFunctionCode","lambda:invokeFunction"]},"effect":{"constant_value":"Allow"},"resources":{"constant_value":["arn:aws:lambda:us-east-1:123456789012:function:pizza-*"]},"sid":{"constant_value":"ViewAndConfigureFunctions"}}]},"schema_version":0}]}},"relevant_attributes":[{"resource":"data.aws_iam_policy_document.demo_policy","attribute":["json"]}],"timestamp":"2023-11-01T20:19:44Z"} +{ + "format_version": "1.2", + "terraform_version": "1.5.7", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_iam_policy.demo_policy", + "mode": "managed", + "type": "aws_iam_policy", + "name": "demo_policy", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "description": "This is a demo policy", + "name": "demo-policy", + "path": "/", + "policy": "{\"Statement\":[{\"Action\":\"iam:PassRole\",\"Condition\":{\"StringEquals\":{\"iam:PassedToService\":\"lambda.amazonaws.com\"}},\"Effect\":\"Allow\",\"Resource\":\"arn:aws:iam::123456789012:role/topping-*\",\"Sid\":\"PassExecutionRole\"},{\"Action\":[\"lambda:ListFunctions\",\"lambda:ListEventSourceMappings\",\"lambda:GetAccountSettings\",\"iam:ListRoles\"],\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"ReadOnlyPermissions\"},{\"Action\":[\"lambda:invokeFunction\",\"lambda:UpdateFunctionCode\",\"lambda:ListVersionsByFunction\",\"lambda:ListTags\",\"lambda:ListProvisionedConcurrencyConfigs\",\"lambda:ListAliases\",\"lambda:GetPolicy\",\"lambda:GetFunctionEventInvokeConfig\",\"lambda:GetFunctionCodeSigningConfig\",\"lambda:GetFunction\",\"lambda:CreateFunction\"],\"Effect\":\"Allow\",\"Resource\":\"arn:aws:lambda:us-east-1:123456789012:function:pizza-*\",\"Sid\":\"ViewAndConfigureFunctions\"}],\"Version\":\"2012-10-17\"}", + "tags": null + }, + "sensitive_values": { + "tags_all": {} + } + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_iam_policy.demo_policy", + "mode": "managed", + "type": "aws_iam_policy", + "name": "demo_policy", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "description": "This is a demo policy", + "name": "demo-policy", + "path": "/", + "policy": "{\"Statement\":[{\"Action\":\"iam:PassRole\",\"Condition\":{\"StringEquals\":{\"iam:PassedToService\":\"lambda.amazonaws.com\"}},\"Effect\":\"Allow\",\"Resource\":\"arn:aws:iam::123456789012:role/topping-*\",\"Sid\":\"PassExecutionRole\"},{\"Action\":[\"lambda:ListFunctions\",\"lambda:ListEventSourceMappings\",\"lambda:GetAccountSettings\",\"iam:ListRoles\"],\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"ReadOnlyPermissions\"},{\"Action\":[\"lambda:invokeFunction\",\"lambda:UpdateFunctionCode\",\"lambda:ListVersionsByFunction\",\"lambda:ListTags\",\"lambda:ListProvisionedConcurrencyConfigs\",\"lambda:ListAliases\",\"lambda:GetPolicy\",\"lambda:GetFunctionEventInvokeConfig\",\"lambda:GetFunctionCodeSigningConfig\",\"lambda:GetFunction\",\"lambda:CreateFunction\"],\"Effect\":\"Allow\",\"Resource\":\"arn:aws:lambda:us-east-1:123456789012:function:pizza-*\",\"Sid\":\"ViewAndConfigureFunctions\"}],\"Version\":\"2012-10-17\"}", + "tags": null + }, + "after_unknown": { + "arn": true, + "id": true, + "name_prefix": true, + "policy_id": true, + "tags_all": true + }, + "before_sensitive": false, + "after_sensitive": { + "tags_all": {} + } + } + } + ], + "prior_state": { + "format_version": "1.0", + "terraform_version": "1.5.7", + "values": { + "root_module": { + "resources": [ + { + "address": "data.aws_iam_policy_document.demo_policy", + "mode": "data", + "type": "aws_iam_policy_document", + "name": "demo_policy", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "id": "1993420229", + "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"PassExecutionRole\",\n \"Effect\": \"Allow\",\n \"Action\": \"iam:PassRole\",\n \"Resource\": \"arn:aws:iam::123456789012:role/topping-*\",\n \"Condition\": {\n \"StringEquals\": {\n \"iam:PassedToService\": \"lambda.amazonaws.com\"\n }\n }\n },\n {\n \"Sid\": \"ReadOnlyPermissions\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"lambda:ListFunctions\",\n \"lambda:ListEventSourceMappings\",\n \"lambda:GetAccountSettings\",\n \"iam:ListRoles\"\n ],\n \"Resource\": \"*\"\n },\n {\n \"Sid\": \"ViewAndConfigureFunctions\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"lambda:invokeFunction\",\n \"lambda:UpdateFunctionCode\",\n \"lambda:ListVersionsByFunction\",\n \"lambda:ListTags\",\n \"lambda:ListProvisionedConcurrencyConfigs\",\n \"lambda:ListAliases\",\n \"lambda:GetPolicy\",\n \"lambda:GetFunctionEventInvokeConfig\",\n \"lambda:GetFunctionCodeSigningConfig\",\n \"lambda:GetFunction\",\n \"lambda:CreateFunction\"\n ],\n \"Resource\": \"arn:aws:lambda:us-east-1:123456789012:function:pizza-*\"\n }\n ]\n}", + "override_json": null, + "override_policy_documents": null, + "policy_id": null, + "source_json": null, + "source_policy_documents": null, + "statement": [ + { + "actions": [ + "iam:PassRole" + ], + "condition": [ + { + "test": "StringEquals", + "values": [ + "lambda.amazonaws.com" + ], + "variable": "iam:PassedToService" + } + ], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [], + "resources": [ + "arn:aws:iam::123456789012:role/topping-*" + ], + "sid": "PassExecutionRole" + }, + { + "actions": [ + "iam:ListRoles", + "lambda:GetAccountSettings", + "lambda:ListEventSourceMappings", + "lambda:ListFunctions" + ], + "condition": [], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [], + "resources": [ + "*" + ], + "sid": "ReadOnlyPermissions" + }, + { + "actions": [ + "lambda:CreateFunction", + "lambda:GetFunction", + "lambda:GetFunctionCodeSigningConfig", + "lambda:GetFunctionEventInvokeConfig", + "lambda:GetPolicy", + "lambda:ListAliases", + "lambda:ListProvisionedConcurrencyConfigs", + "lambda:ListTags", + "lambda:ListVersionsByFunction", + "lambda:UpdateFunctionCode", + "lambda:invokeFunction" + ], + "condition": [], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [], + "resources": [ + "arn:aws:lambda:us-east-1:123456789012:function:pizza-*" + ], + "sid": "ViewAndConfigureFunctions" + } + ], + "version": "2012-10-17" + }, + "sensitive_values": { + "statement": [ + { + "actions": [ + false + ], + "condition": [ + { + "values": [ + false + ] + } + ], + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [], + "resources": [ + false + ] + }, + { + "actions": [ + false, + false, + false, + false + ], + "condition": [], + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [], + "resources": [ + false + ] + }, + { + "actions": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + "condition": [], + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [], + "resources": [ + false + ] + } + ] + } + } + ] + } + } + }, + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": "~\u003e 4.0", + "expressions": { + "region": { + "constant_value": "us-east-1" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_iam_policy.demo_policy", + "mode": "managed", + "type": "aws_iam_policy", + "name": "demo_policy", + "provider_config_key": "aws", + "expressions": { + "description": { + "constant_value": "This is a demo policy" + }, + "name": { + "constant_value": "demo-policy" + }, + "policy": { + "references": [ + "data.aws_iam_policy_document.demo_policy.json", + "data.aws_iam_policy_document.demo_policy" + ] + } + }, + "schema_version": 0 + }, + { + "address": "data.aws_iam_policy_document.demo_policy", + "mode": "data", + "type": "aws_iam_policy_document", + "name": "demo_policy", + "provider_config_key": "aws", + "expressions": { + "statement": [ + { + "actions": { + "constant_value": [ + "iam:PassRole" + ] + }, + "condition": [ + { + "test": { + "constant_value": "StringEquals" + }, + "values": { + "constant_value": [ + "lambda.amazonaws.com" + ] + }, + "variable": { + "constant_value": "iam:PassedToService" + } + } + ], + "effect": { + "constant_value": "Allow" + }, + "resources": { + "constant_value": [ + "arn:aws:iam::123456789012:role/topping-*" + ] + }, + "sid": { + "constant_value": "PassExecutionRole" + } + }, + { + "actions": { + "constant_value": [ + "iam:ListRoles", + "lambda:GetAccountSettings", + "lambda:ListEventSourceMappings", + "lambda:ListFunctions" + ] + }, + "effect": { + "constant_value": "Allow" + }, + "resources": { + "constant_value": [ + "*" + ] + }, + "sid": { + "constant_value": "ReadOnlyPermissions" + } + }, + { + "actions": { + "constant_value": [ + "lambda:CreateFunction", + "lambda:GetFunction", + "lambda:GetFunctionCodeSigningConfig", + "lambda:GetFunctionEventInvokeConfig", + "lambda:GetPolicy", + "lambda:ListAliases", + "lambda:ListProvisionedConcurrencyConfigs", + "lambda:ListTags", + "lambda:ListVersionsByFunction", + "lambda:UpdateFunctionCode", + "lambda:invokeFunction" + ] + }, + "effect": { + "constant_value": "Allow" + }, + "resources": { + "constant_value": [ + "arn:aws:lambda:us-east-1:123456789012:function:pizza-*" + ] + }, + "sid": { + "constant_value": "ViewAndConfigureFunctions" + } + } + ] + }, + "schema_version": 0 + } + ] + } + }, + "relevant_attributes": [ + { + "resource": "data.aws_iam_policy_document.demo_policy", + "attribute": [ + "json" + ] + } + ], + "timestamp": "2023-11-01T20:19:44Z" +} \ No newline at end of file diff --git a/iam_check/test/multiple_policies/identity_codes.json b/iam_check/test/multiple_policies/identity_codes.json new file mode 100644 index 0000000..fa168a6 --- /dev/null +++ b/iam_check/test/multiple_policies/identity_codes.json @@ -0,0 +1,22 @@ +{ + "BlockingFindings": [ + { + "findingType": "SUGGESTION", + "code": "ALLOW_WITH_UNSUPPORTED_TAG_CONDITION_KEY_FOR_SERVICE", + "message": "Using the effect Allow with the condition key aws:ResourceTag/environment and actions for services with the following prefixes does not affect the policy: ec2. The actions for the listed service are not allowed by this statement. We recommend that you move these actions to a different statement without this condition key.", + "resourceName": "test_stream", + "policyName": "aws_kinesis_stream.test_stream", + "details": { + "result": "FAIL", + "message": "Using the effect Allow with the condition key aws:ResourceTag/environment and actions for services with the following prefixes does not affect the policy: ec2. The actions for the listed service are not allowed by this statement. We recommend that you move these actions to a different statement without this condition key.", + "reasons": [ + { + "description": "New access in the statement with index: 0.", + "statementIndex": 0 + } + ] + } + } + ], + "NonBlockingFindings": [] +} \ No newline at end of file diff --git a/iam_check/test/multiple_policies/identity_codes_reference_policy.json b/iam_check/test/multiple_policies/identity_codes_reference_policy.json new file mode 100644 index 0000000..bad21e7 --- /dev/null +++ b/iam_check/test/multiple_policies/identity_codes_reference_policy.json @@ -0,0 +1,30 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "kinesis:Get*", + "kinesis:DescribeStreamSummary" + ], + "Resource": [ + "arn:aws:kinesis:us-east-1:111122223333:stream/stream1" + ] + }, + { + "Effect": "Allow", + "Action": [ + "kinesis:ListStreams", + "ec2:DescribeVolumes" + ], + "Resource": [ + "*" + ], + "Condition": { + "StringEquals": { + "aws:ResourceTag/environment": "production" + } + } + } + ] +} \ No newline at end of file diff --git a/iam_check/test/multiple_policies/test.tf b/iam_check/test/multiple_policies/test.tf index 5a4bc3d..1349e71 100644 --- a/iam_check/test/multiple_policies/test.tf +++ b/iam_check/test/multiple_policies/test.tf @@ -7,6 +7,10 @@ terraform { } } +provider "aws" { + region = "us-west-2" +} + resource "aws_s3_bucket" "example" { bucket = "my-tf-test-bucket" } @@ -17,7 +21,7 @@ resource "aws_s3_bucket_policy" "allow_access_from_another_account" { } data "aws_iam_policy_document" "allow_access_from_another_account" { - statement { + statement { principals { type = "AWS" identifiers = ["123456789012"] @@ -60,8 +64,13 @@ resource "aws_iam_user_policy" "lb_ro" { "ec2:Describe*", ] Effect = "Allow" - Resource = "*" + Resource = "*", + Condition = { + "StringEquals" = { + "aws:ResourceTag/environment" = "production" + } + } }, ] }) -} \ No newline at end of file +} diff --git a/iam_check/test/multiple_policies/test_plan.json b/iam_check/test/multiple_policies/test_plan.json index 1221a21..31e64a0 100644 --- a/iam_check/test/multiple_policies/test_plan.json +++ b/iam_check/test/multiple_policies/test_plan.json @@ -1 +1,521 @@ -{"format_version":"1.2","terraform_version":"1.5.7","planned_values":{"root_module":{"resources":[{"address":"aws_iam_access_key.lb","mode":"managed","type":"aws_iam_access_key","name":"lb","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"pgp_key":null,"status":"Active","user":"loadbalancer"},"sensitive_values":{}},{"address":"aws_iam_user.lb","mode":"managed","type":"aws_iam_user","name":"lb","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"force_destroy":false,"name":"loadbalancer","path":"/system/","permissions_boundary":null,"tags":{"tag-key":"tag-value"},"tags_all":{"tag-key":"tag-value"}},"sensitive_values":{"tags":{},"tags_all":{}}},{"address":"aws_iam_user_policy.lb_ro","mode":"managed","type":"aws_iam_user_policy","name":"lb_ro","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"name":"test","name_prefix":null,"policy":"{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":[\"ec2:Describe*\"],\"Effect\":\"Allow\",\"Resource\":\"*\"}]}","user":"loadbalancer"},"sensitive_values":{}},{"address":"aws_s3_bucket.example","mode":"managed","type":"aws_s3_bucket","name":"example","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"my-tf-test-bucket","force_destroy":false,"tags":null,"timeouts":null},"sensitive_values":{"cors_rule":[],"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"replication_configuration":[],"server_side_encryption_configuration":[],"tags_all":{},"versioning":[],"website":[]}},{"address":"aws_s3_bucket_policy.allow_access_from_another_account","mode":"managed","type":"aws_s3_bucket_policy","name":"allow_access_from_another_account","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"policy":"{\"Statement\":[{\"Action\":[\"s3:ListBucket\",\"s3:GetObject\"],\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"123456789012\"},\"Resource\":\"*\",\"Sid\":\"\"}],\"Version\":\"2012-10-17\"}"},"sensitive_values":{}}]}},"resource_changes":[{"address":"aws_iam_access_key.lb","mode":"managed","type":"aws_iam_access_key","name":"lb","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"pgp_key":null,"status":"Active","user":"loadbalancer"},"after_unknown":{"create_date":true,"encrypted_secret":true,"encrypted_ses_smtp_password_v4":true,"id":true,"key_fingerprint":true,"secret":true,"ses_smtp_password_v4":true},"before_sensitive":false,"after_sensitive":{"secret":true,"ses_smtp_password_v4":true}}},{"address":"aws_iam_user.lb","mode":"managed","type":"aws_iam_user","name":"lb","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"force_destroy":false,"name":"loadbalancer","path":"/system/","permissions_boundary":null,"tags":{"tag-key":"tag-value"},"tags_all":{"tag-key":"tag-value"}},"after_unknown":{"arn":true,"id":true,"tags":{},"tags_all":{},"unique_id":true},"before_sensitive":false,"after_sensitive":{"tags":{},"tags_all":{}}}},{"address":"aws_iam_user_policy.lb_ro","mode":"managed","type":"aws_iam_user_policy","name":"lb_ro","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"name":"test","name_prefix":null,"policy":"{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":[\"ec2:Describe*\"],\"Effect\":\"Allow\",\"Resource\":\"*\"}]}","user":"loadbalancer"},"after_unknown":{"id":true},"before_sensitive":false,"after_sensitive":{}}},{"address":"aws_s3_bucket.example","mode":"managed","type":"aws_s3_bucket","name":"example","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"my-tf-test-bucket","force_destroy":false,"tags":null,"timeouts":null},"after_unknown":{"acceleration_status":true,"acl":true,"arn":true,"bucket_domain_name":true,"bucket_prefix":true,"bucket_regional_domain_name":true,"cors_rule":true,"grant":true,"hosted_zone_id":true,"id":true,"lifecycle_rule":true,"logging":true,"object_lock_configuration":true,"object_lock_enabled":true,"policy":true,"region":true,"replication_configuration":true,"request_payer":true,"server_side_encryption_configuration":true,"tags_all":true,"versioning":true,"website":true,"website_domain":true,"website_endpoint":true},"before_sensitive":false,"after_sensitive":{"cors_rule":[],"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"replication_configuration":[],"server_side_encryption_configuration":[],"tags_all":{},"versioning":[],"website":[]}}},{"address":"aws_s3_bucket_policy.allow_access_from_another_account","mode":"managed","type":"aws_s3_bucket_policy","name":"allow_access_from_another_account","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"policy":"{\"Statement\":[{\"Action\":[\"s3:ListBucket\",\"s3:GetObject\"],\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"123456789012\"},\"Resource\":\"*\",\"Sid\":\"\"}],\"Version\":\"2012-10-17\"}"},"after_unknown":{"bucket":true,"id":true},"before_sensitive":false,"after_sensitive":{}}}],"prior_state":{"format_version":"1.0","terraform_version":"1.5.7","values":{"root_module":{"resources":[{"address":"data.aws_iam_policy_document.allow_access_from_another_account","mode":"data","type":"aws_iam_policy_document","name":"allow_access_from_another_account","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"id":"2649786899","json":"{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"s3:ListBucket\",\n \"s3:GetObject\"\n ],\n \"Resource\": \"*\",\n \"Principal\": {\n \"AWS\": \"123456789012\"\n }\n }\n ]\n}","override_json":null,"override_policy_documents":null,"policy_id":null,"source_json":null,"source_policy_documents":null,"statement":[{"actions":["s3:GetObject","s3:ListBucket"],"condition":[],"effect":"Allow","not_actions":[],"not_principals":[],"not_resources":[],"principals":[{"identifiers":["123456789012"],"type":"AWS"}],"resources":["*"],"sid":""}],"version":"2012-10-17"},"sensitive_values":{"statement":[{"actions":[false,false],"condition":[],"not_actions":[],"not_principals":[],"not_resources":[],"principals":[{"identifiers":[false]}],"resources":[false]}]}}]}}},"configuration":{"provider_config":{"aws":{"name":"aws","full_name":"registry.terraform.io/hashicorp/aws","version_constraint":"~\u003e 4.0"}},"root_module":{"resources":[{"address":"aws_iam_access_key.lb","mode":"managed","type":"aws_iam_access_key","name":"lb","provider_config_key":"aws","expressions":{"user":{"references":["aws_iam_user.lb.name","aws_iam_user.lb"]}},"schema_version":0},{"address":"aws_iam_user.lb","mode":"managed","type":"aws_iam_user","name":"lb","provider_config_key":"aws","expressions":{"name":{"constant_value":"loadbalancer"},"path":{"constant_value":"/system/"},"tags":{"constant_value":{"tag-key":"tag-value"}}},"schema_version":0},{"address":"aws_iam_user_policy.lb_ro","mode":"managed","type":"aws_iam_user_policy","name":"lb_ro","provider_config_key":"aws","expressions":{"name":{"constant_value":"test"},"policy":{},"user":{"references":["aws_iam_user.lb.name","aws_iam_user.lb"]}},"schema_version":0},{"address":"aws_s3_bucket.example","mode":"managed","type":"aws_s3_bucket","name":"example","provider_config_key":"aws","expressions":{"bucket":{"constant_value":"my-tf-test-bucket"}},"schema_version":0},{"address":"aws_s3_bucket_policy.allow_access_from_another_account","mode":"managed","type":"aws_s3_bucket_policy","name":"allow_access_from_another_account","provider_config_key":"aws","expressions":{"bucket":{"references":["aws_s3_bucket.example.id","aws_s3_bucket.example"]},"policy":{"references":["data.aws_iam_policy_document.allow_access_from_another_account.json","data.aws_iam_policy_document.allow_access_from_another_account"]}},"schema_version":0},{"address":"data.aws_iam_policy_document.allow_access_from_another_account","mode":"data","type":"aws_iam_policy_document","name":"allow_access_from_another_account","provider_config_key":"aws","expressions":{"statement":[{"actions":{"constant_value":["s3:GetObject","s3:ListBucket"]},"principals":[{"identifiers":{"constant_value":["123456789012"]},"type":{"constant_value":"AWS"}}],"resources":{"constant_value":["*"]}}]},"schema_version":0}]}},"relevant_attributes":[{"resource":"aws_iam_user.lb","attribute":["name"]},{"resource":"aws_s3_bucket.example","attribute":["id"]},{"resource":"data.aws_iam_policy_document.allow_access_from_another_account","attribute":["json"]}],"timestamp":"2023-11-07T23:00:11Z"} +{ + "format_version": "1.2", + "terraform_version": "1.5.7", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_iam_access_key.lb", + "mode": "managed", + "type": "aws_iam_access_key", + "name": "lb", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "pgp_key": null, + "status": "Active", + "user": "loadbalancer" + }, + "sensitive_values": {} + }, + { + "address": "aws_iam_user.lb", + "mode": "managed", + "type": "aws_iam_user", + "name": "lb", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "force_destroy": false, + "name": "loadbalancer", + "path": "/system/", + "permissions_boundary": null, + "tags": { + "tag-key": "tag-value" + }, + "tags_all": { + "tag-key": "tag-value" + } + }, + "sensitive_values": { + "tags": {}, + "tags_all": {} + } + }, + { + "address": "aws_iam_user_policy.lb_ro", + "mode": "managed", + "type": "aws_iam_user_policy", + "name": "lb_ro", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "name": "test", + "name_prefix": null, + "policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":[\"ec2:Describe*\"],\"Condition\":{\"StringEquals\":{\"aws:ResourceTag/environment\":\"production\"}},\"Effect\":\"Allow\",\"Resource\":\"*\"}]}", + "user": "loadbalancer" + }, + "sensitive_values": {} + }, + { + "address": "aws_s3_bucket.example", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "bucket": "my-tf-test-bucket", + "force_destroy": false, + "tags": null, + "timeouts": null + }, + "sensitive_values": { + "cors_rule": [], + "grant": [], + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "replication_configuration": [], + "server_side_encryption_configuration": [], + "tags_all": {}, + "versioning": [], + "website": [] + } + }, + { + "address": "aws_s3_bucket_policy.allow_access_from_another_account", + "mode": "managed", + "type": "aws_s3_bucket_policy", + "name": "allow_access_from_another_account", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "policy": "{\"Statement\":[{\"Action\":[\"s3:ListBucket\",\"s3:GetObject\"],\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"123456789012\"},\"Resource\":\"*\",\"Sid\":\"\"}],\"Version\":\"2012-10-17\"}" + }, + "sensitive_values": {} + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_iam_access_key.lb", + "mode": "managed", + "type": "aws_iam_access_key", + "name": "lb", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "pgp_key": null, + "status": "Active", + "user": "loadbalancer" + }, + "after_unknown": { + "create_date": true, + "encrypted_secret": true, + "encrypted_ses_smtp_password_v4": true, + "id": true, + "key_fingerprint": true, + "secret": true, + "ses_smtp_password_v4": true + }, + "before_sensitive": false, + "after_sensitive": { + "secret": true, + "ses_smtp_password_v4": true + } + } + }, + { + "address": "aws_iam_user.lb", + "mode": "managed", + "type": "aws_iam_user", + "name": "lb", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "force_destroy": false, + "name": "loadbalancer", + "path": "/system/", + "permissions_boundary": null, + "tags": { + "tag-key": "tag-value" + }, + "tags_all": { + "tag-key": "tag-value" + } + }, + "after_unknown": { + "arn": true, + "id": true, + "tags": {}, + "tags_all": {}, + "unique_id": true + }, + "before_sensitive": false, + "after_sensitive": { + "tags": {}, + "tags_all": {} + } + } + }, + { + "address": "aws_iam_user_policy.lb_ro", + "mode": "managed", + "type": "aws_iam_user_policy", + "name": "lb_ro", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "name": "test", + "name_prefix": null, + "policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":[\"ec2:Describe*\"],\"Condition\":{\"StringEquals\":{\"aws:ResourceTag/environment\":\"production\"}},\"Effect\":\"Allow\",\"Resource\":\"*\"}]}", + "user": "loadbalancer" + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + }, + { + "address": "aws_s3_bucket.example", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "example", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "bucket": "my-tf-test-bucket", + "force_destroy": false, + "tags": null, + "timeouts": null + }, + "after_unknown": { + "acceleration_status": true, + "acl": true, + "arn": true, + "bucket_domain_name": true, + "bucket_prefix": true, + "bucket_regional_domain_name": true, + "cors_rule": true, + "grant": true, + "hosted_zone_id": true, + "id": true, + "lifecycle_rule": true, + "logging": true, + "object_lock_configuration": true, + "object_lock_enabled": true, + "policy": true, + "region": true, + "replication_configuration": true, + "request_payer": true, + "server_side_encryption_configuration": true, + "tags_all": true, + "versioning": true, + "website": true, + "website_domain": true, + "website_endpoint": true + }, + "before_sensitive": false, + "after_sensitive": { + "cors_rule": [], + "grant": [], + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "replication_configuration": [], + "server_side_encryption_configuration": [], + "tags_all": {}, + "versioning": [], + "website": [] + } + } + }, + { + "address": "aws_s3_bucket_policy.allow_access_from_another_account", + "mode": "managed", + "type": "aws_s3_bucket_policy", + "name": "allow_access_from_another_account", + "provider_name": "registry.terraform.io/hashicorp/aws", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "policy": "{\"Statement\":[{\"Action\":[\"s3:ListBucket\",\"s3:GetObject\"],\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"123456789012\"},\"Resource\":\"*\",\"Sid\":\"\"}],\"Version\":\"2012-10-17\"}" + }, + "after_unknown": { + "bucket": true, + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + } + ], + "prior_state": { + "format_version": "1.0", + "terraform_version": "1.5.7", + "values": { + "root_module": { + "resources": [ + { + "address": "data.aws_iam_policy_document.allow_access_from_another_account", + "mode": "data", + "type": "aws_iam_policy_document", + "name": "allow_access_from_another_account", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 0, + "values": { + "id": "2649786899", + "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"s3:ListBucket\",\n \"s3:GetObject\"\n ],\n \"Resource\": \"*\",\n \"Principal\": {\n \"AWS\": \"123456789012\"\n }\n }\n ]\n}", + "override_json": null, + "override_policy_documents": null, + "policy_id": null, + "source_json": null, + "source_policy_documents": null, + "statement": [ + { + "actions": [ + "s3:GetObject", + "s3:ListBucket" + ], + "condition": [], + "effect": "Allow", + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [ + { + "identifiers": [ + "123456789012" + ], + "type": "AWS" + } + ], + "resources": [ + "*" + ], + "sid": "" + } + ], + "version": "2012-10-17" + }, + "sensitive_values": { + "statement": [ + { + "actions": [ + false, + false + ], + "condition": [], + "not_actions": [], + "not_principals": [], + "not_resources": [], + "principals": [ + { + "identifiers": [ + false + ] + } + ], + "resources": [ + false + ] + } + ] + } + } + ] + } + } + }, + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "full_name": "registry.terraform.io/hashicorp/aws", + "version_constraint": "~\u003e 4.0", + "expressions": { + "region": { + "constant_value": "us-west-2" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_iam_access_key.lb", + "mode": "managed", + "type": "aws_iam_access_key", + "name": "lb", + "provider_config_key": "aws", + "expressions": { + "user": { + "references": [ + "aws_iam_user.lb.name", + "aws_iam_user.lb" + ] + } + }, + "schema_version": 0 + }, + { + "address": "aws_iam_user.lb", + "mode": "managed", + "type": "aws_iam_user", + "name": "lb", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "loadbalancer" + }, + "path": { + "constant_value": "/system/" + }, + "tags": { + "constant_value": { + "tag-key": "tag-value" + } + } + }, + "schema_version": 0 + }, + { + "address": "aws_iam_user_policy.lb_ro", + "mode": "managed", + "type": "aws_iam_user_policy", + "name": "lb_ro", + "provider_config_key": "aws", + "expressions": { + "name": { + "constant_value": "test" + }, + "policy": {}, + "user": { + "references": [ + "aws_iam_user.lb.name", + "aws_iam_user.lb" + ] + } + }, + "schema_version": 0 + }, + { + "address": "aws_s3_bucket.example", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "example", + "provider_config_key": "aws", + "expressions": { + "bucket": { + "constant_value": "my-tf-test-bucket" + } + }, + "schema_version": 0 + }, + { + "address": "aws_s3_bucket_policy.allow_access_from_another_account", + "mode": "managed", + "type": "aws_s3_bucket_policy", + "name": "allow_access_from_another_account", + "provider_config_key": "aws", + "expressions": { + "bucket": { + "references": [ + "aws_s3_bucket.example.id", + "aws_s3_bucket.example" + ] + }, + "policy": { + "references": [ + "data.aws_iam_policy_document.allow_access_from_another_account.json", + "data.aws_iam_policy_document.allow_access_from_another_account" + ] + } + }, + "schema_version": 0 + }, + { + "address": "data.aws_iam_policy_document.allow_access_from_another_account", + "mode": "data", + "type": "aws_iam_policy_document", + "name": "allow_access_from_another_account", + "provider_config_key": "aws", + "expressions": { + "statement": [ + { + "actions": { + "constant_value": [ + "s3:GetObject", + "s3:ListBucket" + ] + }, + "principals": [ + { + "identifiers": { + "constant_value": [ + "123456789012" + ] + }, + "type": { + "constant_value": "AWS" + } + } + ], + "resources": { + "constant_value": [ + "*" + ] + } + } + ] + }, + "schema_version": 0 + } + ] + } + }, + "relevant_attributes": [ + { + "resource": "aws_iam_user.lb", + "attribute": [ + "name" + ] + }, + { + "resource": "data.aws_iam_policy_document.allow_access_from_another_account", + "attribute": [ + "json" + ] + }, + { + "resource": "aws_s3_bucket.example", + "attribute": [ + "id" + ] + } + ], + "timestamp": "2024-04-20T21:53:24Z" +} \ No newline at end of file diff --git a/iam_check/test/test_accessAnalyzer.py b/iam_check/test/test_accessAnalyzer.py index 13c6a4e..82d7b24 100644 --- a/iam_check/test/test_accessAnalyzer.py +++ b/iam_check/test/test_accessAnalyzer.py @@ -1,7 +1,7 @@ from lib import _load_json_file from lib.reporter import Reporter from lib.tfPlan import TerraformPlan -from lib.iamcheck_AccessAnalyzer import Comparator, Validator +from lib.iamcheck_AccessAnalyzer import Comparator, Validator, PolicyAnalysis from iam_check.config import load_config_yaml import pytest import json @@ -18,6 +18,16 @@ def test_a2_policy_validation(self): findings = _load_json_file("test/iam_policy/findings.json") assert(Reporter(None, None, None).build_report_from(check.findings).to_json() == findings) + def test_a2_code_blocking(self): + file = _load_json_file(f"test/multiple_policies/test_plan.json") + plan = TerraformPlan(**file) + reference_policy = _load_json_file(f"test/multiple_policies/identity_codes_reference_policy.json") + check = Validator("123456789012", "us-west-2", "aws") + check.run(plan) + test_findings = _load_json_file(f"test/multiple_policies/identity_codes.json") + report = Reporter(None, [], None, ['ALLOW_WITH_UNSUPPORTED_TAG_CONDITION_KEY_FOR_SERVICE']).build_report_from(check.findings).to_json() + assert(report["BlockingFindings"][0]['code'] == "ALLOW_WITH_UNSUPPORTED_TAG_CONDITION_KEY_FOR_SERVICE") + def test_a2_policy_check_no_new_access_mixed_policies(self): for dir_name in ["multiple_policies", "role_inline_assume_policy"]: file = _load_json_file(f"test/{dir_name}/test_plan.json")