Skip to content

Commit

Permalink
GKE: Support Control Plane Authority / UserManagedKeysConfig (GoogleC…
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmedtd authored Oct 30, 2024
1 parent 5b23601 commit fd0fd05
Show file tree
Hide file tree
Showing 3 changed files with 440 additions and 2 deletions.
13 changes: 11 additions & 2 deletions mmv1/third_party/terraform/acctest/bootstrap_test_utils.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ var SharedCryptoKey = map[string]string{
type BootstrappedKMS struct {
*cloudkms.KeyRing
*cloudkms.CryptoKey
CryptoKeyVersions []*cloudkms.CryptoKeyVersion
}

func BootstrapKMSKey(t *testing.T) BootstrappedKMS {
Expand Down Expand Up @@ -77,6 +78,7 @@ func BootstrapKMSKeyWithPurposeInLocationAndName(t *testing.T, purpose, location
return BootstrappedKMS{
&cloudkms.KeyRing{},
&cloudkms.CryptoKey{},
nil,
}
}

Expand Down Expand Up @@ -111,8 +113,8 @@ func BootstrapKMSKeyWithPurposeInLocationAndName(t *testing.T, purpose, location
if transport_tpg.IsGoogleApiErrorWithCode(err, 404) {
algos := map[string]string{
"ENCRYPT_DECRYPT": "GOOGLE_SYMMETRIC_ENCRYPTION",
"ASYMMETRIC_SIGN": "RSA_SIGN_PKCS1_4096_SHA512",
"ASYMMETRIC_DECRYPT": "RSA_DECRYPT_OAEP_4096_SHA512",
"ASYMMETRIC_SIGN": "RSA_SIGN_PKCS1_4096_SHA256",
"ASYMMETRIC_DECRYPT": "RSA_DECRYPT_OAEP_4096_SHA256",
}
template := cloudkms.CryptoKeyVersionTemplate{
Algorithm: algos[purpose],
Expand All @@ -138,9 +140,16 @@ func BootstrapKMSKeyWithPurposeInLocationAndName(t *testing.T, purpose, location
t.Fatalf("Unable to bootstrap KMS key. CryptoKey is nil!")
}

// TODO(b/372305432): Use the pagination properly.
ckvResp, err := kmsClient.Projects.Locations.KeyRings.CryptoKeys.CryptoKeyVersions.List(keyName).Do()
if err != nil {
t.Fatalf("Unable to list cryptoKeyVersions: %v", err)
}

return BootstrappedKMS{
keyRing,
cryptoKey,
ckvResp.CryptoKeyVersions,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2190,6 +2190,62 @@ func ResourceContainerCluster() *schema.Resource {
},
},
},
"user_managed_keys_config": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Description: `The custom keys configuration of the cluster.`,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cluster_ca": {
Type: schema.TypeString,
Optional: true,
Description: `The Certificate Authority Service caPool to use for the cluster CA in this cluster.`,
},
"etcd_api_ca": {
Type: schema.TypeString,
Optional: true,
Description: `The Certificate Authority Service caPool to use for the etcd API CA in this cluster.`,
},
"etcd_peer_ca": {
Type: schema.TypeString,
Optional: true,
Description: `The Certificate Authority Service caPool to use for the etcd peer CA in this cluster.`,
},
"aggregation_ca": {
Type: schema.TypeString,
Optional: true,
Description: `The Certificate Authority Service caPool to use for the aggreation CA in this cluster.`,
},
"service_account_signing_keys": {
Type: schema.TypeSet,
Optional: true,
Description: `The Cloud KMS cryptoKeyVersions to use for signing service account JWTs issued by this cluster.`,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"service_account_verification_keys": {
Type: schema.TypeSet,
Optional: true,
Description: `The Cloud KMS cryptoKeyVersions to use for verifying service account JWTs issued by this cluster.`,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"control_plane_disk_encryption_key": {
Type: schema.TypeString,
Optional: true,
Description: `The Cloud KMS cryptoKey to use for Confidential Hyperdisk on the control plane nodes.`,
},
"gkeops_etcd_backup_encryption_key": {
Type: schema.TypeString,
Optional: true,
Description: `Resource path of the Cloud KMS cryptoKey to use for encryption of internal etcd backups.`,
},
},
},
},
{{- if ne $.TargetVersionName "ga" }}
"workload_alts_config": {
Type: schema.TypeList,
Expand Down Expand Up @@ -2517,6 +2573,10 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er
cluster.Fleet = expandFleet(v)
}

if v, ok := d.GetOk("user_managed_keys_config"); ok {
cluster.UserManagedKeysConfig = expandUserManagedKeysConfig(v)
}

if err := validateNodePoolAutoConfig(cluster); err != nil {
return err
}
Expand Down Expand Up @@ -3019,6 +3079,9 @@ func resourceContainerClusterRead(d *schema.ResourceData, meta interface{}) erro
if err := d.Set("fleet", flattenFleet(cluster.Fleet)); err != nil {
return err
}
if err := d.Set("user_managed_keys_config", flattenUserManagedKeysConfig(cluster.UserManagedKeysConfig)); err != nil {
return err
}
if err := d.Set("enable_k8s_beta_apis", flattenEnableK8sBetaApis(cluster.EnableK8sBetaApis)); err != nil {
return err
}
Expand Down Expand Up @@ -4188,6 +4251,20 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
log.Printf("[INFO] GKE cluster %s fleet config has been updated", d.Id())
}

if d.HasChange("user_managed_keys_config") {
req := &container.UpdateClusterRequest{
Update: &container.ClusterUpdate{
UserManagedKeysConfig: expandUserManagedKeysConfig(d.Get("user_managed_keys_config")),
},
}
updateF := updateFunc(req, "updating GKE cluster user managed keys config.")
if err := transport_tpg.LockedCall(lockKey, updateF); err != nil {
return err
}

log.Printf("[INFO] GKE cluster %s user managed key config has been updated to %#v", d.Id(), req.Update.UserManagedKeysConfig)
}

if d.HasChange("enable_k8s_beta_apis") {
log.Print("[INFO] Enable Kubernetes Beta APIs")
if v, ok := d.GetOk("enable_k8s_beta_apis"); ok {
Expand Down Expand Up @@ -5530,6 +5607,32 @@ func expandFleet(configured interface{}) *container.Fleet {
}
}

func expandUserManagedKeysConfig(configured interface{}) *container.UserManagedKeysConfig {
l := configured.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil
}

config := l[0].(map[string]interface{})
umkc := &container.UserManagedKeysConfig{
ClusterCa: config["cluster_ca"].(string),
EtcdApiCa: config["etcd_api_ca"].(string),
EtcdPeerCa: config["etcd_peer_ca"].(string),
AggregationCa: config["aggregation_ca"].(string),
ControlPlaneDiskEncryptionKey: config["control_plane_disk_encryption_key"].(string),
GkeopsEtcdBackupEncryptionKey: config["gkeops_etcd_backup_encryption_key"].(string),
}
if v, ok := config["service_account_signing_keys"]; ok {
sk := v.(*schema.Set)
umkc.ServiceAccountSigningKeys = tpgresource.ConvertStringSet(sk)
}
if v, ok := config["service_account_verification_keys"]; ok {
vk := v.(*schema.Set)
umkc.ServiceAccountVerificationKeys = tpgresource.ConvertStringSet(vk)
}
return umkc
}

func expandEnableK8sBetaApis(configured interface{}, enabledAPIs []string) *container.K8sBetaAPIConfig {
l := configured.([]interface{})
if len(l) == 0 || l[0] == nil {
Expand Down Expand Up @@ -6446,6 +6549,27 @@ func flattenFleet(c *container.Fleet) []map[string]interface{} {
}
}

func flattenUserManagedKeysConfig(c *container.UserManagedKeysConfig) []map[string]interface{} {
if c == nil {
return nil
}
f := map[string]interface{}{
"cluster_ca": c.ClusterCa,
"etcd_api_ca": c.EtcdApiCa,
"etcd_peer_ca": c.EtcdPeerCa,
"aggregation_ca": c.AggregationCa,
"control_plane_disk_encryption_key": c.ControlPlaneDiskEncryptionKey,
"gkeops_etcd_backup_encryption_key": c.GkeopsEtcdBackupEncryptionKey,
}
if len(c.ServiceAccountSigningKeys) != 0 {
f["service_account_signing_keys"] = schema.NewSet(schema.HashString, tpgresource.ConvertStringArrToInterface(c.ServiceAccountSigningKeys))
}
if len(c.ServiceAccountVerificationKeys) != 0 {
f["service_account_verification_keys"] = schema.NewSet(schema.HashString, tpgresource.ConvertStringArrToInterface(c.ServiceAccountVerificationKeys))
}
return []map[string]interface{}{f}
}

func flattenEnableK8sBetaApis(c *container.K8sBetaAPIConfig) []map[string]interface{} {
if c == nil {
return nil
Expand Down
Loading

0 comments on commit fd0fd05

Please sign in to comment.