Skip to content

Commit 580e7dd

Browse files
committed
add restrict-gke-clusters policy
1 parent 74f871c commit 580e7dd

File tree

5 files changed

+612
-0
lines changed

5 files changed

+612
-0
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# This policy uses the Sentinel tfplan/v2 import to restrict the
2+
# size of the pool of GKE clusters and the types of their VMs
3+
# Restrict both the default node pool of clusters and additional node pools
4+
5+
# Import common-functions/tfplan-functions/tfplan-functions.sentinel
6+
# with alias "plan"
7+
import "tfplan-functions" as plan
8+
9+
## Parameters
10+
# Set maximum pool size
11+
param max_pool_size default 10
12+
13+
# Set allowed GCP machine types
14+
# include "null" since machine_type not required for google_container_cluster
15+
param allowed_types default [
16+
"n1-standard-1",
17+
"n1-standard-2",
18+
"n1-standard-4",
19+
"null",
20+
]
21+
22+
# Get all GKE clusters
23+
allGKEClusters = plan.find_resources("google_container_cluster")
24+
25+
# Filter to GKE clusters with invalid initial_node_count
26+
# But don't count null node_count as invalid
27+
GKEClustersWithInvalidNodeCount = plan.filter_attribute_greater_than_value(
28+
allGKEClusters, "initial_node_count", max_pool_size, false)
29+
clusters_with_invalid_initial_node_count = 0
30+
for GKEClustersWithInvalidNodeCount["messages"] as address, message {
31+
if message not contains "null" {
32+
print(message)
33+
clusters_with_invalid_initial_node_count += 1
34+
}
35+
}
36+
37+
# Filter to GKE clusters with invalid machine type
38+
# Warnings will be printed for all violations since the last parameter is true
39+
GKEClustersWithInvalidMachineType = plan.filter_attribute_not_in_list(allGKEClusters,
40+
"node_config.0.machine_type", allowed_types, true)
41+
clusters_with_invalid_machine_type = length(GKEClustersWithInvalidMachineType["messages"])
42+
43+
# Get all GKE node pools
44+
allGKENodePools = plan.find_resources("google_container_node_pool")
45+
46+
# Filter to GKE node pools with invalid initial_node_count
47+
# But don't count null initial_node_count as invalid
48+
GKENodePoolsWithInvalidInitialNodeCount = plan.filter_attribute_greater_than_value(
49+
allGKENodePools,"initial_node_count", max_pool_size, false)
50+
node_pools_with_invalid_initial_node_count = 0
51+
for GKENodePoolsWithInvalidInitialNodeCount["messages"] as address, message {
52+
if message not contains "null" {
53+
print(message)
54+
node_pools_with_invalid_initial_node_count += 1
55+
}
56+
}
57+
58+
# Filter to GKE node pools with invalid node_count
59+
# But don't count null node_count as invalid
60+
GKENodePoolsWithInvalidNodeCount = plan.filter_attribute_greater_than_value(
61+
allGKENodePools, "node_count", max_pool_size, false)
62+
node_pools_with_invalid_node_count = 0
63+
for GKENodePoolsWithInvalidNodeCount["messages"] as address, message {
64+
if message not contains "null" {
65+
print(message)
66+
node_pools_with_invalid_node_count += 1
67+
}
68+
}
69+
70+
# Filter to GKE node pools with invalid autoscaling.max_node_count
71+
# But don't count null max_node_count as invalid
72+
GKENodePoolsWithInvalidMaxNodeCount = plan.filter_attribute_greater_than_value(
73+
allGKENodePools,"autoscaling.0.max_node_count", max_pool_size, false)
74+
node_pools_with_invalid_max_node_count = 0
75+
for GKENodePoolsWithInvalidMaxNodeCount["messages"] as address, message {
76+
if message not contains "null" {
77+
print(message)
78+
node_pools_with_invalid_max_node_count += 1
79+
}
80+
}
81+
82+
# Filter to GKE node pools with invalid machine type
83+
# Warnings will be printed for all violations since the last parameter is true
84+
GKENodePoolsWithInvalidMachineType = plan.filter_attribute_not_in_list(
85+
allGKENodePools,"node_config.0.machine_type", allowed_types, true)
86+
node_pools_with_invalid_machine_type = length(GKENodePoolsWithInvalidMachineType["messages"])
87+
88+
# Main rule
89+
validated = clusters_with_invalid_initial_node_count is 0 and
90+
clusters_with_invalid_machine_type is 0 and
91+
node_pools_with_invalid_initial_node_count is 0 and
92+
node_pools_with_invalid_node_count is 0 and
93+
node_pools_with_invalid_max_node_count is 0 and
94+
node_pools_with_invalid_machine_type is 0
95+
96+
main = rule {
97+
validated
98+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"modules": {
3+
"tfplan-functions": {
4+
"path": "../../../common-functions/tfplan-functions/tfplan-functions.sentinel"
5+
}
6+
},
7+
"mock": {
8+
"tfplan/v2": "mock-tfplan-fail.sentinel"
9+
},
10+
"test": {
11+
"main": false
12+
}
13+
}
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
terraform_version = "0.13.5"
2+
3+
variables = {
4+
"environment": {
5+
"name": "environment",
6+
"value": "gke-dev",
7+
},
8+
"gcp_project": {
9+
"name": "gcp_project",
10+
"value": "roger-berlind-demos",
11+
},
12+
"gcp_region": {
13+
"name": "gcp_region",
14+
"value": "us-east1",
15+
},
16+
"initial_node_count": {
17+
"name": "initial_node_count",
18+
"value": 1,
19+
},
20+
"master_password": {
21+
"name": "master_password",
22+
"value": "k8smasterk8smaster",
23+
},
24+
"master_username": {
25+
"name": "master_username",
26+
"value": "k8smaster",
27+
},
28+
"node_disk_size": {
29+
"name": "node_disk_size",
30+
"value": "20",
31+
},
32+
"node_machine_type": {
33+
"name": "node_machine_type",
34+
"value": "n1-standard-1",
35+
},
36+
}
37+
38+
resource_changes = {
39+
"google_container_cluster.primary": {
40+
"address": "google_container_cluster.primary",
41+
"change": {
42+
"actions": [
43+
"create",
44+
],
45+
"after": {
46+
"description": null,
47+
"enable_binary_authorization": false,
48+
"enable_intranode_visibility": null,
49+
"enable_kubernetes_alpha": false,
50+
"enable_legacy_abac": false,
51+
"enable_shielded_nodes": false,
52+
"enable_tpu": null,
53+
"initial_node_count": 15,
54+
"ip_allocation_policy": [],
55+
"location": "us-east1",
56+
"maintenance_policy": [],
57+
"master_auth": [
58+
{
59+
"client_certificate_config": [
60+
{
61+
"issue_client_certificate": false,
62+
},
63+
],
64+
"password": "k8smasterk8smaster",
65+
"username": "k8smaster",
66+
},
67+
],
68+
"master_authorized_networks_config": [],
69+
"min_master_version": null,
70+
"name": "my-gke-cluster",
71+
"network": "default",
72+
"node_config": [
73+
{
74+
"machine_type": "n1-standard-8",
75+
"metadata": {
76+
"disable-legacy-endpoints": "true",
77+
},
78+
"min_cpu_platform": null,
79+
"oauth_scopes": [
80+
"https://www.googleapis.com/auth/cloud-platform",
81+
],
82+
"preemptible": false,
83+
"tags": null,
84+
},
85+
],
86+
"pod_security_policy_config": [],
87+
"private_cluster_config": [],
88+
"remove_default_node_pool": true,
89+
"resource_labels": null,
90+
"resource_usage_export_config": [],
91+
"timeouts": null,
92+
"vertical_pod_autoscaling": [],
93+
"workload_identity_config": [],
94+
},
95+
"after_unknown": {
96+
"addons_config": true,
97+
"authenticator_groups_config": true,
98+
"cluster_autoscaling": true,
99+
"cluster_ipv4_cidr": true,
100+
"database_encryption": true,
101+
"default_max_pods_per_node": true,
102+
"endpoint": true,
103+
"id": true,
104+
"instance_group_urls": true,
105+
"ip_allocation_policy": [],
106+
"label_fingerprint": true,
107+
"logging_service": true,
108+
"maintenance_policy": [],
109+
"master_auth": [
110+
{
111+
"client_certificate": true,
112+
"client_certificate_config": [
113+
{},
114+
],
115+
"client_key": true,
116+
"cluster_ca_certificate": true,
117+
},
118+
],
119+
"master_authorized_networks_config": [],
120+
"master_version": true,
121+
"monitoring_service": true,
122+
"network_policy": true,
123+
"node_config": [
124+
{
125+
"disk_size_gb": true,
126+
"disk_type": true,
127+
"guest_accelerator": true,
128+
"image_type": true,
129+
"labels": true,
130+
"local_ssd_count": true,
131+
"metadata": {},
132+
"oauth_scopes": [
133+
false,
134+
],
135+
"service_account": true,
136+
"shielded_instance_config": true,
137+
"taint": true,
138+
"workload_metadata_config": true,
139+
},
140+
],
141+
"node_locations": true,
142+
"node_pool": true,
143+
"node_version": true,
144+
"operation": true,
145+
"pod_security_policy_config": [],
146+
"private_cluster_config": [],
147+
"project": true,
148+
"release_channel": true,
149+
"resource_usage_export_config": [],
150+
"self_link": true,
151+
"services_ipv4_cidr": true,
152+
"subnetwork": true,
153+
"vertical_pod_autoscaling": [],
154+
"workload_identity_config": [],
155+
},
156+
"before": null,
157+
},
158+
"deposed": "",
159+
"index": null,
160+
"mode": "managed",
161+
"module_address": "",
162+
"name": "primary",
163+
"provider_name": "registry.terraform.io/hashicorp/google",
164+
"type": "google_container_cluster",
165+
},
166+
"google_container_node_pool.primary": {
167+
"address": "google_container_node_pool.primary",
168+
"change": {
169+
"actions": [
170+
"create",
171+
],
172+
"after": {
173+
"autoscaling": [
174+
{
175+
"max_node_count": 20,
176+
"min_node_count": 1,
177+
},
178+
],
179+
"cluster": "my-gke-cluster",
180+
"initial_node_count": 12,
181+
"location": "us-east1",
182+
"name": "my-node-pool",
183+
"node_config": [
184+
{
185+
"machine_type": "n1-standard-8",
186+
"metadata": {
187+
"disable-legacy-endpoints": "true",
188+
},
189+
"min_cpu_platform": null,
190+
"oauth_scopes": [
191+
"https://www.googleapis.com/auth/cloud-platform",
192+
],
193+
"preemptible": true,
194+
"tags": null,
195+
},
196+
],
197+
"node_count": 16,
198+
"timeouts": null,
199+
},
200+
"after_unknown": {
201+
"autoscaling": [
202+
{},
203+
],
204+
"id": true,
205+
"instance_group_urls": true,
206+
"management": true,
207+
"max_pods_per_node": true,
208+
"name_prefix": true,
209+
"node_config": [
210+
{
211+
"disk_size_gb": true,
212+
"disk_type": true,
213+
"guest_accelerator": true,
214+
"image_type": true,
215+
"labels": true,
216+
"local_ssd_count": true,
217+
"metadata": {},
218+
"oauth_scopes": [
219+
false,
220+
],
221+
"service_account": true,
222+
"shielded_instance_config": true,
223+
"taint": true,
224+
"workload_metadata_config": true,
225+
},
226+
],
227+
"node_locations": true,
228+
"project": true,
229+
"upgrade_settings": true,
230+
"version": true,
231+
},
232+
"before": null,
233+
},
234+
"deposed": "",
235+
"index": null,
236+
"mode": "managed",
237+
"module_address": "",
238+
"name": "primary",
239+
"provider_name": "registry.terraform.io/hashicorp/google",
240+
"type": "google_container_node_pool",
241+
},
242+
}
243+
244+
output_changes = {}

0 commit comments

Comments
 (0)