Skip to main content

OpenSearch Local Access

Access the OpenSearch cluster from your local machine using SSM port forwarding through a bastion host.

Why This Exists

OpenSearch runs in a private VPC subnet with no public access. To connect locally for development:

  1. Launch on-demand bastion via Slack bot
  2. Port forward through bastion using SSM Session Manager
  3. Access OpenSearch at https://localhost:9200

Cost: ~$0.001 per 3-hour session (bastion auto-terminates)

Prerequisites

  • AWS CLI installed and configured
  • Session Manager plugin installed (AWS docs)
  • AWS profile configured: docustack-dev-admin
  • Access to DocuStack Slack workspace

Quick Start

1. Create Bastion Host

In Slack, run:

/infra bastion create

Wait ~2 minutes for confirmation. The bastion will auto-terminate after 3 hours.

2. Start Port Forwarding

Save this script as opensearch-tunnel.sh:

#!/bin/bash
# opensearch-tunnel.sh - Port forward to OpenSearch via bastion

export AWS_PROFILE=docustack-dev-admin
export AWS_REGION=us-east-1

echo "🔍 Finding bastion instance..."

# Get bastion instance ID
BASTION_INSTANCE_ID=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=*bastion*" "Name=instance-state-name,Values=running" \
--query 'Reservations[0].Instances[0].InstanceId' \
--output text \
--region $AWS_REGION)

if [ -z "$BASTION_INSTANCE_ID" ] || [ "$BASTION_INSTANCE_ID" = "None" ]; then
echo "❌ Bastion not found or not running"
echo " Run: /infra bastion create"
exit 1
fi

echo "✅ Bastion Instance: $BASTION_INSTANCE_ID"
echo "🔐 Starting port forwarding..."
echo ""
echo "📍 OpenSearch Cluster: https://localhost:9200"
echo "📊 OpenSearch Dashboards: https://localhost:9200/_dashboards"
echo ""
echo "🔑 Get credentials:"
echo " aws ssm get-parameter --name /docustack/dev/opensearch/master-password --with-decryption --region us-east-1 --query 'Parameter.Value' --output text"
echo ""
echo "⏰ Bastion auto-terminates in 3 hours"
echo "Press Ctrl+C to stop port forwarding"
echo ""

aws ssm start-session \
--target $BASTION_INSTANCE_ID \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{"host":["vpc-docustack-dev-search-l72zsvwumer5mdquvl3uqwckam.us-east-1.es.amazonaws.com"],"portNumber":["443"],"localPortNumber":["9200"]}' \
--region $AWS_REGION

Make it executable and run:

chmod +x opensearch-tunnel.sh
./opensearch-tunnel.sh

3. Get Credentials

In another terminal:

export AWS_PROFILE=docustack-dev-admin
export AWS_REGION=us-east-1

PASSWORD=$(aws ssm get-parameter \
--name /docustack/dev/opensearch/master-password \
--with-decryption \
--query 'Parameter.Value' \
--output text \
--region $AWS_REGION)

echo "Username: admin"
echo "Password: $PASSWORD"

4. Test Connection

# Check cluster health
curl -k -u admin:$PASSWORD https://localhost:9200/_cluster/health | jq

# Expected output:
# {
# "cluster_name": "vpc-docustack-dev-search",
# "status": "green",
# "number_of_nodes": 1,
# ...
# }

5. Access OpenSearch Dashboards

Open in browser:

https://localhost:9200/_dashboards

Accept the security warning (SSL certificate is for VPC endpoint, not localhost)

Login with:

  • Username: admin
  • Password: (from step 3)

Common Tasks

Search Documents

# List all indices
curl -k -u admin:$PASSWORD https://localhost:9200/_cat/indices?v

# Search an index
curl -k -u admin:$PASSWORD https://localhost:9200/my-index/_search | jq

Create Index

curl -k -u admin:$PASSWORD -X PUT https://localhost:9200/my-index \
-H 'Content-Type: application/json' \
-d '{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
}
}'

Index a Document

curl -k -u admin:$PASSWORD -X POST https://localhost:9200/my-index/_doc \
-H 'Content-Type: application/json' \
-d '{
"title": "Test Document",
"content": "This is a test"
}'

Troubleshooting

Error: "Bastion not found or not running"

Cause: Bastion hasn't been created or has already terminated.

Solution:

# Create bastion via Slack
/infra bastion create

# Wait ~2 minutes, then retry

Error: "Parameter not found"

Cause: Missing --region us-east-1 flag.

Solution: Always specify region:

aws ssm get-parameter \
--name /docustack/dev/opensearch/master-password \
--with-decryption \
--region us-east-1 \
--query 'Parameter.Value' \
--output text

Error: "Connection refused" or "Port forwarding failed"

Cause: Bastion instance not ready or wrong endpoint.

Solution:

  1. Verify bastion is running:
    aws ec2 describe-instances \
    --filters "Name=tag:Name,Values=*bastion*" "Name=instance-state-name,Values=running" \
    --region us-east-1
  2. Wait 30 seconds after bastion creation for SSM agent to start
  3. Verify OpenSearch endpoint in script matches current deployment

Browser Security Warning

Cause: SSL certificate is for vpc-docustack-dev-search-*.es.amazonaws.com, not localhost.

Solution: This is expected. Click "Advanced" → "Proceed to localhost" (safe for local development).

Error: "Unauthorized" or 403

Cause: Incorrect credentials or expired password.

Solution:

  1. Verify password from SSM:
    aws ssm get-parameter \
    --name /docustack/dev/opensearch/master-password \
    --with-decryption \
    --region us-east-1
  2. Check username is admin (not Administrator or other)

Bastion Auto-Terminated

Cause: Bastion instances auto-terminate after 3 hours.

Solution:

  • Extend lifetime: In Slack, run /infra bastion extend (adds 2 hours)
  • Create new bastion: Run /infra bastion create again

Security Notes

  • No SSH keys: Uses SSM Session Manager with IAM authentication
  • No public access: OpenSearch is in private subnet only
  • Encrypted: All traffic encrypted (TLS 1.2+)
  • Audit trail: All SSM sessions logged to CloudWatch
  • Auto-termination: Bastion terminates after 3 hours to prevent forgotten instances

Environment Variables

For convenience, add to your shell profile:

# ~/.zshrc or ~/.bashrc
export AWS_PROFILE=docustack-dev-admin
export AWS_REGION=us-east-1

Cost

ResourceCost
OpenSearch domain (t3.small.search)$31/month
Bastion instance (t4g.nano, 3 hours)~$0.001/session
SSM Session ManagerFree

Total: ~$31/month + negligible bastion costs