diff --git a/google/node_config.go b/google/node_config.go index 2580fb27dfd..52be088ccf9 100644 --- a/google/node_config.go +++ b/google/node_config.go @@ -147,6 +147,27 @@ var schemaNodeConfig = &schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, }, + "shielded_instance_config": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enable_secure_boot": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "enable_integrity_monitoring": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + }, + }, + }, + "taint": { Removed: "This field is in beta. Use it in the the google-beta provider instead. See https://terraform.io/docs/providers/google/provider_versions.html for more details.", Type: schema.TypeList, @@ -301,6 +322,15 @@ func expandNodeConfig(v interface{}) *containerBeta.NodeConfig { } nc.Tags = tags } + + if v, ok := nodeConfig["shielded_instance_config"]; ok && len(v.([]interface{})) > 0 { + conf := v.([]interface{})[0].(map[string]interface{}) + nc.ShieldedInstanceConfig = &containerBeta.ShieldedInstanceConfig{ + EnableSecureBoot: conf["enable_secure_boot"].(bool), + EnableIntegrityMonitoring: conf["enable_integrity_monitoring"].(bool), + } + } + // Preemptible Is Optional+Default, so it always has a value nc.Preemptible = nodeConfig["preemptible"].(bool) @@ -319,18 +349,19 @@ func flattenNodeConfig(c *containerBeta.NodeConfig) []map[string]interface{} { } config = append(config, map[string]interface{}{ - "machine_type": c.MachineType, - "disk_size_gb": c.DiskSizeGb, - "disk_type": c.DiskType, - "guest_accelerator": flattenContainerGuestAccelerators(c.Accelerators), - "local_ssd_count": c.LocalSsdCount, - "service_account": c.ServiceAccount, - "metadata": c.Metadata, - "image_type": c.ImageType, - "labels": c.Labels, - "tags": c.Tags, - "preemptible": c.Preemptible, - "min_cpu_platform": c.MinCpuPlatform, + "machine_type": c.MachineType, + "disk_size_gb": c.DiskSizeGb, + "disk_type": c.DiskType, + "guest_accelerator": flattenContainerGuestAccelerators(c.Accelerators), + "local_ssd_count": c.LocalSsdCount, + "service_account": c.ServiceAccount, + "metadata": c.Metadata, + "image_type": c.ImageType, + "labels": c.Labels, + "tags": c.Tags, + "preemptible": c.Preemptible, + "min_cpu_platform": c.MinCpuPlatform, + "shielded_instance_config": flattenShieldedInstanceConfig(c.ShieldedInstanceConfig), }) if len(c.OauthScopes) > 0 { @@ -351,6 +382,17 @@ func flattenContainerGuestAccelerators(c []*containerBeta.AcceleratorConfig) []m return result } +func flattenShieldedInstanceConfig(c *containerBeta.ShieldedInstanceConfig) []map[string]interface{} { + result := []map[string]interface{}{} + if c != nil { + result = append(result, map[string]interface{}{ + "enable_secure_boot": c.EnableSecureBoot, + "enable_integrity_monitoring": c.EnableIntegrityMonitoring, + }) + } + return result +} + func taintDiffSuppress(k, old, new string, d *schema.ResourceData) bool { if strings.HasSuffix(k, "#") { oldCount, oldErr := strconv.Atoi(old) diff --git a/google/resource_container_cluster_test.go b/google/resource_container_cluster_test.go index 875ca855d84..cd7d7ef22fd 100644 --- a/google/resource_container_cluster_test.go +++ b/google/resource_container_cluster_test.go @@ -634,6 +634,29 @@ func TestAccContainerCluster_withNodeConfigScopeAlias(t *testing.T) { }) } +func TestAccContainerCluster_withNodeConfigShieldedInstanceConfig(t *testing.T) { + t.Parallel() + + clusterName := fmt.Sprintf("cluster-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckContainerClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccContainerCluster_withNodeConfigShieldedInstanceConfig(clusterName), + }, + { + ResourceName: "google_container_cluster.with_node_config", + ImportStateIdPrefix: "us-central1-f/", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccContainerCluster_network(t *testing.T) { t.Parallel() @@ -1720,6 +1743,47 @@ resource "google_container_cluster" "with_node_config_scope_alias" { }`, acctest.RandString(10)) } +func testAccContainerCluster_withNodeConfigShieldedInstanceConfig(clusterName string) string { + return fmt.Sprintf(` +resource "google_container_cluster" "with_node_config" { + name = "%s" + zone = "us-central1-f" + initial_node_count = 1 + + node_config { + machine_type = "n1-standard-1" + disk_size_gb = 15 + disk_type = "pd-ssd" + local_ssd_count = 1 + oauth_scopes = [ + "https://www.googleapis.com/auth/monitoring", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write" + ] + service_account = "default" + metadata = { + foo = "bar" + disable-legacy-endpoints = "true" + } + labels = { + foo = "bar" + } + tags = ["foo", "bar"] + preemptible = true + min_cpu_platform = "Intel Broadwell" + + // Updatable fields + image_type = "COS" + + shielded_instance_config { + enable_secure_boot = true + enable_integrity_monitoring = true + } + } +}`, clusterName) +} + func testAccContainerCluster_networkRef() string { return fmt.Sprintf(` resource "google_compute_network" "container_network" { diff --git a/google/resource_container_node_pool_test.go b/google/resource_container_node_pool_test.go index e44fd84b2cc..8a34681265c 100644 --- a/google/resource_container_node_pool_test.go +++ b/google/resource_container_node_pool_test.go @@ -513,6 +513,39 @@ func TestAccContainerNodePool_EmptyGuestAccelerator(t *testing.T) { }) } +func TestAccContainerNodePool_shieldedInstanceConfig(t *testing.T) { + t.Parallel() + + cluster := fmt.Sprintf("tf-nodepool-test-%s", acctest.RandString(10)) + np := fmt.Sprintf("tf-nodepool-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckContainerNodePoolDestroy, + Steps: []resource.TestStep{ + { + Config: testAccContainerNodePool_shieldedInstanceConfig(cluster, np), + }, + { + ResourceName: "google_container_node_pool.np", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"max_pods_per_node"}, + }, + { + Config: testAccContainerNodePool_updateShieldedInstanceConfig(cluster, np), + }, + { + ResourceName: "google_container_node_pool.np", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"max_pods_per_node"}, + }, + }, + }) +} + func testAccCheckContainerNodePoolDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) @@ -1090,3 +1123,46 @@ resource "google_container_node_pool" "np" { } }`, cluster, np) } + +func testAccContainerNodePool_shieldedInstanceConfig(cluster, np string) string { + return fmt.Sprintf(` +resource "google_container_cluster" "cluster" { + name = "%s" + location = "us-central1-a" + initial_node_count = 1 +} + +resource "google_container_node_pool" "np" { + name = "%s" + location = "us-central1-a" + cluster = "${google_container_cluster.cluster.name}" + initial_node_count = 2 + node_config { + shielded_instance_config { + enable_integrity_monitoring = true + } + } +}`, cluster, np) +} + +func testAccContainerNodePool_updateShieldedInstanceConfig(cluster, np string) string { + return fmt.Sprintf(` +resource "google_container_cluster" "cluster" { + name = "%s" + location = "us-central1-a" + initial_node_count = 1 +} + +resource "google_container_node_pool" "np" { + name = "%s" + location = "us-central1-a" + cluster = "${google_container_cluster.cluster.name}" + initial_node_count = 2 + node_config { + shielded_instance_config { + enable_secure_boot = true + enable_integrity_monitoring = true + } + } +}`, cluster, np) +} diff --git a/website/docs/r/container_cluster.html.markdown b/website/docs/r/container_cluster.html.markdown index 57c49b585a4..708f7715300 100644 --- a/website/docs/r/container_cluster.html.markdown +++ b/website/docs/r/container_cluster.html.markdown @@ -191,6 +191,8 @@ for more details. Structure is documented below. will have statically granted permissions beyond those provided by the RBAC configuration or IAM. Defaults to `false` +* `enable_shielded_nodes` - (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) Enable Shielded Nodes features on all nodes in this cluster. Defaults to `false`. + * `initial_node_count` - (Optional) The number of nodes to create in this cluster's default node pool. In regional or multi-zonal clusters, this is the number of nodes per zone. Must be set if `node_pool` is not set. If you're using @@ -557,6 +559,8 @@ The `node_config` block supports: -> Projects that enable the [Cloud Compute Engine API](https://cloud.google.com/compute/) with Terraform may need these roles added manually to the service account. Projects that enable the API in the Cloud Console should have them added automatically. +* `shielded_instance_config` - (Optional) Shielded Instance options. Structure is documented below. + * `tags` - (Optional) The list of instance tags applied to all nodes. Tags are used to identify valid sources or targets for network firewalls. @@ -629,6 +633,16 @@ resource_usage_export_config { } ``` +The `shielded_instance_config` block supports: + +* `enable_secure_boot` (Optional) - Defines if the instance has Secure Boot enabled. + +Secure Boot helps ensure that the system only runs authentic software by verifying the digital signature of all boot components, and halting the boot process if signature verification fails. Defaults to `false`. + +* `enable_integrity_monitoring` (Optional) - Defines if the instance has integrity monitoring enabled. + +Enables monitoring and attestation of the boot integrity of the instance. The attestation is performed against the integrity policy baseline. This baseline is initially derived from the implicitly trusted boot image when the instance is created. Defaults to `true`. + The `taint` block supports: * `key` (Required) Key for taint.