CLOUD 18 min

Secure Serverless in AWS: Cognito, API Gateway & Lambda

Design and deploy an enterprise Serverless architecture on AWS. Deep dive into Cognito User Pools, API Gateway authorizers, Lambda state management, and Cold Start mitigation.

Written by Samir El Azem Crovetto • Senior Backend Engineer & DevSecOps

The Serverless Paradigm and its Production Threat Landscape

The Serverless computing model on Amazon Web Services (AWS) — centered on AWS Lambda, Amazon API Gateway, and Amazon Cognito — shifts the burden of operating system patching, auto-scaling, and physical infrastructure management to the cloud provider. However, abstracting away server maintenance does not eliminate security obligations; on the contrary, it concentrates attack surfaces directly on application logic, identity federation, and inter-service IAM permissions.

In misconfigured serverless deployments, critical threat vectors emerge:

  • Overprivileged IAM Execution Roles: Lambda functions provisioned with AdministratorAccess or wildcard permissions (*) across DynamoDB, S3, or KMS. If code injection or insecure deserialization occurs, the attacker inherits full cloud tenancy rights.
  • Event Injection Vulnerabilities: Unlike monolithic web architectures that strictly process traditional HTTP requests, Lambda functions are triggered by heterogeneous event sources: API Gateway JSON payloads, SQS messages, DynamoDB streams, or EventBridge buses. Processing unsanitized event data directly yields SQL, NoSQL, or command injection.
  • Plaintext Secrets in Environment Variables: Hardcoding database credentials, third-party API tokens, or cryptographic private keys in plaintext Lambda environment variables, exposing them via AWS Management Console, GetFunction API calls, and CI/CD deployment logs.
  • Denial of Wallet and Concurrency Exhaustion: Omitting reserved concurrency limits and API Gateway throttling policies, enabling attackers to drive auto-scaling runaway costs and starve legitimate workloads of account-wide concurrency.

Engineering a resilient serverless architecture requires applying Zero Trust principles from the network edge to the internal compute runtime.


Reference Architecture: Authorization and Execution Flow

The enterprise architecture couples AWS WAF for perimeter rate-limiting and threat inspection, Amazon Cognito for identity management and OIDC token issuance, Amazon API Gateway for native edge JWT verification, AWS Lambda functions restricted by least-privilege IAM roles, and AWS Secrets Manager for secure, cached credential injection:

sequenceDiagram
    autonumber
    actor Client as Web / Mobile Client
    participant Cognito as Amazon Cognito User Pool
    participant WAF as AWS WAF (Rate Limiting)
    participant APIGW as Amazon API Gateway (Authorizer)
    participant Lambda as AWS Lambda (Least Privilege)
    participant Secrets as AWS Secrets Manager
    participant DB as Amazon DynamoDB

    Client->>Cognito: PKCE Authentication Flow (OAuth 2.1)
    Cognito-->>Client: Issue Signed JWTs (id_token + access_token)
    Client->>WAF: HTTPS Request with Bearer Token
    WAF->>APIGW: Sanitized Traffic (Anti-DDoS & Inspection)
    Note over APIGW: Edge JWT Validation:<br/>Cryptographic Signature, Expiry, Issuer & Scopes
    alt Invalid or Expired Token
        APIGW-->>Client: HTTP 401 Unauthorized (Zero Lambda Invocations)
    else Valid Token
        APIGW->>Lambda: Invocation with User Identity Claims
        Lambda->>Secrets: Fetch Credentials (In-Memory Local Cache)
        Secrets-->>Lambda: KMS-Decrypted Secret Value
        Lambda->>DB: CRUD Operation (Scoped by Exact Table ARN)
        DB-->>Lambda: Query Result Set
        Lambda-->>APIGW: JSON Response Payload
        APIGW-->>Client: HTTP 200 OK with Data
    end

1. Amazon Cognito User Pools: Identity Governance and OIDC Tokens

