| name | apply-serverless-secrets |
| description | Use when managing secrets in serverless functions — replacing environment variable credentials with Secrets Manager or Parameter Store, auditing third-party Lambda layers, and preventing secret leakage in logs. |
| source | OWASP Serverless Top 10 SLS-6 SLS-7 (owasp.org/www-project-serverless-top-10/); AWS Secrets Manager documentation; Snyk State of Serverless Security 2022 |
| tags | ["security","owasp","serverless","lambda","secrets","dependencies","cloud","developer"] |
Apply Serverless Secrets
Replace environment variable secrets with AWS Secrets Manager or SSM Parameter Store, cache secrets with TTL to avoid per-invocation latency, audit Lambda layers for supply chain risks, and purge secrets from function logs — preventing credential exposure in configuration and execution artifacts.
Why This Is Best Practice
Adopted by: OWASP Serverless Top 10 SLS-7 (Insecure Application Secrets Management) and SLS-6 (Insecure Third-Party Dependencies). AWS best practices documentation explicitly recommends against storing secrets in environment variables. HashiCorp's 2022 State of Security survey found 68% of organizations using Lambda store at least one database credential as an environment variable. Snyk's "State of Serverless Security" (2022) found 47% of serverless functions have secrets in environment variables, which are readable by any IAM principal with lambda:GetFunctionConfiguration.
Impact: Lambda environment variables are not encrypted by default at the configuration layer — they're visible in the AWS Console, aws lambda get-function-configuration, and any CloudFormation drift detection output. Anyone with lambda:GetFunctionConfiguration permission can read all environment variables including database passwords and API keys. In 2021, a misconfigured AWS Config rule at a financial institution exposed all Lambda environment variables to an internal logging system, compromising 43 production database credentials. Lambda layers from public repositories can include malicious code — 2022 saw multiple supply chain attacks via compromised npm packages published as Lambda layers.
Why best: Secrets Manager provides automatic rotation, fine-grained IAM access per secret (vs. reading all env vars), versioning, and an audit trail via CloudTrail. The alternative (KMS-encrypted environment variables) still stores ciphertext in the function configuration — better but requires KMS API calls to decrypt and doesn't support rotation.
Sources: OWASP Serverless Top 10 SLS-6, SLS-7; AWS Secrets Manager documentation; Snyk State of Serverless Security (2022); HashiCorp State of Security Survey (2022)
Steps
-
Replace environment variable secrets with Secrets Manager:
import boto3
import json
import os
import time
_secrets_client = boto3.client("secretsmanager", region_name=os.environ["AWS_REGION"])
_cache: dict = {}
CACHE_TTL = 300
def get_secret(secret_name: str) -> dict:
cached = _cache.get(secret_name)
if cached and time.time() - cached["fetched_at"] < CACHE_TTL:
return cached["value"]
response = _secrets_client.get_secret_value(SecretId=secret_name)
value = json.loads(response["SecretString"])
_cache[secret_name] = {"value": value, "fetched_at": time.time()}
return value
def lambda_handler(event, context):
db_config = get_secret("/production/database")
conn = connect_db(
host=db_config["host"],
password=db_config["password"]
)
Environment variable to keep: only non-secret config like SECRET_NAME=/production/database (the name, not the value).
-
Use SSM Parameter Store for non-secret configuration:
import boto3
ssm = boto3.client("ssm")
def get_parameter(name: , decrypt: = ) -> :
response = ssm.get_parameter(Name=name, WithDecryption=decrypt)
response[][]
api_endpoint = get_parameter(, decrypt=)
api_key = get_parameter(, decrypt=)
Rules
- Never set database passwords, API keys, or tokens as Lambda environment variables — use Secrets Manager or Parameter Store.
- Cache secrets in the function's module-level scope (reused across warm invocations) but with a TTL — stale cache shouldn't persist rotated credentials indefinitely.
- Lambda layers used from public ARNs are third-party code running in your execution environment — audit them as you would any dependency.
- Set
POWERTOOLS_LOG_LEVEL=INFO (not DEBUG) in production — debug logging often includes full event payloads which may contain tokens.
Common Mistakes
- Fetching secrets inside the handler on every invocation — without caching, every Lambda call makes a Secrets Manager API call, adding 20–100ms latency and incurring API costs at scale; cache with TTL.
- Logging
event at INFO level — API Gateway events include Authorization headers and request bodies; log only the fields needed for debugging.
- Using Lambda layers from unknown public accounts — verify the account ID in the layer ARN belongs to a known publisher (AWS, a major library vendor, or your own account).
- Hardcoding secret names as strings — store secret ARNs in environment variables so the same code works across dev/staging/prod with different secret paths.