ECRレジストリレベルでイメージスキャンを有効化する

ECRレジストリレベルでイメージスキャンを有効化する

ECRレジストリレベルでイメージスキャンを有効化する

ECRリポジトリが提供する機能の1つに、イメージスキャンがあります。

Amazon ECR イメージスキャニングは、コンテナイメージ内のソフトウェアの脆弱性を特定するのに役立ちます。次のスキャンタイプが提供されています。

イメージスキャン

今回はECRレジストリレベルでイメージスキャンを有効化します。

なおイメージスキャンを有効化するためには、今回ご紹介する手順が推奨されています。
以下のページでご紹介した通り、ECRリポジトリ単位でイメージスキャンを有効化する方法もありますが、現在こちらの方法は非推奨となっています。

あわせて読みたい
ECRリポジトリレベルでイメージスキャンを有効化する 【ECRリポジトリレベルでイメージスキャンを有効化する】 ECRリポジトリが提供する機能の1つに、イメージスキャンがあります。 Amazon ECR イメージスキャニングは、コ...

構築する環境

Diagram of enable image scanning at ECR registry level.

CloudFormationスタックを作成し、その内部に2つのリソースを定義します。

1つ目はECRです。
このリポジトリに対してイメージをプッシュします。

2つ目はLambda関数です。
この関数をCloudFormationカスタムリソースとして設定します。
この関数の働きは、レジストリレベルでイメージスキャンを有効化することです。
関数のランタイムはPython3.8とします。
CloudFormationカスタムリソースを設定することで、CloudFormationスタック作成時に、この関数を実行できるようになります。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。

https://github.com/awstut-an-r/awstut-fa/tree/main/083

テンプレートファイルのポイント解説

本ページでは、レジストリレベルでイメージプッシュ時にスキャンを有効化する方法を中心に取り上げます。

CloudFormationカスタムリソースに関する基本的な事項については、以下のページをご確認ください。

あわせて読みたい
CloudFormationカスタムリソース入門 【CloudFormationカスタムリソースの挙動を確認する構成】 CloudFormationの機能の1つにカスタムリソースがあります。 カスタムリソースを使用すると、テンプレートにカ...

CloudFormationカスタムリソースを使用して、CloudFormationスタック削除時に、自動的にECRリポジトリ内のイメージを削除する方法については、以下のページをご確認ください。

あわせて読みたい
CFNカスタムリソースでECRイメージを削除する 【CloudFormationカスタムリソースでECRイメージを削除する】 CloudFormationを使ってECRを作成し、そこにイメージをプッシュすると、CloudFormationスタック時にエラー...

ECR

Resources:
  ECRRepository:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: !Ref Prefix
Code language: YAML (yaml)

ECRリポジトリを作成します。
特別な設定は不要です。

CloudFormationカスタムリソース

カスタムリソース

Resources:
  CustomResource:
    Type: Custom::CustomResource
    Properties:
      ServiceToken: !GetAtt ECRFunction.Arn
Code language: YAML (yaml)

ServiceTokenプロパティに、後述のLambda関数のARNを指定します。
この設定によって、CloudFormationスタックの操作時に、都度関数が実行されることになります。

カスタムリソースで実行するLambda関数

Resources:
  ECRFunction:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        ZipFile: |
          import boto3
          import cfnresponse
          import os

          account_id = os.environ['ACCOUNT_ID']
          ecr_repository_name = os.environ['ECR_REPOSITORY_NAME']

          ecr_client = boto3.client('ecr')

          CREATE = 'Create'
          DELETE = 'Delete'
          response_data = {}

          def lambda_handler(event, context):
            try:
              if event['RequestType'] == CREATE:
                put_response = ecr_client.put_registry_scanning_configuration(
                  scanType='BASIC',
                  rules=[
                    {
                      'scanFrequency': 'SCAN_ON_PUSH',
                      'repositoryFilters': [
                        {
                          'filter': ecr_repository_name,
                          'filterType': 'WILDCARD'
                        }
                      ]
                    }
                  ]
                )
                print(put_response)

              ...

              cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data)

            except Exception as e:
              print(e)
              cfnresponse.send(event, context, cfnresponse.FAILED, response_data)
      Environment:
        Variables:
          ACCOUNT_ID: !Ref AWS::AccountId
          ECR_REPOSITORY_NAME: !Ref ECRRepository
      FunctionName: !Sub "${Prefix}-function-ecr"
      Handler: !Ref Handler
      Runtime: !Ref Runtime
      Role: !GetAtt ECRFunctionRole.Arn
