Serverless.com セキュリティ

Reading time: 29 minutes

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

基本情報

組織

組織は、Serverless Frameworkエコシステム内の最上位のエンティティです。これは、複数のプロジェクト、チーム、およびアプリケーションを包含する集団、例えば会社、部門、またはその他の大規模なエンティティを表します。

チーム

チームは、組織内にアクセスを持つユーザーです。チームは、役割に基づいてメンバーを整理するのに役立ちます。**コラボレーターは既存のアプリを表示およびデプロイでき、管理者**は新しいアプリを作成し、組織の設定を管理できます。

アプリケーション

アプリは、組織内の関連サービスの論理的なグループ化です。これは、複数のサーバーレスサービスで構成され、協調して機能を提供する完全なアプリケーションを表します。

サービス

サービスは、サーバーレスアプリケーションのコアコンポーネントです。これは、すべての関数、設定、および必要なリソースをカプセル化した、あなたの全サーバーレスプロジェクトを表します。通常、serverless.ymlファイルで定義され、サービスにはサービス名、プロバイダー設定、関数、イベント、リソース、プラグイン、およびカスタム変数などのメタデータが含まれます。

yaml
service: my-service
provider:
name: aws
runtime: nodejs14.x
functions:
hello:
handler: handler.hello
Function

Functionは、AWS Lambda関数のような単一のサーバーレス関数を表します。これは、イベントに応じて実行されるコードを含んでいます。

これは、serverless.ymlfunctionsセクションで定義され、ハンドラー、ランタイム、イベント、環境変数、およびその他の設定を指定します。

yaml
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
イベント

イベントは、サーバーレス関数を呼び出すトリガーです。関数がどのように、いつ実行されるべきかを定義します。

一般的なイベントタイプには、HTTPリクエスト、スケジュールされたイベント(cronジョブ)、データベースイベント、ファイルアップロードなどがあります。

yaml
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
- schedule:
rate: rate(10 minutes)
リソース

リソース は、データベース、ストレージバケット、またはIAMロールなど、サービスが依存する追加のクラウドリソースを定義することを可能にします。

それらは resources セクションの下に指定され、通常はAWSのCloudFormation構文を使用します。

yaml
resources:
Resources:
MyDynamoDBTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: my-table
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
プロバイダー

プロバイダーオブジェクトは、クラウドサービスプロバイダー(例:AWS、Azure、Google Cloud)を指定し、そのプロバイダーに関連する設定を含みます。

ランタイム、リージョン、ステージ、認証情報などの詳細が含まれています。

yaml
yamlCopy codeprovider:
name: aws
runtime: nodejs14.x
region: us-east-1
stage: dev
ステージとリージョン

ステージは、サービスがデプロイできる異なる環境(例:開発、ステージング、本番)を表します。これは、環境固有の設定とデプロイを可能にします。

yaml
provider:
stage: dev

リージョンは、リソースが展開される地理的地域を指定します。これは、レイテンシ、コンプライアンス、および可用性の考慮にとって重要です。

yaml
provider:
region: us-west-2
プラグイン

プラグイン は、Serverless Frameworkの機能を拡張し、新しい機能を追加したり、他のツールやサービスと統合したりします。これらは plugins セクションで定義され、npmを介してインストールされます。

yaml
plugins:
- serverless-offline
- serverless-webpack
レイヤー

レイヤーは、共有コードや依存関係を関数とは別にパッケージ化して管理することを可能にします。これにより再利用性が促進され、デプロイメントパッケージのサイズが削減されます。レイヤーはlayersセクションで定義され、関数によって参照されます。

yaml
layers:
commonLibs:
path: layer-common
functions:
hello:
handler: handler.hello
layers:
- { Ref: CommonLibsLambdaLayer }
変数とカスタム変数

変数 は、デプロイ時に解決されるプレースホルダーの使用を許可することによって動的な構成を可能にします。

  • 構文: ${variable} 構文は、環境変数、ファイルの内容、または他の構成パラメータを参照できます。
yaml
functions:
hello:
handler: handler.hello
environment:
TABLE_NAME: ${self:custom.tableName}
  • カスタム変数: custom セクションは、serverless.yml 全体で再利用できるユーザー固有の変数と構成を定義するために使用されます。
yaml
custom:
tableName: my-dynamodb-table
stage: ${opt:stage, 'dev'}
出力

