Skip to content

Commit b724137

Browse files
Add support for managed_server_ca to Memorystore instance (#14352) (#23430)
[upstream:cdbfce4d09bee704ccf26ce9ca502dff4e038ffa] Signed-off-by: Modular Magician <[email protected]>
1 parent aae0c53 commit b724137

File tree

5 files changed

+210
-0
lines changed

5 files changed

+210
-0
lines changed

.changelog/14352.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
unknown: Add support for `managed_server_ca` to Memorystore instance

google/services/memorystore/resource_memorystore_instance.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,32 @@ resolution and up to nine fractional digits.`,
710710
},
711711
},
712712
},
713+
"managed_server_ca": {
714+
Type: schema.TypeList,
715+
Computed: true,
716+
Description: `Instance's Certificate Authority. This field will only be populated if instance's transit_encryption_mode is SERVER_AUTHENTICATION`,
717+
Elem: &schema.Resource{
718+
Schema: map[string]*schema.Schema{
719+
"ca_certs": {
720+
Type: schema.TypeList,
721+
Computed: true,
722+
Description: `The PEM encoded CA certificate chains for managed server authentication`,
723+
Elem: &schema.Resource{
724+
Schema: map[string]*schema.Schema{
725+
"certificates": {
726+
Type: schema.TypeList,
727+
Computed: true,
728+
Description: `The certificates that form the CA chain, from leaf to root order`,
729+
Elem: &schema.Schema{
730+
Type: schema.TypeString,
731+
},
732+
},
733+
},
734+
},
735+
},
736+
},
737+
},
738+
},
713739
"name": {
714740
Type: schema.TypeString,
715741
Computed: true,
@@ -1256,6 +1282,9 @@ func resourceMemorystoreInstanceRead(d *schema.ResourceData, meta interface{}) e
12561282
if err := d.Set("kms_key", flattenMemorystoreInstanceKmsKey(res["kmsKey"], d, config)); err != nil {
12571283
return fmt.Errorf("Error reading Instance: %s", err)
12581284
}
1285+
if err := d.Set("managed_server_ca", flattenMemorystoreInstanceManagedServerCa(res["managedServerCa"], d, config)); err != nil {
1286+
return fmt.Errorf("Error reading Instance: %s", err)
1287+
}
12591288
if err := d.Set("terraform_labels", flattenMemorystoreInstanceTerraformLabels(res["labels"], d, config)); err != nil {
12601289
return fmt.Errorf("Error reading Instance: %s", err)
12611290
}
@@ -2443,6 +2472,41 @@ func flattenMemorystoreInstanceKmsKey(v interface{}, d *schema.ResourceData, con
24432472
return v
24442473
}
24452474

2475+
func flattenMemorystoreInstanceManagedServerCa(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
2476+
if v == nil {
2477+
return nil
2478+
}
2479+
original := v.(map[string]interface{})
2480+
if len(original) == 0 {
2481+
return nil
2482+
}
2483+
transformed := make(map[string]interface{})
2484+
transformed["ca_certs"] =
2485+
flattenMemorystoreInstanceManagedServerCaCaCerts(original["caCerts"], d, config)
2486+
return []interface{}{transformed}
2487+
}
2488+
func flattenMemorystoreInstanceManagedServerCaCaCerts(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
2489+
if v == nil {
2490+
return v
2491+
}
2492+
l := v.([]interface{})
2493+
transformed := make([]interface{}, 0, len(l))
2494+
for _, raw := range l {
2495+
original := raw.(map[string]interface{})
2496+
if len(original) < 1 {
2497+
// Do not include empty json objects coming back from the api
2498+
continue
2499+
}
2500+
transformed = append(transformed, map[string]interface{}{
2501+
"certificates": flattenMemorystoreInstanceManagedServerCaCaCertsCertificates(original["certificates"], d, config),
2502+
})
2503+
}
2504+
return transformed
2505+
}
2506+
func flattenMemorystoreInstanceManagedServerCaCaCertsCertificates(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
2507+
return v
2508+
}
2509+
24462510
func flattenMemorystoreInstanceTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
24472511
if v == nil {
24482512
return v
@@ -3317,5 +3381,49 @@ func resourceMemorystoreInstanceDecoder(d *schema.ResourceData, meta interface{}
33173381

33183382
}
33193383

3384+
// Such custom code is necessary as the instance's certificate authority has to be retrieved via a dedicated
3385+
// getCertificateAuthority API.
3386+
// See https://cloud.google.com/memorystore/docs/valkey/reference/rest/v1/projects.locations.instances/getCertificateAuthority
3387+
// for details about this API.
3388+
config := meta.(*transport_tpg.Config)
3389+
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
3390+
if err != nil {
3391+
return nil, err
3392+
}
3393+
3394+
// Only instances with SERVER_AUTHENTICATION mode have certificate authority set
3395+
if v, ok := res["transitEncryptionMode"].(string); ok && v == "SERVER_AUTHENTICATION" {
3396+
url, err := tpgresource.ReplaceVars(d, config, "{{MemorystoreBasePath}}projects/{{project}}/locations/{{region}}/instances/{{instance_id}}/certificateAuthority")
3397+
if err != nil {
3398+
return nil, err
3399+
}
3400+
3401+
billingProject := ""
3402+
3403+
project, err := tpgresource.GetProject(d, config)
3404+
if err != nil {
3405+
return nil, fmt.Errorf("Error fetching project for instance: %s", err)
3406+
}
3407+
3408+
billingProject = project
3409+
3410+
// err == nil indicates that the billing_project value was found
3411+
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
3412+
billingProject = bp
3413+
}
3414+
3415+
certificateAuthority, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
3416+
Config: config,
3417+
Method: "GET",
3418+
Project: billingProject,
3419+
RawURL: url,
3420+
UserAgent: userAgent,
3421+
})
3422+
if err != nil {
3423+
return nil, fmt.Errorf("Error reading certificateAuthority: %s", err)
3424+
}
3425+
3426+
res["managedServerCa"] = certificateAuthority["managedServerCa"]
3427+
}
33203428
return res, nil
33213429
}

google/services/memorystore/resource_memorystore_instance_generated_meta.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ fields:
6464
- field: 'maintenance_schedule.schedule_deadline_time'
6565
- field: 'maintenance_schedule.start_time'
6666
- field: 'managed_backup_source.backup'
67+
- field: 'managed_server_ca.ca_certs.certificates'
6768
- field: 'mode'
6869
- field: 'name'
6970
- field: 'node_config.size_gb'

google/services/memorystore/resource_memorystore_instance_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,3 +1469,85 @@ data "google_project" "project" {
14691469
}
14701470
`, params.name, params.replicaCount, params.shardCount, params.nodeType, params.deletionProtectionEnabled, params.engineVersion, strBuilder.String(), zoneDistributionConfigBlock, maintenancePolicyBlock, persistenceBlock, lifecycleBlock, secondaryInstanceBlock, params.name, params.name, params.name)
14711471
}
1472+
1473+
func TestAccMemorystoreInstance_memorystoreInstanceTlsEnabled(t *testing.T) {
1474+
t.Parallel()
1475+
1476+
context := map[string]interface{}{
1477+
"random_suffix": acctest.RandString(t, 10),
1478+
}
1479+
1480+
acctest.VcrTest(t, resource.TestCase{
1481+
PreCheck: func() { acctest.AccTestPreCheck(t) },
1482+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
1483+
CheckDestroy: testAccCheckMemorystoreInstanceDestroyProducer(t),
1484+
Steps: []resource.TestStep{
1485+
{
1486+
Config: testAccMemorystoreInstance_memorystoreInstanceTlsEnabled(context),
1487+
Check: resource.TestCheckResourceAttrSet("google_memorystore_instance.instance-tls", "managed_server_ca.0.ca_certs.0.certificates.0"),
1488+
},
1489+
{
1490+
ResourceName: "google_memorystore_instance.instance-tls",
1491+
ImportState: true,
1492+
ImportStateVerify: true,
1493+
ImportStateVerifyIgnore: []string{"gcs_source", "instance_id", "labels", "location", "managed_backup_source", "terraform_labels"},
1494+
},
1495+
},
1496+
})
1497+
}
1498+
1499+
func testAccMemorystoreInstance_memorystoreInstanceTlsEnabled(context map[string]interface{}) string {
1500+
return acctest.Nprintf(`
1501+
resource "google_memorystore_instance" "instance-tls" {
1502+
instance_id = "tf-test-tls-instance%{random_suffix}"
1503+
shard_count = 1
1504+
desired_auto_created_endpoints {
1505+
network = google_compute_network.producer_net.id
1506+
project_id = data.google_project.project.project_id
1507+
}
1508+
location = "us-central1"
1509+
deletion_protection_enabled = false
1510+
maintenance_policy {
1511+
weekly_maintenance_window {
1512+
day = "MONDAY"
1513+
start_time {
1514+
hours = 1
1515+
minutes = 0
1516+
seconds = 0
1517+
nanos = 0
1518+
}
1519+
}
1520+
}
1521+
depends_on = [
1522+
google_network_connectivity_service_connection_policy.default
1523+
]
1524+
transit_encryption_mode = "SERVER_AUTHENTICATION"
1525+
}
1526+
1527+
resource "google_network_connectivity_service_connection_policy" "default" {
1528+
name = "tf-test-my-policy%{random_suffix}"
1529+
location = "us-central1"
1530+
service_class = "gcp-memorystore"
1531+
description = "my basic service connection policy"
1532+
network = google_compute_network.producer_net.id
1533+
psc_config {
1534+
subnetworks = [google_compute_subnetwork.producer_subnet.id]
1535+
}
1536+
}
1537+
1538+
resource "google_compute_subnetwork" "producer_subnet" {
1539+
name = "tf-test-my-subnet%{random_suffix}"
1540+
ip_cidr_range = "10.0.0.248/29"
1541+
region = "us-central1"
1542+
network = google_compute_network.producer_net.id
1543+
}
1544+
1545+
resource "google_compute_network" "producer_net" {
1546+
name = "tf-test-my-network%{random_suffix}"
1547+
auto_create_subnetworks = false
1548+
}
1549+
1550+
data "google_project" "project" {
1551+
}
1552+
`, context)
1553+
}

