この記事は3-shake Advent Calendar 2024の22日目の記事です。
AWS Signerを使ったコンテナイメージの署名処理を扱った案件があったのでこちらの紹介となります。ただ、後述するように完成には至ってないです。それでもAWS Signerを使った署名処理と署名検証についての概要をお伝えできるかなと思います。
今回のシステムはAWS ECS で Web サービスを運用しています。GitHub Actions を利用してデプロイを行っています。構成としては至ってベーシックな形になっています。 今回、コンテナイメージのセキュリティ強化のため、ECR に保存されているイメージが改竄されていないことを保証する要件が追加されました。この記事では、AWS Signer を用いたコンテナイメージの署名と検証の実装、そして現状の課題と今後について記述します。
AWS Signerとは
AWS Signer はフルマネージドなコード署名サービスです。従来は Lambda 関数などで利用されていましたが、2023年の6月にECRのイメージ署名にも対応しました。
Notary ProjectのNotation CLIを用いることで、ECRに保存されているコンテナイメージを署名することができ、署名ファイルをコンテナイメージとともにECRに保存できます。これによりコンテナイメージの真正性と完全性を検証することができます。
なお、AWS Signerによるイメージ署名に゙関してはNRI ネットコム様のスライドに詳しく書かれているのでこちらを参照するとより理解が深まります。
デプロイフロー
変更前
デプロイフローとしてはGitHub Actionsでレポジトリ内のソースをdocker buildしたものをECRにpushし、ECS Serviceにデプロイするシンプルなワークフローになります。
変更後
このワークフローにコンテナイメージ署名の処理を追加します。notationコマンドにSigner Profileのarnを指定して、署名と検証をそれぞれ行う形になります。
今回は、GitHub Actions ワークフローに AWS Signer を使った処理を組み込みます。ECRにpushしたイメージに対して署名を行うように変更しました。署名したあとに署名検証を行うことになります。
後述しますが、これだけだと本来は不完全なものです。
実装
ここから実装を見て行きます。先述したワークフローに帰るために以下の変更が必要となります。
Terraform
インフラ側の変更を見ていきましょう。追加箇所としてはSigner Profileの追加とGitHub Actions用のIAM Policyへの権限追加となります。変更箇所以外は今回は割愛しています。
platform_idを"Notation-OCI-SHA384-ECDSA"に指定してSigner Profileを作成します。レポジトリ名をProfile名にしており、レポジトリ名が -
区切りで、Profile名が -
を使えないという事情で _
への置換処理をしています。
- Siner Profile
resource "aws_signer_signing_profile" "main" { platform_id = "Notation-OCI-SHA384-ECDSA" # profile名に-が使えないので置換 name = replace(var.repository_name, "-", "_") }
先に作ったSigner Profileへの"signer:GetSigningProfile"と"signer:SignPayload"の許可をデプロイ用のRoleのPolicyに付与します。
- GitHub Actions用IAM Role
data "aws_iam_policy_document" "deploy_policy" { #前略 # イメージ署名 # Inline policies for Signer - AWS Signer # https://docs.aws.amazon.com/ja_jp/signer/latest/developerguide/authen-inlinepolicies.html statement { sid = "SignImage" effect = "Allow" actions = [ "signer:GetSigningProfile", "signer:SignPayload" ] resources = [ var.signer_profile_arn ] } # 後略 }
デプロイ
signer policyのファイルをあらかじめ作っておきます。このPolicyを利用して、署名検証を行います。
{ "version":"1.0", "trustPolicies":[ { "name":"aws-signer-tp", "registryScopes":[ "*" ], "signatureVerification":{ "level":"strict" }, "trustStores":[ "signingAuthority:aws-signer-ts" ], "trustedIdentities":[ "arn:aws:signer:${region}:${account_id}:/signing-profiles/${profile_name}" ] } ] }
既存のECSのデプロイワークフローにnotationのインストール、イメージ署名処理、イメージ署名検証の処理を追記します。リリースブランチにpushされたことを契機にデプロイが走る形です。
name: Deploy to ECS on: push: branches: ['release'] env: AWS_REGION: ap-northeast-1 ECR_REPOSITORY: ${レポジトリ名} SIGNER_PROFILE_ARN: ${Signer Profile ARN} SIGNER_POLICY_JSON: .github/aws/signer_policy.json jobs: deploy: name: Deploy to ECR, ECS runs-on: ubuntu-latest steps: ### 前略 - name: Setup Notation run: | wget https://d2hvyiie56hcat.cloudfront.net/linux/amd64/installer/deb/latest/aws-signer-notation-cli_amd64.deb sudo dpkg -i aws-signer-notation-cli_amd64.deb - name: Sign image env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} IMAGE_TAG: ${{ github.sha }} run: | notation sign $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG --plugin "com.amazonaws.signer.notation.plugin" --id "$SIGNER_PROFILE_ARN" - name: Verify image env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} IMAGE_TAG: ${{ github.sha }} run: | notation policy import $SIGNER_POLICY_JSON notation verify $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG ### 後略
課題
ここまででイメージの署名処理および署名検証の実装はできました。しかしながら、いくつか課題があります。
CIとCDの分離
先の実装を見るとわかるのですが、署名したイメージを即時署名検証していることがわかります。これは同じイメージに対して行われているため、実質的な検証にはなっていません。真の改竄検知のためには、CI/CD パイプラインを分離し、デプロイ時に別途署名検証を行う必要があります。
また、pushしたコンテナイメージの脆弱性チェックもデプロイ前に行うことが望ましいです。
そこで下記のように変更したいところです。 ただ、デプロイのフローが変わってしまうので、調整が必要でまだ手をつけていない状態になります。
正規手順以外でデプロイされたイメージの検証
さらに、正規のデプロイフロー以外で起動されたタスクのイメージ検証も課題です。署名されていないイメージが起動されていても何もチェックができていない状態です。
これに対するアプローチとしては、EventBridgeでタスクが起動したイベントを拾って、イメージの署名をチェックし、検証できなかったものに゙関しては処理を行う(タスクの停止や通知など)という方法があります。これはContainers on AWSで紹介されているので、この方法を実装できたらと考えています。
署名検証のサービス統合
ここまで見ていて気付いたかもしれませんが、ECS Serviceがタスクを起動するときに署名されているかどうかをチェックするようにECSサービスと統合されていれば、独自に署名検証を実装する必要はありません。
このへん、Google CloudのBinary Authorizationはサービスと統合されているので、署名検証を自前で書く必要がないと理解してます。AWSもサービスと統合して楽に使えるようになることを期待してます。
まとめ
現状でできていることは以下のとおりです。
- ECRへpushしたイメージの署名処理
現状課題となっているものは以下のとおりです。
- CI/CDの分離
- 署名されていないコンテナイメージが起動されていないかのチェック
この記事では、AWS Signer を用いたコンテナイメージの署名実装と、残された課題について説明しました。
まだできていないことが多いですが、まずビルドしたイメージに対して署名を行うという第一歩を踏み出しました。ここから署名検証の仕組みを強化し、よりセキュアなコンテナ運用を実現するために、引き続き改善に取り組んでいきたいと思ってます。
参考リンク
- AWS がコンテナイメージへの署名を導入
- AWS Signer と Amazon EKS におけるコンテナイメージ署名の提供開始 | Amazon Web Services ブログ
- ECS × AWS Signer を使ったイメージ署名ワークフローを試してみた - Speaker Deck
- Sign container images in Signer - AWS Signer
- Container image signing and verification using AWS Signer for Amazon ECS and AWS Fargate | Containers on AWS
- Binary Authorization の概要 | Google Cloud