Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ module "plane_infra" {
enable_aws_lb_controller = true # to use aws ALB
cluster_version = "1.34"

# Optional: create the OpenSearch ↔ Bedrock connector/model integration
create_opensearch_bedrock_connector = true
# bedrock_model_region = "us-east-1" # defaults to `region`
# bedrock_model = "amazon.titan-embed-text-v1" # default
# bedrock_model_name = "plane-eks-cluster-bedrock" # defaults to "${cluster_name}-bedrock"

tags = {
Environment = "plane"
}
Expand All @@ -48,6 +54,80 @@ module "plane_infra" {

Override defaults by passing `eks`, `cache`, `mq`, `opensearch`, `object_store`, or `db` objects. See [terraform/README.md](terraform/README.md) for all options.

### OpenSearch ↔ Bedrock connector integration (optional)

The connector is deployed via a CloudFormation stack and registers a Bedrock embedding model in OpenSearch ML Commons. Because the IAM role used by the connector Lambda must be mapped inside OpenSearch **before** the connector is registered, the setup requires two `terraform apply` passes.

#### Step 1 — Deploy infrastructure without the connector

Set `create_opensearch_bedrock_connector = false` (or omit the flag) on the first apply. This provisions the OpenSearch domain and all other infrastructure, but skips the connector CloudFormation stack.

```hcl
module "plane_infra" {
# ...
create_opensearch_bedrock_connector = false
}
```

```bash
terraform apply
```

#### Step 2 — Map the IAM role inside OpenSearch

The connector Lambda runs under an IAM role (`LambdaInvokeOpenSearchMLCommonsRole` by default). You must map this role to the OpenSearch `ml_full_access` and `all_access` built-in roles before registering the connector, otherwise the registration will fail.

Verify the cluster is reachable:

```bash
curl -u 'admin:<admin-password>' https://<opensearch-endpoint>
```

Map to `ml_full_access`:

```bash
curl -X PUT \
'https://<opensearch-endpoint>/_plugins/_security/api/rolesmapping/ml_full_access' \
-H 'Content-Type: application/json' \
-u 'admin:<admin-password>' \
-d '{
"backend_roles": [
"arn:aws:iam::<account-id>:role/LambdaInvokeOpenSearchMLCommonsRole"
]
}'
# {"status":"CREATED","message":"'ml_full_access' created."}
```

Map to `all_access` (required for model registration):

```bash
curl -X PUT \
'https://<opensearch-endpoint>/_plugins/_security/api/rolesmapping/all_access' \
-H 'Content-Type: application/json' \
-u 'admin:<admin-password>' \
-d '{
"backend_roles": [
"arn:aws:iam::<account-id>:role/LambdaInvokeOpenSearchMLCommonsRole"
]
}'
# {"status":"OK","message":"'all_access' updated."}
```

#### Step 3 — Deploy the connector

Set `create_opensearch_bedrock_connector = true` and apply again. Terraform will deploy the CloudFormation stack, which invokes the Lambda to register the Bedrock connector and model in OpenSearch ML Commons.

```hcl
module "plane_infra" {
# ...
create_opensearch_bedrock_connector = true
}
```

```bash
terraform apply
```

### Outputs

Add these output blocks to your configuration to expose module outputs (e.g. in `main.tf` or `outputs.tf`):
Expand Down
33 changes: 32 additions & 1 deletion terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,23 @@ locals {
private_subnet_cidrs = [
for i in range(local.subnet_count) : cidrsubnet(var.vpc_cidr, 6, local.subnet_count + i)
]

bedrock_allowed_regions = toset(["us-east-1", "us-west-2", "eu-central-1", "ap-northeast-1", "ap-southeast-1"])

effective_bedrock_model_region = coalesce(
var.bedrock_model_region,
contains(local.bedrock_allowed_regions, var.region) ? var.region : "us-east-1"
)

opensearch_bedrock_effective = var.opensearch_bedrock != null ? var.opensearch_bedrock : {
create_connector = var.create_opensearch_bedrock_connector
bedrock_model_region = local.effective_bedrock_model_region
bedrock_model = coalesce(var.bedrock_model, "amazon.titan-embed-text-v1")
bedrock_model_name = coalesce(var.bedrock_model_name, "${var.cluster_name}-bedrock")
add_process_function = var.add_process_function
add_offline_batch_inference = var.add_offline_batch_inference
lambda_invoke_mlcommons_role_name = var.lambda_invoke_mlcommons_role_name
}
}

module "vpc" {
Expand Down Expand Up @@ -144,7 +161,21 @@ module "opensearch" {
instance_type = var.opensearch.instance_type
instance_count = var.opensearch.instance_count
ebs_volume_size = var.opensearch.ebs_volume_size
tags = var.tags

enable_vpc = true
vpc_id = module.vpc.vpc_id
subnet_ids = [module.vpc.private_subnet_ids[0]]

allowed_ingress_security_group_ids = [module.eks.node_security_group_id]

create_connector = local.opensearch_bedrock_effective.create_connector
bedrock_model_region = local.opensearch_bedrock_effective.bedrock_model_region
bedrock_model = local.opensearch_bedrock_effective.bedrock_model
bedrock_model_name = local.opensearch_bedrock_effective.bedrock_model_name
add_process_function = local.opensearch_bedrock_effective.add_process_function
add_offline_batch_inference = local.opensearch_bedrock_effective.add_offline_batch_inference
lambda_invoke_opensearch_mlcommons_role_name = local.opensearch_bedrock_effective.lambda_invoke_mlcommons_role_name
tags = var.tags

depends_on = [aws_secretsmanager_secret_version.plane_password]
}
Expand Down
Loading