In this tutorial you will use Terraform to provision an Amazon OpenSearch domain, create an OpenSearch UI Application, and automatically set up a sample dashboard — all from a single terraform apply command.
Deploy OpenSearch UI with Terraform
By the end you will have a working OpenSearch UI Application with a pre-built dashboard you can open in your browser.
Prerequisites
Before you start, make sure you have:
- Terraform >= 1.5 installed — Install Terraform
- AWS CLI v2 configured with credentials — Install AWS CLI
- An AWS account with permissions to create OpenSearch, Lambda, and IAM resources
- Basic familiarity with the terminal (you don't need prior Terraform experience)
Architecture Overview
The Terraform configuration creates the following resources:
OpenSearch Domain
└──▶ OpenSearch UI Application (managed dashboards)
└──▶ IAM Role + Policy
└──▶ Lambda Function (dashboard automation)
└──▶ Lambda Invocation (runs automatically after deploy)Optionally, you can also enable:
- VPC access — restricts the application to a private network
- IAM Identity Center — enables SSO authentication
Here is what each piece does:
| Resource | What it does |
|---|---|
| OpenSearch Domain | Managed search and analytics engine that stores your data |
| OpenSearch UI Application | Provides a hosted dashboards experience on top of the domain |
| IAM Role | Grants the Lambda function permission to call OpenSearch APIs |
| Lambda Function | Creates a workspace, ingests sample data, and builds a dashboard |
| Lambda Invocation | Triggers the Lambda automatically after everything is provisioned |
Clone the Sample Repo
The full Terraform code lives in the companion repository. Clone it and navigate to the terraform/ directory:
git clone https://github.com/aws-samples/sample-automate-opensearch-ui-dashboards-deployment.git
cd sample-automate-opensearch-ui-dashboards-deployment/terraformThe directory structure looks like this:
terraform/
├── main.tf # Core resources (domain, app, IAM, Lambda)
├── variables.tf # Input variables with defaults
├── outputs.tf # Values printed after deployment
├── vpc.tf # Optional VPC resources
├── idc.tf # Optional IDC resources
├── terraform.tfvars.example # Sample variable values
├── README.md # Reference documentation
└── lambda/
├── index.py # Python handler for dashboard setup
└── dashboards/
└── sample.ndjson # Sample dashboard definitionConfigure Variables
Copy the example variables file:
cp terraform.tfvars.example terraform.tfvarsOpen terraform.tfvars in your editor. The defaults work out of the box, but you can customize them:
# AWS region for all resources
region = "us-east-1"
# OpenSearch domain settings
domain_name = "opensearch-ui-demo"
engine_version = "OpenSearch_2.17"
instance_type = "r6g.large.search"
instance_count = 1
ebs_volume_size = 100
# OpenSearch UI Application name
app_name = "opensearch-ui-app"All 12 variables have sensible defaults, so you can skip this step entirely if you just want to try it out.
Deploy
Deployment is a three-step process: init, plan, apply.
Step 1 — Initialize Terraform
terraform initThis downloads the required providers (AWS, AWSCC, Archive, Null) and sets up the working directory. You should see Terraform has been successfully initialized! at the end.
Step 2 — Preview the plan
terraform planTerraform shows you every resource it will create — without actually creating anything. Review the output to confirm it looks right. You should see resources like aws_opensearch_domain.this, awscc_opensearch_application.this, and aws_lambda_function.dashboard_automation.
Step 3 — Apply
terraform applyTerraform asks you to confirm. Type yes and press Enter.
Now sit back — the OpenSearch domain takes about 15–20 minutes to create. After the domain is ready, Terraform creates the UI Application, deploys the Lambda function, and invokes it to set up your sample dashboard.
Here is a simplified look at the key resources Terraform creates. (See the full code in the companion repo .)
OpenSearch Domain — the data engine:
resource "aws_opensearch_domain" "this" {
domain_name = var.domain_name
engine_version = var.engine_version
cluster_config {
instance_type = var.instance_type
instance_count = var.instance_count
}
ebs_options {
ebs_enabled = true
volume_size = var.ebs_volume_size
volume_type = "gp3"
}
encrypt_at_rest { enabled = true }
node_to_node_encryption { enabled = true }
}This creates a single-node OpenSearch cluster with encryption enabled. The var.* references pull values from your terraform.tfvars file.
OpenSearch UI Application — the dashboards layer:
resource "awscc_opensearch_application" "this" {
name = var.app_name
data_sources = [{
data_source_arn = aws_opensearch_domain.this.arn
data_source_description = "Primary OpenSearch Domain"
}]
app_configs = [
{ key = "opensearchDashboards.dashboardAdmin.users", value = "[\"*\"]" },
{ key = "opensearchDashboards.dashboardAdmin.groups", value = "[\"${aws_iam_role.lambda_role.arn}\"]" },
]
}Notice the awscc_ prefix — this resource comes from the AWS Cloud Control provider because the standard AWS provider does not yet have an aws_opensearch_application resource. The data_sources block connects the application to the domain you just created.
Lambda Function — automates dashboard setup:
resource "aws_lambda_function" "dashboard_automation" {
function_name = "${var.domain_name}-dashboard-automation"
role = aws_iam_role.lambda_role.arn
handler = "index.handler"
runtime = "python3.11"
timeout = 300
filename = data.archive_file.lambda_zip.output_path
source_code_hash = data.archive_file.lambda_zip.output_base64sha256
environment {
variables = {
APP_ENDPOINT = "application-${var.app_name}-..."
DOMAIN_ENDPOINT = aws_opensearch_domain.this.endpoint
}
}
}Terraform packages the lambda/ directory into a zip and deploys it. The Lambda reads the application endpoint from its environment variables and uses SigV4-signed requests to create a workspace, ingest sample data, and build a dashboard.
Post-deploy trigger — runs the Lambda automatically:
resource "aws_lambda_invocation" "setup_dashboards" {
function_name = aws_lambda_function.dashboard_automation.function_name
input = jsonencode({ action = "setup_dashboards" })
depends_on = [
awscc_opensearch_application.this,
aws_lambda_function.dashboard_automation,
]
}The depends_on block ensures the Lambda only runs after both the application and the function are fully provisioned.
Verify Deployment
After terraform apply completes, you should see output like this:
Apply complete! Resources: 7 added, 0 changed, 0 destroyed.
Outputs:
app_endpoint = "application-opensearch-ui-app-abc123.us-east-1.opensearch.amazonaws.com"
app_id = "abc123"
domain_arn = "arn:aws:es:us-east-1:123456789012:domain/opensearch-ui-demo"
domain_endpoint = "search-opensearch-ui-demo-xyz.us-east-1.es.amazonaws.com"To verify everything worked:
-
Check the outputs — Run
terraform outputto see the endpoints again at any time. -
Open the application — Copy the
app_endpointvalue and open it in your browser:https://<app_endpoint>/_dashboardsYou should see the OpenSearch Dashboards welcome page.
-
Find the sample dashboard — Navigate to the "Sample Workspace" in the workspace selector. You should see the "Application Metrics" dashboard with an HTTP Status Code Distribution pie chart.
-
Verify in the AWS Console — Go to the OpenSearch Service console in your region. You should see both the domain and the UI Application listed.
Optional: VPC Access
To restrict the application to a private VPC, add these variables to your terraform.tfvars:
enable_vpc = true
vpc_id = "vpc-0123456789abcdef0"
subnet_ids = ["subnet-aaa", "subnet-bbb"]Then run terraform apply again. This creates:
- A security group allowing HTTPS (port 443) from the VPC CIDR
- VPC configuration on the Lambda function
- VPC endpoint authorization for the OpenSearch UI Application
Note: VPC endpoint authorization uses aws opensearch authorize-vpc-endpoint-access via the AWS CLI. Make sure the AWS CLI is installed on the machine running Terraform.
Optional: IDC Integration
To enable IAM Identity Center (SSO) for the application, add:
enable_idc = true
idc_instance_arn = "arn:aws:sso:::instance/ssoins-0123456789abcdef0"Then run terraform apply. This creates an IAM role trusted by the OpenSearch service and configures the UI Application to use your Identity Center instance for authentication.
Cleanup
When you are done, destroy all resources to stop incurring charges:
terraform destroyType yes when prompted. This removes the OpenSearch domain, UI Application, Lambda function, IAM roles, and all optional resources. The domain deletion takes a few minutes.
Cost note: The default r6g.large.search instance runs continuously and is the primary cost driver. Always run terraform destroy when you are finished experimenting.
Next Steps
- Browse the full source code: aws-samples/sample-automate-opensearch-ui-dashboards-deployment
- Customize the dashboard by editing
lambda/dashboards/sample.ndjson - Add more data sources or workspaces by extending
main.tf - Explore the OpenSearch UI documentation for console-based setup