Skip to content

Commit 2ae739b

Browse files
feat: add confidential nodes example (#2227)
Co-authored-by: Andrew Peabody <[email protected]>
1 parent dec005b commit 2ae739b

File tree

21 files changed

+918
-0
lines changed

21 files changed

+918
-0
lines changed

autogen/safer-cluster/main.tf.tmpl

+2
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ module "gke" {
110110
monitoring_enable_managed_prometheus = var.monitoring_enable_managed_prometheus
111111
monitoring_enabled_components = var.monitoring_enabled_components
112112

113+
enable_confidential_nodes = var.enable_confidential_nodes
114+
113115
// We never use the default service account for the cluster. The default
114116
// project/editor permissions can create problems if nodes were to be ever
115117
// compromised.

autogen/safer-cluster/variables.tf.tmpl

+6
Original file line numberDiff line numberDiff line change
@@ -544,3 +544,9 @@ variable "deletion_protection" {
544544
description = "Whether or not to allow Terraform to destroy the cluster."
545545
default = true
546546
}
547+
548+
variable "enable_confidential_nodes" {
549+
type = bool
550+
description = "An optional flag to enable confidential node config."
551+
default = false
552+
}

build/int.cloudbuild.yaml

+15
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,21 @@ steps:
466466
- verify simple-fleet-app-operator-permissions
467467
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
468468
args: ['/bin/bash', '-c', 'cft test run TestSimpleFleetAppOperatorPermissions --stage teardown --verbose']
469+
- id: apply test-confidential-safer-cluster
470+
waitFor:
471+
- init-all
472+
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
473+
args: ['/bin/bash', '-c', 'cft test run TestConfidentialSaferCluster --stage apply --verbose']
474+
- id: verify test-confidential-safer-cluster
475+
waitFor:
476+
- apply test-confidential-safer-cluster
477+
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
478+
args: ['/bin/bash', '-c', 'cft test run TestConfidentialSaferCluster --stage verify --verbose']
479+
- id: teardown test-confidential-safer-cluster
480+
waitFor:
481+
- verify test-confidential-safer-cluster
482+
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
483+
args: ['/bin/bash', '-c', 'cft test run TestConfidentialSaferCluster --stage teardown --verbose']
469484
tags:
470485
- 'ci'
471486
- 'integration'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Confidential Safer GKE Cluster
2+
3+
This example illustrates how to instantiate the Safer Cluster module
4+
with confidential nodes enabled and database encrypted with KMS key.
5+
6+
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
7+
## Inputs
8+
9+
| Name | Description | Type | Default | Required |
10+
|------|-------------|------|---------|:--------:|
11+
| project\_id | The project ID to host the cluster in. | `string` | n/a | yes |
12+
| region | The region to host the cluster in. | `string` | `"us-central1"` | no |
13+
14+
## Outputs
15+
16+
| Name | Description |
17+
|------|-------------|
18+
| ca\_certificate | The cluster ca certificate (base64 encoded). |
19+
| client\_token | The bearer token for auth. |
20+
| cluster\_name | Cluster name. |
21+
| explicit\_k8s\_version | Explicit version used for cluster creation. |
22+
| keyring | The name of the keyring. |
23+
| kms\_key\_name | KMS Key Name. |
24+
| kubernetes\_endpoint | The cluster endpoint. |
25+
| location | n/a |
26+
| master\_kubernetes\_version | Kubernetes version of the master. |
27+
| network\_name | The name of the VPC being created. |
28+
| project\_id | The project ID the cluster is in. |
29+
| region | The region in which the cluster resides. |
30+
| service\_account | The service account to default running nodes as if not overridden in `node_pools`. |
31+
| subnet\_names | The names of the subnet being created. |
32+
| zones | List of zones in which the cluster resides. |
33+
34+
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
35+
36+
To provision this example, run the following from within this directory:
37+
- `terraform init` to get the plugins
38+
- `terraform plan` to see the infrastructure plan
39+
- `terraform apply` to apply the infrastructure build
40+
- `terraform destroy` to destroy the built infrastructure
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright 2024 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+
locals {
18+
key_name = "gke-key-${random_string.suffix.result}"
19+
}
20+
21+
module "kms" {
22+
source = "terraform-google-modules/kms/google"
23+
version = "~> 3.0"
24+
project_id = var.project_id
25+
location = var.region
26+
keyring = "gke-keyring-${random_string.suffix.result}"
27+
keys = [local.key_name]
28+
prevent_destroy = false
29+
}
30+
31+
resource "google_project_service_identity" "container_identity" {
32+
provider = google-beta
33+
project = var.project_id
34+
service = "container.googleapis.com"
35+
}
36+
37+
resource "google_kms_crypto_key_iam_member" "sm_sa_encrypter_decrypter" {
38+
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
39+
member = google_project_service_identity.container_identity.member
40+
crypto_key_id = module.kms.keys[local.key_name]
41+
}
+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/**
2+
* Copyright 2024 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+
resource "random_string" "suffix" {
18+
length = 4
19+
special = false
20+
upper = false
21+
}
22+
23+
locals {
24+
cluster_type = "confidential-safer"
25+
network_name = "confidential-safer-network-${random_string.suffix.result}"
26+
subnet_name = "confidential-safer-subnet"
27+
master_auth_subnetwork = "confidential-safer-master-subnet"
28+
pods_range_name = "ip-range-pods-${random_string.suffix.result}"
29+
svc_range_name = "ip-range-svc-${random_string.suffix.result}"
30+
subnet_names = [for subnet_self_link in module.gcp-network.subnets_self_links : split("/", subnet_self_link)[length(split("/", subnet_self_link)) - 1]]
31+
}
32+
33+
data "google_client_config" "default" {}
34+
35+
provider "kubernetes" {
36+
host = "https://${module.gke.endpoint}"
37+
token = data.google_client_config.default.access_token
38+
cluster_ca_certificate = base64decode(module.gke.ca_certificate)
39+
}
40+
41+
// A random valid k8s version is retrived
42+
// to specify as an explicit version.
43+
data "google_container_engine_versions" "current" {
44+
project = var.project_id
45+
location = var.region
46+
}
47+
48+
resource "random_shuffle" "version" {
49+
input = data.google_container_engine_versions.current.valid_master_versions
50+
result_count = 1
51+
}
52+
53+
module "gke" {
54+
source = "terraform-google-modules/kubernetes-engine/google//modules/safer-cluster"
55+
version = "~> 35.0"
56+
57+
project_id = var.project_id
58+
name = "${local.cluster_type}-cluster-${random_string.suffix.result}"
59+
regional = true
60+
region = var.region
61+
network = module.gcp-network.network_name
62+
subnetwork = local.subnet_names[index(module.gcp-network.subnets_names, local.subnet_name)]
63+
ip_range_pods = local.pods_range_name
64+
ip_range_services = local.svc_range_name
65+
master_ipv4_cidr_block = "172.16.0.0/28"
66+
add_cluster_firewall_rules = true
67+
firewall_inbound_ports = ["9443", "15017"]
68+
kubernetes_version = random_shuffle.version.result[0]
69+
release_channel = "UNSPECIFIED"
70+
deletion_protection = false
71+
enable_private_endpoint = true
72+
enable_confidential_nodes = true
73+
74+
master_authorized_networks = [
75+
{
76+
cidr_block = "10.60.0.0/17"
77+
display_name = "VPC"
78+
},
79+
]
80+
81+
database_encryption = [
82+
{
83+
"key_name" : module.kms.keys[local.key_name],
84+
"state" : "ENCRYPTED"
85+
}
86+
]
87+
88+
node_pools = [
89+
{
90+
name = "default"
91+
machine_type = "n2d-standard-2"
92+
enable_secure_boot = true
93+
},
94+
]
95+
96+
notification_config_topic = google_pubsub_topic.updates.id
97+
}
98+
99+
resource "google_pubsub_topic" "updates" {
100+
name = "cluster-updates-${random_string.suffix.result}"
101+
project = var.project_id
102+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* Copyright 2024 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+
module "gcp-network" {
18+
source = "terraform-google-modules/network/google"
19+
version = "~> 10.0"
20+
21+
project_id = var.project_id
22+
network_name = local.network_name
23+
routing_mode = "GLOBAL"
24+
25+
subnets = [
26+
{
27+
subnet_name = local.subnet_name
28+
subnet_ip = "10.0.0.0/17"
29+
subnet_region = var.region
30+
subnet_private_access = true
31+
},
32+
{
33+
subnet_name = local.master_auth_subnetwork
34+
subnet_ip = "10.60.0.0/17"
35+
subnet_region = var.region
36+
subnet_private_access = true
37+
},
38+
]
39+
40+
secondary_ranges = {
41+
(local.subnet_name) = [
42+
{
43+
range_name = local.pods_range_name
44+
ip_cidr_range = "192.168.0.0/18"
45+
},
46+
{
47+
range_name = local.svc_range_name
48+
ip_cidr_range = "192.168.64.0/18"
49+
},
50+
]
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* Copyright 2024 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+
output "kubernetes_endpoint" {
18+
description = "The cluster endpoint."
19+
sensitive = true
20+
value = module.gke.endpoint
21+
}
22+
23+
output "cluster_name" {
24+
description = "Cluster name."
25+
value = module.gke.name
26+
}
27+
28+
output "location" {
29+
value = module.gke.location
30+
}
31+
32+
output "master_kubernetes_version" {
33+
description = "Kubernetes version of the master."
34+
value = module.gke.master_version
35+
}
36+
37+
output "client_token" {
38+
description = "The bearer token for auth."
39+
sensitive = true
40+
value = base64encode(data.google_client_config.default.access_token)
41+
}
42+
43+
output "ca_certificate" {
44+
description = "The cluster ca certificate (base64 encoded)."
45+
value = module.gke.ca_certificate
46+
}
47+
48+
output "service_account" {
49+
description = "The service account to default running nodes as if not overridden in `node_pools`."
50+
value = module.gke.service_account
51+
}
52+
53+
output "network_name" {
54+
description = "The name of the VPC being created."
55+
value = module.gcp-network.network_name
56+
}
57+
58+
output "subnet_names" {
59+
description = "The names of the subnet being created."
60+
value = module.gcp-network.subnets_names
61+
}
62+
63+
output "region" {
64+
description = "The region in which the cluster resides."
65+
value = module.gke.region
66+
}
67+
68+
output "zones" {
69+
description = "List of zones in which the cluster resides."
70+
value = module.gke.zones
71+
}
72+
73+
output "project_id" {
74+
description = "The project ID the cluster is in."
75+
value = var.project_id
76+
}
77+
78+
output "explicit_k8s_version" {
79+
description = "Explicit version used for cluster creation."
80+
value = random_shuffle.version.result[0]
81+
}
82+
83+
output "keyring" {
84+
description = "The name of the keyring."
85+
value = module.kms.keyring
86+
}
87+
88+
output "kms_key_name" {
89+
description = "KMS Key Name."
90+
value = module.kms.keys[local.key_name]
91+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Copyright 2024 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+
variable "project_id" {
18+
type = string
19+
description = "The project ID to host the cluster in."
20+
}
21+
22+
variable "region" {
23+
type = string
24+
description = "The region to host the cluster in."
25+
default = "us-central1"
26+
}

0 commit comments

Comments
 (0)