Amazon Cognito User Pools serves as the OAuth 2.1 and OpenID Connect (OIDC) Identity Provider (IdP), providing user registration, Multi-Factor Authentication (MFA), email/SMS account verification, and stringent password policies.

Secure Authentication Flow with PKCE

For modern Single Page Applications (SPAs) and mobile clients, the Authorization Code Flow with PKCE (Proof Key for Code Exchange) is mandatory, as detailed in our guide on modern authentication and authorization. The legacy Implicit Grant flow, which exposed raw tokens in browser URL fragments, is strictly deprecated.

Anatomy of Cognito JWT Tokens

Upon successful authentication, Cognito returns three tokens:

  1. ID Token (idtoken): Contains identity claims (sub, email, cognito:groups, preferredusername). Intended strictly for frontend presentation and UI customization.
  2. Access Token (access_token): Contains the subject identifier (sub), authorized OAuth scopes (e.g. aws.cognito.signin.user.admin or custom resource server scopes), and client metadata. This token must be transmitted in the Authorization: Bearer <token> header to access protected backend APIs.
  3. Refresh Token (refresh_token): Long-lived token stored inside secure HttpOnly cookies to renew token pairs without requiring re-authentication.

2. Amazon API Gateway: Edge Hardening and Validation

Delegating JWT verification to Lambda application code introduces latency and financial penalties: every unauthenticated request triggers Lambda execution costs. API Gateway must validate cryptographic assertions at the edge before invoking compute resources.

Cognito User Pool Authorizer vs. Custom Lambda Authorizer

API Gateway offers two distinct authorization models:

Evaluation Factor Cognito User Pool Authorizer Custom Lambda Authorizer
Mechanism Native JWT validation inside API Gateway infrastructure Separate Lambda execution validating tokens and synthesizing IAM policies
Cost per Verification Free (included in base API Gateway request price) Billed Lambda compute time per un-cached token
Latency Sub-millisecond (direct validation against Cognito JWKS public keys) 50–200 ms (subject to cold-start penalties)
Maintenance Declarative configuration with zero custom code Requires building, testing, and maintaining authorizer code
Target Use Case Standard authentication with Cognito User Pools Custom multi-tenant IdPs or legacy SQL lookup logic

For most modern AWS architectures, the native Cognito User Pool Authorizer provides superior performance, security, and cost efficiency.

JSON Schema Request Validation at Edge

To prevent malformed or malicious payloads from hitting Lambda functions, configure API Gateway Request Validators with strict JSON Schema definitions:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "CreateOrderRequest",
  "type": "object",
  "required": ["productId", "quantity", "shippingAddress"],
  "properties": {
    "productId": { "type": "string", "pattern": "^[a-f0-9\\-]{36}
quot; }, "quantity": { "type": "integer", "minimum": 1, "maximum": 100 }, "shippingAddress": { "type": "string", "minLength": 5, "maxLength": 200 } }, "additionalProperties": false }

If a client transmits extra unexpected properties or malformed parameters, API Gateway immediately rejects the request with HTTP 400 Bad Request, insulating backend functions from attack traffic and parsing overhead.


3. AWS Lambda: Least Privilege and Runtime Isolation

Every Lambda function must be treated as an isolated, ephemeral compute sandbox, adhering to the core tenets of enterprise microservices architecture.

Scoped IAM Execution Roles

Never assign blanket managed policies such as AmazonDynamoDBFullAccess or wildcard Resource: "*". Production IAM execution roles must restrict allowable API actions and bind specifically to target resource ARNs:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCloudWatchLogs",
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:eu-west-1:123456789012:log-group:/aws/lambda/orders-service:*"
    },
    {
      "Sid": "AllowSpecificDynamoDBOperations",
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:UpdateItem"
      ],
      "Resource": "arn:aws:dynamodb:eu-west-1:123456789012:table/ProductionOrders"
    },
    {
      "Sid": "AllowDecryptWithSpecificKMSKey",
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "arn:aws:kms:eu-west-1:123456789012:key/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
    }
  ]
}

Secure Secret Handling with AWS Lambda Extensions

