Satellite on AWS ECS
Prerequisitesβ
Before installing the Levo Satellite on AWS ECS, ensure you have:
- Access to AWS ECS
- AWS credentials configured (
aws configurewith Access Key ID and Secret Access Key) - Levo Authorization Token (refer to Generating CLI Authorization Keys)
- Organization ID (refer to Accessing Organization IDs)
- IAM Role (choose one):
- Option 1: Use the
--create-iam-roleflag in the CLI script to auto-create the role with required permissions - Option 2: Manually create an AWS IAM Role with the following permissions:
- SQS Actions (for queue creation and management):
sqs:CreateQueueβ Create queues on startupsqs:SendMessageβ Write messages to queuessqs:ReceiveMessageβ Read messages from queuessqs:DeleteMessageβ Remove processed messagessqs:GetQueueAttributesβ Get queue metadatasqs:GetQueueUrlβ Resolve queue URLssqs:ChangeMessageVisibilityβ Update message visibility timeoutsqs:SetQueueAttributesβ Configure queue settingssqs:TagQueueβ Add tags to queues
- SQS Resource Pattern:
arn:aws:sqs:${REGION}:${ACCOUNT}:*-levoai_* - CloudWatch Logs Actions (for container logging):
logs:CreateLogGroupβ Create log grouplogs:CreateLogStreamβ Create log streamlogs:PutLogEventsβ Write logs
- ECR Actions (for pulling Docker images):
ecr:GetAuthorizationTokenβ Authenticate with ECRecr:BatchCheckLayerAvailabilityβ Check image layersecr:GetDownloadUrlForLayerβ Get layer download URLsecr:BatchGetImageβ Pull Docker images
- SQS Actions (for queue creation and management):
- Option 1: Use the
- A VPC with at least one subnet and a security group allowing inbound TCP on port 8080
- For Terraform: Terraform CLI installed
- For CLI: AWS CLI v2 installed
Quick Start (CLI)β
Download the installation script:
curl -O https://docs.levo.ai/artifacts/satellite/install-satellite.sh
chmod +x install-satellite.sh
Then proceed to installation methods below.
Network Configuration (CLI Only)β
The Satellite requires a VPC, subnet, and security group. Choose the scenario that matches your setup:
Scenario 1: You Have VPC, Subnet, and Security Groupβ
If you already have these resources configured, use them directly:
./install-satellite.sh \
--region us-east-1 \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--subnets subnet-abc123 \
--security-groups sg-xyz789 \
--create-iam-role \
--assign-public-ip
Requirements:
- Security Group: Must allow inbound TCP on port 8080 from your sensor network (or
0.0.0.0/0for testing) - Subnet: Any subnet with available IP addresses (private subnets recommended)
You can specify multiple subnets (comma-separated) for high availability: --subnets subnet-abc123,subnet-def456
Scenario 2: You Have VPC, But Don't Know Which Subnet/Security Group to Useβ
Discover available resources in your VPC:
# Step 1: List all subnets and security groups
./install-satellite.sh \
--list \
--vpc-id vpc-abc123 \
--region us-east-1
This shows:
- All subnets with CIDR, availability zone, type (public/private), and available IPs
- All security groups with port 8080 status (β = open, β = closed)
# Step 2: Use the discovered IDs
./install-satellite.sh \
--region us-east-1 \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--subnets subnet-abc123 \
--security-groups sg-xyz789 \
--create-iam-role \
--assign-public-ip
Choose a security group with β next to it (port 8080 already open). If none exist, use Scenario 3 to create one.
Scenario 3: You Have VPC, But Need to Create Subnet and/or Security Groupβ
Create both subnet and security group:
./install-satellite.sh \
--region us-east-1 \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--vpc-id vpc-abc123 \
--create-subnet \
--create-security-group \
--sensor-cidr 10.0.0.0/16 \
--create-iam-role \
--assign-public-ip
Create only subnet (you have a security group):
./install-satellite.sh \
--region us-east-1 \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--vpc-id vpc-abc123 \
--create-subnet \
--security-groups sg-xyz789 \
--create-iam-role \
--assign-public-ip
Create only security group (you have a subnet):
./install-satellite.sh \
--region us-east-1 \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--vpc-id vpc-abc123 \
--create-security-group \
--sensor-cidr 10.0.0.0/16 \
--subnets subnet-abc123 \
--create-iam-role \
--assign-public-ip
Customize auto-created resources:
./install-satellite.sh \
--region us-east-1 \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--vpc-id vpc-abc123 \
--create-subnet \
--subnet-cidr 10.1.20.0/24 \
--subnet-az us-east-1a \
--create-security-group \
--sensor-cidr 10.0.0.0/16 \
--create-iam-role \
--assign-public-ip
| Customization Flag | Default | Description |
|---|---|---|
--subnet-cidr | 10.0.10.0/24 | CIDR block for new subnet |
--subnet-az | (first AZ in region) | Availability zone for subnet |
--sensor-cidr | (required with --create-security-group) | CIDR allowed inbound on ports 8080 and 4317 |
--sensor-cidr controls WHO can access your Satellite on ports 8080 and 4317.
# Use your VPC CIDR
--sensor-cidr 172.31.0.0/16
# Or your private network range
--sensor-cidr 10.0.0.0/8
# β οΈ Testing only - EXPOSES TO PUBLIC INTERNET
--sensor-cidr 0.0.0.0/0
This flag is REQUIRED when using --create-security-group
Scenario 4: You Don't Have a VPCβ
If you don't have a VPC, create one first using AWS Console or CLI:
Using AWS Console:
- Go to VPC Console
- Click Create VPC
- Choose VPC and more (creates VPC with subnets automatically)
- Note the VPC ID and subnet IDs
- Use Scenario 1 or 2 above
Using AWS CLI:
# Create VPC
aws ec2 create-vpc --cidr-block 10.0.0.0/16 --region us-east-1
# Note the VPC ID from output, then use Scenario 3 to create subnet and security group
Run any command with --dry-run flag first to preview what will be created without making actual changes.
1. Create a Task Definitionβ
- AWS Console
- Terraform
- CLI (One-Click)
-
Open the AWS ECS console and navigate to Task Definitions
-
Click Create New Task Definition in the top right, then select Create New Task Definition with JSON
NOTE: Ensure you are in the correct AWS region where you want to deploy your service
- Use the following task definition:
{
"family": "levoai-satellite",
"containerDefinitions": [
{
"name": "levoai-satellite",
"image": "levoai/satellite:stable",
"cpu": 0,
"portMappings": [
{
"name": "levoai-satellite-9999-tcp",
"containerPort": 9999,
"hostPort": 9999,
"protocol": "tcp",
"appProtocol": "http"
}
],
"essential": true,
"command": [
"-w",
"1",
"-b",
"0.0.0.0:9999",
"--worker-class",
"uvicorn.workers.UvicornWorker",
"--worker-connections",
"30",
"levoai_e7s.satellite.satellite:create_server()"
],
"environment": [
{
"name": "LEVOAI_BASE_URL",
"value": "https://api.levo.ai"
},
{
"name": "LEVOAI_ORG_ID",
"value": "INSERT YOUR ORG ID HERE"
},
{
"name": "LEVOAI_MODE",
"value": "docker-compose"
},
{
"name": "AWS_DEFAULT_REGION",
"value": "INSERT YOUR AWS REGION HERE"
},
{
"name": "LEVOAI_CONF_OVERRIDES",
"value": "{\"onprem-api\": {\"url\": \"${LEVOAI_BASE_URL}\", \"refresh-token\": \"${LEVOAI_AUTH_KEY}\", \"org-id\": \"${LEVOAI_ORG_ID:-}\", \"org-prefix\": \"${LEVOAI_ORG_PREFIX:-}\"},\"traces_queue\": {\"type\": \"sqs\"},\"spans_queue\": {\"type\": \"sqs\"},\"findings_queue\": {\"type\": \"sqs\"},\"mcp_span_queue\": {\"type\": \"sqs\"},\"ai_span_queue\": {\"type\": \"sqs\"}}"
},
{
"name": "LEVOAI_DEBUG_ENABLED",
"value": "false"
},
{
"name": "LEVOAI_AUTH_KEY",
"value": "INSERT YOUR LEVO.AI AUTH KEY HERE"
},
{
"name": "LEVOAI_LOG_LEVEL",
"value": "INFO"
}
],
"mountPoints": [],
"volumesFrom": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/levoai-satellite",
"awslogs-create-group": "true",
"awslogs-region": "INSERT YOUR AWS REGION HERE",
"awslogs-stream-prefix": "ecs"
}
},
"systemControls": []
},
{
"name": "levoai-tagger",
"image": "levoai/satellite:stable",
"cpu": 0,
"portMappings": [],
"essential": true,
"entryPoint": [
"python",
"-OO"
],
"command": [
"/opt/levoai/e7s/src/python/levoai_e7s/tag_server.py"
],
"environment": [
{
"name": "LEVOAI_BASE_URL",
"value": "https://api.levo.ai"
},
{
"name": "LEVOAI_ORG_ID",
"value": "INSERT YOUR ORG ID HERE"
},
{
"name": "LEVOAI_MODE",
"value": "docker-compose"
},
{
"name": "AWS_DEFAULT_REGION",
"value": "INSERT YOUR AWS REGION HERE"
},
{
"name": "LEVOAI_CONF_OVERRIDES",
"value": "{\"onprem-api\":{\"url\": \"${LEVOAI_BASE_URL}\",\"refresh-token\":\"${LEVOAI_AUTH_KEY}\",\"org-id\": \"${LEVOAI_ORG_ID}\",\"org-prefix\": \"${LEVOAI_ORG_PREFIX}\"},\"dynamic_url_threshold_factor\": 0.5,\"api_rule_evaluation\":{\"enabled\": true},\"enable_ssl_cert_checks\": true,\"traces_queue\":{\"type\": \"sqs\"},\"spans_queue\":{\"type\": \"sqs\"},\"findings_queue\":{\"type\": \"sqs\"},\"mcp_span_queue\":{\"type\": \"sqs\"},\"ai_span_queue\":{\"type\": \"sqs\"}}"
},
{
"name": "PI_DETECTOR_DATA_DIR",
"value": "/opt/levoai/datasets/"
},
{
"name": "LEVOAI_DEBUG_ENABLED",
"value": "false"
},
{
"name": "LEVOAI_AUTH_KEY",
"value": "INSERT YOUR LEVO.AI AUTH KEY HERE"
},
{
"name": "LEVOAI_LOG_LEVEL",
"value": "INFO"
}
],
"mountPoints": [],
"volumesFrom": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/levoai-satellite",
"awslogs-create-group": "true",
"awslogs-region": "INSERT YOUR AWS REGION HERE",
"awslogs-stream-prefix": "ecs"
}
},
"systemControls": []
},
{
"name": "levoai-collector",
"image": "levoai/collector:stable",
"cpu": 0,
"portMappings": [
{
"name": "levoai-collector-4317-tcp",
"containerPort": 4317,
"hostPort": 4317,
"protocol": "tcp",
"appProtocol": "http"
}
],
"essential": true,
"command": [
"--config",
"/etc/opt/levoai/config-ecs.yml"
],
"environment": [],
"mountPoints": [],
"volumesFrom": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/levoai-satellite",
"awslogs-create-group": "true",
"awslogs-region": "INSERT YOUR AWS REGION HERE",
"awslogs-stream-prefix": "ecs"
}
},
"systemControls": []
},
{
"name": "levoai-haproxy",
"image": "levoai/haproxy:stable",
"cpu": 0,
"portMappings": [
{
"name": "levoai-haproxy-8080-tcp",
"containerPort": 8080,
"hostPort": 8080,
"protocol": "tcp",
"appProtocol": "http"
}
],
"essential": true,
"command": [
"-f",
"/levo/haproxy-ecs.cfg"
],
"environment": [
{
"name": "LEVOAI_ORG_ID",
"value": "INSERT YOUR ORG ID HERE"
},
{
"name": "LEVOAI_SATELLITE_AUTHN_ENABLED",
"value": "false"
},
{
"name": "LEVOAI_CONF_OVERRIDES",
"value": "{\"org-id\": \"INSERT YOUR ORG ID HERE\"}"
}
],
"mountPoints": [],
"volumesFrom": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/levoai-satellite",
"awslogs-create-group": "true",
"awslogs-region": "INSERT YOUR AWS REGION HERE",
"awslogs-stream-prefix": "ecs"
}
},
"systemControls": []
}
],
"taskRoleArn": "INSERT THE ARN OF THE ROLE YOU WANT TO ASSIGN TO THIS TASK HERE",
"executionRoleArn": "INSERT THE ARN OF THE ROLE YOU WANT TO ASSIGN TO THIS TASK HERE",
"networkMode": "awsvpc",
"volumes": [],
"placementConstraints": [],
"requiresCompatibilities": [
"FARGATE"
],
"cpu": "4096",
"memory": "8192",
"runtimePlatform": {
"cpuArchitecture": "X86_64",
"operatingSystemFamily": "LINUX"
}
}
Depending on the region you are installing in, you may need to set a different Levo base URL for the satellite.
For example, if the satellite will be used with app.india-1.levo.ai, set the LEVOAI_BASE_URL environment variable as
{
"name": "LEVOAI_BASE_URL",
"value": "https://api.india-1.levo.ai"
},
Download the
curl -O https://docs.levo.ai/artifacts/satellite/main.tf
Initialize and apply the Terraform configuration:
terraform init
terraform apply
You will be prompted to enter:
- Auth Key β your Levo Authorization Token
- Org ID β your Levo Organization ID
- Base URL β choose
1for Levo US SaaS or2for Levo India SaaS - Compute Type β choose
1for EC2 or2for Fargate - Region β your AWS region (e.g.,
us-east-1)
Terraform will create the following resources:
- ECS Task Definition with 4 containers (satellite, tagger, collector, haproxy)
- IAM Role (
levoai-satellite-ecs-role) for ECS task execution - IAM Policy with CloudWatch Logs and SQS permissions
After the task definition is created, proceed to Step 2 to deploy it as a service.
Download the
curl -O https://docs.levo.ai/artifacts/satellite/install-satellite.sh
chmod +x install-satellite.sh
Basic usage:
./install-satellite.sh \
--region <YOUR_REGION> \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--subnets <SUBNET_ID> \
--security-groups <SG_ID> \
--create-iam-role \
--assign-public-ip
Auto-create everything:
./install-satellite.sh \
--region <YOUR_REGION> \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--vpc-id <YOUR_VPC_ID> \
--create-subnet \
--create-security-group \
--sensor-cidr 10.0.0.0/16 \
--create-iam-role \
--assign-public-ip
- Run with
--dry-runto preview commands - Use
--list --vpc-id <VPC_ID> --region <REGION>to discover available subnets/security groups - See Network Configuration above for detailed options
Key Optionsβ
| Flag | Description |
|---|---|
--region | AWS region (required) |
--org-id | Levo.ai Organization ID (required) |
--auth-key | Levo.ai Auth Key (required) |
--subnets | Subnet IDs (comma-separated) |
--security-groups | Security group IDs (comma-separated) |
--create-iam-role | Auto-create IAM role with SQS, CloudWatch, ECR permissions |
--role-arn | Use existing IAM role ARN |
--create-subnet | Auto-create subnet (needs --vpc-id) |
--create-security-group | Auto-create security group (needs --vpc-id) |
--list | Discover subnets/SGs in VPC (needs --vpc-id) |
--assign-public-ip | Assign public IP to task |
--log-level | INFO or DEBUG (default: INFO) |
--base-url | API URL (default: https://api.levo.ai) |
--dry-run | Preview without executing |
For India region, use --base-url https://api.india-1.levo.ai
The CLI script handles Steps 2 and 3 automatically β skip to install traffic capture sensors.
2. Run the Satelliteβ
Now that the task definition is created, deploy the Satellite as a service in an ECS cluster:
- Open the levo-satellite task definition and select the latest revision
- Navigate to Deploy and select Create Service
- Choose the cluster where you want to deploy the Satellite
- Under Compute Options, select Launch Type
- Add a Service name in the Deployment configuration
- Leave other configurations at their default settings and start the service
3. Retrieval Port & External Accessβ
After deployment, the Satellite is accessible at:
External Endpoint: <public-ip>:8080 (via HAProxy)
Public IP Location: ECS Task Details β Container details β Network bindings β External link
Example: <PUBLIC_IP>:8080 (e.g., 52.32.232.165:8080)
Protocol: HTTP (can be wrapped in your own TLS layer)
Port 8080 is the retrieval port used for communication between the Satellite and Sensors.
To find the public IP:
- Head over to the cluster you earlier used to run the satellite on
- Click on Tasks and select the particular satellite task
- Under the Container details for levoai-haproxy, go to Network bindings
It should look something like this:
Network bindings
Host port Container port Protocol External link
8080 8080 tcp <PUBLIC_IP>:8080
NOTE: If you're unable to reach the Satellite, add the necessary inbound rules to the security group used by this task.
Record this informationβyou'll need it to configure the Sensor.
Verify Satellite is running:
curl http://{satellite-ip}:8080/health
Finding Private IP (for VPC-internal sensors):
AWS Console: ECS β Tasks β Click task β Private IP address
AWS CLI:
aws ecs describe-tasks --cluster levoai-satellite \
--tasks $(aws ecs list-tasks --cluster levoai-satellite --query 'taskArns[0]' --output text) \
--query 'tasks[0].attachments[0].details[?name==`privateIPv4Address`].value' --output text
Use: http://{private-ip}:8080
Please proceed to install traffic capture sensors.
Viewing Satellite Logsβ
Download the log viewer script:
curl -O https://docs.levo.ai/artifacts/satellite/levo-logs.sh
chmod +x levo-logs.sh
The Levo Satellite deployment includes multiple containers, each writing logs to CloudWatch. You can view logs for individual containers or all containers together.
Log Levelsβ
The Satellite supports two log levels controlled by the LEVOAI_LOG_LEVEL environment variable:
INFO(default) β Standard operational logs showing key events, API calls, and processing statusDEBUGβ Verbose logs including internal operations, SQS polling, AWS authentication, metrics collection, and detailed request/response data
To change the log level, update the LEVOAI_LOG_LEVEL environment variable in your task definition and redeploy:
- AWS Console
- CLI
- Open your task definition in the ECS console
- Find the
levoai-satelliteandlevoai-taggercontainers - Update the
LEVOAI_LOG_LEVELenvironment variable toDEBUG - Create a new revision and update your service
Redeploy with the --log-level flag:
./install-satellite.sh \
--region us-east-1 \
--org-id <YOUR_ORG_ID> \
--auth-key <YOUR_AUTH_KEY> \
--subnets <SUBNET_ID> \
--security-groups <SG_ID> \
--log-level DEBUG
Use DEBUG level for troubleshooting issues or understanding internal behavior. For production deployments, INFO level is recommended to reduce log volume and costs.
Viewing Logs by Containerβ
The Satellite deployment consists of four containers, each writing to separate log streams within the same CloudWatch log group (/ecs/levoai-satellite):
satelliteβ Main API processing, SQS queue polling, authentication, metrics (stream:ecs/levoai-satellite/)taggerβ API cataloging, endpoint mapping, schema detection (stream:ecs/levoai-tagger/)collectorβ OpenTelemetry trace collection and processing (stream:ecs/levoai-collector/)haproxyβ Incoming HTTP connections on port 8080 (stream:ecs/levoai-haproxy/)
Each container writes to its own log stream, so you can view them separately or all together.
Using the Log Viewer Script (Recommended)β
View logs for a specific container (replace <YOUR_CLUSTER> and <YOUR_REGION> with your values):
# View satellite logs (main processing)
./levo-logs.sh satellite --cluster <YOUR_CLUSTER> --region <YOUR_REGION>
# View haproxy logs (incoming connections - clean, simple logs)
./levo-logs.sh haproxy --cluster <YOUR_CLUSTER> --region <YOUR_REGION>
# View tagger logs (API cataloging)
./levo-logs.sh tagger --cluster <YOUR_CLUSTER> --region <YOUR_REGION>
# View collector logs (OpenTelemetry)
./levo-logs.sh collector --cluster <YOUR_CLUSTER> --region <YOUR_REGION>
Additional options:
# View logs from the last hour
./levo-logs.sh satellite --cluster <YOUR_CLUSTER> --since 1h --region <YOUR_REGION>
# View logs without following (print and exit)
./levo-logs.sh haproxy --cluster <YOUR_CLUSTER> --no-follow --region <YOUR_REGION>
# Export logs to a file (for sharing or analysis)
./levo-logs.sh satellite --cluster <YOUR_CLUSTER> --export --export-file satellite-logs.txt --since 2h --region <YOUR_REGION>
./levo-logs.sh haproxy --cluster <YOUR_CLUSTER> --export --export-file haproxy-logs.txt --since 2h --region <YOUR_REGION>
./levo-logs.sh tagger --cluster <YOUR_CLUSTER> --export --export-file tagger-logs.txt --since 2h --region <YOUR_REGION>
./levo-logs.sh collector --cluster <YOUR_CLUSTER> --export --export-file collector-logs.txt --since 2h --region <YOUR_REGION>
# Specify custom log group (if not using default /ecs/levoai-satellite)
./levo-logs.sh satellite --cluster <YOUR_CLUSTER> --log-group /ecs/my-custom-log-group --region <YOUR_REGION>
Replace <YOUR_CLUSTER> with your ECS cluster name (e.g., levoai-satellite) and <YOUR_REGION> with your AWS region (e.g., us-east-1).
Using AWS CLI Directlyβ
# View ALL satellite logs (all containers mixed together)
aws logs tail /ecs/levoai-satellite --follow --format short --region <YOUR_REGION>
# View logs from a SPECIFIC container only
aws logs tail /ecs/levoai-satellite \
--log-stream-name-prefix ecs/levoai-haproxy/ \
--follow --format short --region <YOUR_REGION>
# View satellite container logs only
aws logs tail /ecs/levoai-satellite \
--log-stream-name-prefix ecs/levoai-satellite/ \
--follow --format short --region <YOUR_REGION>
Without --log-stream-name-prefix, the AWS CLI will show logs from all containers mixed together, which can be overwhelming when DEBUG logging is enabled. Use the log viewer script or specify the stream prefix to view individual container logs.
Using AWS Consoleβ
- Navigate to CloudWatch β Log groups
- Select
/ecs/levoai-satellite - You'll see multiple log streams - use the filter dropdown to select a specific container:
ecs/levoai-satellite/β Satellite logsecs/levoai-haproxy/β HAProxy logsecs/levoai-tagger/β Tagger logsecs/levoai-collector/β Collector logs
- Or use the search bar to filter log content by text