website/docs/r/memorystore_instance.html.markdown

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,10 @@ In addition to the arguments listed above, the following computed attributes are
834834
The backup collection full resource name.
835835
Example: projects/{project}/locations/{location}/backupCollections/{collection}
836836

837+
* `managed_server_ca` -
838+
Instance's Certificate Authority. This field will only be populated if instance's transit_encryption_mode is SERVER_AUTHENTICATION
839+
Structure is [documented below](#nested_managed_server_ca).
840+
837841
* `terraform_labels` -
838842
The combination of labels configured directly on the resource
839843
and default labels configured on the provider.
@@ -1028,6 +1032,20 @@ In addition to the arguments listed above, the following computed attributes are
10281032
(Output)
10291033
Output only. Ports of the exposed endpoint.
10301034

1035+
<a name="nested_managed_server_ca"></a>The `managed_server_ca` block contains:
1036+
1037+
* `ca_certs` -
1038+
(Output)
1039+
The PEM encoded CA certificate chains for managed server authentication
1040+
Structure is [documented below](#nested_managed_server_ca_ca_certs).
1041+
1042+
1043+
<a name="nested_managed_server_ca_ca_certs"></a>The `ca_certs` block contains:
1044+
1045+
* `certificates` -
1046+
(Output)
1047+
The certificates that form the CA chain, from leaf to root order
1048+
10311049
## Timeouts
10321050

10331051
This resource provides the following

0 commit comments

Comments
 (0)