Deploy on AWS (ECS Express Mode)
How to run a Sentinel gateway in your AWS account on ECS Express Mode, register its URL, and avoid the health-check loop
To deploy SUPERWISE® Sentinel on AWS, run the Sentinel gateway container as an ECS Express Mode service with a /healthz health check, its three identity values in Secrets Manager, and its public URL registered as SENTINEL_EXTERNAL_HOST. Express Mode provisions the load balancer, HTTPS certificate, target groups, security groups, and auto scaling for you, and pulls the image directly from the SUPERWISE registry, so no image mirroring is needed.
ECS Express Mode is one example, not the only option. The gateway is a standard container, so on AWS it runs just as well on EKS (with the Helm chart), plain ECS, App Runner, or EC2. This page walks through ECS Express Mode end to end; pick the service that fits your platform. See Deploy a gateway for the full list.
Before you start
- Complete Before you deploy: create the Sentinel, and have
SENTINEL_ID,SW_CLIENT_ID, andSW_CLIENT_SECRETin your shell. - AWS CLI 2.36 or later, signed in, with deploy access to the account.
- The commands below also use
TEAM(a name for this gateway's resources) andACCOUNT_ID(your AWS account ID).
1. Create the cluster, roles, and secrets
aws ecs create-cluster --cluster-name "sentinel-${TEAM}"
# Execution role: pulls the image and reads the secrets
aws iam create-role --role-name "sentinel-execution-role-${TEAM}" \
--assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow",
"Principal":{"Service":"ecs-tasks.amazonaws.com"},"Action":"sts:AssumeRole"}]}'
aws iam attach-role-policy --role-name "sentinel-execution-role-${TEAM}" \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
# Infrastructure role: provisions the load balancer and networking
aws iam create-role --role-name "sentinel-infra-role-${TEAM}" \
--assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow",
"Principal":{"Service":"ecs.amazonaws.com"},"Action":"sts:AssumeRole"}]}'
aws iam attach-role-policy --role-name "sentinel-infra-role-${TEAM}" \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSInfrastructureRoleforExpressGatewayServices
# Per gateway: one secret per team
aws secretsmanager create-secret --name "sentinel/${TEAM}/SENTINEL_ID" \
--secret-string "$SENTINEL_ID" --query ARN --output text
# Per organization: create once, reuse for every gateway
for n in SW_CLIENT_ID SW_CLIENT_SECRET; do
aws secretsmanager describe-secret --secret-id "sentinel/$n" >/dev/null 2>&1 \
|| aws secretsmanager create-secret --name "sentinel/$n" --secret-string "${!n}"
aws secretsmanager describe-secret --secret-id "sentinel/$n" --query ARN --output text
done
sleep 60 # let the roles propagate before first useGrant the execution role secretsmanager:GetSecretValue on those three secret ARNs.
Use the full secret ARNs, including the random suffix Secrets Manager appends, in the IAM policy's
Resourcefield. The short form without the suffix resolves in the container definition but silently fails to match in an IAM policy.
2. Create the service and capture its URL
GATEWAY_URL=$(aws ecs create-express-gateway-service \
--service-name "sentinel-${TEAM}" \
--cluster "sentinel-${TEAM}" \
--execution-role-arn "arn:aws:iam::${ACCOUNT_ID}:role/sentinel-execution-role-${TEAM}" \
--infrastructure-role-arn "arn:aws:iam::${ACCOUNT_ID}:role/sentinel-infra-role-${TEAM}" \
--health-check-path "/healthz" \
--scaling-target '{"minTaskCount":2,"maxTaskCount":10}' \
--primary-container '{
"image": "us-central1-docker.pkg.dev/admina33d6818/sentinel-public/sentinel:latest",
"containerPort": 8000,
"secrets": [
{"name":"SENTINEL_ID","valueFrom":"<SENTINEL_ID secret ARN>"},
{"name":"SW_CLIENT_ID","valueFrom":"<SW_CLIENT_ID secret ARN>"},
{"name":"SW_CLIENT_SECRET","valueFrom":"<SW_CLIENT_SECRET secret ARN>"}
]
}' \
--query "service.activeConfigurations[0].ingressPaths[0].endpoint" --output text)
echo "$GATEWAY_URL" # https://se-<id>.ecs.<region>.on.awsAlways pass
--health-check-path "/healthz". The AWS CLI help says the default is/ping, but the target group is created with/, which the gateway answers with a 404. Tasks then start, heartbeat, and get replaced in a loop.From the SUPERWISE side this looks like success: the Sentinel shows Active the whole time, because each task does heartbeat before the load balancer replaces it. If traffic fails against a Sentinel that shows Active, check the ECS service events.
The URL is a generated identifier, not your service name, and routing is by host header only. The load balancer's own DNS name returns a 404 from the balancer itself, not from the gateway. Use the assigned hostname, which carries a valid AWS-managed certificate and needs no ACM or DNS work.
If $GATEWAY_URL comes back empty, the load balancer is still provisioning. Wait a minute, then read the URL from the service's detail page in the ECS console.
3. Register the URL
Set SENTINEL_EXTERNAL_HOST to the gateway's URL, so the Connect dialog in the SUPERWISE app points at an address your applications can reach:
aws ecs update-express-gateway-service \
--service-arn "<service ARN>" \
--primary-container '{ ...same block, plus: ...
"environment": [{"name":"SENTINEL_EXTERNAL_HOST","value":"'"$GATEWAY_URL"'"}]
}'Updates run blue/green, so two tasks and two target groups during a rollout are expected.
4. Raise the load balancer idle timeout
Raise the provisioned load balancer's idle timeout from its 60-second default, or long streaming responses are cut short. See Raise the request timeout.
5. Verify the gateway
The Sentinel turns Active in the SUPERWISE app within about a minute. First check that the container is serving. /healthz answers 200 OK:
curl -i "$GATEWAY_URL"/healthzHTTP/1.1 200 OK
...
{"status":"ok"}/healthz shows only that the gateway is up. Then confirm a guardrail fires with POST /test, as described in Verify the gateway. If traffic fails while the Sentinel shows Active, check the ECS service events for the health-check loop described above.
Update or remove it
To run a newer image or change a variable, run aws ecs update-express-gateway-service with the full container block, as in step 3. Updates run blue/green.
To remove the gateway, delete the service. The Sentinel's configuration stays in the SUPERWISE app.
aws ecs delete-express-gateway-service --service-arn "<service ARN>"Common errors
Tasks start and get replaced in a loop while the Sentinel shows Active
The target group's health check is on /, which the gateway answers with a 404. Recreate or update the service with --health-check-path "/healthz". See step 2.
The load balancer's DNS name returns 404
Routing is by host header only, so the balancer answers its own DNS name with a 404 before the request reaches the gateway. Use the assigned https://se-<id>.ecs.<region>.on.aws hostname.
The task cannot read its secrets
The IAM policy names a secret ARN without the random suffix Secrets Manager appends. The short form resolves in the container definition but does not match in an IAM policy. Use the full ARN. See step 1.
Long responses are cut short
The load balancer's idle timeout is still at its 60-second default. See step 4.
Get Sentinel: Create a free SUPERWISE account.
See also
- Deploy a gateway: every way to deploy, and what a team gateway needs on any platform.
- Deploy on Google Cloud (Cloud Run) and Deploy on Azure (Container Apps).
- Deploy with Helm on Kubernetes: EKS and any other cluster.
- Gateway reference: environment variables, routes, and states.
Updated about 5 hours ago