re:Invent 2025 - Implementing security best practices for serverless applications
Session CNS360 presented a layered security framework for serverless applications on AWS, from foundational IAM controls and API protection through OAuth 2.0 identity flows. The session also shows how those same patterns carry forward to agentic applications being built with MCP and Amazon Bedrock AgentCore.
Building serverless applications on AWS removes the burden of managing infrastructure, but it shifts responsibility for security decisions onto the application team. Chris McPeek, Principal Solutions Architect at AWS, and Heeki Park, Principal Solutions Architect at AWS, addressed this directly in session CNS360 at re:Invent 2025. Using a fitness tracking API as a reference architecture (an Amazon API Gateway endpoint that routes activity data through an AWS Lambda function to an Amazon DynamoDB table), they walked through the security decisions that matter at each layer. In this post, we'll cover the foundational AWS Identity and Access Management (IAM) controls that every serverless application needs, the OAuth 2.0 flows that power identity-aware APIs, and how both patterns apply to agentic applications.
Building a layered IAM foundation
The first recommendation from Chris was structural: separate your development and production accounts. When developers work directly in a production account, even well-intentioned changes can create problems. Keeping sandbox and production environments in separate accounts creates a clean boundary, where developers can iterate quickly in their own space and a structured deployment pipeline controls what reaches production.
Within an account, Lambda functions have a security model worth understanding in detail. A Lambda function has two distinct policies working in tandem. The resource-based policy governs which services can invoke the function (for example, allowing API Gateway to trigger it when a request arrives). The execution role governs what the function can access while it runs (for example, writing records to DynamoDB). Both policies need to be scoped to exactly what is needed and nothing more.
Least privilege is easy to agree with but harder to practice consistently. If you see a wildcard (*) in a policy document, stop and ask whether it belongs there. For most cases, specify exact API actions and exact resource ARNs (Amazon Resource Names). Chris described an iterative approach: set permissions, run tests, verify behavior, then tighten. Doing this inside a CI/CD (continuous integration and continuous delivery) pipeline means those checks happen on every deployment automatically.
Two additional tools help enforce boundaries at scale. Permission boundaries cap the maximum permissions a developer can grant to a role, even if the developer's own policy is broad. The effective permissions for a principal are the intersection of what the policy allows and what the boundary permits. Service Control Policies (SCPs), applied through AWS Organizations, enforce compliance rules across accounts simultaneously without touching individual roles. A practical example from the session: an SCP that blocks developers from creating a public API Gateway endpoint, requiring APIs to be private and routed through a VPC (Virtual Private Cloud) for inspection before traffic reaches the application.
Encryption at rest requires a few explicit choices. Lambda environment variables can be encrypted with AWS Key Management Service (AWS KMS), and API Gateway's caching feature has an encryption option to enable explicitly. Encryption in transit is handled for you: API Gateway only accepts HTTPS requests, so you cannot accidentally expose an unencrypted endpoint.
Input validation belongs at two layers. At the API Gateway level, you can configure request validation to check the body and query string parameters against a schema before the request ever reaches Lambda. Inside the function, AWS Lambda Powertools provides strict type validation with minimal boilerplate. When a downstream service does not support IAM natively (for example, a self-managed database), AWS Secrets Manager is the right place to store those credentials. For public-facing endpoints, AWS WAF (Web Application Firewall) gives you control by IP address, geographic region, and managed rule sets from AWS Marketplace partners.
For runtime detection, Amazon GuardDuty analyzes VPC flow logs and surfaces unexpected behavior that static analysis missed. Amazon Inspector scans your code and dependencies during development, before anything ships to production.
Identity-aware APIs with OAuth 2.0
The second half of the session shifted from infrastructure controls to identity. Heeki framed OAuth 2.0 as the foundational security mechanism for both serverless APIs and agentic applications, and spent considerable time making the flows concrete.
OAuth 2.0 defines five key entities: the resource owner (the end user), the user agent (the browser or client), the client application (your frontend), the resource server (your protected API), and the authorization server (your identity provider). In the demo, Amazon Cognito served as the authorization server. Two flows cover the scenarios you will encounter most often.
The authorization code flow handles user-facing authentication. The user logs in, approves access, and the identity provider issues a short-lived authorization code. The client application exchanges that code, along with its client ID and client secret, for three tokens: an ID token (identifies who the user is), an access token (defines what actions the user can take, expressed as scopes), and a refresh token (used to obtain fresh tokens without asking the user to re-authenticate). Heeki emphasized that these tokens should stay within the server-side application and never be exposed to the browser. When a request arrives at API Gateway, the token is passed to an authorizer, which validates it against Cognito before invoking the Lambda function on the backend.
The client credentials flow handles machine-to-machine communication. There is no user interaction and no authorization code. The client application exchanges its client ID and client secret directly for tokens. If you understand the exchange phase of the authorization code flow, you already understand client credentials. It is the same mechanism, without the user-facing login step. This is the flow to reach for when one service needs to call another service autonomously.
For more granular permission logic, Heeki introduced Amazon Verified Permissions. You can attach a Lambda authorizer to API Gateway that passes incoming tokens to Verified Permissions for evaluation. Verified Permissions uses Cedar (an open-source policy language) to define exactly which principals can take which actions on which resources. The Cedar policy shown in the session granted a specific Cognito user group GET access to defined API paths, with the entire policy expressed as code and version-controlled alongside the application.
Security in agentic applications
The session closed by connecting this security foundation to agentic applications. The fitness tracker example illustrated the transition: rather than writing imperative code to query the API, an agent takes natural language input (for example, a question about performance trends across 30 days of training data) and decides which tools to call to gather and process that information.
The Model Context Protocol (MCP), an open specification created by Anthropic, standardizes how agents call tools. An MCP client in the agent connects to MCP servers provided by different API teams. Each MCP server wraps an existing API, so teams do not need to rebuild what they already have. Machine-to-machine calls between the agent and an MCP server use the client credentials flow. Calls from the MCP server to a downstream API that requires user context may use the authorization code flow instead, with mechanisms to surface the approval request back to the user even when they are several hops removed from the endpoint.
Amazon Bedrock AgentCore, announced at re:Invent 2025, provides managed infrastructure for this pattern. AgentCore Identity handles inbound and outbound authentication. For inbound access, applications running on AWS (on Amazon Elastic Compute Cloud (Amazon EC2), AWS Fargate, or Lambda) use an IAM role; external callers use OAuth 2.0. For outbound access, calls to AWS resources (such as Amazon Simple Storage Service (Amazon S3) buckets or DynamoDB tables) use an IAM role; calls to external services use OAuth 2.0, with the flow selected based on whether user context needs to be preserved. AgentCore Gateway acts as a front door for the tools you expose to agent applications, playing the same role that API Gateway plays for traditional REST APIs.
Three principles from the session are worth carrying forward. First, apply least privilege as a default: be explicit about resources and actions in every policy, and treat wildcards as a prompt to re-examine the scope. Second, defense in depth means stacking controls across layers. IAM execution roles, resource-based policies, WAF, input validation, SCPs, and runtime detection each protect a different surface, and none is sufficient on its own. Third, automate these controls so they hold on every deployment: Amazon Inspector in your pipeline, GuardDuty for runtime detection, and SCPs to enforce standards across accounts.
The OAuth 2.0 patterns from this session apply whether you are building a traditional serverless API today or an agentic application tomorrow. The flows are the same; what changes is the infrastructure you wire them through.
Watch the full session: CNS360 - Implementing security best practices for serverless applications
Relevant content
- Accepted Answer
- Accepted Answerasked 4 years ago
- Accepted Answerasked a year ago
AWS OFFICIALUpdated 2 years ago