出力 は、サービスがデプロイされた後に返される値を定義します。これにはリソースARN、エンドポイント、またはその他の有用な情報が含まれます。これらは outputs セクションの下に指定され、他のサービスに情報を公開したり、デプロイ後の簡単なアクセスのために使用されることがよくあります。

yaml
¡outputs:
ApiEndpoint:
Description: "API Gateway endpoint URL"
Value:
Fn::Join:
- ""
- - "https://"
- Ref: ApiGatewayRestApi
- ".execute-api."
- Ref: AWS::Region
- ".amazonaws.com/"
- Ref: AWS::Stage
IAMロールと権限

IAMロールと権限 は、あなたの関数やその他のリソースのセキュリティ資格情報とアクセス権を定義します。これらは、必要な権限を指定するために provider または個々の関数設定の下で管理されます。

yaml
provider:
[...]
iam:
role:
statements:
- Effect: 'Allow'
Action:
- 'dynamodb:PutItem'
- 'dynamodb:Get*'
- 'dynamodb:Scan*'
- 'dynamodb:UpdateItem'
- 'dynamodb:DeleteItem'
Resource: arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/${self:service}-customerTable-${sls:stage}
環境変数

変数を使用すると、設定や秘密を関数にハードコーディングすることなく渡すことができます。これらは、プロバイダーまたは個々の関数のenvironmentセクションの下で定義されます。

yaml
provider:
environment:
STAGE: ${self:provider.stage}
functions:
hello:
handler: handler.hello
environment:
TABLE_NAME: ${self:custom.tableName}
依存関係

依存関係 は、あなたの関数が必要とする外部ライブラリやモジュールを管理します。通常、npmやpipのようなパッケージマネージャーを介して処理され、serverless-webpackのようなツールやプラグインを使用してデプロイメントパッケージにバンドルされます。

yaml
plugins:
- serverless-webpack
フック

フック は、デプロイメントライフサイクルの特定のポイントでカスタムスクリプトやコマンドを実行することを可能にします。これらは、プラグインを使用するか、serverless.yml内で定義され、デプロイメントの前後にアクションを実行します。

yaml
custom:
hooks:
before:deploy:deploy: echo "Starting deployment..."

チュートリアル

これは公式チュートリアルの要約です from the docs:

  1. AWSアカウントを作成する(Serverless.comはAWSインフラストラクチャで開始します)
  2. serverless.comにアカウントを作成する
  3. アプリを作成する:
bash
# Create temp folder for the tutorial
mkdir /tmp/serverless-tutorial
cd /tmp/serverless-tutorial

# Install Serverless cli
npm install -g serverless

# Generate template
serverless #Choose first one (AWS / Node.js / HTTP API)
## Indicate a name like "Tutorial"
## Login/Register
## Create A New App
## Indicate a name like "tutorialapp)

これにより、tutorialappというアプリが作成され、serverless.comで確認できるようになります。また、Tutorialというフォルダーが作成され、helloworldコードを含むJSコードがある**handler.jsファイルと、その関数を宣言するserverless.yml**ファイルが含まれます:

javascript
exports.hello = async (event) => {
return {
statusCode: 200,
body: JSON.stringify({
message: "Go Serverless v4! Your function executed successfully!",
}),
}
}
  1. ダッシュボードに行き、AWSプロバイダーを作成します https://app.serverless.com/<org name>/settings/providers?providerId=new&provider=aws
  2. serverless.comにAWSへのアクセスを許可するために、次の構成ファイルを使用してcloudformationスタックを実行するように求められます(この執筆時点で): https://serverless-framework-template.s3.amazonaws.com/roleTemplate.yml
  3. このテンプレートは、**SFRole-<ID>というロールを生成し、arn:aws:iam::aws:policy/AdministratorAccess**を持ち、Serverless.comのAWSアカウントがそのロールにアクセスできるようにするTrust Identityを持つアカウントに対して設定されます。
