[アップデート]信頼できる検証済みコード以外はデプロイ禁止!!Lambdaでコード署名による検証が利用可能になりました

Lambdaのセキュリティレベルを担保するために有効なアップデートです
2020.11.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

CX事業本部@大阪の岩田です。

少し前になってしまいますが、2020/11/23付けのアップデートによりLambdaでコード署名による検証が利用可能になりました。

この機能を利用することでデプロイ対象のパッケージがコード署名作成時から改竄されていないことが担保され、セキュリティレベルを高く保つことが可能です。AWS IoTの利用経験がある方はAWS IoTのジョブ機能をイメージして頂くと分かりやすいかもしれません。このブログではLambdaのコード署名について簡単に紹介させて頂きます。

概要

このアップデートにより、Lambda関数に対してコード署名の検証を有効化できるようになりました。この設定が有効化されている場合、デプロイパッケージにはAWS Signerを利用したコード署名が要求されます。パッケージに付与されたコード署名はデプロイ時に検証され、関数実行時のパフォーマンスには影響しません。

コード署名による検証が有効化されている場合、Lambdaの実行基盤はデプロイパッケージに対して以下のチェックを実施します。

  • 署名の有効期限
    • コード署名が有効期限切れになっていないことを確認します。
  • 不一致
    • コード署名設定で許可された署名プロファイルの1つで署名されていることを検証します。コード署名が存在しない場合も不一致扱いとなります。
  • 失効
    • コードパッケージの署名が失効していないことを検証します。

コード署名の検証ポリシーには「Warn」もしくは「Enforce」が指定可能です。それぞれの振る舞いは以下のようになります。

  • 「Warn」を指定した場合、署名の検証が失敗してもデプロイ自体は可能です。LambdaはCloudWatchにメトリクスをパブリッシュし、CloudTrailに警告ログを記録します。
  • 「Enforce」を指定した場合、署名の検証が失敗するとLambda関数/レイヤーはデプロイできません。

なお、コード署名による検証を利用するための追加料金は不要となっています。

やってみる

では、実際にコード署名による検証を試してみましょう。以下AWSブログの手順に沿って進めていきます。

New – Code Signing, a Trust and Integrity Control for AWS Lambda/

署名プロファイルの作成

まずAWS Signerの管理コンソールから署名プロファイルを作成します。

Lambdaのコード署名設定を作成

続いてLambdaの管理コンソールからコード署名設定を作成します。署名プロファイルには先程AWS Signerで作成した署名プロファイルを指定します。今回は署名検証ポリシーとして「Enforce」を指定しました。

「設定を作成する」をクリックするとコード署名設定の作成完了です。

Lamba関数の設定変更

続いてLambda関数の設定を変更し、コード署名による検証を有効化します。

設定項目が増えていますね。「編集」をクリックし、先程作成したコード署名設定を紐付けます。

設定完了後の画面です。

これでLambdaのパッケージにコード署名が要求されるようになりました。試しにコード署名の無い普通のZIPパッケージのデプロイを試みます。

エラーになりました。期待通り動作していそうです。

署名対象のLambdaのコードを準備

署名されていないパッケージがデプロイできなくなったので、今度は署名付きのパッケージを作成します。まずは通常のデプロイパッケージをS3バケットにアップロードしておきます。この際指定するS3バケットにはバージョニングの設定が必須です。ご注意下さい。

$aws s3 cp lambda_function.zip s3://<S3バケット名>

署名ジョブの作成

デプロイパッケージに対して署名を付与するため、署名ジョブを作成します。マネコンから実行しようとするとJavaScriptのエラーで動作しなかったため、ここはAWS CLIで実行しました。

aws signer start-signing-job \
              --source 's3={bucketName=<S3バケット名>,key=lambda_function.zip,version=NSbv_yV2YnrEE6MsEuyUf0.KDaSuGzMX}' \
              --destination 's3={bucketName=<S3バケット名>,prefix=<署名アップロードする先のプレフィックス>}' \
              --profile-name <先程作成した署名プロファイルの名前>

ジョブ実行後にAWS Signerの管理コンソールを確認しましょう。

ジョブの詳細です。

「署名の送信先キー」で指定されたオブジェクトキーにLambdaのパッケージとコード署名が保存されています。このZIPファイルをDLして解凍すると、元々のパッケージに加えてコード署名が保存されたMETA_INFというディレクトリが現れます。META_INFディレクトリの中身を確認してみましょう。

$ head -n 10  META_INF/aws_signer_signature_v1.0.SF
-----BEGIN PKCS7-----
MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgIFADCABgkqhkiG9w0B
BwEAAKCAMIICgTCCAgegAwIBAgIRAKmKAVPfIdeYoxk/pGCeqxMwCgYIKoZIzj0E
AwMwbjELMAkGA1UEBhMCVVMxDDAKBgNVBAoMA0FXUzEVMBMGA1UECwwMQ3J5cHRv
Z3JhcGh5MQswCQYDVQQIDAJXQTEtMCsGA1UEAwwkU2lnbmVyIGFwLW5vcnRoZWFz
dC0xIFNVQk9SRElOQVRFIENBMB4XDTIwMTEyODE2MDE0NloXDTIwMTIwMTE3MDE0
NlowYjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0dGxl
MQwwCgYDVQQKDANBV1MxFTATBgNVBAsMDENyeXB0b2dyYXBoeTEPMA0GA1UEAwwG
c2lnbmVyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+hCsDpERTd/a9oCwhxWc78oJ
2PPo33HnIm6Xqtk6dj0LJZrUqZYZu9186gbatbVaQFB7EP5Zk7+Ou/AFB6MZaq+J

こんな感じで署名されています。

コード署名付きのパッケージをデプロイ

コード署名付きのパッケージが作成できたので、先程「署名の送信先キー」で指定されていたオブジェクトキーを指定してLambda関数のコードをデプロイしましょう。今度は署名の検証が成功するので、問題なくデプロイされます。

署名されたパッケージをデプロイした場合、このように管理コンソールからのコード編集は無効になります。

署名プロファイルを取り消してみる

試しにAWS Signerの管理コンソールから署名プロファイルを取り消してみましょう。取り消しの有効開始日として過去日付を指定します。これで、先程作成したパッケージの署名は有効期限が切れているということになります。

取り消し完了です。

この状態で再度先程の署名済みパッケージをデプロイしてみましょう。

今度は失敗しました。正しく検証できていそうです。

まとめ

Lambdaのコード署名検証機能についてご紹介しました。これでセキュリティ要件が厳しい環境でもLambdaが利用しやすくなったのではないでしょうか?今回は紹介しませんでしたが、既にSAM CLIではpackageもしくはdeployのオプションに--signing-profilesを指定することでコード署名付きのデプロイパッケージが簡単に生成できるようになっています。デプロイパイプラインの中に組み込むのも比較的容易になっているので、導入を検討してみてはいかがでしょうか?