Skip to content

Commit 085458a

Browse files
authored
Add CheckNoPublicAccess command and update CheckAccessNotGranted with resource type support (#34)
1 parent 0bceb9f commit 085458a

19 files changed

+778
-33
lines changed

README.md

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ The principal used to execute the tool requires the following permissions.
4242
"Action": [
4343
"access-analyzer:ValidatePolicy",
4444
"access-analyzer:CheckNoNewAccess",
45-
"access-analyzer:CheckAccessNotGranted"
45+
"access-analyzer:CheckAccessNotGranted",
46+
"access-analyzer:CheckNoPublicAccess"
4647
],
4748
"Resource": "*"
4849
}
@@ -54,6 +55,7 @@ The principal used to execute the tool requires the following permissions.
5455
| access-analyzer:ValidatePolicy | Called for each policy to validate against IAM policy best practices. |
5556
| access-analyzer:CheckNoNewAccess | Called for each policy to validate against a reference policy to compare permissions. |
5657
| access-analyzer:CheckAccessNotGranted | Called for each policy to validate that it does not grant access to a list of IAM actions, considered as critical permissions, provided as input. |
58+
| access-analyzer:CheckNoPublicAccess | Called for each policy to validate that it does not grant public access to supported resource types. |
5759

5860

5961
### Basic usage
@@ -103,7 +105,27 @@ Parses IAM identity-based and resource-based policies from Terraform templates.
103105
```
104106
tf-policy-validator check-access-not-granted --config iam_check/config/default.yaml --template-path iam_check/test/test_policy_accessanalyzer.json --region us-west-2 --actions lambda:invokeFunction
105107
```
106-
Parses IAM identity-based and resource-based policies from Terraform templates. Then runs the policies through IAM Access Analyzer for a custom check against a list of IAM actions. Returns the findings from the custom check in JSON format. Exits with a non-zero error code if any findings categorized as blocking, based on access granted to at least one of the listed IAM actions, are found in your template. Exits with an error code of zero if all findings are non-blocking or there are no findings.
108+
Parses IAM identity-based and resource-based policies from AWS Terraform templates. Then runs the policies through IAM Access Analyzer for a custom check against a list of IAM actions and/or resource ARNs. If both actions and resources are provided, a custom check will be run to determine whether access is granted to allow the specified actions on the specified resources. Returns the findings from the custom check in JSON format. Exits with a non-zero error code if any findings categorized as blocking, based on access granted to at least one of the listed IAM actions and/or resources, are found in your template. Exits with an error code of zero if all findings are non-blocking or there are no findings.
109+
110+
| Arguments | Required | Options | Description |
111+
| --------- | ----- | ---------| ----------- |
112+
| --help | | | show this help message and exit |
113+
| --template-path | | FILE_NAME | The path to the Terraform plan file (JSON). |
114+
| --region | Yes | REGION | The destination region the resources will be deployed to. |
115+
| --profile | | PROFILE | The named profile to use for AWS API calls. |
116+
| --enable-logging | | | Enables log output to stdout |
117+
| --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. |
118+
| --actions | At least one of actions or resources is required. | ACTION,ACTION,ACTION | List of comma-separated actions. |
119+
| --resources | At least one of actions or resources is required. | RESOURCE,RESOURCE,RESOURCE | List of comma-separated resource ARNs, maximum 100 resource ARNs.
120+
| --treat-findings-as-non-blocking | | | When not specified, the tool detects any findings, it will exit with a non-zero exit code. When specified, the tool exits with an exit code of 0. |
121+
| --exclude-resource-types | | aws_resource_type, aws_resource_type | List of comma-separated resource types. Resource types should be the same as terraform template resource names such as aws_iam_group_policy, aws_iam_role |
122+
| --config |Yes | FILE_NAME1, FILE_NAME2, ... | A list of config files for running this script |
123+
124+
**check-no-public-access**
125+
```
126+
tf-policy-validator check-no-public-access --config iam_check/config/default.yaml --template-path iam_check/test/test_policy_accessanalyzer.json --region us-west-2
127+
```
128+
Parses resource-based policies from Terraform templates. Then runs the policies through IAM Access Analyzer for a custom check for public access to resources. Returns the findings from the custom check in JSON format. Exits with a non-zero error code if any findings categorized as blocking, based on whether public access is granted to at least one of the resources, are found in your template. Exits with an error code of zero if all findings are non-blocking or there are no findings.
107129

