Creating Custom Domain Names for Amazon Bedrock AgentCore Runtime
Introduction
When deploying AI agents to Amazon Bedrock AgentCore Runtime (currently in preview), customers often want to use custom domain names to create a professional and seamless experience.
Benefits of Amazon Bedrock AgentCore Runtime
If you’re building AI agents, you have probably wrestled with hosting challenges: managing infrastructure, handling authentication, scaling, and maintaining security.
Benefits of Custom Domains
When using Amazon Bedrock AgentCore Runtime with Open Authorization (OAuth) authentication, custom domains offer several advantages.
Solution Overview
In this solution, we use CloudFront as a reverse proxy to transform requests from your custom domain into Amazon Bedrock AgentCore Runtime API calls.
Prerequisites
To follow this walkthrough, you must have the following in place.
Create an Agent with Inbound Authentication
If you already have an agent deployed with OAuth authentication, you can skip to the next section to set up the custom domain.
Set Up the Custom Domain Solution
Now let’s implement the custom domain solution using the AWS CDK.
Deploy Your Custom Domain
Now you can deploy the solution and verify it works with both custom and default domains.
Test Your Endpoint
After you deploy the custom domain, you can test your endpoints using either the custom domain or the CloudFront default domain.
Considerations
As you implement this solution in production, there are some important considerations to keep in mind.
Clean Up
To avoid ongoing costs, delete the resources when you no longer need them.
Conclusion
In this post, we showed you how to create custom domain names for your Amazon Bedrock AgentCore Runtime agent endpoints using CloudFront as a reverse proxy.
About the Authors
Rahmat Fedayizada and Paras Bhuva share their expertise in solutions architecture and AI initiatives.
Creating Custom Domains for Amazon Bedrock AgentCore Runtime with CloudFront
When deploying AI agents to the Amazon Bedrock AgentCore Runtime (currently in preview), it’s often important to present a professional and user-friendly interface. By default, AgentCore Runtime agents utilize endpoints that look like this: https://bedrock-agentcore.{region}.amazonaws.com/runtimes/{EncodedAgentARN}/invocations. To enhance the user experience, we aim to transform these endpoints into custom domains, such as https://agent.yourcompany.com.
In this post, we will explore how to achieve this using Amazon CloudFront as a reverse proxy, alongside Amazon Route 53 and AWS Certificate Manager (ACM). This potent combination offers a secure and scalable solution that seamlessly integrates into your existing agent architecture.
Benefits of Amazon Bedrock AgentCore Runtime
If you’re venturing into the world of AI agents, you’re likely aware of the various hosting challenges, such as:
- Infrastructure management
- Authentication handling
- Scaling solutions
- Security maintenance
Amazon Bedrock AgentCore Runtime simplifies these concerns significantly:
- Framework Agnostic: Compatible with LangGraph, CrewAI, Strands Agents, or any custom-built agents.
- Extended Execution Times: Supports up to 8 hours for complex reasoning tasks that traditional serverless functions may struggle with.
- Isolated MicroVMs: Ensures each user session runs in its own microVM for enhanced security, vital for enterprise applications.
- Consumption-based Pricing: Pay for what you use instead of provisioning excess resources.
- Built-in Authentication & Observability: Integrated features streamline the process of developing AI agents.
Benefits of Custom Domains
Utilizing custom domains with Amazon Bedrock AgentCore Runtime offers several advantages beyond basic functionality:
- Custom Branding: Brand recognition is essential. Client-side applications can display your unique domain instead of AWS infrastructure details.
- Better Developer Experience: Simplifies endpoint usage by letting developers work with memorable, branded URLs instead of lengthy AWS endpoints.
- Simplified Maintenance: Manage numerous agents and configurations with ease, especially when deploying across different environments.
Solution Overview
In our proposed solution, we leverage CloudFront as a reverse proxy. This setup transforms requests from your custom domain into Amazon Bedrock AgentCore Runtime API calls. Rather than using the default endpoint, your applications can interact with user-friendly URLs, like https://agent.yourcompany.com/.
Here’s the workflow:
- A client application authenticates through Amazon Cognito and obtains a bearer token.
- The client sends an HTTPS request to your custom domain.
- Route 53 resolves the DNS query to CloudFront.
- CloudFront forwards the authenticated request to the Amazon Bedrock Runtime agent.
- The agent processes the request and returns the response through the same route.
This architecture allows the same CloudFront distribution to serve both your frontend application and backend agent endpoints, minimizing cross-origin resource sharing (CORS) issues.
Prerequisites
Before diving into implementation, ensure you have the following components:
- Amazon Bedrock AgentCore Runtime set up in a supported AWS Region (note that CloudFront requires SSL certificates to be in the
us-east-1Region). - Domain Options: Choose between an existing domain (like
agent.yourcompany.com), registering a new domain through Route 53, or using a default URL from CloudFront for quick testing.
Create an Agent with Inbound Authentication
To proceed with setting up your agent with OAuth authentication using Amazon Cognito, follow these steps:
-
Directory Structure:
your_project_directory/ ├── agent_example.py # Main agent code ├── requirements.txt # Dependencies └── __init__.py # Python package marker -
Agent Code in
agent_example.py:from strands import Agent from bedrock_agentcore.runtime import BedrockAgentCoreApp agent = Agent() app = BedrockAgentCoreApp() @app.entrypoint def invoke(payload): user_message = payload.get("prompt", "Hello") response = agent(user_message) return str(response) if __name__ == "__main__": app.run() -
Dependencies in
requirements.txt:strands-agents bedrock-agentcore -
Creating Amazon Cognito User Pool and Test User:
# Create User Pool and capture Pool ID export POOL_ID=$(aws cognito-idp create-user-pool --pool-name "MyUserPool" --policies '{"PasswordPolicy":{"MinimumLength":8}}' --region us-east-1 | jq -r '.UserPool.Id') # Create App Client and capture Client ID export CLIENT_ID=$(aws cognito-idp create-user-pool-client --user-pool-id $POOL_ID --client-name "MyClient" --no-generate-secret --explicit-auth-flows "ALLOW_USER_PASSWORD_AUTH" "ALLOW_REFRESH_TOKEN_AUTH" --region us-east-1 | jq -r '.UserPoolClient.ClientId') # Create and configure a test user aws cognito-idp admin-create-user --user-pool-id $POOL_ID --username "testuser" --temporary-password "Temp1234" --region us-east-1 --message-action SUPPRESS aws cognito-idp admin-set-user-password --user-pool-id $POOL_ID --username "testuser" --password "MyPassword123" --region us-east-1 --permanent echo "Pool ID: $POOL_ID" echo "Discovery URL: https://cognito-idp.us-east-1.amazonaws.com/$POOL_ID/.well-known/openid-configuration" echo "Client ID: $CLIENT_ID" -
Deploy the Agent:
Using the Amazon Bedrock AgentCore command-line interface:
pip install bedrock-agentcore-starter-toolkit agentcore configure --entrypoint agent_example.py --name my_agent --execution-role your-execution-role-arn --requirements-file requirements.txt --authorizer-config "{\"customJWTAuthorizer\":{\"discoveryUrl\":\"https://cognito-idp.us-east-1.amazonaws.com/$POOL_ID/.well-known/openid-configuration\",\"allowedClients\":[\"$CLIENT_ID\"]}}" agentcore launchMake note of your agent’s runtime Amazon Resource Name (ARN) for future configuration.
Set Up the Custom Domain Solution
Now let’s implement the custom domain solution using the AWS Cloud Development Kit (CDK).
-
Create a New Directory and Initialize the Project:
mkdir agentcore-custom-domain cd agentcore-custom-domain cdk init app --language python source .venv/bin/activate pip install aws-cdk-lib constructs -
Configure the CloudFront Origin:
Here’s how to encode the agent ARN and prepare the configuration:
import urllib.parse agent_runtime_arn = "arn:aws:bedrock-agentcore:us-east-1:accountId:runtime/my_agent-xbcDkz4FR9" encoded_arn = urllib.parse.quote(agent_runtime_arn, safe="") region = agent_runtime_arn.split(':')[3] -
Handle CORS Requirements:
If your frontend application runs on a different domain, configure CORS headers:
from aws_cdk.aws_cloudfront import ResponseHeadersPolicy, ResponseHeadersCorsBehavior cors_policy = ResponseHeadersPolicy(self, 'CorsPolicy', cors_behavior=ResponseHeadersCorsBehavior( access_control_allow_origins=['*'], access_control_allow_headers=[ 'Authorization', 'Content-Type', 'X-Amzn-*', 'X-Requested-With' ], access_control_allow_methods=['GET', 'POST', 'OPTIONS'], access_control_allow_credentials=False, access_control_expose_headers=['*'], origin_override=True ) ) -
Create the CloudFront Distribution:
from aws_cdk.aws_cloudfront import ( Distribution, BehaviorOptions, CachePolicy, AllowedMethods, ViewerProtocolPolicy, OriginProtocolPolicy, OriginRequestPolicy ) from aws_cdk.aws_cloudfront_origins import HttpOrigin bedrock_agentcore_hostname = f"bedrock-agentcore.{region}.amazonaws.com" origin_path = f"/runtimes/{encoded_arn}/invocations" distribution = Distribution(self, 'Distribution', default_behavior=BehaviorOptions( origin=HttpOrigin( bedrock_agentcore_hostname, origin_path=origin_path, protocol_policy=OriginProtocolPolicy.HTTPS_ONLY, read_timeout=Duration.seconds(120) ), viewer_protocol_policy=ViewerProtocolPolicy.REDIRECT_TO_HTTPS, cache_policy=CachePolicy.CACHING_DISABLED, allowed_methods=AllowedMethods.ALLOW_ALL, response_headers_policy=cors_policy, origin_request_policy=OriginRequestPolicy.ALL_VIEWER, ), domain_names=[domain_name] if domain_name else None, certificate=certificate if domain_name else None, ) -
Configure SSL Certificates and DNS Records:
from aws_cdk.aws_certificatemanager import Certificate, CertificateValidation from aws_cdk.aws_route53 import HostedZone, ARecord, RecordTarget from aws_cdk.aws_route53_targets import CloudFrontTarget hosted_zone = HostedZone.from_lookup(self, 'HostedZone', domain_name="yourcompany.com" ) certificate = Certificate(self, 'Certificate', domain_name="my-agent.yourcompany.com", validation=CertificateValidation.from_dns(hosted_zone), ) ARecord(self, 'AliasRecord', zone=hosted_zone, record_name="my-agent.yourcompany.com", target=RecordTarget.from_alias(CloudFrontTarget(distribution)), ) -
Complete CDK Stack Configuration:
Here’s the complete AWS CDK stack combining all parts:
import urllib.parse from aws_cdk import Stack, CfnOutput, Duration from aws_cdk.aws_cloudfront import ( Distribution, BehaviorOptions, CachePolicy, AllowedMethods, ViewerProtocolPolicy, OriginProtocolPolicy, ResponseHeadersPolicy, ResponseHeadersCorsBehavior, OriginRequestPolicy ) from aws_cdk.aws_cloudfront_origins import HttpOrigin from aws_cdk.aws_certificatemanager import Certificate, CertificateValidation from aws_cdk.aws_route53 import HostedZone, ARecord, RecordTarget from aws_cdk.aws_route53_targets import CloudFrontTarget from constructs import Construct class AgentcoreCustomDomainStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) agent_runtime_arn = "arn:aws:bedrock-agentcore:us-east-1:accountId:runtime/my_agent-xbcDkz4FR9" region = agent_runtime_arn.split(':')[3] domain_name = "agent.yourcompany.com" hosted_zone_id = "Z1234567890ABC" enable_cors = True encoded_arn = urllib.parse.quote(agent_runtime_arn, safe="") bedrock_agentcore_hostname = f"bedrock-agentcore.{region}.amazonaws.com" origin_path = f"/runtimes/{encoded_arn}/invocations" cors_policy = None if enable_cors: cors_policy = ResponseHeadersPolicy(self, 'CorsPolicy', cors_behavior=ResponseHeadersCorsBehavior( access_control_allow_origins=['*'], access_control_allow_headers=[ 'Authorization', 'Content-Type', 'X-Amzn-*', 'X-Requested-With' ], access_control_allow_methods=['GET', 'POST', 'OPTIONS'], access_control_expose_headers=['*'], access_control_allow_credentials=False, origin_override=True ) ) distribution_props = { "default_behavior": BehaviorOptions( origin=HttpOrigin( bedrock_agentcore_hostname, origin_path=origin_path, protocol_policy=OriginProtocolPolicy.HTTPS_ONLY, read_timeout=Duration.seconds(120) ), viewer_protocol_policy=ViewerProtocolPolicy.REDIRECT_TO_HTTPS, cache_policy=CachePolicy.CACHING_DISABLED, allowed_methods=AllowedMethods.ALLOW_ALL, response_headers_policy=cors_policy, origin_request_policy=OriginRequestPolicy.ALL_VIEWER, ) } if domain_name: hosted_zone = HostedZone.from_hosted_zone_attributes(self, 'HostedZone', zone_name="yourcompany.com", hosted_zone_id=hosted_zone_id ) certificate = Certificate(self, 'Certificate', domain_name=domain_name, validation=CertificateValidation.from_dns(hosted_zone), ) distribution_props["domain_names"] = [domain_name] distribution_props["certificate"] = certificate distribution = Distribution(self, 'Distribution', **distribution_props) if domain_name: ARecord(self, 'AliasRecord', zone=hosted_zone, record_name=domain_name, target=RecordTarget.from_alias( CloudFrontTarget(distribution)), ) if domain_name: domain_url = f"https://{domain_name}/" CfnOutput(self, "AgentEndpoint", value=domain_url, description="Your custom domain endpoint" ) CfnOutput(self, "CloudFrontDistribution", value=f"https://{distribution.distribution_domain_name}/", description="CloudFront default domain (works without custom domain)" ) -
Configure the AWS CDK App Entry Point:
# app.py import aws_cdk as cdk from agentcore_custom_domain.agentcore_custom_domain_stack import AgentcoreCustomDomainStack app = cdk.App() AgentcoreCustomDomainStack(app, "AgentCoreCustomDomainStack", env=cdk.Environment(region='us-east-1'), ) app.synth()
Deploy Your Custom Domain
To deploy the solution, update the following values in agentcore_custom_domain_stack.py:
- Your Amazon Bedrock AgentCore Runtime ARN
- Your domain name (if using a custom domain)
- Your hosted zone ID (if using a custom domain)
Then deploy using the AWS CDK:
cdk deploy
Test Your Endpoint
After deployment, verify your endpoints with either the custom or default domain. First, retrieve a JWT token from Amazon Cognito:
export TOKEN=$(aws cognito-idp initiate-auth \
--client-id "your-client-id" \
--auth-flow USER_PASSWORD_AUTH \
--auth-parameters USERNAME='testuser',PASSWORD='MyPassword123' \
--region us-east-1 | jq -r '.AuthenticationResult.AccessToken')
Testing with the Custom Domain
curl -X POST "https://my-agent.yourcompany.com/" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "X-Amzn-Bedrock-AgentCore-Runtime-Session-Id: session-12345678901234567890123456789012345" \
-d '{"prompt": "Hello, how can you help me today?"}'
Testing with the Default CloudFront Domain
curl -X POST "https://d1234567890123.cloudfront.net/" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "X-Amzn-Bedrock-AgentCore-Runtime-Session-Id: session-12345678901234567890123456789012345" \
-d '{"prompt": "Hello, how can you help me today?"}'
With everything correctly set up, you should receive a response from your agent through either endpoint!
Considerations
As you implement this solution, keep the following considerations in mind:
- Cost Implications: CloudFront adds costs for data transfer and requests. Review the pricing model beforehand.
- Security Enhancements: Consider implementing AWS WAF rules for protection, rate limiting to prevent abuse, and geo-restrictions for access.
- Monitoring: Enable CloudFront access logs and configure Amazon CloudWatch alarms to monitor performance and error rates.
Clean Up
To prevent ongoing costs, ensure to delete Resources you no longer require. You may need to manually remove Route 53 hosted zones and ACM certificates from their respective consoles.
Conclusion
In this post, we demonstrated how to craft custom domain names for your Amazon Bedrock AgentCore Runtime endpoints using CloudFront as a reverse proxy. This approach not only streamlines integration for development teams but also fortifies your branding efforts and simplifies maintenance.
We encourage you to adapt this solution to meet your specific needs and explore advanced features for enhanced security and monitoring.
For further information, check the Amazon Bedrock AgentCore Developer Guide. Explore the Amazon CloudFront documentation for best practices and AWS Certificate Manager documentation for SSL certificates.
Amazon Bedrock AgentCore is currently in preview and subject to changes. Standard AWS pricing applies for additional services utilized.
About the Authors
Rahmat Fedayizada is a Senior Solutions Architect at AWS, working with energy firms to design scalable, secure architectures.
Paras Bhuva leads a team of Solutions Architects at AWS, helping customers accelerate their transformations in application modernization and AI.
Feel free to explore and customize these solutions according to your organization’s specific requirements!