securing-serverless-functions について
Lambda や Azure Functions などのサーバーレス関数を保護・監査するための、開発者やクラウドセキュリティチーム向けガイドです。最小権限、シークレット管理、依存関係スキャン、入力検証、実行時監視を扱います。
主な機能
- 01関数の IAM 権限を制限
- 02シークレット管理サービスで認証情報を保管
- 03CI/CD で依存関係をスキャン
- 04イベント入力の検証とサニタイズ
- 05実行時監視とログの設定
活用シーン
- 01サーバーレス関数の過剰な権限の監査
- 02デプロイ前の脆弱な依存関係の検出
- 03ハードコードされたシークレットや入力インジェクションの調査
- 04関数の異常な動作の監視
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill securing-serverless-functionsインストール後、Claude Code で/securing-serverless-functionsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEreferences/api-reference.mdscripts/agent.py詳細
サーバーレス関数のセキュリティ保護
使用するタイミング
- 機密データやクラウド API にアクセスする Lambda 関数または Azure Functions をデプロイするとき
- 過剰に許可された IAM ロールがないか、既存のサーバーレスワークロードを監査するとき
- 自動セキュリティスキャンを実施する DevSecOps パイプラインにサーバーレス関数を統合するとき
- 関数コード内にハードコードされたシークレットや脆弱な依存関係が見つかったとき
- インジェクションや認証情報の窃取を検出するため、サーバーレスワークロードのランタイム監視を確立するとき
使用しないでください。コンテナベースのコンピューティングのセキュリティ(securing-kubernetes-on-cloud を参照)、API Gateway の設定(implementing-cloud-waf-rules を参照)、またはサーバーレスアーキテクチャの設計判断には使用しないでください。
前提条件
- デプロイアクセス権のある AWS Lambda、Azure Functions、または GCP Cloud Functions
- 依存関係スキャンツール(npm audit、Snyk、Dependabot)を備えた CI/CD パイプライン
- シークレット管理用の AWS Secrets Manager、Azure Key Vault、または HashiCorp Vault
- 関数監視用の CloudWatch、Application Insights、または Cloud Logging
ワークフロー
ステップ 1:最小権限の IAM ロールを適用する
各 Lambda 関数に専用の IAM ロールを割り当て、アクセスする特定のリソースだけに権限を限定します。関数間で IAM ロールを共有しないでください。
# Create a least-privilege role for a specific Lambda function
aws iam create-role \
--role-name order-processor-lambda-role \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "lambda.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}'
# Attach a scoped policy (not AmazonDynamoDBFullAccess)
aws iam put-role-policy \
--role-name order-processor-lambda-role \
--policy-name order-processor-policy \
--policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["dynamodb:PutItem", "dynamodb:GetItem"],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/Orders"
},
{
"Effect": "Allow",
"Action": ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"],
"Resource": "arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/order-processor:*"
},
{
"Effect": "Allow",
"Action": ["secretsmanager:GetSecretValue"],
"Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:order-api-key-*"
}
]
}'
ステップ 2:ハードコードされたシークレットを排除する
環境変数内の平文の認証情報を、シークレット管理サービスへの参照に置き換えます。Lambda 拡張機能または SDK 呼び出しを使用して、実行時にシークレットを取得します。
# INSECURE: Hardcoded credentials in environment variable
# DB_PASSWORD = os.environ['DB_PASSWORD'] # Stored as plaintext in Lambda config
# SECURE: Retrieve from AWS Secrets Manager with caching
import boto3
from botocore.exceptions import ClientError
import json
_secret_cache = {}
def get_secret(secret_name):
if secret_name in _secret_cache:
return _secret_cache[secret_name]
client = boto3.client('secretsmanager')
response = client.get_secret_value(SecretId=secret_name)
secret = json.loads(response['SecretString'])
_secret_cache[secret_name] = secret
return secret
def lambda_handler(event, context):
db_creds = get_secret('production/database/credentials')
db_host = db_creds['host']
db_password = db_creds['password']
# Use credentials securely
# Enable encryption at rest for Lambda environment variables
aws lambda update-function-configuration \
--function-name order-processor \
--kms-key-arn arn:aws:kms:us-east-1:123456789012:key/key-id
ステップ 3:依存関係の脆弱性をスキャンする
CI/CD パイプラインに自動依存関係スキャンを統合し、デプロイ前に脆弱なパッケージを検出します。
# npm audit for Node.js Lambda functions
cd lambda-function/
npm audit --audit-level=high
npm audit fix
# Snyk scanning in CI/CD pipeline
snyk test --severity-threshold=high
snyk monitor --project-name=order-processor-lambda
# pip-audit for Python Lambda functions
pip-audit -r requirements.txt --desc on --fix
# Scan Lambda deployment package with Trivy
trivy fs --severity HIGH,CRITICAL ./lambda-package/
# GitHub Actions CI/CD security scanning
name: Lambda Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: npm ci
- name: Run npm audit
run: npm audit --audit-level=high
- name: Snyk vulnerability scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
- name: Scan with Semgrep for code vulnerabilities
uses: returntocorp/semgrep-action@v1
with:
config: p/owasp-top-ten
ステップ 4:入力検証を実装する
すべてのイベント入力データを検証およびサニタイズし、Lambda イベントソースを介した SQL インジェクション、コマンドインジェクション、NoSQL インジェクションなどの攻撃を防ぎます。
import re
import json
from jsonschema import validate, ValidationError
# Define expected input schema
ORDER_SCHEMA = {
"type": "object",
"properties": {
"orderId": {"type": "string", "pattern": "^[a-zA-Z0-9-]{1,36}$"},
"customerId": {"type": "string", "pattern": "^[a-zA-Z0-9]{1,20}$"},
"amount": {"type": "number", "minimum": 0.01, "maximum": 999999.99},
"currency": {"type": "string", "enum": ["USD", "EUR", "GBP"]}
},
"required": ["orderId", "customerId", "amount", "currency"],
"additionalProperties": False
}
def lambda_handler(event, context):
# Validate API Gateway event body
try:
body = json.loads(event.get('body', '{}'))
validate(instance=body, schema=ORDER_SCHEMA)
except (json.JSONDecodeError, ValidationError) as e:
return {
'statusCode': 400,
'body': json.dumps({'error': 'Invalid input', 'details': str(e)})
}
# Safe to proceed with validated input
order_id = body['orderId']
# Use parameterized queries for database operations
ステップ 5:関数 URL と API Gateway の認証を設定する
適切な認証を設定して、関数の呼び出しエンドポイントを保護します。IAM 認証または Cognito 認証なしで Lambda 関数 URL を公開しないでください。
# Secure Lambda function URL with IAM auth (not NONE)
aws lambda create-function-url-config \
--function-name order-processor \
--auth-type AWS_IAM \
--cors '{
"AllowOrigins": ["https://app.company.com"],
"AllowMethods": ["POST"],
"AllowHeaders": ["Content-Type", "Authorization"],
"MaxAge": 3600
}'
# API Gateway with Cognito authorizer
aws apigateway create-authorizer \
--rest-api-id abc123 \
--name CognitoAuth \
--type COGNITO_USER_POOLS \
--provider-arns "arn:aws:cognito-idp:us-east-1:123456789012:userpool/us-east-1_EXAMPLE"
ステップ 6:ランタイム監視とログ記録を有効にする
GuardDuty Lambda Network Activity Monitoring と CloudWatch の構造化ログを設定し、関数の異常な動作を検出します。
# Enable GuardDuty Lambda protection
aws guardduty update-detector \
--detector-id <detector-id> \
--features '[{"Name": "LAMBDA_NETWORK_ACTIVITY_LOGS", "Status": "ENABLED"}]'
# Configure Lambda to use structured logging
aws lambda update-function-configuration \
--function-name order-processor \
--logging-config '{"LogFormat": "JSON", "ApplicationLogLevel": "INFO", "SystemLogLevel": "WARN"}'
主な概念
| 用語 | 定義 |
|---|---|
| コールドスタート | コンテナのプロビジョニングを含む関数の初回呼び出しです。レイテンシが増加し、キャッシュされたシークレットを利用できない時間が発生します |
| イベントインジェクション | API Gateway、S3、SQS、またはその他のイベントソースからの Lambda イベントデータに悪意のある入力を埋め込み、関数を悪用する攻撃です |
| 実行ロール | 実行中に Lambda が引き受ける IAM ロールで、関数が使用できるすべてのクラウド API 権限を定義します |
| 関数 URL | Lambda 関数の直接 HTTPS エンドポイントです。IAM 認証または認証なしで設定できます(NONE は安全ではありません) |
| レイヤー | 共有コードまたは依存関係を含む Lambda のデプロイパッケージです。脆弱性がないか個別にスキャンする必要があります |
| 予約済み同時実行数 | 関数の同時実行数の上限です。リソース枯渇攻撃の防止に役立ちます |
| プロビジョニング済み同時実行数 | コールドスタートのレイテンシを削減し、シークレットのキャッシュを確保する、事前に初期化された関数インスタンスです |
ツールとシステム
- AWS Lambda Power Tuning:セキュリティとパフォーマンスのバランスを取るため、Lambda のメモリとタイムアウトの設定を最適化するオープンソースツールです。
- Snyk:Lambda の依存関係をスキャンして既知の脆弱性を検出し、自動修正の提案を行う SCA ツールです。
- Semgrep:サーバーレスに特化したルールを備え、インジェクションの脆弱性、ハードコードされたシークレット、安全でない設定を検出する SAST ツールです。
- GuardDuty Lambda Protection:Lambda のネットワークアクティビティを監視し、悪意のあるエンドポイントへの接続を検出する AWS サービスです。
- AWS X-Ray:分散トレーシングサービスです。Lambda の呼び出しにおける不審な外部接続やレイテンシーの異常を検出します。
よくあるシナリオ
シナリオ:API Gateway から Lambda、RDS への経路での SQL インジェクション
コンテキスト:Lambda 関数が API Gateway からユーザー入力を受け取り、文字列連結によって SQL クエリを組み立て、RDS PostgreSQL データベースに対して実行します。攻撃者は API 経由で SQL ペイロードを挿入します。
アプローチ:
- Lambda 関数のコードを監査し、SQL クエリで文字列連結が使われている箇所を確認します。
- 文字列形式のクエリをすべて、データベースドライバーを使ったパラメーター化クエリに置き換えます。
- データベース操作の前に、JSON Schema を使用して入力検証を実装します。
- API Gateway に WAF ルールを追加し、一般的な SQL インジェクションのパターンをブロックします。
- CI/CD パイプラインに Semgrep を導入し、
python.django.security.injection.sqlルールセットを使用します。 - GuardDuty Lambda Protection を有効にして、異常なデータベース接続パターンを検出します。
注意点:根本的なコードの脆弱性を修正せずに WAF ルールだけに頼ると、攻撃者はエンコードの細工によって回避できます。ORM メソッドを誤って使用した場合(生のクエリなど)も、インジェクションが可能です。
出力形式
Serverless Security Assessment Report
=======================================
Account: 123456789012
Functions Assessed: 47
Assessment Date: 2025-02-23
CRITICAL FINDINGS:
[SLS-001] order-processor: SQL injection via string concatenation
Language: Python 3.12 | Runtime: Lambda
Vulnerable Code: f"SELECT * FROM orders WHERE id = '{order_id}'"
Remediation: Use parameterized queries with psycopg2
[SLS-002] payment-handler: Hardcoded Stripe API key in environment variable
Key: sk_live_XXXX... (unencrypted)
Remediation: Migrate to AWS Secrets Manager with KMS encryption
HIGH FINDINGS:
[SLS-003] 12 functions share the same IAM execution role with s3:*
[SLS-004] 8 functions have function URLs with AuthType: NONE
[SLS-005] 23 functions have dependencies with known HIGH CVEs
DEPENDENCY VULNERABILITIES:
[email protected]: CVE-2023-45857 (HIGH) - 5 functions affected
[email protected]: CVE-2022-23529 (CRITICAL) - 3 functions affected
[email protected]: CVE-2021-23337 (HIGH) - 11 functions affected
SUMMARY:
Critical: 2 | High: 5 | Medium: 12 | Low: 8
Functions with Least Privilege: 14/47 (30%)
Functions with Secrets Manager: 19/47 (40%)
Functions with Input Validation: 22/47 (47%)