108130
| Arguments | Required | Options | Description |
109131
| --------- | -------- | ---------| ----------- |
@@ -113,11 +135,24 @@ Parses IAM identity-based and resource-based policies from Terraform templates.
113135
| --profile | | PROFILE | The named profile to use for AWS API calls. |
114136
| --enable-logging | | | Enables log output to stdout |
115137
| --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. |
116-
| --actions | Yes | ACTION,ACTION,ACTION | List of comma-separated actions. |
117138
| --treat-findings-as-non-blocking | | | When not specified, the tool detects any findings, it will exit with a non-zero exit code. When specified, the tool exits with an exit code of 0. |
118139
| --exclude-resource-types | | aws_resource_type, aws_resource_type | List of comma-separated resource types. Resource types should be the same as terraform template resource names such as aws_iam_group_policy, aws_iam_role |
119140
| --config |Yes | FILE_NAME1, FILE_NAME2, ... | A list of config files for running this script |
120141

142+
Resource-based policies that can be checked with `check-no-public-access` are limited to the resource types currently supported by IAM Policy Validator for Terraform. The following resource types are supported:
143+
- AWS::EFS::FileSystem
144+
- AWS::OpenSearchService::Domain
145+
- AWS::KMS::Key
146+
- AWS::S3::Bucket
147+
- AWS::S3::AccessPoint
148+
- AWS::S3::Glacier
149+
- AWS::S3Outposts::Bucket
150+
- AWS::SecretsManager::Secret
151+
- AWS::SNS::Topic
152+
- AWS::SQS::Queue
153+
- Role trust policies (AWS::IAM::AssumeRolePolicyDocument)
154+
155+
121156
### Example to check Terraform template
122157
```
123158
$ cd iam_check/test/
@@ -128,6 +163,7 @@ $ cd ../..
128163
$ tf-policy-validator --config iam_check/config/default.yaml --template-path iam_check/test/tf.json --region us-east-1 --treat-finding-type-as-blocking ERROR # For TF 0.12 and prior, replace tf.json with tf.out
129164
$ tf-policy-validator check-no-new-access --config iam_check/config/default.yaml --template-path iam_check/test/test_policy_accessanalyzer.json --region us-west-2 --reference-policy-type identity --reference-policy iam_check/test/test_policy.json
130165
$ tf-policy-validator check-access-not-granted --config iam_check/config/default.yaml --template-path iam_check/test/test_policy_accessanalyzer.json --region us-west-2 --actions lambda:invokeFunction
166+
$ tf-policy-validator check-no-public-access --config iam_check/config/default.yaml --template-path iam_check/test/test_policy_accessanalyzer.json --region us-west-2
131167
```
132168

133169
_More examples can be found [here](iam_check/doc/)_.

iam_check/config/default.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ arnServiceMap:
3131
# aws_lambda_layer_version_permission: layer_name?fakeLayberName
3232
aws_media_store_container_policy: container_name?fakeContainerName
3333
aws_networkfirewall_resource_policy: resource_arn?fakeResourceArn
34+
aws_opensearch_domain: domain_name?fakeDomainName
35+
aws_opensearch_domain_policy: domain_name?fakeDomainName
3436
aws_organizations_policy: name?fakename
3537
aws_s3_access_point: name?fakename
3638
aws_s3_bucket: bucket?fakeBucket
@@ -92,6 +94,8 @@ iamPolicyAttributes:
9294
# aws_lambda_layer_version_permission: policy
9395
aws_media_store_container_policy: policy
9496
aws_networkfirewall_resource_policy: policy
97+
aws_opensearch_domain: access_policies
98+
aws_opensearch_domain_policy: access_policies
9599
aws_organizations_policy: content
96100
aws_s3_access_point: policy
97101
aws_s3_bucket: policy

iam_check/iam_check.py

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from .argument_actions import ParseFindingsToIgnoreFromCLI, ParseAllowExternalPrincipalsFromCLI, ParseListFromCLI
1313
from .lib import _load_json_file, iamcheck_AccessAnalyzer, account_config, tfPlan
1414
from .lib.reporter import default_finding_types_that_are_blocking, Reporter
15+
from iam_check.application_error import ApplicationError as ApplicationError
1516

1617
# Global Variables
1718
LOGGER = logging.getLogger('iam-policy-validator-for-terraform')
@@ -42,7 +43,14 @@ def validate_from_cli(opts):
4243
checker.run(plan)
4344
findings = checker.findings
4445
elif opts.subparser == 'check-access-not-granted':
45-
checker=iamcheck_AccessAnalyzer.AccessChecker(account.Region, opts.actions)
46+
if opts.actions is None and opts.resources is None:
47+
raise ApplicationError("ERROR: At least one of --actions or --resources must be specified.")
48+
else :
49+
checker=iamcheck_AccessAnalyzer.AccessChecker(account.Region, opts.actions, opts.resources)
50+
checker.run(plan)
51+
findings = checker.findings
52+
elif opts.subparser == 'check-no-public-access':
53+
checker = iamcheck_AccessAnalyzer.PublicAccessChecker(account.Region)
4654
checker.run(plan)
4755
findings = checker.findings
4856
else:
@@ -131,15 +139,24 @@ def add_policy_analysis_subparsers():
131139
default=True, action='store_false')
132140

