Skip to content

Commit 81a1c95

Browse files
Add CMEK to vertexai IndexEndpoint (#15214) (#10787)
[upstream:464f2796fb780a74235c6904d20f16c08316dd2d] Signed-off-by: Modular Magician <[email protected]>
1 parent 105af30 commit 81a1c95

File tree

5 files changed

+103
-0
lines changed

5 files changed

+103
-0
lines changed

.changelog/15214.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
vertexai: added `kmsKeyName` field to `google_vertex_ai_index_endpoint ` resource
3+
```

google-beta/services/vertexai/resource_vertex_ai_index_endpoint.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,23 @@ func ResourceVertexAIIndexEndpoint() *schema.Resource {
6767
Optional: true,
6868
Description: `The description of the Index.`,
6969
},
70+
"encryption_spec": {
71+
Type: schema.TypeList,
72+
Optional: true,
73+
ForceNew: true,
74+
Description: `Customer-managed encryption key spec for an IndexEndpoint. If set, this IndexEndpoint and all sub-resources of this IndexEndpoint will be secured by this key.`,
75+
MaxItems: 1,
76+
Elem: &schema.Resource{
77+
Schema: map[string]*schema.Schema{
78+
"kms_key_name": {
79+
Type: schema.TypeString,
80+
Required: true,
81+
ForceNew: true,
82+
Description: `Required. The Cloud KMS resource identifier of the customer managed encryption key used to protect a resource. Has the form: 'projects/my-project/locations/my-region/keyRings/my-kr/cryptoKeys/my-key'. The key needs to be in the same region as where the compute resource is created.`,
83+
},
84+
},
85+
},
86+
},
7087
"labels": {
7188
Type: schema.TypeMap,
7289
Optional: true,
@@ -213,6 +230,12 @@ func resourceVertexAIIndexEndpointCreate(d *schema.ResourceData, meta interface{
213230
} else if v, ok := d.GetOkExists("public_endpoint_enabled"); !tpgresource.IsEmptyValue(reflect.ValueOf(publicEndpointEnabledProp)) && (ok || !reflect.DeepEqual(v, publicEndpointEnabledProp)) {
214231
obj["publicEndpointEnabled"] = publicEndpointEnabledProp
215232
}
233+
encryptionSpecProp, err := expandVertexAIIndexEndpointEncryptionSpec(d.Get("encryption_spec"), d, config)
234+
if err != nil {
235+
return err
236+
} else if v, ok := d.GetOkExists("encryption_spec"); !tpgresource.IsEmptyValue(reflect.ValueOf(encryptionSpecProp)) && (ok || !reflect.DeepEqual(v, encryptionSpecProp)) {
237+
obj["encryptionSpec"] = encryptionSpecProp
238+
}
216239
effectiveLabelsProp, err := expandVertexAIIndexEndpointEffectiveLabels(d.Get("effective_labels"), d, config)
217240
if err != nil {
218241
return err
@@ -359,6 +382,9 @@ func resourceVertexAIIndexEndpointRead(d *schema.ResourceData, meta interface{})
359382
if err := d.Set("public_endpoint_domain_name", flattenVertexAIIndexEndpointPublicEndpointDomainName(res["publicEndpointDomainName"], d, config)); err != nil {
360383
return fmt.Errorf("Error reading IndexEndpoint: %s", err)
361384
}
385+
if err := d.Set("encryption_spec", flattenVertexAIIndexEndpointEncryptionSpec(res["encryptionSpec"], d, config)); err != nil {
386+
return fmt.Errorf("Error reading IndexEndpoint: %s", err)
387+
}
362388
if err := d.Set("terraform_labels", flattenVertexAIIndexEndpointTerraformLabels(res["labels"], d, config)); err != nil {
363389
return fmt.Errorf("Error reading IndexEndpoint: %s", err)
364390
}
@@ -612,6 +638,23 @@ func flattenVertexAIIndexEndpointPublicEndpointDomainName(v interface{}, d *sche
612638
return v
613639
}
614640

641+
func flattenVertexAIIndexEndpointEncryptionSpec(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
642+
if v == nil {
643+
return nil
644+
}
645+
original := v.(map[string]interface{})
646+
if len(original) == 0 {
647+
return nil
648+
}
649+
transformed := make(map[string]interface{})
650+
transformed["kms_key_name"] =
651+
flattenVertexAIIndexEndpointEncryptionSpecKmsKeyName(original["kmsKeyName"], d, config)
652+
return []interface{}{transformed}
653+
}
654+
func flattenVertexAIIndexEndpointEncryptionSpecKmsKeyName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
655+
return v
656+
}
657+
615658
func flattenVertexAIIndexEndpointTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
616659
if v == nil {
617660
return v
@@ -684,6 +727,32 @@ func expandVertexAIIndexEndpointPublicEndpointEnabled(v interface{}, d tpgresour
684727
return v, nil
685728
}
686729

730+
func expandVertexAIIndexEndpointEncryptionSpec(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
731+
if v == nil {
732+
return nil, nil
733+
}
734+
l := v.([]interface{})
735+
if len(l) == 0 || l[0] == nil {
736+
return nil, nil
737+
}
738+
raw := l[0]
739+
original := raw.(map[string]interface{})
740+
transformed := make(map[string]interface{})
741+
742+
transformedKmsKeyName, err := expandVertexAIIndexEndpointEncryptionSpecKmsKeyName(original["kms_key_name"], d, config)
743+
if err != nil {
744+
return nil, err
745+
} else if val := reflect.ValueOf(transformedKmsKeyName); val.IsValid() && !tpgresource.IsEmptyValue(val) {
746+
transformed["kmsKeyName"] = transformedKmsKeyName
747+
}
748+
749+
return transformed, nil
750+
}
751+
752+
func expandVertexAIIndexEndpointEncryptionSpecKmsKeyName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
753+
return v, nil
754+
}
755+
687756
func expandVertexAIIndexEndpointEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
688757
if v == nil {
689758
return map[string]string{}, nil

google-beta/services/vertexai/resource_vertex_ai_index_endpoint_generated_meta.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ fields:
1010
- field: 'display_name'
1111
- field: 'effective_labels'
1212
provider_only: true
13+
- field: 'encryption_spec.kms_key_name'
1314
- field: 'etag'
1415
- field: 'labels'
1516
- field: 'name'

google-beta/services/vertexai/resource_vertex_ai_index_endpoint_generated_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ func TestAccVertexAIIndexEndpoint_vertexAiIndexEndpointTestExample(t *testing.T)
3434
t.Parallel()
3535

3636
context := map[string]interface{}{
37+
"kms_key_name": acctest.BootstrapKMSKeyInLocation(t, "us-central1").CryptoKey.Name,
3738
"network_name": acctest.BootstrapSharedServiceNetworkingConnection(t, "vpc-network-1"),
3839
"random_suffix": acctest.RandString(t, 10),
3940
}
@@ -58,6 +59,16 @@ func TestAccVertexAIIndexEndpoint_vertexAiIndexEndpointTestExample(t *testing.T)
5859

5960
func testAccVertexAIIndexEndpoint_vertexAiIndexEndpointTestExample(context map[string]interface{}) string {
6061
return acctest.Nprintf(`
62+
resource "google_project_service_identity" "vertexai_sa" {
63+
service = "aiplatform.googleapis.com"
64+
}
65+
66+
resource "google_kms_crypto_key_iam_member" "vertexai_encrypterdecrypter" {
67+
crypto_key_id = "%{kms_key_name}"
68+
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
69+
member = google_project_service_identity.vertexai_sa.member
70+
}
71+
6172
resource "google_vertex_ai_index_endpoint" "index_endpoint" {
6273
display_name = "sample-endpoint"
6374
description = "A sample vertex endpoint"
@@ -66,6 +77,14 @@ resource "google_vertex_ai_index_endpoint" "index_endpoint" {
6677
label-one = "value-one"
6778
}
6879
network = "projects/${data.google_project.project.number}/global/networks/${data.google_compute_network.vertex_network.name}"
80+
81+
encryption_spec {
82+
kms_key_name = "%{kms_key_name}"
83+
}
84+
85+
depends_on = [
86+
google_kms_crypto_key_iam_member.vertexai_encrypterdecrypter,
87+
]
6988
}
7089
7190
data "google_compute_network" "vertex_network" {

website/docs/r/vertex_ai_index_endpoint.html.markdown

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ The following arguments are supported:
149149
(Optional)
150150
If true, the deployed index will be accessible through public endpoint.
151151

152+
* `encryption_spec` -
153+
(Optional)
154+
Customer-managed encryption key spec for an IndexEndpoint. If set, this IndexEndpoint and all sub-resources of this IndexEndpoint will be secured by this key.
155+
Structure is [documented below](#nested_encryption_spec).
156+
152157
* `region` -
153158
(Optional)
154159
The region of the index endpoint. eg us-central1
@@ -168,6 +173,12 @@ The following arguments are supported:
168173
(Optional)
169174
A list of Projects from which the forwarding rule will target the service attachment.
170175

176+
<a name="nested_encryption_spec"></a>The `encryption_spec` block supports:
177+
178+
* `kms_key_name` -
179+
(Required)
180+
Required. The Cloud KMS resource identifier of the customer managed encryption key used to protect a resource. Has the form: `projects/my-project/locations/my-region/keyRings/my-kr/cryptoKeys/my-key`. The key needs to be in the same region as where the compute resource is created.
181+
171182
## Attributes Reference
172183

173184
In addition to the arguments listed above, the following computed attributes are exported:

0 commit comments

Comments
 (0)