Skip to content

Commit ad2bec7

Browse files
authored
feat: support cse feature (#120)
Signed-off-by: Sammy Huang <sammy.huang@zilliz.com>
1 parent 778ac1d commit ad2bec7

File tree

8 files changed

+206
-4
lines changed

8 files changed

+206
-4
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ terraform.rc
3535
**/rendered-agent.yaml
3636
**/test-module
3737

38+
39+
.notebook/**

examples/aws-project-byoc-I/README.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,28 @@ The example automatically creates **4 IAM roles** with specific purposes:
240240

241241
---
242242

243-
### 6. ECR Integration
243+
### 6. Encryption
244+
245+
#### Client-Side Encryption (CSE)
246+
- **Enable AWS CSE with automatic KMS key creation**:
247+
```hcl
248+
enable_aws_cse = true
249+
```
250+
- **Purpose**: Enables client-side encryption for Milvus data
251+
- **Behavior**: Automatically creates a new KMS key for CSE operations
252+
- **Output**: `cse_key_arn` - The ARN of the created CSE KMS key
253+
254+
- **Enable AWS CSE with existing KMS key**:
255+
```hcl
256+
enable_aws_cse = true
257+
aws_cse_exiting_key_arn = "arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012"
258+
```
259+
- **Purpose**: Uses your existing KMS key for client-side encryption
260+
- **Note**: The existing key must allow the storage role to use it for encryption/decryption
261+
262+
---
263+
264+
### 7. ECR Integration
244265

245266
#### Default
246267
- **Default ECR Configuration**:
@@ -275,7 +296,7 @@ The example automatically creates **4 IAM roles** with specific purposes:
275296

276297
---
277298

278-
### 7. Resource Tagging
299+
### 8. Resource Tagging
279300

280301
#### Default
281302
- **Default Tags**: Resources are automatically tagged with:
@@ -501,6 +522,7 @@ After successful deployment:
501522
|--------|-------------|
502523
| `data_plane_id` | BYOC project data plane ID |
503524
| `project_id` | BYOC project ID |
525+
| `cse_key_arn` | CSE KMS key ARN (if `enable_aws_cse = true`) |
504526

505527
## Important Notes
506528

examples/aws-project-byoc-I/main.tf

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ module "eks" {
7979
depends_on = [module.private_link]
8080
}
8181

82+
module "kms" {
83+
count = var.enable_aws_cse ? 1 : 0
84+
source = "../../modules/aws_byoc_i/kms"
85+
prefix = local.prefix_name
86+
trust_role_arn = local.storage_role.arn
87+
aws_cse_exiting_key_arn = var.aws_cse_exiting_key_arn
88+
}
89+
8290
resource "zillizcloud_byoc_i_project_agent" "this" {
8391
project_id = local.project_id
8492
data_plane_id = local.data_plane_id
@@ -108,11 +116,16 @@ resource "zillizcloud_byoc_i_project" "this" {
108116
storage = {
109117
bucket_id = local.s3_bucket_id
110118
}
119+
cse = var.enable_aws_cse ? {
120+
default_aws_cse_key_arn = module.kms[0].cse_key_arn
121+
aws_cse_role_arn = module.kms[0].cse_role_arn
122+
external_id = module.kms[0].external_id
123+
} : null
111124
}
112125

113126
// depend on private link to establish agent tunnel connection
114127
depends_on = [zillizcloud_byoc_i_project_agent.this,
115-
module.eks, module.private_link, module.vpc, module.s3]
128+
module.eks, module.private_link, module.vpc, module.s3, module.kms]
116129
lifecycle {
117130
ignore_changes = [data_plane_id, project_id, aws, ext_config]
118131
prevent_destroy = true
@@ -121,6 +134,13 @@ resource "zillizcloud_byoc_i_project" "this" {
121134
ext_config = base64encode(jsonencode(local.ext_config))
122135
}
123136

137+
138+
139+
140+
output "cse_key_arn" {
141+
value = var.enable_aws_cse ? module.kms[0].cse_key_arn : null
142+
}
143+
124144
output "data_plane_id" {
125145
value = local.dataplane_id
126146
}

examples/aws-project-byoc-I/terraform.sample.tfvars

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,9 @@ minimal_roles = {
105105
name = "" # Custom name for node role (optional)
106106
# use_existing_arn = "arn:aws:iam::123456789012:role/your-existing-node-role" # Use existing role by ARN (optional)
107107
}
108-
}
108+
}
109+
110+
# Enable AWS Client-Side Encryption (CSE) for Milvus data
111+
# When enabled without aws_cse_exiting_key_arn, a new KMS key will be created automatically
112+
enable_aws_cse = false
113+
aws_cse_exiting_key_arn = "" # Optional: Use existing KMS key ARN for CSE

examples/aws-project-byoc-I/variables.tf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,15 @@ variable "s3_kms_key_arn" {
210210
type = string
211211
default = ""
212212
}
213+
214+
variable "enable_aws_cse" {
215+
description = "Enable AWS CSE"
216+
type = bool
217+
default = false
218+
}
219+
220+
variable "aws_cse_exiting_key_arn" {
221+
description = "The ARN of the existing KMS key to use for AWS CSE"
222+
type = string
223+
default = ""
224+
}

modules/aws_byoc_i/kms/main.tf

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
data "aws_caller_identity" "current" {}
2+
3+
locals {
4+
create_key = var.aws_cse_exiting_key_arn == ""
5+
cse_key_arn = local.create_key ? aws_kms_key.zilliz_cse[0].arn : var.aws_cse_exiting_key_arn
6+
}
7+
8+
# Multi-Region symmetric KMS key for Zilliz cluster encryption and decryption
9+
resource "aws_kms_key" "zilliz_cse" {
10+
count = local.create_key ? 1 : 0
11+
12+
description = "Multi-Region symmetric KMS key for Zilliz cluster encryption and decryption"
13+
key_usage = "ENCRYPT_DECRYPT"
14+
customer_master_key_spec = "SYMMETRIC_DEFAULT"
15+
multi_region = true
16+
enable_key_rotation = true
17+
18+
tags = {
19+
Vendor = "zilliz-byoc"
20+
}
21+
22+
policy = jsonencode({
23+
Version = "2012-10-17"
24+
Id = "key-default-1"
25+
Statement = [
26+
{
27+
Sid = "Enable IAM User Permissions"
28+
Effect = "Allow"
29+
Principal = {
30+
#
31+
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
32+
}
33+
Action = "kms:*"
34+
Resource = "*"
35+
}
36+
]
37+
})
38+
}
39+
40+
resource "aws_kms_alias" "zilliz_cse" {
41+
count = local.create_key ? 1 : 0
42+
43+
name = "alias/${var.prefix}-zilliz-cse"
44+
target_key_id = aws_kms_key.zilliz_cse[0].key_id
45+
}
46+
47+
# IAM role for Zilliz cse cross-account access
48+
resource "aws_iam_role" "zilliz_cse" {
49+
name = "${var.prefix}-zilliz-cse-role"
50+
51+
tags = {
52+
Vendor = "zilliz-byoc"
53+
}
54+
55+
assume_role_policy = jsonencode({
56+
Version = "2012-10-17"
57+
Statement = [
58+
{
59+
Effect = "Allow"
60+
Principal = {
61+
AWS = var.trust_role_arn
62+
}
63+
Action = "sts:AssumeRole"
64+
Condition = {
65+
StringEquals = {
66+
"sts:ExternalId" = var.prefix
67+
}
68+
}
69+
}
70+
]
71+
})
72+
}
73+
74+
# Inline policy granting KMS encrypt/decrypt/describe on the cse key
75+
resource "aws_iam_role_policy" "zilliz_cse_policy" {
76+
name = "${var.prefix}-zilliz-cse-policy"
77+
role = aws_iam_role.zilliz_cse.id
78+
79+
policy = jsonencode({
80+
Version = "2012-10-17"
81+
Statement = [
82+
{
83+
Effect = "Allow"
84+
Action = [
85+
"kms:Decrypt",
86+
"kms:Encrypt",
87+
"kms:DescribeKey",
88+
"kms:GenerateDataKey",
89+
"kms:GenerateDataKeyWithoutPlaintext"
90+
]
91+
Resource = [
92+
local.cse_key_arn
93+
]
94+
}
95+
]
96+
})
97+
}

modules/aws_byoc_i/kms/output.tf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
output "cse_key_arn" {
2+
description = "ARN of the KMS CMEK key (created or existing)"
3+
value = local.cse_key_arn
4+
}
5+
6+
output "cse_role_arn" {
7+
description = "ARN of the IAM role for cross-account CMEK access"
8+
value = aws_iam_role.zilliz_cse.arn
9+
}
10+
11+
output "external_id" {
12+
description = "External ID for the role"
13+
value = var.prefix
14+
}

modules/aws_byoc_i/kms/variable.tf

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
variable "trust_role_arn" {
2+
description = "The arn of the trust role"
3+
type = string
4+
nullable = false
5+
6+
validation {
7+
condition = can(regex("^arn:aws:iam::[0-9]{12}:role/.+$", var.trust_role_arn))
8+
error_message = "trust_role_arn must be a valid IAM role ARN (e.g. arn:aws:iam::123456789012:role/MyRole)."
9+
}
10+
}
11+
12+
13+
14+
variable "prefix" {
15+
description = "prefix of the resource name"
16+
type = string
17+
nullable = false
18+
19+
validation {
20+
condition = length(var.prefix) > 0
21+
error_message = "prefix must not be empty."
22+
}
23+
}
24+
25+
26+
variable "aws_cse_exiting_key_arn" {
27+
description = "ARN of an existing KMS key to use. When set, no new key is created."
28+
type = string
29+
nullable = true
30+
}

0 commit comments

Comments
 (0)