This document details the security configuration required for the solution. In particular, it covers:
- HTTPS Setup
- Image URL Fetching (SSRF)
Following these guidelines will help ensure that traffic is encrypted over the public network.
Using HTTPS on your ALB guarantees that all client-to-ALB communication is encrypted. This is achieved by:
- Obtaining and managing SSL/TLS certificates using AWS Certificate Manager (ACM). You'll need a domain but you can request a free certificate.
- Configuring HTTPS listeners on the ALB
- Automating HTTP to HTTPS redirect for clients that inadvertently access HTTP endpoints
- Allowing traffic in the Security Group of the ALB
-
Navigate to AWS Certificate Manager (ACM):
In the AWS Management Console, go to ACM in the region where your ALB is deployed. -
Request the Certificate:
- Click on "Request a certificate".
- Choose "Request a public certificate" (or a private one if using a private CA).
- Enter your domain names (e.g.,
example.com,*.example.com). - Complete the validation (via DNS or email). DNS validation is generally preferred for automation purposes.
-
Certificate Validation:
Ensure that the certificate status becomes "Issued" before proceeding.
- Create or Modify the ALB Listener:
- Open the EC2 Dashboard and navigate to Load Balancers.
- If you already have an ALB, select it; otherwise, create a new ALB.
- Under the Listeners tab, click Manage listener > Edit Listener.
- Configure the listener protocol to HTTPS with port 443.
- Select the certificate you requested from ACM.
To enhance security, ensure that any HTTP requests are automatically redirected to HTTPS.
-
Create an HTTP Listener on Port 80:
- Add a listener on port 80.
- In the listener settings, add a rule to redirect all traffic to port 443 with the protocol changed to HTTPS.
Example AWS CLI command for redirection:
aws elbv2 create-listener \ --load-balancer-arn <your-alb-arn> \ --protocol HTTP \ --port 80 \ --default-actions Type=redirect,RedirectConfig="Protocol=https,Port=443,StatusCode=HTTP_301"
- Create a Security Group:
- Go to the CloudFormation stack you originally used to deploy, select Resources and search for ProxyALBSecurityGroup
- Click on the Security Group
- Edit the Inbound Rules to allow traffic on Port 443 from
0.0.0.0/0and (optionally) delete the Inbound Rule on Port 80. Note: If you delete the rule on port 80, you will need to update the base url to use HTTPS only as it won't redirect HTTP traffic to HTTPS.
Now you should be able to test your application! Use the base url like:
https://<your-domain>/api/v1
The multimodal API accepts an image_url content part that is either an inline base64 data: URL or a
remote URL. When a remote URL is given, the gateway makes the outbound request itself, so a caller who
can reach the API can influence where the gateway connects. Without validation, that is a server-side
request forgery (SSRF) vector: a request could point the gateway at endpoints only reachable from the
task or instance, and the fetched bytes would be sent to the model and returned in the completion.
On ECS/Fargate the notable targets are:
- the container credential endpoint,
169.254.170.2, which serves the task role's temporary credentials - the EC2 instance metadata service,
169.254.169.254 localhostand any VPC-internal service reachable from the task's subnet and security group
Remote image URLs are validated in src/api/image_url.py before any request
is made. A URL is only fetched when all of the following hold:
| Check | Behaviour |
|---|---|
| Scheme | Only http and https. file:, gopher:, ftp:, dict: and others are rejected. |
| Address | Every address the host resolves to must be globally routable. This blocks the link-local range that serves both metadata endpoints, as well as loopback, private, shared address space, reserved and multicast ranges, including their IPv4-mapped IPv6 forms. |
| Redirects | Followed manually, up to 3 hops, and re-validated at every hop so a public URL cannot redirect to an internal one. |
| Response size | Capped, so a large or endless response cannot exhaust task memory. |
| Content type | Normalised to a format Bedrock accepts (image/jpeg, image/png, image/gif, image/webp). |
Rejected requests return 400 with a generic message, so error responses cannot be used to probe which
internal hosts exist.
The checks above resolve the host and then let the HTTP client resolve it again when connecting. A hostname served by an attacker-controlled DNS server with a very short TTL could in principle return a permitted address to the check and an internal address to the connection (DNS rebinding). To rule that out, and to reduce the blast radius generally, apply the controls that fit your deployment:
# Only allow images from hosts you trust. Strongest option; recommended if you know the hosts.
IMAGE_URL_ALLOWED_HOSTS=images.example.com,cdn.example.com
# Or refuse remote URLs entirely and require callers to send base64 data URLs.
ENABLE_IMAGE_URL_FETCH=false
# Lower the response size cap from the 10 MB default if your images are smaller.
IMAGE_URL_MAX_SIZE_MB=5Set these as environment variables on the ECS task definition or the Lambda function.
In addition:
- Scope the task role. This is the control that limits the damage if the credential endpoint is ever
reached. The bundled templates already grant the task role only
bedrock:InvokeModel,bedrock:InvokeModelWithResponseStream,bedrock:ListFoundationModelsandbedrock:ListInferenceProfiles. Keep it that narrow; credentials obtained through any future SSRF-style issue then grant nothing beyond model invocation. - Restrict egress to limit which VPC-internal services and internet hosts the task can reach. Note
the limit of this control: security groups do not filter link-local traffic, so an egress rule
cannot protect the container credential endpoint at
169.254.170.2or the EC2 instance metadata service at169.254.169.254. Those are served locally and never traverse the ENI where the security group applies. - Require IMDSv2 if you run the gateway on EC2 or ECS-on-EC2, so instance metadata cannot be read
with a plain
GET. On ECS-on-EC2 you can also block container access to instance metadata entirely withECS_AWSVPC_BLOCK_IMDS=truein/etc/ecs/ecs.config. Neither setting applies to Fargate.
Deployments created before this hardening was added pass the caller-supplied image URL straight to the HTTP client with no validation. If you are running the gateway from an image built before this change, treat it as exposed to the SSRF vector described above.
Redeploy from the current version, or rebuild your container image from the current source. See How to upgrade? in the README.
Redeploying is the mitigation, not merely the preferred one. Be aware that on Fargate there is no
network-level workaround: as noted above, security groups cannot filter the link-local credential
endpoint, and ECS_AWSVPC_BLOCK_IMDS is not available on Fargate. The environment variables in this
section only exist in the hardened code, so they cannot mitigate an older image either.
Until you can redeploy, the controls that do still apply are:
- Confirm the task role carries no permissions beyond Bedrock invocation, so any credentials reachable through the vector are of limited value.
- Treat the API key as the only thing standing between a caller and this vector: rotate it if it may have been shared beyond its intended users, and restrict who can reach the ALB or API Gateway endpoint.
Note that you cannot determine retrospectively whether the vector was probed. The gateway does not log
request bodies, so an older image leaves no record of the image_url values it fetched; absence of log
evidence is not evidence that nothing was attempted. After upgrading, rejected URLs are recorded as
warnings in CloudWatch, so probing becomes visible from that point on.
By following the steps outlined in this guide, you can configure a secure environment that uses HTTPS via ALB for encrypted traffic.