133141
# check-access-not-granted command
134-
check_access_parser = subparsers.add_parser('check-access-not-granted', help='Parses IAM identity-based and resource-based policies from AWS Terraform templates '
135-
'and runs them through IAM Access Analyzer to check that access to a list of actions is not granted. Returns the response '
136-
'in JSON format.', parents=[parent_parser])
142+
check_access_parser = subparsers.add_parser('check-access-not-granted', help='Parses IAM identity-based and resource-based policies from AWS CloudFormation '
143+
'templates and runs them through IAM Access Analyzer to check that access to a list of actions and/or '
144+
'resources is not granted. Returns the response in JSON format.', parents=[parent_parser])
145+
146+
check_access_parser.add_argument('--resources', dest="resources",
147+
help= 'Resources that policies should not grant access to. '
148+
'Specify as a comma-separated list of resource ARNs to be checked. '
149+
'A maximum of 100 resources can be specified for a single request. '
150+
'The tool will not make multiple requests if you provide more resources than the allowed quota. '
151+
'At least one of --actions or --resources must be specified.', action=ParseListFromCLI)
152+
153+
check_access_parser.add_argument('--actions', dest="actions",
154+
help= 'Actions that policies should not grant. '
155+
'Specify as a comma separated list of actions to be checked. '
156+
'A maximum of 100 actions can be specified for a single request. '
157+
'The tool will make multiple requests if you provide more actions than the allowed quota. '
158+
'At least one of --actions or --resources must be specified.', action=ParseListFromCLI)
137159

138-
check_access_parser.add_argument('--actions', dest="actions", required=True,
139-
help= 'Actions that policies should not grant.'
140-
'Specify as a comma separated list of actions to be checked.'
141-
'The tool will make multiple requests if you provide more actions than the allowed quota.', action=ParseListFromCLI)
142-
143160
check_access_parser.add_argument('--ignore-finding', dest="ignore_finding", metavar='FINDING_CODE,RESOURCE_NAME,RESOURCE_NAME.FINDING_CODE',
144161
help='Allow findings to be ignored.\n'
145162
'Specify as a comma separated list of findings to be ignored. Can be individual '
@@ -150,6 +167,22 @@ def add_policy_analysis_subparsers():
150167
check_access_parser.add_argument('--treat-findings-as-non-blocking', dest="findings_are_blocking",
151168
help='If set, all findings will be treated as non-blocking',
152169
default=True, action='store_false')
170+
#check-no-public-access command
171+
check_no_public_access_parser = subparsers.add_parser('check-no-public-access', help='Parses resource-based policies from AWS Terraform templates and runs them through '
172+
'IAM Access Analyzer to check that public access to resources of supported types is not granted. Returns the response '
173+
'in JSON format.', parents=[parent_parser])
174+
175+
check_no_public_access_parser.add_argument('--ignore-finding', dest="ignore_finding", metavar='FINDING_CODE,RESOURCE_NAME,RESOURCE_NAME.FINDING_CODE',
176+
help='Allow findings to be ignored.\n'
177+
'Specify as a comma separated list of findings to be ignored. Can be individual '
178+
'finding codes (e.g. "PASS_ROLE_WITH_STAR_IN_RESOURCE"), a specific resource name '
179+
'(e.g. "MyResource"), or a combination of both separated by a period.'
180+
'(e.g. "MyResource.PASS_ROLE_WITH_STAR_IN_RESOURCE").',
181+
action=ParseFindingsToIgnoreFromCLI)
182+
check_no_public_access_parser.add_argument('--treat-findings-as-non-blocking', dest="findings_are_blocking",
183+
help='If set, all findings will be treated as non-blocking',
184+
default=True, action='store_false')
185+
153186

154187
add_policy_analysis_subparsers()
155188

@@ -177,4 +210,4 @@ def add_policy_analysis_subparsers():
177210
except Exception as e:
178211
traceback.print_exc()
179212
print(f'ERROR: Unexpected error occurred. {str(e)}', file=sys.stderr)
180-
exit(1)
213+
exit(1)

0 commit comments

Comments
 (0)