Instead of injecting database passwords or third-party API keys directly into plaintext environment variables, leverage the official AWS Parameters and Secrets Lambda Extension. Running as a companion process within the Lambda execution environment, it pulls credentials over local HTTP sockets and maintains an in-memory cached copy:

// Node.js / TypeScript leveraging the local companion extension
async function getDatabaseSecret(): Promise<string> {
  const secretName = 'production/aurora/credentials';
  const url = `http://localhost:2773/secretsmanager/get?secretId=${encodeURIComponent(secretName)}`;

  const response = await fetch(url, {
    headers: {
      'X-Aws-Parameters-Secrets-Token': process.env.AWS_SESSION_TOKEN || '',
    },
  });

  if (!response.ok) {
    throw new Error(`Failed to retrieve secret: ${response.statusText}`);
  }

  const data = await response.json();
  return JSON.parse(data.SecretString).password;
}

Key security benefits:

  • Eliminates plaintext secrets from configuration consoles and Git repositories.
  • Transparently supports automated secret rotation without redeploying Lambda code.
  • Reduces Secrets Manager API cost and latency by over 90% via local TTL caching.

4. Mitigating Cold Starts and Optimizing Latency

Cold starts occur when AWS Lambda provisions a fresh Firecracker microVM, downloads package artifacts, and initializes the runtime environment (Node.js, Python, or JVM).

Recommended Latency Mitigations:

  1. AWS Lambda SnapStart (Java): For Java microservices, SnapStart pre-initializes the execution environment, takes an encrypted snapshot of the microVM memory and disk state, and restores it in sub-milliseconds on demand, eliminating JIT warm-up penalties.
  2. Provisioned Concurrency: For endpoints with strict SLAs, maintains a predetermined pool of pre-warmed execution environments ready to serve requests immediately.
  3. Artifact Bundling Optimization: Use bundlers like esbuild or build GraalVM Native Images to minimize deployment package footprint and reduce bootstrap decompression times.

5. Infrastructure as Code with AWS SAM

The following AWS Serverless Application Model (SAM) template formalizes the edge-to-compute security baseline:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Hardened Serverless Architecture with Cognito, API Gateway & Lambda

Globals:
  Function:
    Timeout: 10
    MemorySize: 512
    Runtime: nodejs20.x
    Architectures:
      - arm64 # Graviton architecture for optimal price-performance

Resources:
  # Secured API Gateway with native Cognito Authorizer
  SecureApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: prod
      Auth:
        DefaultAuthorizer: CognitoAuth
        Authorizers:
          CognitoAuth:
            UserPoolArn: !GetAtt CustomerUserPool.Arn
            Identity:
              Header: Authorization
              ValidationExpression: "^Bearer .*"

  # Least-privilege Lambda Function
  OrderProcessingFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Events:
        CreateOrder:
          Type: Api
          Properties:
            RestApiId: !Ref SecureApiGateway
            Path: /orders
            Method: post

  # Cognito User Pool
  CustomerUserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      UserPoolName: production-customer-pool
      Policies:
        PasswordPolicy:
          MinimumLength: 12
          RequireUppercase: true
          RequireLowercase: true
          RequireNumbers: true
          RequireSymbols: true
      MfaConfiguration: "OPTIONAL"

Governance and Security Checklist

  • [x] Client authentication restricted to OAuth 2.1 Authorization Code Flow with PKCE.
  • [x] Cryptographic JWT signature and expiration verified at the API Gateway edge.
  • [x] Strict JSON Schema request validation enabled to reject malformed input.
  • [x] Lambda IAM execution roles tightly scoped to explicit resource ARNs.
  • [x] Secrets retrieved dynamically via AWS Secrets Manager extension with in-memory caching.
  • [x] Concurrency quotas and WAF throttling deployed to protect against Denial-of-Wallet attacks.

If you need to audit your organization's cloud architecture, implement Zero Trust bastions, or harden container clusters and serverless backends, explore my Cybersecurity Consulting Services or reach out directly via About Me.