ECRレジストリレベルでイメージスキャンを有効化する
ECRリポジトリが提供する機能の1つに、イメージスキャンがあります。
Amazon ECR イメージスキャニングは、コンテナイメージ内のソフトウェアの脆弱性を特定するのに役立ちます。次のスキャンタイプが提供されています。
イメージスキャン
今回はECRレジストリレベルでイメージスキャンを有効化します。
なおイメージスキャンを有効化するためには、今回ご紹介する手順が推奨されています。
以下のページでご紹介した通り、ECRリポジトリ単位でイメージスキャンを有効化する方法もありますが、現在こちらの方法は非推奨となっています。
構築する環境
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スタック削除時に、自動的にECRリポジトリ内のイメージを削除する方法については、以下のページをご確認ください。
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メソッドの詳細は以下をご確認ください。
今回は先述の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 amazonlinux
Code language: Dockerfile (dockerfile)
Amazon Linux 2をベースにして、自作のイメージを作成します。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- ECRリポジトリ:fa-083
作成されたリソースをAWS Management Consoleから確認します。
CloudFormationカスタムリソース用Lambda関数の実行結果を確認します。
スタック作成時に、put_registry_scanning_configurationメソッドが実行されたことがわかります。
次にECRレジストリを確認します。
Scan configurationを見ると、ベーシックスキャンがfa-083リポジトリに対して有効化されていることがわかります。
次にECRリポジトリを確認します。
Scan frequencyの項目が「Scan on push」とあります。
イメージスキャンが有効化されていることがわかります。
続いてリポジトリの詳細を確認します。
Image scan settingsを見ると、ここの項目はDisabledに設定されています。
つまりリポジトリレベルではイメージスキャンが無効化されていますが、レジストリレベルでは有効化されているということです。
動作確認
準備が整いましたので、本リポジトリにイメージをプッシュします。
プッシュは以下のコマンドを実行します。
イメージのプッシュ後、改めてリポジトリを確認します。
Scan statusの項目が「Complete」とあります。
イメージプッシュ時に自動的にスキャンが実行されたことがわかります。
Vulnerabilitiesの項目の「detail」を確認します。
検出された脆弱性が深刻度とともに表示されました。
このようにECRレジストリレベルでプッシュ時のスキャンを有効化することによって、自動的にイメージをスキャンできることを確認しました。
まとめ
ECRレジストリレベルで、プッシュ時のスキャンを有効化する方法と、その効果を確認しました。