Yaml roleTemplate
yaml
Description: This stack creates an IAM role that can be used by Serverless Framework for use in deployments.
Resources:
SFRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS: arn:aws:iam::486128539022:root
Action:
- sts:AssumeRole
Condition:
StringEquals:
sts:ExternalId: !Sub "ServerlessFramework-${OrgUid}"
Path: /
RoleName: !Ref RoleName
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
ReporterFunction:
Type: Custom::ServerlessFrameworkReporter
Properties:
ServiceToken: "arn:aws:lambda:us-east-1:486128539022:function:sp-providers-stack-reporter-custom-resource-prod-tmen2ec"
OrgUid: !Ref OrgUid
RoleArn: !GetAtt SFRole.Arn
Alias: !Ref Alias
Outputs:
SFRoleArn:
Description: "ARN for the IAM Role used by Serverless Framework"
Value: !GetAtt SFRole.Arn
Parameters:
OrgUid:
Description: Serverless Framework Org Uid
Type: String
Alias:
Description: Serverless Framework Provider Alias
Type: String
RoleName:
Description: Serverless Framework Role Name
Type: String
信頼関係
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::486128539022:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "ServerlessFramework-7bf7ddef-e1bf-43eb-a111-4d43e0894ccb"
}
}
}
]
}
  1. チュートリアルでは、基本的に新しいAPIエンドポイントを新しいJSファイルで処理するcreateCustomer.jsというファイルを作成するように求められ、新しいDynamoDBテーブルを生成し、環境変数を定義し、生成されたラムダを使用するロールを設定するためにserverless.ymlファイルを修正するように求められています。
javascript
"use strict"
const AWS = require("aws-sdk")
module.exports.createCustomer = async (event) => {
const body = JSON.parse(Buffer.from(event.body, "base64").toString())
const dynamoDb = new AWS.DynamoDB.DocumentClient()
const putParams = {
TableName: process.env.DYNAMODB_CUSTOMER_TABLE,
Item: {
primary_key: body.name,
email: body.email,
},
}
await dynamoDb.put(putParams).promise()
return {
statusCode: 201,
}
}
  1. **serverless deploy**を実行してデプロイします
  2. デプロイメントはCloudFormationスタックを介して行われます
  3. ラムダはAPIゲートウェイを介して公開されており、直接のURLではありません
  4. テストします
  5. 前のステップでは、APIエンドポイントラムダ関数がデプロイされたURLが表示されます

Serverless.comのセキュリティレビュー

誤設定されたIAMロールと権限

過度に許可されたIAMロールは、クラウドリソースへの不正アクセスを許可し、データ漏洩やリソースの操作につながる可能性があります。

ラムダ関数に対して権限が指定されていない場合、ログを生成するための権限のみを持つロールが作成されます。例えば:

最小ラムダ権限
json
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:CreateLogStream",
"logs:CreateLogGroup",
"logs:TagResource"
],
"Resource": [
"arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/jito-cranker-scripts-dev*:*"
],
"Effect": "Allow"
},
{
"Action": ["logs:PutLogEvents"],
"Resource": [
"arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/jito-cranker-scripts-dev*:*:*"
],
"Effect": "Allow"
}
]
}

緩和戦略

  • 最小権限の原則: 各関数に必要な権限のみを割り当てる。
yaml
provider:
[...]
iam:
role:
statements:
- Effect: 'Allow'
Action:
- 'dynamodb:PutItem'
- 'dynamodb:Get*'
- 'dynamodb:Scan*'
- 'dynamodb:UpdateItem'
- 'dynamodb:DeleteItem'
Resource: arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/${self:service}-customerTable-${sls:stage}
  • 別々のロールを使用: 関数の要件に基づいてロールを区別する。

安全でない秘密情報と構成管理

敏感な情報(例:APIキー、データベースの資格情報)を直接**serverless.yml**やコードに保存すると、リポジトリが侵害された場合に露出する可能性があります。

推奨される方法は、serverless.comの**serverless.ymlファイルに環境変数を保存するために、ssmまたはs3プロバイダーを使用することです。これにより、デプロイ時にこれらのソースから環境値を取得し、lambdasの環境変数を値のクリアテキストなしで構成できます!

caution

したがって、AWS内のlambdas構成を読み取る権限を持つ人は、これらの環境変数すべてにクリアテキストでアクセスできるようになります!

例えば、以下の例ではSSMを使用して環境変数を取得します:

yaml
provider:
environment:
DB_PASSWORD: ${ssm:/aws/reference/secretsmanager/my-db-password~true}

そして、これが**serverless.yml**ファイルに環境変数の値をハードコーディングするのを防いでも、値はデプロイ時に取得され、lambda環境変数内に平文で追加されることになります。

tip

serveless.comを使用して環境変数を保存する推奨方法は、AWSシークレットに保存し、環境変数にシークレット名を保存し、lambdaコードがそれを取得することです。

