Skip to content

Commit

Permalink
Add CheckNoPublicAccess command and update CheckAccessNotGranted with…
Browse files Browse the repository at this point in the history
… resource type support (#34)
  • Loading branch information
alankuo-aws authored Jun 11, 2024
1 parent 0bceb9f commit 085458a
Show file tree
Hide file tree
Showing 19 changed files with 778 additions and 33 deletions.
42 changes: 39 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ The principal used to execute the tool requires the following permissions.
"Action": [
"access-analyzer:ValidatePolicy",
"access-analyzer:CheckNoNewAccess",
"access-analyzer:CheckAccessNotGranted"
"access-analyzer:CheckAccessNotGranted",
"access-analyzer:CheckNoPublicAccess"
],
"Resource": "*"
}
Expand All @@ -54,6 +55,7 @@ The principal used to execute the tool requires the following permissions.
| access-analyzer:ValidatePolicy | Called for each policy to validate against IAM policy best practices. |
| access-analyzer:CheckNoNewAccess | Called for each policy to validate against a reference policy to compare permissions. |
| 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. |
| access-analyzer:CheckNoPublicAccess | Called for each policy to validate that it does not grant public access to supported resource types. |


### Basic usage
Expand Down Expand Up @@ -103,7 +105,27 @@ Parses IAM identity-based and resource-based policies from Terraform templates.
```
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
```
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.
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.

| Arguments | Required | Options | Description |
| --------- | ----- | ---------| ----------- |
| --help | | | show this help message and exit |
| --template-path | | FILE_NAME | The path to the Terraform plan file (JSON). |
| --region | Yes | REGION | The destination region the resources will be deployed to. |
| --profile | | PROFILE | The named profile to use for AWS API calls. |
| --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. |
| --actions | At least one of actions or resources is required. | ACTION,ACTION,ACTION | List of comma-separated actions. |
| --resources | At least one of actions or resources is required. | RESOURCE,RESOURCE,RESOURCE | List of comma-separated resource ARNs, maximum 100 resource ARNs.
| --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. |
| --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 |
| --config |Yes | FILE_NAME1, FILE_NAME2, ... | A list of config files for running this script |

**check-no-public-access**
```
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
```
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.

| Arguments | Required | Options | Description |
| --------- | -------- | ---------| ----------- |
Expand All @@ -113,11 +135,24 @@ Parses IAM identity-based and resource-based policies from Terraform templates.
| --profile | | PROFILE | The named profile to use for AWS API calls. |
| --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. |
| --actions | Yes | ACTION,ACTION,ACTION | List of comma-separated actions. |
| --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. |
| --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 |
| --config |Yes | FILE_NAME1, FILE_NAME2, ... | A list of config files for running this script |

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:
- AWS::EFS::FileSystem
- AWS::OpenSearchService::Domain
- AWS::KMS::Key
- AWS::S3::Bucket
- AWS::S3::AccessPoint
- AWS::S3::Glacier
- AWS::S3Outposts::Bucket
- AWS::SecretsManager::Secret
- AWS::SNS::Topic
- AWS::SQS::Queue
- Role trust policies (AWS::IAM::AssumeRolePolicyDocument)


### Example to check Terraform template
```
$ cd iam_check/test/
Expand All @@ -128,6 +163,7 @@ $ cd ../..
$ 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
$ 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
$ 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
$ 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
```

_More examples can be found [here](iam_check/doc/)_.
Expand Down
4 changes: 4 additions & 0 deletions iam_check/config/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ arnServiceMap:
# aws_lambda_layer_version_permission: layer_name?fakeLayberName
aws_media_store_container_policy: container_name?fakeContainerName
aws_networkfirewall_resource_policy: resource_arn?fakeResourceArn
aws_opensearch_domain: domain_name?fakeDomainName
aws_opensearch_domain_policy: domain_name?fakeDomainName
aws_organizations_policy: name?fakename
aws_s3_access_point: name?fakename
aws_s3_bucket: bucket?fakeBucket
Expand Down Expand Up @@ -92,6 +94,8 @@ iamPolicyAttributes:
# aws_lambda_layer_version_permission: policy
aws_media_store_container_policy: policy
aws_networkfirewall_resource_policy: policy
aws_opensearch_domain: access_policies
aws_opensearch_domain_policy: access_policies
aws_organizations_policy: content
aws_s3_access_point: policy
aws_s3_bucket: policy
Expand Down
53 changes: 43 additions & 10 deletions iam_check/iam_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from .argument_actions import ParseFindingsToIgnoreFromCLI, ParseAllowExternalPrincipalsFromCLI, ParseListFromCLI
from .lib import _load_json_file, iamcheck_AccessAnalyzer, account_config, tfPlan
from .lib.reporter import default_finding_types_that_are_blocking, Reporter
from iam_check.application_error import ApplicationError as ApplicationError

# Global Variables
LOGGER = logging.getLogger('iam-policy-validator-for-terraform')
Expand Down Expand Up @@ -42,7 +43,14 @@ def validate_from_cli(opts):
checker.run(plan)
findings = checker.findings
elif opts.subparser == 'check-access-not-granted':
checker=iamcheck_AccessAnalyzer.AccessChecker(account.Region, opts.actions)
if opts.actions is None and opts.resources is None:
raise ApplicationError("ERROR: At least one of --actions or --resources must be specified.")
else :
checker=iamcheck_AccessAnalyzer.AccessChecker(account.Region, opts.actions, opts.resources)
checker.run(plan)
findings = checker.findings
elif opts.subparser == 'check-no-public-access':
checker = iamcheck_AccessAnalyzer.PublicAccessChecker(account.Region)
checker.run(plan)
findings = checker.findings
else:
Expand Down Expand Up @@ -131,15 +139,24 @@ def add_policy_analysis_subparsers():
default=True, action='store_false')

# check-access-not-granted command
check_access_parser = subparsers.add_parser('check-access-not-granted', help='Parses IAM identity-based and resource-based policies from AWS Terraform templates '
'and runs them through IAM Access Analyzer to check that access to a list of actions is not granted. Returns the response '
'in JSON format.', parents=[parent_parser])
check_access_parser = subparsers.add_parser('check-access-not-granted', help='Parses IAM identity-based and resource-based policies from AWS CloudFormation '
'templates and runs them through IAM Access Analyzer to check that access to a list of actions and/or '
'resources is not granted. Returns the response in JSON format.', parents=[parent_parser])

check_access_parser.add_argument('--resources', dest="resources",
help= 'Resources that policies should not grant access to. '
'Specify as a comma-separated list of resource ARNs to be checked. '
'A maximum of 100 resources can be specified for a single request. '
'The tool will not make multiple requests if you provide more resources than the allowed quota. '
'At least one of --actions or --resources must be specified.', action=ParseListFromCLI)

check_access_parser.add_argument('--actions', dest="actions",
help= 'Actions that policies should not grant. '
'Specify as a comma separated list of actions to be checked. '
'A maximum of 100 actions can be specified for a single request. '
'The tool will make multiple requests if you provide more actions than the allowed quota. '
'At least one of --actions or --resources must be specified.', action=ParseListFromCLI)

check_access_parser.add_argument('--actions', dest="actions", required=True,
help= 'Actions that policies should not grant.'
'Specify as a comma separated list of actions to be checked.'
'The tool will make multiple requests if you provide more actions than the allowed quota.', action=ParseListFromCLI)

check_access_parser.add_argument('--ignore-finding', dest="ignore_finding", metavar='FINDING_CODE,RESOURCE_NAME,RESOURCE_NAME.FINDING_CODE',
help='Allow findings to be ignored.\n'
'Specify as a comma separated list of findings to be ignored. Can be individual '
Expand All @@ -150,6 +167,22 @@ def add_policy_analysis_subparsers():
check_access_parser.add_argument('--treat-findings-as-non-blocking', dest="findings_are_blocking",
help='If set, all findings will be treated as non-blocking',
default=True, action='store_false')
#check-no-public-access command
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 '
'IAM Access Analyzer to check that public access to resources of supported types is not granted. Returns the response '
'in JSON format.', parents=[parent_parser])

check_no_public_access_parser.add_argument('--ignore-finding', dest="ignore_finding", metavar='FINDING_CODE,RESOURCE_NAME,RESOURCE_NAME.FINDING_CODE',
help='Allow findings to be ignored.\n'
'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").',
action=ParseFindingsToIgnoreFromCLI)
check_no_public_access_parser.add_argument('--treat-findings-as-non-blocking', dest="findings_are_blocking",
help='If set, all findings will be treated as non-blocking',
default=True, action='store_false')


add_policy_analysis_subparsers()

Expand Down Expand Up @@ -177,4 +210,4 @@ def add_policy_analysis_subparsers():
except Exception as e:
traceback.print_exc()
print(f'ERROR: Unexpected error occurred. {str(e)}', file=sys.stderr)
exit(1)
exit(1)
Loading

0 comments on commit 085458a

Please sign in to comment.