diff --git a/mmv1/third_party/terraform/services/container/node_config.go.erb b/mmv1/third_party/terraform/services/container/node_config.go.erb
index 702fb6319d02..546661a54e3e 100644
--- a/mmv1/third_party/terraform/services/container/node_config.go.erb
+++ b/mmv1/third_party/terraform/services/container/node_config.go.erb
@@ -28,6 +28,56 @@ var defaultOauthScopes = []string{
"https://www.googleapis.com/auth/trace.append",
}
+func schemaContainerdConfig() *schema.Schema {
+ return &schema.Schema{
+ Type: schema.TypeList,
+ Optional: true,
+ Description: "Parameters for containerd configuration.",
+ MaxItems: 1,
+ Elem: &schema.Resource{Schema: map[string]*schema.Schema{
+ "private_registry_access_config": &schema.Schema{
+ Type: schema.TypeList,
+ Optional: true,
+ Description: "Parameters for private container registries configuration.",
+ MaxItems: 1,
+ Elem: &schema.Resource{Schema: map[string]*schema.Schema{
+ "enabled": &schema.Schema{
+ Type: schema.TypeBool,
+ Required: true,
+ Description: "Whether or not private registries are configured.",
+ },
+ "certificate_authority_domain_config": &schema.Schema{
+ Type: schema.TypeList,
+ Optional: true,
+ Description: "Parameters for configuring CA certificate and domains.",
+ Elem: &schema.Resource{Schema: map[string]*schema.Schema{
+ "fqdns": &schema.Schema{
+ Type: schema.TypeList,
+ Required: true,
+ Description: "List of fully-qualified-domain-names. IPv4s and port specification are supported.",
+ Elem: &schema.Schema{Type: schema.TypeString},
+ },
+ "gcp_secret_manager_certificate_config": &schema.Schema{
+ Type: schema.TypeList,
+ Required: true,
+ Description: "Parameters for configuring a certificate hosted in GCP SecretManager.",
+ MaxItems: 1,
+ Elem: &schema.Resource{Schema: map[string]*schema.Schema{
+ "secret_uri": &schema.Schema{
+ Type: schema.TypeString,
+ Required: true,
+ Description: "URI for the secret that hosts a certificate. Must be in the format 'projects/PROJECT_NUM/secrets/SECRET_NAME/versions/VERSION_OR_LATEST'.",
+ },
+ }},
+ },
+ }},
+ },
+ }},
+ },
+ }},
+ }
+}
+
func schemaLoggingVariant() *schema.Schema {
return &schema.Schema{
Type: schema.TypeString,
@@ -68,6 +118,7 @@ func schemaNodeConfig() *schema.Schema {
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
+ "containerd_config": schemaContainerdConfig(),
"disk_size_gb": {
Type: schema.TypeInt,
Optional: true,
@@ -729,6 +780,7 @@ func expandNodeConfigDefaults(configured interface{}) *container.NodeConfigDefau
config := configs[0].(map[string]interface{})
nodeConfigDefaults := &container.NodeConfigDefaults{}
+ nodeConfigDefaults.ContainerdConfig = expandContainerdConfig(config["containerd_config"])
if variant, ok := config["logging_variant"]; ok {
nodeConfigDefaults.LoggingConfig = &container.NodePoolLoggingConfig{
VariantConfig: &container.LoggingVariantConfig{
@@ -759,6 +811,10 @@ func expandNodeConfig(v interface{}) *container.NodeConfig {
nodeConfig := nodeConfigs[0].(map[string]interface{})
+ if v, ok := nodeConfig["containerd_config"]; ok {
+ nc.ContainerdConfig = expandContainerdConfig(v)
+ }
+
if v, ok := nodeConfig["machine_type"]; ok {
nc.MachineType = v.(string)
}
@@ -1137,6 +1193,92 @@ func expandCgroupMode(cfg map[string]interface{}) string {
return cgroupMode.(string)
}
+func expandContainerdConfig(v interface{}) *container.ContainerdConfig {
+ if v == nil {
+ return nil
+ }
+ ls := v.([]interface{})
+ if len(ls) == 0 {
+ return nil
+ }
+ if ls[0] == nil {
+ return &container.ContainerdConfig{}
+ }
+ cfg := ls[0].(map[string]interface{})
+
+ cc := &container.ContainerdConfig{}
+ cc.PrivateRegistryAccessConfig = expandPrivateRegistryAccessConfig(cfg["private_registry_access_config"])
+ return cc
+}
+
+func expandPrivateRegistryAccessConfig(v interface{}) *container.PrivateRegistryAccessConfig {
+ if v == nil {
+ return nil
+ }
+ ls := v.([]interface{})
+ if len(ls) == 0 {
+ return nil
+ }
+ if ls[0] == nil {
+ return &container.PrivateRegistryAccessConfig{}
+ }
+ cfg := ls[0].(map[string]interface{})
+
+ pracc := &container.PrivateRegistryAccessConfig{}
+ if enabled, ok := cfg["enabled"]; ok {
+ pracc.Enabled = enabled.(bool)
+ }
+ if caCfgRaw, ok := cfg["certificate_authority_domain_config"]; ok {
+ ls := caCfgRaw.([]interface{})
+ pracc.CertificateAuthorityDomainConfig = make([]*container.CertificateAuthorityDomainConfig, len(ls))
+ for i, caCfg := range ls {
+ pracc.CertificateAuthorityDomainConfig[i] = expandCADomainConfig(caCfg)
+ }
+ }
+
+ return pracc
+}
+
+func expandCADomainConfig(v interface{}) *container.CertificateAuthorityDomainConfig {
+ if v == nil {
+ return nil
+ }
+ cfg := v.(map[string]interface{})
+
+ caConfig := &container.CertificateAuthorityDomainConfig{}
+ if v, ok := cfg["fqdns"]; ok {
+ fqdns := v.([]interface{})
+ caConfig.Fqdns = make([]string, len(fqdns))
+ for i, dn := range fqdns {
+ caConfig.Fqdns[i] = dn.(string)
+ }
+ }
+
+ caConfig.GcpSecretManagerCertificateConfig = expandGCPSecretManagerCertificateConfig(cfg["gcp_secret_manager_certificate_config"])
+
+ return caConfig
+}
+
+func expandGCPSecretManagerCertificateConfig(v interface{}) *container.GCPSecretManagerCertificateConfig {
+ if v == nil {
+ return nil
+ }
+ ls := v.([]interface{})
+ if len(ls) == 0 {
+ return nil
+ }
+ if ls[0] == nil {
+ return &container.GCPSecretManagerCertificateConfig{}
+ }
+ cfg := ls[0].(map[string]interface{})
+
+ gcpSMConfig := &container.GCPSecretManagerCertificateConfig{}
+ if v, ok := cfg["secret_uri"]; ok {
+ gcpSMConfig.SecretUri = v.(string)
+ }
+ return gcpSMConfig
+}
+
func expandSoleTenantConfig(v interface{}) *container.SoleTenantConfig {
if v == nil {
return nil
@@ -1204,6 +1346,8 @@ func flattenNodeConfigDefaults(c *container.NodeConfigDefaults) []map[string]int
result = append(result, map[string]interface{}{})
+ result[0]["containerd_config"] = flattenContainerdConfig(c.ContainerdConfig)
+
result[0]["logging_variant"] = flattenLoggingVariant(c.LoggingConfig)
<% unless version == 'ga' -%>
@@ -1232,6 +1376,7 @@ func flattenNodeConfig(c *container.NodeConfig, v interface{}) []map[string]inte
config = append(config, map[string]interface{}{
"machine_type": c.MachineType,
+ "containerd_config": flattenContainerdConfig(c.ContainerdConfig),
"disk_size_gb": c.DiskSizeGb,
"disk_type": c.DiskType,
"guest_accelerator": flattenContainerGuestAccelerators(c.Accelerators),
@@ -1559,6 +1704,74 @@ func flattenLinuxNodeConfig(c *container.LinuxNodeConfig) []map[string]interface
return result
}
+func flattenContainerdConfig(c *container.ContainerdConfig) []map[string]interface{} {
+ result := []map[string]interface{}{}
+ if c == nil {
+ return result
+ }
+ r := map[string]interface{}{}
+ if c.PrivateRegistryAccessConfig != nil {
+ r["private_registry_access_config"] = flattenPrivateRegistryAccessConfig(c.PrivateRegistryAccessConfig)
+ }
+ return append(result, r)
+}
+
+func flattenPrivateRegistryAccessConfig(c *container.PrivateRegistryAccessConfig) []map[string]interface{} {
+ result := []map[string]interface{}{}
+ if c == nil {
+ return result
+ }
+ r := map[string]interface{}{
+ "enabled": c.Enabled,
+ }
+ if c.CertificateAuthorityDomainConfig != nil {
+ caConfigs := make([]interface{}, len(c.CertificateAuthorityDomainConfig))
+ for i, caCfg := range c.CertificateAuthorityDomainConfig {
+ caConfigs[i] = flattenCADomainConfig(caCfg)
+ }
+ r["certificate_authority_domain_config"] = caConfigs
+ }
+ return append(result, r)
+}
+
+// func flattenCADomainConfig(c *container.CertificateAuthorityDomainConfig) []map[string]interface{} {
+// result := []map[string]interface{}{}
+// if c == nil {
+// return result
+// }
+// r := map[string]interface{}{
+// "fqdns": c.Fqdns,
+// }
+// if c.GcpSecretManagerCertificateConfig != nil {
+// r["gcp_secret_manager_certificate_config"] = flattenGCPSecretManagerCertificateConfig(c.GcpSecretManagerCertificateConfig)
+// }
+// return append(result, r)
+// }
+
+func flattenCADomainConfig(c *container.CertificateAuthorityDomainConfig) map[string]interface{} {
+ if c == nil {
+ return nil
+ }
+ r := map[string]interface{}{
+ "fqdns": c.Fqdns,
+ }
+ if c.GcpSecretManagerCertificateConfig != nil {
+ r["gcp_secret_manager_certificate_config"] = flattenGCPSecretManagerCertificateConfig(c.GcpSecretManagerCertificateConfig)
+ }
+ return r
+}
+
+func flattenGCPSecretManagerCertificateConfig(c *container.GCPSecretManagerCertificateConfig) []map[string]interface{} {
+ result := []map[string]interface{}{}
+ if c == nil {
+ return result
+ }
+ r := map[string]interface{}{
+ "secret_uri": c.SecretUri,
+ }
+ return append(result, r)
+}
+
func flattenConfidentialNodes(c *container.ConfidentialNodes) []map[string]interface{} {
result := []map[string]interface{}{}
if c != nil {
diff --git a/mmv1/third_party/terraform/services/container/resource_container_cluster.go.erb b/mmv1/third_party/terraform/services/container/resource_container_cluster.go.erb
index f82c7581e18d..bb99d27067da 100644
--- a/mmv1/third_party/terraform/services/container/resource_container_cluster.go.erb
+++ b/mmv1/third_party/terraform/services/container/resource_container_cluster.go.erb
@@ -148,6 +148,7 @@ func clusterSchemaNodePoolDefaults() *schema.Schema {
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
+ "containerd_config": schemaContainerdConfig(),
<% unless version == 'ga' -%>
"gcfs_config": schemaGcfsConfig(false),
<% end -%>
@@ -4189,6 +4190,21 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
log.Printf("[INFO] GKE cluster %s Security Posture Config has been updated to %#v", d.Id(), req.Update.DesiredSecurityPostureConfig)
}
+ if d.HasChange("node_pool_defaults") && d.HasChange("node_pool_defaults.0.node_config_defaults.0.containerd_config") {
+ if v, ok := d.GetOk("node_pool_defaults.0.node_config_defaults.0.containerd_config"); ok {
+ req := &container.UpdateClusterRequest{
+ Update: &container.ClusterUpdate{
+ DesiredContainerdConfig: expandContainerdConfig(v),
+ },
+ }
+ updateF := updateFunc(req, "updating GKE cluster containerd config")
+ if err := transport_tpg.LockedCall(lockKey, updateF); err != nil {
+ return err
+ }
+ log.Printf("[INFO] GKE cluster %s containerd config has been updated to %#v", d.Id(), req.Update.DesiredContainerdConfig)
+ }
+ }
+
if d.HasChange("node_pool_auto_config.0.network_tags.0.tags") {
tags := d.Get("node_pool_auto_config.0.network_tags.0.tags").([]interface{})
diff --git a/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb b/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb
index 6773dbb94436..792bf1fd1a4b 100644
--- a/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb
+++ b/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb
@@ -10502,3 +10502,285 @@ resource "google_container_cluster" "with_autopilot" {
}
`, projectID, randomSuffix, clusterName, networkName, subnetworkName)
}
+
+func TestAccContainerCluster_privateRegistry(t *testing.T) {
+ t.Parallel()
+
+ clusterName := fmt.Sprintf("tf-test-cluster-%s", acctest.RandString(t, 10))
+ nodePoolName := fmt.Sprintf("tf-test-nodepool-%s", acctest.RandString(t, 10))
+ secretID := fmt.Sprintf("tf-test-secret-%s", acctest.RandString(t, 10))
+ networkName := acctest.BootstrapSharedTestNetwork(t, "gke-cluster")
+ subnetworkName := acctest.BootstrapSubnet(t, "gke-cluster", networkName)
+ acctest.VcrTest(t, resource.TestCase{
+ PreCheck: func() { acctest.AccTestPreCheck(t) },
+ ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
+ CheckDestroy: testAccCheckContainerClusterDestroyProducer(t),
+ Steps: []resource.TestStep{
+ resource.TestStep{
+ Config: testAccContainerCluster_privateRegistryEnabled(secretID, clusterName, networkName, subnetworkName),
+ Check: resource.ComposeAggregateTestCheckFunc(
+ resource.TestCheckResourceAttr(
+ "google_container_cluster.primary",
+ "node_pool_defaults.0.node_config_defaults.0.containerd_config.0.private_registry_access_config.0.enabled",
+ "true",
+ ),
+ resource.TestCheckResourceAttr(
+ "google_container_cluster.primary",
+ "node_pool_defaults.0.node_config_defaults.0.containerd_config.0.private_registry_access_config.0.certificate_authority_domain_config.#",
+ "2",
+ ),
+ // First CA config
+ resource.TestCheckResourceAttr(
+ "google_container_cluster.primary",
+ "node_pool_defaults.0.node_config_defaults.0.containerd_config.0.private_registry_access_config.0.certificate_authority_domain_config.0.fqdns.0",
+ "my.custom.domain",
+ ),
+ // Second CA config
+ resource.TestCheckResourceAttr(
+ "google_container_cluster.primary",
+ "node_pool_defaults.0.node_config_defaults.0.containerd_config.0.private_registry_access_config.0.certificate_authority_domain_config.1.fqdns.0",
+ "10.1.2.32",
+ ),
+ ),
+ },
+ {
+ ResourceName: "google_container_cluster.primary",
+ ImportState: true,
+ ImportStateVerify: true,
+ ImportStateVerifyIgnore: []string{"deletion_protection"},
+ },
+ {
+ Config: testAccContainerCluster_privateRegistryDisabled(clusterName, networkName, subnetworkName),
+ Check: resource.ComposeAggregateTestCheckFunc(
+ resource.TestCheckResourceAttr(
+ "google_container_cluster.primary",
+ "node_pool_defaults.0.node_config_defaults.0.containerd_config.0.private_registry_access_config.0.enabled",
+ "false",
+ ),
+ resource.TestCheckResourceAttr(
+ "google_container_cluster.primary",
+ "node_pool_defaults.0.node_config_defaults.0.containerd_config.0.private_registry_access_config.0.certificate_authority_domain_config.#",
+ "0",
+ ),
+ ),
+ },
+ resource.TestStep{
+ Config: testAccContainerCluster_withNodePoolPrivateRegistry(secretID, clusterName, nodePoolName, networkName, subnetworkName),
+ },
+ {
+ ResourceName: "google_container_cluster.primary",
+ ImportState: true,
+ ImportStateVerify: true,
+ ImportStateVerifyIgnore: []string{"deletion_protection"},
+ },
+ resource.TestStep{
+ Config: testAccContainerCluster_withNodeConfigPrivateRegistry(secretID, clusterName, networkName, subnetworkName),
+ },
+ {
+ ResourceName: "google_container_cluster.primary",
+ ImportState: true,
+ ImportStateVerify: true,
+ ImportStateVerifyIgnore: []string{"deletion_protection"},
+ },
+ },
+ })
+}
+
+func testAccContainerCluster_privateRegistryEnabled(secretID, clusterName, networkName, subnetworkName string) string {
+ return fmt.Sprintf(`
+data "google_project" "test_project" {
+ }
+
+resource "google_secret_manager_secret" "secret-basic" {
+ secret_id = "%s"
+ replication {
+ user_managed {
+ replicas {
+ location = "us-central1"
+ }
+ }
+ }
+}
+
+resource "google_secret_manager_secret_version" "secret-version-basic" {
+ secret = google_secret_manager_secret.secret-basic.id
+ secret_data = "dummypassword"
+ }
+
+resource "google_secret_manager_secret_iam_member" "secret_iam" {
+ secret_id = google_secret_manager_secret.secret-basic.id
+ role = "roles/secretmanager.admin"
+ member = "serviceAccount:${data.google_project.test_project.number}-compute@developer.gserviceaccount.com"
+ depends_on = [google_secret_manager_secret_version.secret-version-basic]
+ }
+
+resource "google_container_cluster" "primary" {
+ name = "%s"
+ location = "us-central1-a"
+ initial_node_count = 1
+ deletion_protection = false
+ network = "%s"
+ subnetwork = "%s"
+
+ node_pool_defaults {
+ node_config_defaults {
+ containerd_config {
+ private_registry_access_config {
+ enabled = true
+ certificate_authority_domain_config {
+ fqdns = [ "my.custom.domain" ]
+ gcp_secret_manager_certificate_config {
+ secret_uri = google_secret_manager_secret_version.secret-version-basic.name
+ }
+ }
+ certificate_authority_domain_config {
+ fqdns = [ "10.1.2.32" ]
+ gcp_secret_manager_certificate_config {
+ secret_uri = google_secret_manager_secret_version.secret-version-basic.name
+ }
+ }
+ }
+ }
+ }
+ }
+}
+`, secretID, clusterName, networkName, subnetworkName)
+}
+
+func testAccContainerCluster_privateRegistryDisabled(clusterName, networkName, subnetworkName string) string {
+ return fmt.Sprintf(`
+resource "google_container_cluster" "primary" {
+ name = "%s"
+ location = "us-central1-a"
+ initial_node_count = 1
+ deletion_protection = false
+ network = "%s"
+ subnetwork = "%s"
+
+ node_pool_defaults {
+ node_config_defaults {
+ containerd_config {
+ private_registry_access_config {
+ enabled = false
+ }
+ }
+ }
+ }
+}
+`, clusterName, networkName, subnetworkName)
+}
+
+func testAccContainerCluster_withNodePoolPrivateRegistry(secretID, clusterName, nodePoolName, networkName, subnetworkName string) string {
+ return fmt.Sprintf(`
+data "google_project" "test_project" {
+ }
+
+resource "google_secret_manager_secret" "secret-basic" {
+ secret_id = "%s"
+ replication {
+ user_managed {
+ replicas {
+ location = "us-central1"
+ }
+ }
+ }
+}
+resource "google_secret_manager_secret_version" "secret-version-basic" {
+ secret = google_secret_manager_secret.secret-basic.id
+ secret_data = "dummypassword"
+ }
+
+resource "google_secret_manager_secret_iam_member" "secret_iam" {
+ secret_id = google_secret_manager_secret.secret-basic.id
+ role = "roles/secretmanager.admin"
+ member = "serviceAccount:${data.google_project.test_project.number}-compute@developer.gserviceaccount.com"
+ depends_on = [google_secret_manager_secret_version.secret-version-basic]
+ }
+resource "google_container_cluster" "primary" {
+ name = "%s"
+ location = "us-central1-a"
+
+ node_pool {
+ name = "%s"
+ initial_node_count = 1
+ node_config {
+ oauth_scopes = [
+ "https://www.googleapis.com/auth/cloud-platform",
+ ]
+ machine_type = "n1-standard-8"
+ image_type = "COS_CONTAINERD"
+ containerd_config {
+ private_registry_access_config {
+ enabled = true
+ certificate_authority_domain_config {
+ fqdns = [ "my.custom.domain", "10.0.0.127:8888" ]
+ gcp_secret_manager_certificate_config {
+ secret_uri = google_secret_manager_secret_version.secret-version-basic.name
+ }
+ }
+ }
+ }
+}
+}
+ deletion_protection = false
+ network = "%s"
+ subnetwork = "%s"
+}
+`, secretID, clusterName, nodePoolName, networkName, subnetworkName)
+}
+
+func testAccContainerCluster_withNodeConfigPrivateRegistry(secretID, clusterName, networkName, subnetworkName string) string {
+ return fmt.Sprintf(`
+data "google_project" "test_project" {
+ }
+
+resource "google_secret_manager_secret" "secret-basic" {
+ secret_id = "%s"
+ replication {
+ user_managed {
+ replicas {
+ location = "us-central1"
+ }
+ }
+ }
+}
+resource "google_secret_manager_secret_version" "secret-version-basic" {
+ secret = google_secret_manager_secret.secret-basic.id
+ secret_data = "dummypassword"
+ }
+
+resource "google_secret_manager_secret_iam_member" "secret_iam" {
+ secret_id = google_secret_manager_secret.secret-basic.id
+ role = "roles/secretmanager.admin"
+ member = "serviceAccount:${data.google_project.test_project.number}-compute@developer.gserviceaccount.com"
+ depends_on = [google_secret_manager_secret_version.secret-version-basic]
+ }
+resource "google_container_cluster" "primary" {
+ name = "%s"
+ location = "us-central1-a"
+ initial_node_count = 1
+
+ node_config {
+ oauth_scopes = [
+ "https://www.googleapis.com/auth/cloud-platform",
+ ]
+ machine_type = "n1-standard-8"
+ image_type = "COS_CONTAINERD"
+ containerd_config {
+ private_registry_access_config {
+ enabled = true
+ certificate_authority_domain_config {
+ fqdns = [ "my.custom.domain", "10.0.0.127:8888" ]
+ gcp_secret_manager_certificate_config {
+ secret_uri = google_secret_manager_secret_version.secret-version-basic.name
+ }
+ }
+ }
+ }
+}
+ deletion_protection = false
+ network = "%s"
+ subnetwork = "%s"
+}
+`, secretID, clusterName, networkName, subnetworkName)
+}
diff --git a/mmv1/third_party/terraform/services/container/resource_container_node_pool_test.go.erb b/mmv1/third_party/terraform/services/container/resource_container_node_pool_test.go.erb
index 612c40a36a86..612f66e0d713 100644
--- a/mmv1/third_party/terraform/services/container/resource_container_node_pool_test.go.erb
+++ b/mmv1/third_party/terraform/services/container/resource_container_node_pool_test.go.erb
@@ -4734,3 +4734,119 @@ resource "google_container_node_pool" "primary_nodes" {
}
`, projectID, randomSuffix, clusterName, networkName, subnetworkName)
}
+
+func TestAccContainerNodePool_privateRegistry(t *testing.T) {
+ t.Parallel()
+
+ cluster := fmt.Sprintf("tf-test-cluster-%s", acctest.RandString(t, 10))
+ nodepool := fmt.Sprintf("tf-test-nodepool-%s", acctest.RandString(t, 10))
+ secretID := fmt.Sprintf("tf-test-secret-%s", acctest.RandString(t, 10))
+ networkName := acctest.BootstrapSharedTestNetwork(t, "gke-cluster")
+ subnetworkName := acctest.BootstrapSubnet(t, "gke-cluster", networkName)
+
+ acctest.VcrTest(t, resource.TestCase{
+ PreCheck: func() { acctest.AccTestPreCheck(t) },
+ ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
+ CheckDestroy: testAccCheckContainerNodePoolDestroyProducer(t),
+ Steps: []resource.TestStep{
+ resource.TestStep{
+ Config: testAccContainerNodePool_privateRegistryEnabled(secretID, cluster, nodepool, networkName, subnetworkName),
+ Check: resource.ComposeAggregateTestCheckFunc(
+ resource.TestCheckResourceAttr(
+ "google_container_node_pool.np",
+ "node_config.0.containerd_config.0.private_registry_access_config.0.enabled",
+ "true",
+ ),
+ resource.TestCheckResourceAttr(
+ "google_container_node_pool.np",
+ "node_config.0.containerd_config.0.private_registry_access_config.0.certificate_authority_domain_config.#",
+ "2",
+ ),
+ // First CA config
+ resource.TestCheckResourceAttr(
+ "google_container_node_pool.np",
+ "node_config.0.containerd_config.0.private_registry_access_config.0.certificate_authority_domain_config.0.fqdns.0",
+ "my.custom.domain",
+ ),
+ // Second CA config
+ resource.TestCheckResourceAttr(
+ "google_container_node_pool.np",
+ "node_config.0.containerd_config.0.private_registry_access_config.0.certificate_authority_domain_config.1.fqdns.0",
+ "10.1.2.32",
+ ),
+ ),
+ },
+ },
+ })
+}
+
+func testAccContainerNodePool_privateRegistryEnabled(secretID, cluster, nodepool, network, subnetwork string) string {
+ return fmt.Sprintf(`
+data "google_project" "test_project" {
+ }
+
+resource "google_secret_manager_secret" "secret-basic" {
+ secret_id = "%s"
+ replication {
+ user_managed {
+ replicas {
+ location = "us-central1"
+ }
+ }
+ }
+}
+
+resource "google_secret_manager_secret_version" "secret-version-basic" {
+ secret = google_secret_manager_secret.secret-basic.id
+ secret_data = "dummypassword"
+ }
+
+resource "google_secret_manager_secret_iam_member" "secret_iam" {
+ secret_id = google_secret_manager_secret.secret-basic.id
+ role = "roles/secretmanager.admin"
+ member = "serviceAccount:${data.google_project.test_project.number}-compute@developer.gserviceaccount.com"
+ depends_on = [google_secret_manager_secret_version.secret-version-basic]
+ }
+
+resource "google_container_cluster" "cluster" {
+ name = "%s"
+ location = "us-central1-a"
+ initial_node_count = 1
+ deletion_protection = false
+ network = "%s"
+ subnetwork = "%s"
+}
+
+resource "google_container_node_pool" "np" {
+ name = "%s"
+ location = "us-central1-a"
+ cluster = google_container_cluster.cluster.name
+ initial_node_count = 1
+
+ node_config {
+ oauth_scopes = [
+ "https://www.googleapis.com/auth/cloud-platform",
+ ]
+ machine_type = "n1-standard-8"
+ image_type = "COS_CONTAINERD"
+ containerd_config {
+ private_registry_access_config {
+ enabled = true
+ certificate_authority_domain_config {
+ fqdns = [ "my.custom.domain", "10.0.0.127:8888" ]
+ gcp_secret_manager_certificate_config {
+ secret_uri = google_secret_manager_secret_version.secret-version-basic.name
+ }
+ }
+ certificate_authority_domain_config {
+ fqdns = [ "10.1.2.32" ]
+ gcp_secret_manager_certificate_config {
+ secret_uri = google_secret_manager_secret_version.secret-version-basic.name
+ }
+ }
+ }
+ }
+ }
+}
+`, secretID, cluster, network, subnetwork, nodepool)
+}
diff --git a/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown b/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown
index 254eec9bdb6e..005e828892ed 100644
--- a/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown
+++ b/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown
@@ -940,6 +940,8 @@ kubelet_config {
* `linux_node_config` - (Optional) Parameters that can be configured on Linux nodes. Structure is [documented below](#nested_linux_node_config).
+* `containerd_config` - (Optional) Parameters to customize containerd runtime. Structure is [documented below](#nested_containerd_config).
+
* `node_group` - (Optional) Setting this field will assign instances of this pool to run on the specified node group. This is useful for running workloads on [sole tenant nodes](https://cloud.google.com/compute/docs/nodes/sole-tenant-nodes).
* `sole_tenant_config` (Optional) Allows specifying multiple [node affinities](https://cloud.google.com/compute/docs/nodes/sole-tenant-nodes#node_affinity_and_anti-affinity) useful for running workloads on [sole tenant nodes](https://cloud.google.com/kubernetes-engine/docs/how-to/sole-tenancy). `node_affinity` structure is [documented below](#nested_node_affinity).
@@ -1281,6 +1283,26 @@ linux_node_config {
* `CGROUP_MODE_V1`: CGROUP_MODE_V1 specifies to use cgroupv1 for the cgroup configuration on the node image.
* `CGROUP_MODE_V2`: CGROUP_MODE_V2 specifies to use cgroupv2 for the cgroup configuration on the node image.
+The `containerd_config` block supports:
+
+* `private_registry_access_config` (Optional) - Configuration for private container registries. There are two fields in this config:
+
+ * `enabled` (Required) - Enables private registry config. If set to false, all other fields in this object must not be set.
+
+ * `certificate_authority_domain_config` (Optional) - List of configuration objects for CA and domains. Each object identifies a certificate and its assigned domains. See [how to configure for private container registries](https://cloud.google.com/kubernetes-engine/docs/how-to/access-private-registries-private-certificates) for more detail. Example:
+ ```hcl
+ certificate_authority_domain_config {
+ fqdns = [
+ "my.custom.domain",
+ "10.4.5.6",
+ "127.0.0.1:8888",
+ ]
+ gcp_secret_manager_certificate_config {
+ secret_uri = "projects/99999/secrets/my-ca-cert/versions/1"
+ }
+ }
+ ```
+
The `vertical_pod_autoscaling` block supports:
* `enabled` (Required) - Enables vertical pod autoscaling