緩和戦略

  • Secrets Manager統合: AWS Secrets Managerのようなサービスを使用します。
  • 暗号化された変数: 機密データのためにServerless Frameworkの暗号化機能を活用します。
  • アクセス制御: 役割に基づいてシークレットへのアクセスを制限します。

脆弱なコードと依存関係

古いまたは安全でない依存関係は脆弱性を引き起こす可能性があり、不適切な入力処理はコードインジェクション攻撃を引き起こす可能性があります。

緩和戦略

  • 依存関係管理: 定期的に依存関係を更新し、脆弱性をスキャンします。
yaml
plugins:
- serverless-webpack
- serverless-plugin-snyk
  • 入力検証: すべての入力の厳格な検証とサニタイズを実施します。
  • コードレビュー: セキュリティの欠陥を特定するために徹底的なレビューを行います。
  • 静的分析: コードベースの脆弱性を検出するためのツールを使用します。

不十分なログ記録と監視

適切なログ記録と監視がないと、悪意のある活動が検出されず、インシデント対応が遅れる可能性があります。

緩和戦略

  • 集中ログ記録: AWS CloudWatchDatadogのようなサービスを使用してログを集約します。
yaml
plugins:
- serverless-plugin-datadog
  • 詳細なログ記録を有効にする: 機密データを露出させずに重要な情報をキャプチャします。
  • アラートの設定: 疑わしい活動や異常に対してアラートを設定します。
  • 定期的な監視: 潜在的なセキュリティインシデントのためにログとメトリクスを継続的に監視します。

不安全なAPIゲートウェイ設定

オープンまたは不適切に保護されたAPIは、不正アクセス、サービス拒否(DoS)攻撃、またはクロスサイト攻撃に悪用される可能性があります。

緩和戦略

  • 認証と認可: OAuth、APIキー、またはJWTのような堅牢なメカニズムを実装します。
yaml
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
authorizer: aws_iam
  • レート制限とスロットリング: リクエストレートを制限することで悪用を防ぎます。
yaml
provider:
apiGateway:
throttle:
burstLimit: 200
rateLimit: 100
  • 安全なCORS設定: 許可されたオリジン、メソッド、およびヘッダーを制限します。
yaml
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
cors:
origin: https://yourdomain.com
headers:
- Content-Type
  • Webアプリケーションファイアウォール(WAF)の使用: 悪意のあるパターンのHTTPリクエストをフィルタリングおよび監視します。

不十分な関数の分離

共有リソースと不十分な分離は、特権の昇格や関数間の意図しない相互作用を引き起こす可能性があります。

緩和戦略

  • 関数の分離: 独立した操作を確保するために、異なるリソースとIAMロールを割り当てます。
  • リソースのパーティショニング: 異なる関数のために別々のデータベースやストレージバケットを使用します。
  • VPCの使用: ネットワークの分離を強化するために、仮想プライベートクラウド内に関数をデプロイします。
yaml
provider:
vpc:
securityGroupIds:
- sg-xxxxxxxx
subnetIds:
- subnet-xxxxxx
  • 関数の権限を制限: 明示的に必要でない限り、関数が互いのリソースにアクセスしたり干渉したりできないようにします。

不十分なデータ保護

静止中または転送中の暗号化されていないデータは露出する可能性があり、データ侵害や改ざんを引き起こす可能性があります。

緩和戦略

  • 静止中のデータを暗号化: クラウドサービスの暗号化機能を利用します。
yaml
resources:
Resources:
MyDynamoDBTable:
Type: AWS::DynamoDB::Table
Properties:
SSESpecification:
SSEEnabled: true
  • 転送中のデータを暗号化: すべてのデータ送信にHTTPS/TLSを使用します。
  • API通信の保護: 暗号化プロトコルを強制し、証明書を検証します。
  • 暗号化キーを安全に管理: 管理されたキーサービスを使用し、定期的にキーをローテーションします。

適切なエラーハンドリングの欠如

詳細なエラーメッセージは、インフラストラクチャやコードベースに関する機密情報を漏洩させる可能性があり、未処理の例外はアプリケーションのクラッシュを引き起こす可能性があります。

緩和戦略

  • 一般的なエラーメッセージ: エラー応答に内部の詳細を露出させないようにします。
