Skip to content

Commit

Permalink
VPC SC #2: Access level whitelist
Browse files Browse the repository at this point in the history
  • Loading branch information
charliewolf committed Dec 30, 2019
1 parent f0dc14c commit b2a5c1d
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 15 deletions.
44 changes: 38 additions & 6 deletions policies/templates/gcp_vpc_sc_ensure_access_levels_v1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,18 @@ spec:
validation:
openAPIV3Schema:
properties:
required_access_levels:
description: "Required access level names"
mode:
type: string
enum: [whitelist, blacklist, require]
description: "String identifying the operational mode,
whitelist, blacklist or reqired . In the whitelist mode, only
access levels from the access_levels list will be allowed (all
other levels will raise a violation). In the blacklist mode, any
access level not in the access_levels list will not raise a
violation. In required mode, all access levels in the
access_levels list will be required in the perimeter."
access_levels:
description: "Access level names"
type: array
items: string
targets:
Expand Down Expand Up @@ -64,16 +74,38 @@ spec:
lib.has_field(asset, "service_perimeter")
lib.get_constraint_params(constraint, params)
required_access_levels_array := lib.get_default(params, "required_access_levels", [])
required_access_levels := {p | p = required_access_levels_array[_]}
mode := lib.get_default(params, "mode", "require")
perimeter_access_levels_raw := {split(r, "/") | r = asset.service_perimeter.status.access_levels[_]}
perimeter_access_levels := {r[3] | r = perimeter_access_levels_raw[_]}
count(perimeter_access_levels - required_access_levels) != count(perimeter_access_levels) - count(required_access_levels)
# For compatibility reasons, we support the old key name required_access_levels
configured_access_levels := cast_set(lib.get_default(params, "access_levels", lib.get_default(params, "required_access_levels", [])))
message := sprintf("Required access levels missing from service perimeter %v.", [asset.service_perimeter.name])
check_access_level(perimeter_access_levels, configured_access_levels, mode)
message := sprintf("Invalid access levels in service perimeter %v.", [asset.service_perimeter.name])
metadata := {"resource": asset.name, "service_perimeter_name": asset.service_perimeter.name}
}
check_access_level(perimeter_access_levels, configured_access_levels, mode) {
mode == "whitelist"
perimeter := perimeter_access_levels[_]
matches := {perimeter} & configured_access_levels
count(matches) == 0
}
check_access_level(perimeter_access_levels, configured_access_levels, mode) {
mode == "blacklist"
perimeter := perimeter_access_levels[_]
matches := {perimeter} & configured_access_levels
count(matches) > 0
}
check_access_level(perimeter_access_levels, configured_access_levels, mode) {
mode == "require"
intersection := perimeter_access_levels & configured_access_levels
count(intersection) != count(configured_access_levels)
}
#ENDINLINE
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: constraints.gatekeeper.sh/v1alpha1
kind: GCPVPCSCEnsureAccessLevelsConstraintV1
metadata:
name: vpc_sc_ensure_access_levels_blacklist
spec:
severity: high
match:
gcp:
target: ["organization/*"]
parameters:
mode: blacklist
access_levels:
- efgh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
apiVersion: constraints.gatekeeper.sh/v1alpha1
kind: GCPVPCSCEnsureAccessLevelsConstraintV1
metadata:
name: vpc_sc_ensure_access_levels
name: vpc_sc_ensure_access_levels_old
spec:
severity: high
match:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: constraints.gatekeeper.sh/v1alpha1
kind: GCPVPCSCEnsureAccessLevelsConstraintV1
metadata:
name: vpc_sc_ensure_access_levels_require
spec:
severity: high
match:
gcp:
target: ["organization/*"]
parameters:
mode: require
access_levels:
- abcd
- efgh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: constraints.gatekeeper.sh/v1alpha1
kind: GCPVPCSCEnsureAccessLevelsConstraintV1
metadata:
name: vpc_sc_ensure_access_levels_whitelist
spec:
severity: high
match:
gcp:
target: ["organization/*"]
parameters:
mode: whitelist
access_levels:
- abcd
30 changes: 26 additions & 4 deletions validator/vpc_sc_ensure_access_levels.rego
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,37 @@ deny[{
lib.has_field(asset, "service_perimeter")

lib.get_constraint_params(constraint, params)
required_access_levels_array := lib.get_default(params, "required_access_levels", [])
required_access_levels := {p | p = required_access_levels_array[_]}
mode := lib.get_default(params, "mode", "require")

perimeter_access_levels_raw := {split(r, "/") | r = asset.service_perimeter.status.access_levels[_]}
perimeter_access_levels := {r[3] | r = perimeter_access_levels_raw[_]}

count(perimeter_access_levels - required_access_levels) != count(perimeter_access_levels) - count(required_access_levels)
# For compatibility reasons, we support the old key name required_access_levels
configured_access_levels := cast_set(lib.get_default(params, "access_levels", lib.get_default(params, "required_access_levels", [])))

message := sprintf("Required access levels missing from service perimeter %v.", [asset.service_perimeter.name])
check_access_level(perimeter_access_levels, configured_access_levels, mode)

message := sprintf("Invalid access levels in service perimeter %v.", [asset.service_perimeter.name])

metadata := {"resource": asset.name, "service_perimeter_name": asset.service_perimeter.name}
}

check_access_level(perimeter_access_levels, configured_access_levels, mode) {
mode == "whitelist"
perimeter := perimeter_access_levels[_]
matches := {perimeter} & configured_access_levels
count(matches) == 0
}

check_access_level(perimeter_access_levels, configured_access_levels, mode) {
mode == "blacklist"
perimeter := perimeter_access_levels[_]
matches := {perimeter} & configured_access_levels
count(matches) > 0
}

check_access_level(perimeter_access_levels, configured_access_levels, mode) {
mode == "require"
intersection := perimeter_access_levels & configured_access_levels
count(intersection) != count(configured_access_levels)
}
53 changes: 49 additions & 4 deletions validator/vpc_sc_ensure_access_levels_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,62 @@ package templates.gcp.GCPVPCSCEnsureAccessLevelsConstraintV1

import data.validator.gcp.lib as lib

all_violations[violation] {
old_style_violations[violation] {
resource := data.test.fixtures.vpc_sc_ensure_access_levels.assets[_]
constraint := data.test.fixtures.vpc_sc_ensure_access_levels.constraints
constraint := data.test.fixtures.vpc_sc_ensure_access_levels.constraints.old

issues := deny with input.asset as resource
with input.constraint as constraint

violation := issues[_]
}

test_violations_basic {
violation_resources := {r | r = all_violations[_].details.service_perimeter_name}
require_violations[violation] {
resource := data.test.fixtures.vpc_sc_ensure_access_levels.assets[_]
constraint := data.test.fixtures.vpc_sc_ensure_access_levels.constraints.require

issues := deny with input.asset as resource
with input.constraint as constraint

violation := issues[_]
}

whitelist_violations[violation] {
resource := data.test.fixtures.vpc_sc_ensure_access_levels.assets[_]
constraint := data.test.fixtures.vpc_sc_ensure_access_levels.constraints.whitelist

issues := deny with input.asset as resource
with input.constraint as constraint

violation := issues[_]
}

blacklist_violations[violation] {
resource := data.test.fixtures.vpc_sc_ensure_access_levels.assets[_]
constraint := data.test.fixtures.vpc_sc_ensure_access_levels.constraints.blacklist

issues := deny with input.asset as resource
with input.constraint as constraint

violation := issues[_]
}

test_violations_old_style {
violation_resources := {r | r = old_style_violations[_].details.service_perimeter_name}
violation_resources == {"accessPolicies/1008882730434/servicePerimeters/Test_Service_Perimeter_Bad"}
}

test_violations_require {
violation_resources := {r | r = require_violations[_].details.service_perimeter_name}
violation_resources == {"accessPolicies/1008882730434/servicePerimeters/Test_Service_Perimeter_Bad"}
}

test_violations_whitelist {
violation_resources := {r | r = whitelist_violations[_].details.service_perimeter_name}
violation_resources == {"accessPolicies/1008882730433/servicePerimeters/Test_Service_Perimeter_Good"}
}

test_violations_blacklist {
violation_resources := {r | r = blacklist_violations[_].details.service_perimeter_name}
violation_resources == {"accessPolicies/1008882730433/servicePerimeters/Test_Service_Perimeter_Good"}
}

0 comments on commit b2a5c1d

Please sign in to comment.