1. はじめに
ECS on Fargate構成のマルウェア対策について、まとまった情報が見つけられずRFPへの回答に困った経験はありませんでしょうか?自身の経験もとに検討・実装した内容をご紹介します。
マルウェアが混入したイメージをデプロイしてしまうケースや、ユーザのファイルアップロードを受け付けるWebアプリケーションにおいてマルウェアがアップロードされるケースなどへの対策や実装についてご紹介します。
2. コンテナへのマルウェア混入経路
ECS on Fargate構成においては、以下のようなマルウェア混入の可能性が考えられます。
-
Dockerイメージのマルウェア混入
- マルウェアが混入したDockerイメージをデプロイしてしまい、コンテナ内でマルウェアが実行される可能性
- マルウェアの混入経路は以下の通り
- ベースとなるDockerイメージにマルウェアが混入
- DockerHubなどのレジストリへ配置されたDockerイメージにマルウェアが混入
- Githubへ配置したファイルにマルウェアが混入
-
アップロードファイルのマルウェア混入
- ユーザがアップロードしたファイルにマルウェアが混入しており、コンテナ内でマルウェアが実行される可能性
-
脆弱性の悪用によるマルウェア注入
- アプリケーションに脆弱性がある場合に、攻撃者によってマルウェアが注入・実行される可能性
-
未知のマルウェアの混入
- 未知のマルウェアが検知をすり抜けてしまい、EFSやS3などのユーザファイルのアップロード先領域に混入してしまう可能性
3. 構成図
- 全体構成
ポイントは以下です。
- イメージのマルウェアスキャン
CICDパイプライン上でマルウェアスキャンを実施し、Dockerイメージのマルウェア混入を防止 - アップロードファイルスキャン
ユーザのファイルアップロードを受け付けるWebアプリケーションにおいて、ファイルアップロード時にマルウェアスキャンを実施し、マルウェア混入を防止 - コンテナのリードオンリー化
コンテナをReadOnlyRootFilesystemで実行し、攻撃者によるコンテナ内へのマルウェアの書き込みを防止 - 定期スキャン
未知のマルウェアに対する対策として、ユーザファイルのアップロード先領域を定期的にスキャンし、マルウェアの検知を行う
4. セキュリティ対策の実装
4.1 イメージのマルウェアスキャン
CDパイプライン上でマルウェアスキャンを実施し、Dockerイメージのマルウェア混入を防止します。具体的には、Trend Micro Artifact Scannerを利用し、コンテナイメージにウィルススキャンを実施します。
Trend Micro Artifact Scanner (以降TMAS)はCLIツールを任意の環境に実装して実行します。仕組みとしては、スキャン対象のコンテナイメージのSBOMを作成し、SaaSとして存在するバックエンドにSBOMを送信してスキャンをするものです。CLIツールとして実装するので、CI/CDパイプラインや開発時の任意タイミングでのスキャンが可能です。
参考文献:Trend Micro Artifact Scannerについて
TMASとGithubActionsを用いた実装例は以下の記事を参照ください。
4.2 アップロードファイルスキャン
アップロードファイルのマルウェアスキャンを実施し、マルウェア混入を防止します。具体的には、アプリケーションのファイルアップロード時に、ファイルをコンテナ上の一時領域に保管させClamAVを用いてスキャンを実施します。
なお、前提として、アプリケーション自身にファイルアップロードをトリガーとしてコマンドを実行する機能があることが必要です。
構成図は以下になります。
設計ポイントは以下になります。
- ClamAVコンテナを起動したECSタスクを立ち上げておきます。
- ユーザがファイルをアップロードした際にアプリケーションコンテナ上で、対象ファイルをClamAVの
clamdscan
コマンドでスキャンします。 - 裏で、ClamAVコンテナに対象ファイルが送信され、スキャン結果が応答されます、
- スキャン結果がマルウェアだった場合、アプリケーションコンテナ上では
clamdscan
コマンドのオプションに従ってファイルの削除操作などが行われます。
構築方法に関して以下に記載します。
-
ClamAVコンテナでは以下のイメージを利用
- ClamAV
-
stable
というタグのイメージを利用します。
-
ECRを作成してpushします。タグは
stable
とします。 -
ECSクラスタを作成
-
サブネット、セキュリティグループを作成します。
- AppコンテナからTCP3310でClamAVコンテナにアクセスを許可
-
ClamAC向けのNLBを作成します。
- TCP3310をリスナーに設定します
- ClamAV NLBのCFnは後述しています。
-
ClamAC向けのECSタスク定義、ECSサービスを作成します。
- CFnは後述しています。
-
アプリケーションコンテナにClamAVクライアントを導入します
-
設定ファイル
/etc/clamd.d/scan.conf
にNLBのDNS名もしくはIPアドレスを指定する必要があります。FROM amazonlinux:latest # ClamAVのインストール RUN yum install -y clamav;\ yum install -y sudo;\ dnf clean all;\ sudo sh -c 'echo -e "TCPAddr clamavnlb-xxxxxxxxxxxx.elb.ap-northeast-1.amazonaws.com\nTCPSocket 3310" >> /etc/clamd.d/scan.conf';\ # NLBのDNS名もしくはIPアドレスを指定
-
-
アプリケーションでファイルがアップロードされた際に、以下のコマンドを実行するようにコーディング、またはアプリケーションの設定を記述します。
/usr/bin/clamdscan --remove $FILE
$FILE
はアップロードファイルの絶対パスを持つ変数
ClamAV NLBのCFnはコチラ!
InternalNLB:
Type: "AWS::ElasticLoadBalancingV2::LoadBalancer"
Properties:
Name: "clamavnlb"
Scheme: "internal"
Type: "network"
LoadBalancerAttributes:
- Key: "deletion_protection.enabled"
Value: "false"
SecurityGroups:
- # セキュリティグループを指定
Subnets:
- # サブネットを指定
NLBListener:
Type: "AWS::ElasticLoadBalancingV2::Listener"
Properties:
DefaultActions:
- TargetGroupArn: !Ref TargetGroup
Type: forward
LoadBalancerArn: !Ref InternalNLB
Port: 3310
Protocol: TCP
ClamAV ECSタスク定義のCFnはコチラ!
ECSTaskDefinition:
Type: "AWS::ECS::TaskDefinition"
Properties:
Cpu: !Ref ECSTaskCPUUnit
ExecutionRoleArn: !Ref ECSTaskExecutionRole
TaskRoleArn: !Ref ECSTaskRole
Family: !Sub "clamavtask"
Memory: 3072
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
#ContainerDefinitions
ContainerDefinitions:
- Name: "clamav"
# clamavのイメージを保管したECRを指定
Image: "xxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/clamav:stable"
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-region: !Ref "AWS::Region"
awslogs-group: !Ref ECSLogGroup
awslogs-stream-prefix: "clamavservice"
awslogs-create-group: "true"
MemoryReservation: 1024
PortMappings:
- HostPort: 3310
Protocol: tcp
ContainerPort: 3310
Essential: true
Environment:
- Name: 'CLAMAV_NO_FRESHCLAMD'
Value: 'false'
- Name: 'CLAMD_STARTUP_TIMEOUT'
Value: '1800'
- Name: 'CLAMAV_NO_CLAMD'
Value: 'false'
- Name: 'FRESHCLAM_CHECKS'
Value: '6'
- Name: 'CLAMAV_NO_MILTERD'
Value: 'true'
HealthCheck:
Command:
- "CMD-SHELL"
- "echo PING | nc 127.0.0.1 3310 | grep -q PONG"
Retries: 3
Timeout: 10
Interval: 30
StartPeriod: 120
ReadonlyRootFilesystem : false
ClamAV ECSサービスのCFnはコチラ!
ECSService:
Type: AWS::ECS::Service
DependsOn:
- NLBListener
- NLBListener
Properties:
ServiceName: "clamavservice"
Cluster: # ECSクラスターを指定
DesiredCount: 1
PropagateTags: TASK_DEFINITION
LaunchType: FARGATE
EnableExecuteCommand: true
HealthCheckGracePeriodSeconds: 300
LoadBalancers:
- TargetGroupArn: !Ref TargetGroup
ContainerPort: 3310
ContainerName: "clamav"
DeploymentController:
Type: ECS
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- # セキュリティグループを指定
Subnets:
- # サブネットを指定
TaskDefinition: !Ref ECSTaskDefinition
PlatformVersion: "1.4.0"
4.3 コンテナのリードオンリー化
ECSタスク定義でコンテナをReadOnlyRootFilesystemで実行し、攻撃者によるコンテナ内へのマルウェアの書き込みを防止します。
この時の注意点として、アプリケーションが書き込むディレクトリはボリュームマウントしておく必要があります。
これにより、アプリケーションの起動に必要なファイルの書き込みを許可し、それ以外のファイルの書き込みを禁止します。
オマケとして、ECSタスクへecs execでログインするためのボリュームマウントも行います。
以下はTomcatを利用したDockerfileの場合の例です。
#Tomcatの書き込みフォルダをボリュームマウント
VOLUME ${CATALINA_HOME}/webapps
VOLUME ${CATALINA_HOME}/conf
VOLUME ${CATALINA_HOME}/work
VOLUME ${CATALINA_HOME}/temp
#アプリケーションの書き込みフォルダをボリュームマウント ※アプリケーションによって変更
VOLUME /tmp
#ECSタスクへecs execでログインするためのボリュームマウント
RUN mkdir -p /var/lib/amazon
RUN chmod 775 /var/lib/amazon
VOLUME /var/lib/amazon
RUN mkdir -p /var/log/amazon
RUN chmod 775 /var/log/amazon
VOLUME /var/log/amazon
なお、Tomcatの場合の注意点として、コンテナ起動後にwebappsディレクトリにアプリケーションが配置された際に起動されてしまうことを防ぐ必要があります。このためにtomcatを再起動しない限りwar ファイルが展開されないように設定する必要があります。
具体的には、server.xml でautoDeploy="false"と定義します。
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="false">
4.4 定期スキャン
未知のマルウェアに対する対策として、ユーザファイルのアップロード先領域を定期的にスキャンし、マルウェアの検知を行います。
どうしてもファイルアップロード時点では未知のマルウェアが存在します。
これに対しては、ユーザーファイルのアップロード先のEFSやS3などの領域を定期的にスキャンし、マルウェアの検知を行う必要があります。
- EFSのマルウェア検知については既にQiitaで記載してくださっている方がいらっしゃいますので、参考にしてください。
- S3のマルウェア検知についても既にQiitaで記載してくださっている方がいらっしゃいますので、参考にしてください。
おわりに
ECS on Fargate構成のマルウェア対策について、以下の4つの対策についてご紹介しました。
- Dockerイメージのマルウェアスキャン
- アップロードファイルのマルウェアスキャン
- コンテナのリードオンリー化
- 定期スキャン
これらの対策を組み合わせることで、ECS on Fargate構成におけるマルウェア対策を強化することができます。
お客様のRFP回答などにもお役に立てていただければ幸いです。
よろしければ、いいねやフォローをいただけると励みになります。