Skip to content
This repository was archived by the owner on Aug 20, 2025. It is now read-only.

Commit 0f02024

Browse files
charliewolfjoecheuk
authored andcommitted
VPC SC #7: whitelist/blacklist for project<>perimeter combo (#220)
1 parent 42a31f0 commit 0f02024

File tree

8 files changed

+359
-0
lines changed

8 files changed

+359
-0
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Copyright 2019 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
16+
apiVersion: templates.gatekeeper.sh/v1alpha1
17+
kind: ConstraintTemplate
18+
metadata:
19+
name: gcp-vpc-sc-project-perimeter-v1
20+
spec:
21+
crd:
22+
spec:
23+
names:
24+
kind: GCPVPCSCProjectPerimeterConstraintV1
25+
plural: gcpvpcscprojectperimeterconstraintsv1
26+
validation:
27+
openAPIV3Schema:
28+
properties:
29+
mode:
30+
type: string
31+
enum: [whitelist, blacklist]
32+
description: "String identifying the operational mode,
33+
whitelist or blacklist. In the whitelist mode, only perimeters
34+
from the service_perimeters list will be allowed (all others
35+
will raise a violation). In the blacklist mode, any service perimeter
36+
not in the service_perimeters will not raise a violation."
37+
service_perimeters:
38+
type: array
39+
items: string
40+
description: "Array of service perimeters that will be allowed/denied (based on mode)
41+
for this project."
42+
project_id:
43+
type: string
44+
description: "The project ID you are matching"
45+
targets:
46+
validation.gcp.forsetisecurity.org:
47+
rego: | #INLINE("validator/vpc_sc_project_perimeter.rego")
48+
# Copyright 2019 Google LLC
49+
#
50+
# Licensed under the Apache License, Version 2.0 (the "License");
51+
# you may not use this file except in compliance with the License.
52+
# You may obtain a copy of the License at
53+
#
54+
# http://www.apache.org/licenses/LICENSE-2.0
55+
#
56+
# Unless required by applicable law or agreed to in writing, software
57+
# distributed under the License is distributed on an "AS IS" BASIS,
58+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
59+
# See the License for the specific language governing permissions and
60+
# limitations under the License.
61+
#
62+
63+
package templates.gcp.GCPVPCSCProjectPerimeterConstraintV1
64+
65+
import data.validator.gcp.lib as lib
66+
67+
deny[{
68+
"msg": message,
69+
"details": metadata,
70+
}] {
71+
constraint := input.constraint
72+
asset := input.asset
73+
74+
asset.asset_type == "cloudresourcemanager.googleapis.com/Organization"
75+
lib.has_field(asset, "service_perimeter")
76+
77+
lib.get_constraint_params(constraint, params)
78+
79+
mode := params.mode
80+
81+
project_id := params.project_id
82+
service_perimeters := {p | p = params.service_perimeters[_]}
83+
84+
sprintf("projects/%v", [project_id]) == asset.service_perimeter.status.resources[_]
85+
86+
perimeter_is_forbidden(mode, asset.service_perimeter.title, service_perimeters)
87+
88+
message := sprintf("Project %v not allowed in service perimeter %v.", [project_id, asset.service_perimeter.name])
89+
metadata := {"resource": asset.name, "service_perimeter_name": asset.service_perimeter.name, "project_id": project_id}
90+
}
91+
92+
perimeter_is_forbidden(mode, evaluating_service_perimeter, specified_service_perimeters) {
93+
mode == "blacklist"
94+
evaluating_service_perimeter == specified_service_perimeters[_]
95+
}
96+
97+
perimeter_is_forbidden(mode, evaluating_service_perimeter, specified_service_perimeters) {
98+
mode == "whitelist"
99+
count(specified_service_perimeters) == count(specified_service_perimeters - {evaluating_service_perimeter})
100+
}
101+
#ENDINLINE
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright 2019 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
apiVersion: constraints.gatekeeper.sh/v1alpha1
16+
kind: GCPVPCSCProjectPerimeterConstraintV1
17+
metadata:
18+
name: vpc_sc_project_perimeter_blacklist
19+
spec:
20+
severity: high
21+
match:
22+
gcp:
23+
target: ["organization/*"]
24+
parameters:
25+
mode: blacklist
26+
project_id: 179891054368
27+
service_perimeters:
28+
- Test Service Perimeter 1
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright 2019 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
apiVersion: constraints.gatekeeper.sh/v1alpha1
16+
kind: GCPVPCSCProjectPerimeterConstraintV1
17+
metadata:
18+
name: vpc_sc_project_perimeter_whitelist
19+
spec:
20+
severity: high
21+
match:
22+
gcp:
23+
target: ["organization/*"]
24+
parameters:
25+
mode: whitelist
26+
project_id: 179891054368
27+
service_perimeters:
28+
- Test Service Perimeter 1
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
[
2+
{
3+
"name": "//cloudresourcemanager.googleapis.com/organizations/660570133860",
4+
"asset_type": "cloudresourcemanager.googleapis.com/Organization",
5+
"service_perimeter": {
6+
"name": "accessPolicies/1008882730433/servicePerimeters/Test_Service_Perimeter_1",
7+
"title": "Test Service Perimeter 1",
8+
"status": {
9+
"resources": ["projects/179891054368", "projects/179891054369"],
10+
"access_levels": ["accessPolicies/1008882730433/accessLevels/abcd", "accessPolicies/1008882730433/accessLevels/efgh"],
11+
"restricted_services": ["container.googleapis.com"]
12+
}
13+
},
14+
"ancestors": ["organizations/660570133860"]
15+
},
16+
{
17+
"name": "//cloudresourcemanager.googleapis.com/organizations/660570133860",
18+
"asset_type": "cloudresourcemanager.googleapis.com/Organization",
19+
"service_perimeter": {
20+
"name": "accessPolicies/1008882730433/servicePerimeters/Test_Service_Perimeter_2",
21+
"title": "Test Service Perimeter 2",
22+
"status": {
23+
"resources": ["projects/179891054368"],
24+
"access_levels": ["accessPolicies/1008882730433/accessLevels/abcd", "accessPolicies/1008882730433/accessLevels/efgh"],
25+
"restricted_services": ["container.googleapis.com"]
26+
}
27+
},
28+
"ancestors": ["organizations/660570133860"]
29+
},
30+
{
31+
"name": "//cloudresourcemanager.googleapis.com/organizations/660570133860",
32+
"asset_type": "cloudresourcemanager.googleapis.com/Organization",
33+
"service_perimeter": {
34+
"name": "accessPolicies/1008882730433/servicePerimeters/Test_Service_Perimeter_3",
35+
"title": "Test Service Perimeter 3",
36+
"status": {
37+
"resources": ["projects/179891054369"],
38+
"access_levels": ["accessPolicies/1008882730433/accessLevels/abcd", "accessPolicies/1008882730433/accessLevels/efgh"],
39+
"restricted_services": ["container.googleapis.com"]
40+
}
41+
},
42+
"ancestors": ["organizations/660570133860"]
43+
}
44+
]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright 2019 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
apiVersion: constraints.gatekeeper.sh/v1alpha1
16+
kind: GCPVPCSCProjectPerimeterConstraintV1
17+
metadata:
18+
name: vpc_sc_project_perimeter_blacklist
19+
spec:
20+
severity: high
21+
match:
22+
gcp:
23+
target: ["organization/*"]
24+
parameters:
25+
mode: blacklist
26+
project_id: 179891054368
27+
service_perimeters:
28+
- Test Service Perimeter 1
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright 2019 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
apiVersion: constraints.gatekeeper.sh/v1alpha1
16+
kind: GCPVPCSCProjectPerimeterConstraintV1
17+
metadata:
18+
name: vpc_sc_project_perimeter_whitelist
19+
spec:
20+
severity: high
21+
match:
22+
gcp:
23+
target: ["organization/*"]
24+
parameters:
25+
mode: whitelist
26+
project_id: 179891054368
27+
service_perimeters:
28+
- Test Service Perimeter 1
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Copyright 2019 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
16+
package templates.gcp.GCPVPCSCProjectPerimeterConstraintV1
17+
18+
import data.validator.gcp.lib as lib
19+
20+
deny[{
21+
"msg": message,
22+
"details": metadata,
23+
}] {
24+
constraint := input.constraint
25+
asset := input.asset
26+
27+
asset.asset_type == "cloudresourcemanager.googleapis.com/Organization"
28+
lib.has_field(asset, "service_perimeter")
29+
30+
lib.get_constraint_params(constraint, params)
31+
32+
mode := params.mode
33+
34+
project_id := params.project_id
35+
service_perimeters := {p | p = params.service_perimeters[_]}
36+
37+
sprintf("projects/%v", [project_id]) == asset.service_perimeter.status.resources[_]
38+
39+
perimeter_is_forbidden(mode, asset.service_perimeter.title, service_perimeters)
40+
41+
message := sprintf("Project %v not allowed in service perimeter %v.", [project_id, asset.service_perimeter.name])
42+
metadata := {"resource": asset.name, "service_perimeter_name": asset.service_perimeter.name, "project_id": project_id}
43+
}
44+
45+
perimeter_is_forbidden(mode, evaluating_service_perimeter, specified_service_perimeters) {
46+
mode == "blacklist"
47+
evaluating_service_perimeter == specified_service_perimeters[_]
48+
}
49+
50+
perimeter_is_forbidden(mode, evaluating_service_perimeter, specified_service_perimeters) {
51+
mode == "whitelist"
52+
count(specified_service_perimeters) == count(specified_service_perimeters - {evaluating_service_perimeter})
53+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#
2+
# Copyright 2019 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
17+
package templates.gcp.GCPVPCSCProjectPerimeterConstraintV1
18+
19+
import data.validator.gcp.lib as lib
20+
21+
whitelist_violations[violation] {
22+
resource := data.test.fixtures.vpc_sc_project_perimeter.assets[_]
23+
constraint := data.test.fixtures.vpc_sc_project_perimeter.constraints.whitelist
24+
25+
issues := deny with input.asset as resource
26+
with input.constraint as constraint
27+
28+
violation := issues[_]
29+
}
30+
31+
blacklist_violations[violation] {
32+
resource := data.test.fixtures.vpc_sc_project_perimeter.assets[_]
33+
constraint := data.test.fixtures.vpc_sc_project_perimeter.constraints.blacklist
34+
35+
issues := deny with input.asset as resource
36+
with input.constraint as constraint
37+
38+
violation := issues[_]
39+
}
40+
41+
test_violations_whitelist {
42+
violation_resources := {r | r = whitelist_violations[_].details.service_perimeter_name}
43+
violation_resources == {"accessPolicies/1008882730433/servicePerimeters/Test_Service_Perimeter_2"}
44+
}
45+
46+
test_violations_blacklist {
47+
violation_resources := {r | r = blacklist_violations[_].details.service_perimeter_name}
48+
violation_resources == {"accessPolicies/1008882730433/servicePerimeters/Test_Service_Perimeter_1"}
49+
}

0 commit comments

Comments
 (0)