javascript
javascriptCopy code// Node.jsの例
exports.hello = async (event) => {
try {
// 関数のロジック
} catch (error) {
console.error(error);
return {
statusCode: 500,
body: JSON.stringify({ message: '内部サーバーエラー' }),
};
}
};
  • 中央集中的なエラーハンドリング: すべての関数でエラーを一貫して管理し、サニタイズします。
  • エラーの監視とログ記録: 詳細をエンドユーザーに露出させずに、内部でエラーを追跡し分析します。

不安全なデプロイメントプラクティス

露出したデプロイメント構成やCI/CDパイプラインへの不正アクセスは、悪意のあるコードのデプロイや誤設定を引き起こす可能性があります。

緩和戦略

  • CI/CDパイプラインのセキュリティ: 厳格なアクセス制御、多要素認証(MFA)、および定期的な監査を実施します。
  • 構成を安全に保存: デプロイメントファイルをハードコーディングされたシークレットや機密データから解放します。
  • Infrastructure as Code(IaC)セキュリティツールの使用: CheckovTerraform Sentinelのようなツールを使用してセキュリティポリシーを強制します。
  • 不変のデプロイメント: 不正な変更を防ぐために、不変のインフラストラクチャプラクティスを採用します。

プラグインと拡張機能の脆弱性

未検証または悪意のあるサードパーティプラグインを使用すると、サーバーレスアプリケーションに脆弱性が導入される可能性があります。

緩和戦略

  • プラグインを徹底的に評価: 統合前にプラグインのセキュリティを評価し、信頼できるソースからのものを優先します。
  • プラグインの使用を制限: 攻撃面を最小限に抑えるために、必要なプラグインのみを使用します。
  • プラグインの更新を監視: セキュリティパッチの恩恵を受けるためにプラグインを更新します。
  • プラグイン環境を分離: プラグインを隔離された環境で実行し、潜在的な侵害を抑制します。

機密エンドポイントの露出

公開アクセス可能な関数や制限のないAPIは、不正な操作に悪用される可能性があります。

緩和戦略

  • 関数アクセスの制限: VPC、セキュリティグループ、およびファイアウォールルールを使用して、信頼できるソースへのアクセスを制限します。
  • 堅牢な認証の実装: すべての公開エンドポイントが適切な認証と認可を必要とすることを確認します。
  • APIゲートウェイを安全に使用: APIゲートウェイを構成して、入力検証やレート制限を含むセキュリティポリシーを強制します。
  • 未使用のエンドポイントを無効にする: 定期的にレビューし、もはや使用されていないエンドポイントを無効にします。

チームメンバーと外部コラボレーターへの過剰な権限

チームメンバーや外部コラボレーターに過剰な権限を付与すると、不正アクセス、データ侵害、リソースの悪用につながる可能性があります。このリスクは、複数の個人が異なるレベルのアクセスを持つ環境で高まるため、攻撃面が広がり、内部脅威の可能性が増加します。

緩和戦略

  • 最小権限の原則: チームメンバーやコラボレーターがタスクを実行するために必要な権限のみを持つことを確認します。

アクセスキーとライセンスキーのセキュリティ

アクセスキーライセンスキーは、Serverless Framework CLIとの相互作用を認証および承認するために使用される重要な資格情報です。

  • ライセンスキー: CLI経由でログインするために必要なServerless Frameworkバージョン4へのアクセスを認証するためのユニークな識別子です。
  • アクセスキー: Serverless Framework Dashboardと認証するためにServerless Framework CLIが使用する資格情報です。serverless cliでログインすると、アクセスキーが生成されてラップトップに保存されます。また、SERVERLESS_ACCESS_KEYという名前の環境変数として設定することもできます。

セキュリティリスク

  1. コードリポジトリを通じた露出:
  • アクセスキーやライセンスキーをハードコーディングしたり、バージョン管理システムに誤ってコミットしたりすると、不正アクセスにつながる可能性があります。
  1. 不安全なストレージ:
  • 環境変数や構成ファイル内に平文でキーを保存することは、漏洩の可能性を高めます。
  1. 不適切な配布:
  • 不安全なチャネル(例:メール、チャット)を通じてキーを共有すると、悪意のある行為者によって傍受される可能性があります。
  1. ローテーションの欠如:
  • 定期的にキーをローテーションしないと、キーが侵害された場合の露出期間が延びます。
  1. 過剰な権限:
  • 幅広い権限を持つキーは、複数のリソースにわたって不正な操作を行うために悪用される可能性があります。

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする