Skip to content

Commit 26797c4

Browse files
authored
Support CheckNoPublicAccess check and CheckAccessNotGranted check with resource type support (#11)
1 parent d3a58f2 commit 26797c4

File tree

5 files changed

+96
-30
lines changed

5 files changed

+96
-30
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ FROM python:3.10
55
# Install tf-policy-validator
66
# Cloning the `terraform-iam-policy-validator` repo for default config for terraform templates
77
# ToDo: Once we start using the tags for releases, we should use the tag associated with the version we download by using flag --branch <tag>
8-
RUN pip install tf-policy-validator==0.0.6 && git clone https://github.com/awslabs/terraform-iam-policy-validator.git
8+
RUN pip install tf-policy-validator==0.0.8 && git clone https://github.com/awslabs/terraform-iam-policy-validator.git
99

1010
ENV TERRAFORM_CONFIG_DEFAULT=/terraform-iam-policy-validator/iam_check/config/default.yaml
1111

README.md

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,27 @@ See [action.yml](action.yaml) for the full documentation for this action's input
2020
<th style="text-align: center;">VALIDATE_POLICY</th>
2121
<th style="text-align: center;">CHECK_NO_NEW_ACCESS</th>
2222
<th style="text-align: center;">CHECK_ACCESS_NOT_GRANTED</th>
23+
<th style="text-align: center;">CHECK_NO_PUBLIC_ACCESS</th>
2324
</tr>
2425
<tr>
2526
<td>policy-check-type</td>
26-
<td>Name of the policy check.<br />Note: Each value corresponds to an IAM Access Analyzer API. <br />- <a href="https://docs.aws.amazon.com/access-analyzer/latest/APIReference/API_ValidatePolicy.html">ValidatePolicy</a><br />- <a href="https://docs.aws.amazon.com/access-analyzer/latest/APIReference/API_CheckNoNewAccess.html">CheckNoNewAccess</a><br />- <a href="https://docs.aws.amazon.com/access-analyzer/latest/APIReference/API_CheckAccessNotGranted.html">CheckAccessNotGranted</a></td>
27-
<td>VALIDATE_POLICY, CHECK_NO_NEW_ACCESS, CHECK_ACCESS_NOT_GRANTED.</td>
27+
<td>Name of the policy check.<br />Note: Each value corresponds to an IAM Access Analyzer API. <br />- <a href="https://docs.aws.amazon.com/access-analyzer/latest/APIReference/API_ValidatePolicy.html">ValidatePolicy</a><br />- <a href="https://docs.aws.amazon.com/access-analyzer/latest/APIReference/API_CheckNoNewAccess.html">CheckNoNewAccess</a><br />- <a href="https://docs.aws.amazon.com/access-analyzer/latest/APIReference/API_CheckAccessNotGranted.html">CheckAccessNotGranted</a><br />- <a href="https://docs.aws.amazon.com/access-analyzer/latest/APIReference/API_CheckNoPublicAccess.html">CheckNoPublicAccess</a></td>
28+
<td>VALIDATE_POLICY, CHECK_NO_NEW_ACCESS, CHECK_ACCESS_NOT_GRANTED, CHECK_NO_PUBLIC_ACCESS.</td>
2829
<td>Yes</td>
2930
<td>✅</td>
3031
<td>✅</td>
3132
<td>✅</td>
33+
<td>✅</td>
3234
</tr>
3335
<tr>
3436
<td>template-path</td>
35-
<td>The path to the Terraform template.</td>
37+
<td>The path to the CloudFormation template.</td>
3638
<td>FILE_PATH.json</td>
3739
<td>Yes</td>
3840
<td>✅</td>
3941
<td>✅</td>
4042
<td>✅</td>
43+
<td>✅</td>
4144
</tr>
4245
<tr>
4346
<td>region</td>
@@ -47,6 +50,7 @@ See [action.yml](action.yaml) for the full documentation for this action's input
4750
<td>✅</td>
4851
<td>✅</td>
4952
<td>✅</td>
53+
<td>✅</td>
5054
</tr>
5155
<tr>
5256
<td>ignore-finding</td>
@@ -56,31 +60,47 @@ See [action.yml](action.yaml) for the full documentation for this action's input
5660
<td>✅</td>
5761
<td>✅</td>
5862
<td>✅</td>
63+
<td>✅</td>
5964
</tr>
6065
<tr>
6166
<td>actions</td>
62-
<td>List of comma-separated actions. Example format - ACTION,ACTION,ACTION. <br /><br /><strong>This attribute is only considered and required when policy-check-type is "CHECK_ACCESS_NOT_GRANTED".</strong></td>
67+
<td>List of comma-separated actions. Example format - ACTION,ACTION,ACTION. <br /><br /><strong>This attribute is only considered when policy-check-type is "CHECK_ACCESS_NOT_GRANTED". At least one of "actions" or "resources" must be provided</strong></td>
6368
<td>ACTION,ACTION,ACTION</td>
6469
<td>No</td>
6570
<td>❌</td>
6671
<td>❌</td>
6772
<td>✅</td>
73+
<td>❌</td>
74+
</tr>
75+
<tr>
76+
<td>resources</td>
77+
<td>List of comma-separated resource ARNs. Example format - RESOURCE,RESOURCE,RESOURCE. <br /><br /><strong>This attribute is only considered when policy-check-type is "CHECK_ACCESS_NOT_GRANTED". At least one of "actions" or "resources" must be provided</strong></td>
78+
<td>RESOURCE,RESOURCE,RESOURCE</td>
79+
<td>No</td>
80+
<td>❌</td>
81+
<td>❌</td>
82+
<td>✅</td>
83+
<td>❌</td>
6884
</tr>
6985
<tr>
7086
<td>reference-policy</td>
7187
<td>A JSON formatted file that specifies the path to the reference policy that is used for a permissions comparison. <br /><br /><strong>This attribute is only considered and required when policy-check-type is "CHECK_NO_NEW_ACCESS".</strong></td>
88+
<td>FILE_PATH.json</td>
7289
<td>No</td>
7390
<td>❌</td>
7491
<td>✅</td>
7592
<td>❌</td>
93+
<td>❌</td>
7694
</tr>
7795
<tr>
7896
<td>reference-policy-type</td>
7997
<td>The policy type associated with the IAM policy under analysis and the reference policy. Valid values: IDENTITY, RESOURCE. <br /><br /><strong> This attribute is only considered and required when policy-check-type is "CHECK_NO_NEW_ACCESS"</strong></td>
98+
<td>REFERENCE_POLICY_TYPE</td>
8099
<td>No</td>
81100
<td>❌</td>
82101
<td>✅</td>
83102
<td>❌</td>
103+
<td>❌</td>
84104
</tr>
85105
<tr>
86106
<td>treat-finding-type-as-blocking</td>
@@ -90,14 +110,17 @@ See [action.yml](action.yaml) for the full documentation for this action's input
90110
<td>✅</td>
91111
<td>❌</td>
92112
<td>❌</td>
113+
<td>❌</td>
93114
</tr>
94115
<tr>
95116
<td>treat-findings-as-non-blocking</td>
96-
<td>By default, the tool will exit with a non-zero exit code when it detects any findings. Set this flag to exit with an exit code of 0 when it detects findings. You can use this to run new checks in a shadow or log only mode before enforcing them. <br /><br /><strong>This attribute is considered only when policy-check-type is "CHECK_NO_NEW_ACCESS" or "CHECK_ACCESS_NOT_GRANTED".</strong></td>
117+
<td>By default, the tool will exit with a non-zero exit code when it detects any findings. Set this flag to exit with an exit code of 0 when it detects findings. You can use this to run new checks in a shadow or log only mode before enforcing them. <br /><br /><strong>This attribute is considered only when policy-check-type is "CHECK_NO_NEW_ACCESS", "CHECK_ACCESS_NOT_GRANTED", or "CHECK_NO_PUBLIC_ACCESS.</strong></td>
118+
<td> </td>
97119
<td>No</td>
98120
<td>❌</td>
99121
<td>✅</td>
100122
<td>✅</td>
123+
<td>✅</td>
101124
</tr>
102125
<tr>
103126
<td>allow-external-principals</td>
@@ -107,14 +130,17 @@ See [action.yml](action.yaml) for the full documentation for this action's input
107130
<td>✅</td>
108131
<td>❌</td>
109132
<td>❌</td>
133+
<td>❌</td>
110134
</tr>
111135
<tr>
112136
<td>allow-dynamic-ref-without-version</td>
113137
<td>Override the default behavior and allow dynamic SSM references without version numbers. The version number ensures that the SSM parameter value that was validated is the one that is deployed.</td>
138+
<td> </td>
114139
<td>No</td>
115140
<td>✅</td>
116141
<td>✅</td>
117142
<td>✅</td>
143+
<td>✅</td>
118144
</tr>
119145
<tr>
120146
<td>exclude-resource-types</td>
@@ -124,6 +150,7 @@ See [action.yml](action.yaml) for the full documentation for this action's input
124150
<td>✅</td>
125151
<td>✅</td>
126152
<td>✅</td>
153+
<td>✅</td>
127154
</tr>
128155
</tbody>
129156
</table>
@@ -135,18 +162,17 @@ See [action.yml](action.yaml) for the full documentation for this action's input
135162

136163
- Setting up the role: Role used in the GitHub workflow should have necessary permissions required
137164
- to be called from the GitHub workflows - setup OpenID Connect(OIDC) provider and IAM role & Trust policy as described in step 1 & 2 in [this](https://aws.amazon.com/blogs/security/use-iam-roles-to-connect-github-actions-to-actions-in-aws/) blog
138-
- to call the AWS APIs for the policy checks - ValidatePolicy, CheckNoNewAccess, CheckAccessNotGranted. Refer [this](https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-checks-validating-policies.html) page for more details
165+
- to call the AWS APIs for the policy checks - ValidatePolicy, CheckNoNewAccess, CheckAccessNotGranted, CheckNoPublicAccess. Refer [this](https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-checks-validating-policies.html) page for more details
139166

140167
```
141168
- name: Checkout Repo
142169
uses: actions/checkout@v4
143170
- name: Configure AWS Credentials
144171
uses: aws-actions/configure-aws-credentials@v4
145172
with:
146-
role-to-assume: ${{ secrets.POLICY_VALIDATOR_ROLE }} # Role with permissions to invoke access-analyzer:ValidatePolicy,access-analyzer:CheckNoNewAccess, access-analyzer:CheckAccessNotGranted
173+
role-to-assume: ${{ secrets.POLICY_VALIDATOR_ROLE }} # Role with permissions to invoke access-analyzer:ValidatePolicy,access-analyzer:CheckNoNewAccess, access-analyzer:CheckAccessNotGranted, access-analyzer:CheckNoPublicAccess
147174
aws-region: aws-example-region
148175
```
149-
150176
#### Getting started using starter workflows
151177

152178
To get started quickly, add a starter workflow to the `.github/workflows` directory of your repository. In order to do that, do the following -
@@ -191,13 +217,26 @@ Please find the starter workflow [here](https://github.com/actions/starter-workf
191217
#### Using for the `CHECK_ACCESS_NOT_GRANTED` CHECK
192218

193219
```
194-
- name: Run CHECK_ACCESS_NOT_GRANTED check
195-
id: run-check-no-new-access
220+
- name: Run CHECK_ACCESS_NOT_GRANTED check
221+
id: run-check-access-not-granted
196222
uses: aws-actions/[email protected]
197223
with:
198224
policy-check-type: 'CHECK_ACCESS_NOT_GRANTED'
199225
template-path: file-path-to-the-cfn-templates
200226
actions: "action1, action2.."
227+
resources: "resource1, resource2.."
228+
region: aws-example-region
229+
```
230+
231+
#### Using for the `CHECK_NO_PUBLIC_ACCESS` CHECK
232+
233+
```
234+
- name: Run CHECK_NO_PUBLIC_ACCESS check
235+
id: run-check-no-public-access
236+
uses: aws-actions/[email protected]
237+
with:
238+
policy-check-type: 'CHECK_NO_PUBLIC_ACCESS'
239+
template-path: file-path-to-the-cfn-templates
201240
region: aws-example-region
202241
```
203242

action.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ inputs:
1616
ignore-finding:
1717
description: '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. Valid options: FINDING_CODE,RESOURCE_NAME,RESOURCE_NAME.FINDING_CODE'
1818
actions:
19-
description: 'List of comma-separated actions. Example format - ACTION,ACTION,ACTION. This attribute is considered and required when policy-check-type is "CHECK_ACCESS_NOT_GRANTED"'
19+
description: 'List of comma-separated actions. Example format - ACTION,ACTION,ACTION. This attribute is considered when policy-check-type is "CHECK_ACCESS_NOT_GRANTED". At least one of "actions" or "resources" must be specified.'
20+
resources:
21+
description: 'List of comma-separated resource ARNs. Example format - RESOURCE,RESOURCE,RESOURCE. This attribute is considered when policy-check-type is "CHECK_ACCESS_NOT_GRANTED" At least one of "actions" or "resources" must be specified.'
2022
reference-policy:
2123
description: 'A JSON formatted file that specifies the path to the reference policy that is used for a permissions comparison. This attribute is considered and required when policy-check-type is "CHECK_NO_NEW_ACCESS"'
2224
reference-policy-type:

main.py

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
VALIDATE_POLICY = "VALIDATE_POLICY"
88
CHECK_NO_NEW_ACCESS = "CHECK_NO_NEW_ACCESS"
99
CHECK_ACCESS_NOT_GRANTED = "CHECK_ACCESS_NOT_GRANTED"
10+
CHECK_NO_PUBLIC_ACCESS = "CHECK_NO_PUBLIC_ACCESS"
1011

1112
CLI_POLICY_VALIDATOR = "tf-policy-validator"
1213

@@ -26,7 +27,10 @@
2627
"INPUT_REFERENCE-POLICY-TYPE",
2728
}
2829

29-
CHECK_ACCESS_NOT_GRANTED_SPECIFIC_REQUIRED_INPUTS = {"INPUT_ACTIONS"}
30+
# Use tuple to specify that at least one of the enclosed inputs is required.
31+
CHECK_ACCESS_NOT_GRANTED_SPECIFIC_REQUIRED_INPUTS = {("INPUT_ACTIONS", "INPUT_RESOURCES")}
32+
33+
CHECK_NO_PUBLIC_ACCESS_SPECIFIC_REQUIRED_INPUTS = set()
3034

3135
# excluding the "INPUT_POLICY-CHECK-TYPE". Contains only other required inputs in cfn-policy-validator
3236
COMMON_OPTIONAL_INPUTS = {
@@ -46,11 +50,15 @@
4650
# Excluding the TREAT-FINDINGS-AS-NON-BLOCKING which is a flag and needs special handling
4751
CHECK_ACCESS_NOT_GRANTED_SPECIFIC_OPTIONAL_INPUTS = set()
4852

53+
# Excluding the TREAT-FINDINGS-AS-NON-BLOCKING which is a flag and needs special handling
54+
CHECK_NO_PUBLIC_ACCESS_SPECIFIC_OPTIONAL_INPUTS = set()
55+
4956

5057
VALID_POLICY_CHECK_TYPES = [
5158
VALIDATE_POLICY,
5259
CHECK_NO_NEW_ACCESS,
5360
CHECK_ACCESS_NOT_GRANTED,
61+
CHECK_NO_PUBLIC_ACCESS
5462
]
5563

5664
# Name of the output defined in the GitHub action schema
@@ -99,6 +107,10 @@ def get_required_inputs(policy_check):
99107
check_specific_required_inputs = (
100108
CHECK_ACCESS_NOT_GRANTED_SPECIFIC_REQUIRED_INPUTS
101109
)
110+
elif policy_check == CHECK_NO_PUBLIC_ACCESS:
111+
check_specific_required_inputs = (
112+
CHECK_NO_PUBLIC_ACCESS_SPECIFIC_REQUIRED_INPUTS
113+
)
102114
required_inputs = COMMON_REQUIRED_INPUTS.union(check_specific_required_inputs)
103115
return required_inputs
104116

@@ -114,6 +126,10 @@ def get_optional_inputs(policy_check):
114126
check_specific_optional_inputs = (
115127
CHECK_ACCESS_NOT_GRANTED_SPECIFIC_OPTIONAL_INPUTS
116128
)
129+
elif policy_check == CHECK_NO_PUBLIC_ACCESS:
130+
check_specific_optional_inputs = (
131+
CHECK_NO_PUBLIC_ACCESS_SPECIFIC_OPTIONAL_INPUTS
132+
)
117133
optional_inputs = check_specific_optional_inputs.union(COMMON_OPTIONAL_INPUTS)
118134
return optional_inputs
119135

@@ -147,19 +163,30 @@ def get_sub_command(inputFields, areRequiredFields):
147163
flags = []
148164

149165
for input in inputFields:
150-
# The default values to these environment variable when passed to docker is empty string through GitHub Actions
151-
if os.environ[input] != "":
152-
flag_name = get_flag_name(input)
153-
flags.extend(["--{}".format(flag_name), os.environ[input]])
154-
elif areRequiredFields:
155-
raise ValueError("Missing value for required field: {}", input)
166+
# Checking that at least one of a set of required fields is provided
167+
if isinstance(input, tuple):
168+
provided = False
169+
for field in input:
170+
if os.environ[field] != "":
171+
flag_name = get_flag_name(field)
172+
flags.extend(["--{}".format(flag_name), os.environ[field]])
173+
provided = True
174+
if provided == False:
175+
raise ValueError(f"Missing value for at least one of the required fields: {str(input)}")
176+
else:
177+
# The default values to these environment variable when passed to docker is empty string through GitHub Actions
178+
if os.environ[input] != "":
179+
flag_name = get_flag_name(input)
180+
flags.extend(["--{}".format(flag_name), os.environ[input]])
181+
elif areRequiredFields:
182+
raise ValueError("Missing value for required field: {}", input)
156183

157184
return flags
158185

159186

160187
def get_treat_findings_as_non_blocking_flag(policy_check):
161188
# This is specific to custom checks - CheckAccessNotGranted & CheckNoNewAccess
162-
if policy_check in (CHECK_ACCESS_NOT_GRANTED, CHECK_NO_NEW_ACCESS):
189+
if policy_check in (CHECK_ACCESS_NOT_GRANTED, CHECK_NO_NEW_ACCESS, CHECK_NO_PUBLIC_ACCESS):
163190
val = os.environ[TREAT_FINDINGS_AS_NON_BLOCKING]
164191
if val == "True":
165192
return ["--{}".format(get_flag_name(TREAT_FINDINGS_AS_NON_BLOCKING))]

0 commit comments

Comments
 (0)