Back to Blog
How-To 10 min read

SOC 2 Controls for AWS Lambda: Serverless Security That Auditors Accept

Implement SOC 2 controls in AWS Lambda functions — covering IAM execution roles, secrets injection, function-level logging, cold start security, and dependency scanning for serverless.

Key Takeaways
  • Assign a dedicated IAM execution role per Lambda function with only the permissions that function needs — never reuse a shared permissive role.
  • Inject secrets via AWS Secrets Manager or Parameter Store at function startup — never pass them as environment variable plaintext in the Lambda console.
  • Enable CloudWatch Logs structured logging with request ID and user context on every Lambda invocation.
  • Use Lambda Layers for shared dependencies and scan layer contents with Inspector or Trivy.
  • Enable AWS Config rules for Lambda to detect functions with over-privileged roles or disabled logging.

SOC 2 and serverless: what changes

Lambda abstracts away servers, but SOC 2 controls still apply to the function code and its permissions. The shared responsibility model for Lambda: AWS manages the execution environment, OS patches, and infrastructure. You are responsible for function code, IAM execution roles, environment variables, and network configuration.

Serverless changes some control implementations: there is no long-running process to secure, no SSH access to harden, and no persistent disk to encrypt. But logical access (CC6), monitoring (CC7), and change management (CC8) still require explicit configuration.

Auditors probe Lambda for: overly permissive execution roles (wildcards in the IAM policy), secrets stored as plaintext environment variables visible in the Lambda console, missing or disabled CloudWatch logging, and functions deployed outside of a CI/CD pipeline (manual zip uploads).

IAM execution roles per function

Create one IAM execution role per Lambda function. Use the principle of least privilege: if the function only reads from one DynamoDB table, the role should have only `dynamodb:GetItem` and `dynamodb:Query` on that specific table ARN. Avoid `Resource: "*"` in Lambda execution role policies.

Enforce this with IAM Access Analyzer: enable it in your AWS account and review findings that highlight over-privileged Lambda roles. Configure Access Analyzer to alert on policies with `*` actions or `*` resources in the Lambda execution role.

Use AWS CDK or Terraform to define Lambda execution roles as code. Policy-as-code means roles go through your change management process (code review, PR approval) before deployment, satisfying CC8.1.

Secrets injection in Lambda

Do not store database passwords or API keys as Lambda environment variables in plaintext — they are visible to anyone with Lambda:GetFunctionConfiguration permission. Use AWS Secrets Manager or Parameter Store (SecureString).

Pattern for Secrets Manager: initialise the boto3 or AWS SDK client outside the handler (in the global scope) so it runs once on cold start. Fetch the secret and cache it in a module-level variable. Add a TTL check to refresh secrets periodically (every 5 minutes) without requiring a cold start.

For Parameter Store SecureStrings, use `ssm.get_parameter(Name=name, WithDecryption=True)`. Grant the Lambda execution role `ssm:GetParameter` on the specific parameter ARN and `kms:Decrypt` on the KMS key used to encrypt the SecureString.

Structured logging and CloudWatch

Lambda automatically sends stdout and stderr to CloudWatch Logs. Ensure your function writes structured JSON logs, not plain text. Add fields: request_id (from context.aws_request_id), function_name (from context.function_name), user_id (from your auth token), and event_type.

Enable Lambda Insights for enhanced monitoring: function duration, memory usage, cold starts, and error rates. Lambda Insights is an extension that writes a performance log event after each invocation.

Set a retention policy on each Lambda log group. Lambda creates log groups automatically, but retention defaults to Never Expire. Use a Lambda-backed custom resource or AWS Config auto-remediation to enforce a 365-day retention policy on all /aws/lambda/* log groups.

Dependency scanning for Lambda packages

Lambda function packages include all dependencies in the deployment zip. Scan the zip contents with Trivy (`trivy fs ./function-package`) or Snyk (`snyk test`) in CI before deployment. Both tools detect CVEs in Python, Node.js, Java, and Go dependency trees.

For Lambda Layers (shared dependency packages), scan layer contents independently. Treat a layer update as a deployment event requiring the same CI scanning gate as function code changes.

Use AWS Inspector Lambda scanning (Inspector v2) for continuous post-deployment scanning. Inspector scans function packages for vulnerabilities and surfaces findings in the Inspector console and Security Hub. Configure Security Hub to create OpsCenter issues for critical/high Inspector findings.

AWS Config rules for Lambda compliance

Enable these AWS Config managed rules for Lambda: `lambda-function-settings-check` (verifies function timeout, memory, and runtime are within policy), `lambda-inside-vpc` (verifies functions requiring VPC access are actually in a VPC), and `lambda-function-public-access-prohibited` (verifies no Lambda has a resource-based policy allowing public invocation).

Create a custom Config rule using AWS Config Rule Development Kit to check that all Lambda execution roles do not contain `Resource: "*"` with write actions. Run this rule on configuration change for any Lambda function or IAM role.

Set up Config conformance packs that bundle Lambda rules with your other infrastructure rules (S3, RDS, EC2). This gives auditors a single dashboard showing compliance posture across your entire AWS account.

Lambda SOC 2 checklist

Before your audit: (1) One IAM execution role per function — no shared permissive roles. (2) No plaintext secrets in Lambda environment variables. (3) Secrets fetched from Secrets Manager or Parameter Store at cold start. (4) Structured JSON logging with request_id and user_id. (5) CloudWatch log group retention set to 365 days on all Lambda log groups. (6) Trivy or Snyk scan in CI for every function package. (7) AWS Config rules enabled and passing. (8) No Lambda functions with public resource-based policies.

Evidence to collect: IAM execution role policy JSON for each function, AWS Config compliance dashboard screenshot, Inspector findings report, CloudWatch log retention settings screenshot, and a sample Lambda log showing structured JSON output.

Frequently Asked Questions

Does AWS Lambda have a SOC 2 report?
Yes — Lambda is covered under the AWS SOC 2 Type II report. The AWS report covers infrastructure controls for the Lambda service itself (the execution environment, the control plane). Your responsibility includes function code, IAM roles, environment configuration, and the runtime dependencies you package.
How does Lambda cold start affect security?
Cold starts are a performance concern, not a direct security concern. However, secrets fetched on cold start have a window of exposure if the cold start is very slow and times out — ensure your secrets fetch has a timeout and error handling so the function fails closed (returns 503) rather than proceeding without credentials.
Should Lambda functions be in a VPC?
Place Lambda functions in a VPC only if they need to access VPC resources (RDS, ElastiCache, internal services). VPC placement adds cold start latency. If a Lambda only calls public AWS APIs (DynamoDB, S3, Secrets Manager), VPC placement is not required and adds complexity without security benefit.
How do I manage Lambda function versions for change management?
Use Lambda versions and aliases. Publish a new version on each deployment (aws lambda publish-version). Use aliases (prod, staging) that point to specific versions. This creates an immutable record of every deployed version, supporting CC8.1 (change management) with rollback capability.
Is Lambda function URL a SOC 2 risk?
Lambda function URLs allow direct HTTP invocation without API Gateway. They are fine for authenticated use cases but must not be configured with auth-type NONE (public). If you use function URLs, set AuthType to AWS_IAM and control access via resource-based policies. Consider this a high-risk misconfiguration if left as public.

Automate your compliance today

AuditPath runs 86+ automated checks across AWS, GitHub, Okta, and 14 more integrations. SOC 2 and DPDP Act. Free plan available.

Start for free