Code language: YAML (yaml)

関数そのものの設定に特別な項目はありません。
1つ挙げるとすると、環境変数がポイントです。
必要なパラメータ(リポジトリ名やアカウントID)を、環境変数として関数に渡します。

event[‘RequestType’]の値を参照して、スタック操作に応じた処理を実装します。
今回はスタック作成時に本処理を実行します。
ですからif文を使って、この値が「Create」の時に以下の処理が実行されるようにします。

  • boto3でECR用クライアントオブジェクトを作成する。
  • put_registry_scanning_configurationメソッドで、ECRレジストリのイメージスキャンを有効化する。

put_registry_scanning_configurationメソッドの詳細は以下をご確認ください。

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ecr.html#ECR.Client.put_registry_scanning_configuration

今回は先述のECRリポジトリに対して、イメージのプッシュ時に、ベーシックスキャンを実行するように設定します。
本メソッドを実行する上でのパラメータについては、API Referenceも参照してください。

https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_GetRegistryScanningConfiguration.html

パラメータを簡単に整理します。
scanTypeは「BASIC」を指定し、ベーシックスキャンを実行するように設定します。
rulesで実行するスキャンの対象や頻度を設定します。
scanFrequencyに「SCAN_ON_PUSH」を指定し、イメージのプッシュ時に、スキャンを実行するように設定します。
repositoryFiltersでスキャン対象を設定します。
filterでスキャンの対象とするリポジトリ名を指定します。今回は先述のECRリポジトリ名を設定します。
filterTypeは「WILDCARD」を設定します。この値は固定値です。

このLambda関数のIAMロールを確認します。

Resources:
  ECRFunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - lambda.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: !Sub "${Prefix}-ECRDeleteImagesPolicy"
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - ecr:PutRegistryScanningConfiguration
                Resource: "*"
              ...
Code language: YAML (yaml)

ecr:PutRegistryScanningConfigurationを許可します。

(参考) Dockerfile

FROM amazonlinuxCode language: Dockerfile (dockerfile)

Amazon Linux 2をベースにして、自作のイメージを作成します。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

あわせて読みたい
CloudFormationのネストされたスタックで環境を構築する 【CloudFormationのネストされたスタックで環境を構築する方法】 CloudFormationにおけるネストされたスタックを検証します。 CloudFormationでは、スタックをネストす...

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • ECRリポジトリ:fa-083

作成されたリソースをAWS Management Consoleから確認します。
CloudFormationカスタムリソース用Lambda関数の実行結果を確認します。

Detail of Custom Resource Lambda Function Invocation 1.

スタック作成時に、put_registry_scanning_configurationメソッドが実行されたことがわかります。

次にECRレジストリを確認します。

Detail of ECR Registry 1.

Scan configurationを見ると、ベーシックスキャンがfa-083リポジトリに対して有効化されていることがわかります。

次にECRリポジトリを確認します。

Detail of ECR Registry 2.

Scan frequencyの項目が「Scan on push」とあります。
イメージスキャンが有効化されていることがわかります。

続いてリポジトリの詳細を確認します。

Detail of ECR Registry 3.

Image scan settingsを見ると、ここの項目はDisabledに設定されています。
つまりリポジトリレベルではイメージスキャンが無効化されていますが、レジストリレベルでは有効化されているということです。

動作確認

準備が整いましたので、本リポジトリにイメージをプッシュします。
プッシュは以下のコマンドを実行します。

Detail of ECR Registry 4.

イメージのプッシュ後、改めてリポジトリを確認します。

Detail of ECR Registry 5.

Scan statusの項目が「Complete」とあります。
イメージプッシュ時に自動的にスキャンが実行されたことがわかります。

Vulnerabilitiesの項目の「detail」を確認します。

Detail of ECR Registry 6.

検出された脆弱性が深刻度とともに表示されました。

このようにECRレジストリレベルでプッシュ時のスキャンを有効化することによって、自動的にイメージをスキャンできることを確認しました。

まとめ

ECRレジストリレベルで、プッシュ時のスキャンを有効化する方法と、その効果を確認しました。