OWASPCheat Sheet

CS-Serverless_FaaS_Security Serverless / FaaS Security Cheat Sheet

Official page ↗
Project
OWASP Cheat Sheet Series

Introduction

Serverless computing (Functions as a Service — FaaS) platforms such as AWS Lambda, Azure Functions, and Google Cloud Functions simplify application development and scaling. However, the execution model (short-lived, event-driven functions running in managed environments) introduces unique security risks compared to traditional architectures. This cheat sheet provides best practices to secure serverless applications and minimize attack surfaces.

Key Risks

• Over-permissioned functions (broad IAM roles, `*` policies). • Unvalidated event inputs (API Gateway, S3, Pub/Sub, IoT). • Cold start data leakage (persistent state, side-channel timing). • Function chaining abuse (compromised function invoking others). • Shared environment risks (multi-tenant leakage, `/tmp` reuse). • Hardcoded secrets in code or platform config. • Excessive network access.

Best Practices

1. Principle of Least Privilege • Assign minimal IAM permissions to each function. • Use role-per-function (avoid shared high-privilege roles). • Scope database/API keys to the smallest set of actions needed. Bad IAM Policy (too broad): ```json { "Effect": "Allow", "Action": "*", "Resource": "*" } ``` Good IAM Policy (scoped): ```json { "Effect": "Allow", "Action": ["dynamodb:GetItem", "dynamodb:PutItem"], "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/Orders" } ``` 2. Environment Isolation • Disable default network access unless required (e.g. outbound internet access). • Place functions in private subnets with controlled egress. • Isolate sensitive functions (e.g. payment, auth) from general-purpose ones. • Separate production vs. staging environments with strict boundaries. AWS Lambda VPC Config (restrictive): ```yaml VpcConfig: SubnetIds: • subnet-123456 SecurityGroupIds: • sg-restrict-outbound ``` 3. Secure Function Invocation • Enforce authentication and authorization on all triggers (API Gateway, Pub/Sub, S3, IoT). • Validate function-to-function calls with signed tokens or workload identities. • Apply rate limiting and throttling to mitigate DoS and abuse. API Gateway Authorizer Example (JWT validation): ```json { "Type": "JWT", "IdentitySource": "$request.header.Authorization", "Issuer": "https://secure-idp.example.com/", "Audience": "my-api-client" } ``` 4. Event Data Validation • Treat all event payloads as untrusted input. • Apply strong input validation & sanitization (length, type, format). • Protect against common injection attacks (SQLi, XSS, JSON injection, deserialization). • Strip unnecessary fields and metadata before processing. Example: Python input validation for Lambda ```python import json import re def lambda_handler(event, context): body = json.loads(event["body"]) email = body.get("email", "") if not re.match(r"[^@]+@[^@]+\.[^@]+", email): return {"statusCode": 400, "body": "Invalid email"} # process safely return {"statusCode": 200, "body": "OK"} ``` 5. Cold Start & Execution Context Security • Do not assume function runtime context is clean between invocations. • Avoid storing secrets or temporary sensitive data in global/static variables. • Protect against side-channel leaks (timing differences, leftover files in /tmp). • For sensitive workloads, enforce single-use execution environments if the platform supports it. Bad: ```python # Secret stays in global variable across invocations SECRET_KEY = "hardcoded-secret" ``` Good: ```python import os from my_secrets_lib import get_secret def lambda_handler(event, context): secret = get_secret("db-password") # fetch fresh each time ... ``` 6. Secrets Management See the Secrets Management Cheat Sheet for secret lifecycle controls. • Fetch secrets at runtime from a vault or caching extension — not from platform-level function configuration (e.g. Lambda Environment Variables). • Use ephemeral credentials (STS, workload identity federation). • Rotate secrets automatically. AWS Lambda Secret Fetch (Python via Parameters and Secrets Extension): Note: Ensure that the AWS Lambda Parameters and Secrets Extension is added and enabled for your function (for example, as a Lambda layer). Otherwise, `http://localhost:2773` will not be available and requests to it will fail. ```python import os import json import urllib.request import urllib.parse def get_secret(secret_name): """ Retrieves a secret using the AWS Lambda Extension local endpoint. This method is faster and more cost-effective due to local caching. """ # The extension provides a local HTTP endpoint on port 2773 encoded_name = urllib.parse.quote_plus(secret_name) secrets_extension_endpoint = ( f"http://localhost:2773/secretsmanager/get?secretId={encoded_name}" ) # Authenticate using the identity token provided by the Lambda environment. # Fail fast if the token is missing to avoid confusing 4xx errors. session_token = os.environ.get("AWS_SESSION_TOKEN") if not session_token: raise RuntimeError( "Missing AWS_SESSION_TOKEN required for " "Parameters and Secrets Extension authentication." ) headers = { "X-Aws-Parameters-Secrets-Token": session_token } request = urllib.request.Request( secrets_extension_endpoint, headers=headers, method="GET" ) with urllib.request.urlopen(request, timeout=3) as response: if response.status != 200: raise Exception( f"Error retrieving secret: {response.read().decode('utf-8')}" ) response_json = json.loads(response.read()) secret_string = response_json["SecretString"] return json.loads(secret_string) ``` 7. Monitoring & Logging • Use centralized logging (CloudWatch, Azure Monitor, GCP Logging). • Mask secrets and PII. Example: Redacting fields ```python import logging def log_event(event): safe_event = {k: ("***" if "password" in k else v) for k,v in event.items()} logging.info(safe_event) ``` 8. Supply Chain Security • Scan dependencies (`npm audit`, `pip-audit`, `safety`). • Use minimal deployment packages. • Sign deployment packages and verify signatures against an approved publisher before deployment. A checksum alone does not authenticate the publisher. For AWS Lambda, use code signing configurations with allowed signing profiles and `UntrustedArtifactOnDeployment` set to `Enforce`; the default `Warn` setting allows deployments that fail expiry, publisher, or revocation checks. Layers added to functions with code signing enabled must also be signed by an allowed profile.

Do’s and Don’ts

Do: • Enforce least privilege per function. • Validate all event inputs. • Fetch secrets from vaults, not platform config. • Restrict network egress. • Monitor invocations and logs. Don’t: • Hardcode secrets in code or configs. • Assume clean runtime between invocations. • Give `*` IAM permissions. • Leave sensitive data in `/tmp` or globals. • Trust event sources blindly.

References