ECS-Fargate環境にAqua Platformをデプロイしてみた #Aqua Platform #コンテナ #セキュリティ #AWS #ECS #CloudFormation
この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。
はじめに
Aqua Securityの提供するコンテナセキュリティ製品であるAqua Platformは、ECS-Fargate上に環境をデプロイ可能です。
本稿ではCloudFormationを活用して、ECS-Fargate上にAqua Server・Aqua Gatewayをデプロイし、MicroEnforcerをデプロイするまでの手順を紹介していきます。
また、本稿を読み進めるにあたって、以下の注意点があります。
- 本稿では、EC2のインスタンス上に作られたLinux環境とAWSマネジメントコンソールで作業を進めて行きます。EC2のインスタンス上に作られたLinux環境のことを、本稿では作業環境と呼称します。
- AWS CLIのConfig設定など、AWS CLIの一般的な使用方法については割愛します。
- Aquaのイメージレジストリとドキュメントサイトは、権限が付与されていないと、利用できません。
コンポーネントの紹介
次に、本稿に登場するコンポーネントを紹介します。
- Aqua Server:Aqua Platformの中央制御コンポーネントです(コンソールまたは管理コンソールとも呼ばれます)。
- Aqua Gateway:Aqua ServerとMicroEnforcerの間の通信を処理します。
- Aqua Database:Aqua ServerおよびAqua Gatewayで使用されるデータベースです。Aqua Platformの構成(セキュリティ関連のポリシー、ユーザーの役割、オプションなど)及びセキュリティ監査の結果に関連する情報を格納します。
- MicroEnforcer:Aqua Platformのエージェントとして機能し、実行中のコンテナにランタイム保護の機能を提供します。
なお、Enforcerにはいくつか種類があり、その中でもMicroEnforcerはECS-Fargate上で使用されるものです。
各コンポーネントの構成は、下図の通りになっております。
作業全体のオーバービュー
- Aqua Serverをデプロイする
- ECR上のリポジトリにAquaイメージをpushする
- CloudFormationでECS-Fargate上に、Aqua Server・Aqua Gatewayをデプロイする
- MicroEnforcerをデプロイする
- 事前準備 - MicroEnforcerのバイナリの取得
- 事前準備 - アプリケーションイメージの中で使われるENTRYPOINT・CMDを取得する
- 事前準備 - MicroEnforcerのEnforcer Groupの作成
- 埋め込みタイプでMicroEnforcerをFargateにデプロイする
- DockerfileをビルドしてECRにpushする
- ECS-Fargateタスク定義の作成
- ECS-Fargateタスクの起動
- MicroEnforcerによるランタイム保護が効いているかを検証
- Aqua Platform上でランタイム保護を設定する
- ECS-Fargate上のコンテナにシェルログインしてコマンドをテストする
Aqua Serverをデプロイする
この項では、CloudFormationを使ってECS-Fargate上にAqua Serverをデプロイする流れを紹介します。
ECS-FargateにAqua Server・Aqua Gatewayをデプロイする手順は、大きく分けて2つの工程に分かれます。
1つ目の工程は、Aqua社のレジストリからAqua Server・Aqua Gatewayのイメージをpullし、そのイメージをECR上のリポジトリにpushするという手順です。この工程では、作業環境上でCLIによる操作で手順を実行していきます。
2つ目の工程は、CloudFormation上でスタックを作成し、ECS-Fargate上にAqua Server・Aqua Gatewayをデプロイしていきます。この工程では、AWSマネジメントコンソール上で、主にGUIによる操作で手順を実行していきます。
ECR上のリポジトリにAquaイメージをpushする
この項では、作業環境上にて、Aqua社のレジストリからAqua Server・Aqua Gatewayのイメージをpullし、作業環境上からECRにイメージをpushする手順を紹介します。
まず、あらかじめ以下の作業が完了していることを確認してから、手順に取り掛かってください。
- 作業環境上にDockerのインストールが完了していること。
- 作業環境上にAWS CLIのインストール・初期設定が完了していること。
最初に、次の手順に従ってAqua Server・Aqua Gatewayのイメージをpullします。今回の例では、
$ docker login registry.aquasec.com -u <aqua_username> -p <aqua_password> $ docker pull registry.aquasec.com/console:<version> $ docker pull registry.aquasec.com/gateway:<version>
次に作業環境上にて、aws ecr get-login-passwordコマンドでECRにログインし、イメージのタグを付け直した後、ECRにイメージをpushします。
この手順の後、AWSマネジメントコンソールのECRの画面より、pushしたイメージが確認できます。
CloudFormationでECS-Fargate上に、Aqua Server・Aqua Gatewayをデプロイする
この項では、AWSマネジメントコンソール上で、CloudFormationのスタックを作成し、ECS-FargateにAqua Server・Aqua Gatewayをデプロイする手順を紹介します。
まず、あらかじめ以下の作業が完了していることを確認してから、手順に取り掛かってください。
- AWSマネジメントコンソール上で「ecsTaskExecutionRole」に以下のポリシーがアタッチされていること
- AmazonEC2ContainerRegistryReadOnly
- AmazonECSTaskExecutionRolePolicy
- 2つ以上のサブネットを持つVPCを用意すること
- 外部で取得した証明書をACMにインポートし、ARNの値を控えること
最初に、Aqua社のGithubレポジトリから、CloudFormationで使うyamlファイルを取得します。また。Github上のREADMEの中の「Launch Stack」から直接Cloudformationの画面に行くことも可能です。
https://github.com/aquasecurity/aqua-aws/tree/master/cloudformation/aqua-ecs-fargate
次にAWSマネジメントコンソールより、CloudFormationの画面へ行き、「スタックの作成」-「新しいリソースを使用」をクリックします。
「スタックの作成」の画面で、「前提条件 - テンプレートの準備」から「テンプレートの準備完了」・「テンプレートファイルのアップロード」のラジオボタンにチェックを入れます。
「テンプレートの指定」から「ファイルの選択」をクリックし、Aqua社のGithubレポジトリから取得した、yamlファイルを選択し、「次へ」をクリックします。
「スタックの詳細を指定」の画面でスタックの情報を入力していきます。赤線で囲われた項目に、設定項目を入力していきます。
また、デフォルト値があらかじめ入っている箇所は、変更する必要はありません。
設定値の入力例
スタックの名前:任意の名前 ※文字数の制限があるため、短めにすることを推奨します VPC ID:任意のVPC VPC CIDR:VPCのCIDRを入力します。例:10.0.0.0/16 ECS Instance Subnets:任意のサブネットを2つ選択 Aqua LB Subnets:任意のサブネットを2つ選択 SSL cert ARN:SSL証明書のARN値 Aqua LB Scheme:interenet-facing(デフォルト値) Web Console Source:0.0.0.0/0(デフォルト値) AquaServerImage:Aqua ServerのECR上のリポジトリ名 AquaGatewayImage:Aqua GatewayのECR上のリポジトリ名 RDS instance type:db.t3medium(デフォルト値) RDS storage size(GB):50(デフォルト値) Enable Multi-AZ RDS:true(デフォルト値) AuditRdsInstanceClass:db.t3medium(デフォルト値) ClusterName:任意の名前 ※文字数の制限があるため、短めにすることを推奨します
「スタックオプションの設定」という画面に行くので、何も入力せず、「次へ」をクリックします。
設定値の確認画面に行くので、設定内容に誤りがないか確認し、一番下の、「AWS CloudFormationによってIAMリソースがカスタム名で作成される場合があることを承認します。」にチェックを入れ、「スタックの作成」をクリックします。
CloudFormationでスタックの作成には20~30分程掛かります。スタックの作成が終了すると、スタックのステータスが「CREATE_COMPLETE」となり、ECS-Fargate上にAqua Server・Aqua Gatewayがデプロイされます。
CloudFormationでのスタックの作成が完了したため、Aqua Platformにログインします。
AWSマネジメントコンソールのロードバランサーの画面から、AquaConsoleLBのDNS名をコピーし、httpsのURLとしてブラウザ上で表示します。
Aqua Platformのログイン画面が開くので、初期パスワードを入力します。
ライセンスを入力する欄が表示されるので、Aqua Platformのライセンスを入力します。
Aqua PlatformのDashboardが表示されます。
MicroEnforcerをデプロイする
この項では、Aqua Platformのエージェントとなる、MicroEnforcerの説明と、MicroEnforcerをデプロイするための事前準備について紹介します。
MicroEnforcerをデプロイするための方法は2つあります。
1つ目の方法は、アプリケーションコンテナをデプロイする際に、MicroEnforcerのバイナリをDockerfileの中に埋め込んでから、コンテナを立ち上げるという方法です。
2つ目の方法は、アプリケーションコンテナとは別に、サイドカータイプのコンテナを用意して、サイドカーコンテナのDockerfile中にMicroEnforcerのバイナリを埋め込みます。そして、アプリケーションコンテナが立ち上がる際に、サイドカーコンテナからアプリケーションコンテナへMicroEnforcerの情報を渡してから、コンテナを立ち上げるという方法です。
本稿では1つ目の方法を実施します。
事前準備 - MicroEnforcerのバイナリの取得
この項では、ECS-Fargate上で動作するコンテナに埋め込むMicroEnforcerのバイナリを取得する手順を紹介します。
Aqua社のドキュメントサイトにアクセスし、サイト中のリンクよりMicroEnforcerのバイナリを取得します。
事前準備 - アプリケーションイメージの中で使われるENTRYPOINT・CMDを取得する
この項では、ECS-Fargate上で動作するコンテナのDockerfile内に記述するENTRYPOINT・CMDの値を取得する手順を紹介します。今回の例では、nginx:1.21のイメージをアプリケーションイメージとして使います。
作業環境上で、次のコマンドを実行し、ENTRYPOINT・CMDの値を算出します。
$ docker inspect nginx:1.21 -f "{{json .Config.Cmd}}" ##CMDの値を求めるコマンド $ docker inspect nginx:1.21 -f "{{json .Config.Entrypoint}}" ##ENTRYPOINTCMDの値を求めるコマンド
今回の例だと、想定される値は下記の通りです。
["nginx","-g","daemon off;"] ##CMDの値 ["/docker-entrypoint.sh"] ##ENTRYPOINTCMDの値
事前準備 - MicroEnforcerのEnforcer Groupの作成
この項では、コンテナ上に埋め込むMicroEnforcerが所属する、Enforcer Groupを作成する手順を紹介します。
Aqua PlatformのUI画面より、「Administration」-「Enforcers」からEnforcerのページにアクセスし、新しいEnforcer Groupを作成します。
Enforcerの管理画面から右上の「Add Enforcer Group」のボタンをクリックし、Enforcer Groupの作成画面に移動します。
Enforcer Groupの作成画面で以下の設定を入力し、画面右上の「Create Group」をクリックします。
なお、ここで設定するLogical Nameの値は、タスク定義を作成する際に使用するので、控えるようにしてください。
- Enforcer Group:MicroEnforcer
- Group Name:任意の名前
- Logical Name:任意の名前
Enforcer Groupの作成が完了すると、MicroEnforcerのトークンの値とDockerfileのサンプルが表示されるので、控えてください。
補足ですが、上記の画面の情報は、後からでもEnforcer Groupの管理画面から見に行くことが出来ます。
埋め込みタイプでMicroEnforcerをFargateにデプロイする
この項では、埋め込み型MicroEnforcerをデプロイしていく流れを紹介します。
先の事前準備の手順で用意したMicroEnforcerのバイナリと、ENTRYPOINT・CMDの値をアプリケーションコンテナのDockerfileの中に埋め込んでコンテナをデプロイします。
事前準備で用意した、Dockerfileの雛型をベースに、コンテナのイメージを作っていきます。
DockerfileをビルドしてECRにpushする
この項では、ECS-Fargate上で動作するコンテナのDockerfileを作成する手順について紹介します。
まず、あらかじめ以下の作業が完了していることを確認してから、手順に取り掛かってください。
- 作業環境上に、Dockerのインストールが完了していること。
- 作業環境上に、AWS CLIのインストール・初期設定が完了していること。
作業環境上に、Dockerfileのビルドに使うための作業ディレクトリを作成し、事前準備で用意した、MicroEnforcerのバイナリと、policy.json・firewall.jsonという名前の空ファイルを配置します。(今回は空ファイルを使用しましたが、イメージプロファイルやコンテナファイアウォールを利用する場合は、別途設定が必要です。)
次に作業環境上の作業ディレクトリに移動して、事前準備で取得したDockerfileのサンプルを編集し、ビルドします。今回の例だとnginx:1.21のイメージをアプリケーションイメージとして使います。
元のサンプルから編集する箇所は、2つあります。
1つ目は、事前準備で用意した、ENTRYPOINT・CMDの値を入力する箇所です。
2つ目は、本稿ではオプションのため省きましたが、Aqua Platformのファイアウォールポリシーを適用したい場合に、セキュリティポリシーの情報の入ってるJSONファイルをエクスポートして、Dockerfile埋め込むことが出来ます。本稿ではセキュリティポリシーの手順は省略しているため、空ファイルを使用してます。
$ vi Dockerfile ===== ここから下viの内容 ===== FROM nginx:1.21 ADD microenforcer /bin/microenforcer RUN ["chmod", "+x", "/bin/microenforcer"] RUN ["/bin/microenforcer", "aqua-init"] ADD policy.json /.aquasec/policy/policy.json ADD firewall.json /.aquasec/policy/firewall.json CMD ["nginx","-g","daemon off;"] ENTRYPOINT ["/bin/microenforcer", "/docker-entrypoint.sh"] ENV LD_PRELOAD='/.aquasec/bin/$PLATFORM/slklib.so' ===== viの内容ここまで ===== $ docker build --no-cache -t <imagename>:<version> .
次に作業環境上にて、aws ecr get-login-passwordコマンドでECRにログインし、イメージのタグを付け直した後、ECRにイメージをpushします。
ECS-Fargateタスク定義の作成
この項では、アプリケーションコンテナを動作させるための、タスク定義を作成する手順を紹介します。
AWSマネジメントコンソールのECSの画面より、「タスク定義」をクリックします。
タスク定義の画面から「新しいタスク定義の作成」をクリックします。
ECS起動タイプに「Fargate」を選択し、「次のステップ」をクリックします。
「新しいタスク定義の作成」の画面が表示されます。
下記の入力例を参考に、設定項目を入力します。
入力例:
タスクとコンテナの定義の設定 タスク定義名:任意の値 タスクロール:任意のロール 例:ecsTaskExcutionRole ネットワークモード:awsvpc(デフォルト値) オペレーティングシステムファミリー:任意のOS 例:Linux タスクの実行 IAM ロール タスク実行ロール:ecsTaskExcutionRole(デフォルト値) タスクサイズ タスクメモリ (GB):任意の値 タスク CPU (vCPU):任意の値
「コンテナの定義」-「コンテナの追加」をクリックします。
下記の入力例を参考に、設定項目を入力し、「追加」をクリックします。
コンテナの追加 スタンダード コンテナ名:任意の名前 イメージ:対象のイメージのECR上のURI 詳細コンテナ設定 環境 基本:レ点チェックを入れる エントリポイント:事前準備で取得した値 コマンド:事前準備で取得した値 環境変数: AQUA_LOGICAL_NAME:「MicroEnforcerのEnforcer Groupの作成」で設定したLogicalName AQUA_SERVER:Aqua GatewayのIPアドレス・ポート番号 AQUA_TOKEN:「MicroEnforcerのEnforcer Groupの作成」で取得したトークン
「新しいタスク定義の作成」の画面に戻り、画面下部の「作成」をクリックすると、タスク定義が完成されます。
ECS-Fargateタスクの起動
この項では、先の手順で作成したタスク定義を使って、ECS-Fargate上で実際にコンテナを動作させる手順を紹介します。
ECSクラスターの管理画面の「サービス」タブから「作成」をクリックします。
「サービスの設定」の画面が表示されるので、下記の入力例を参考に設定値を入力し、「次のステップ」をクリックします。
起動タイプ:Fargate オペレーティングシステムファミリー:任意のOS 例 Linux タスク定義: ファミリー:前項で作成したタスク定義を入力 リビジョン:任意の世代を入力 プラットフォームのバージョン:LATEST(デフォルト値) クラスター:任意の値 サービス名:任意の名前 タスクの数:任意の値 例 1 最小ヘルス数:100(デフォルト値) 最大率:200(デフォルト値) デプロイサーキットメーカー:無効(デフォルト値)
「ネットワーク構成」の画面が表示されるので、下記の入力例を参考に設定値を入力し、「次のステップ」をクリックします。
VPCとセキュリティグループ クラスターVPC:任意のVPC サブネット:任意のサブネット パブリックIPの自動割り当て:ENABLED(デフォルト値) 詳細オプション:デフォルト値 タスクのタグ付け設定:デフォルト値 Tags:空欄(デフォルト値)
「Auto Scaling」の画面が表示されるので、何も入力せず、「次のステップ」をクリックします。
「確認」の画面が表示されるので、設定内容を確認し、「サービスの作成」をクリックします。
「起動ステータス」の画面が表示されるので、チェックが通ったことを確認し、「サービスの表示」をクリックします。
Fargateタスクをクリックします。
ステータスが「RUNNING」となっていることを確認します。
Aqua PlatformのEnforcerの画面から、MicroEnforcerとの疎通が取れていることを確認できます。
MicroEnforcerによるランタイム保護が効いているかを検証
この項では、実際にコンテナの中に入ってコマンドを実行してみて、MicroEnforcerによるランタイム保護が効いているか確認する流れを紹介します。
本稿では、Aqua Platformでデフォルトで有効になっている、「Drift Prevention」と呼ばれるランタイム保護を使ってテストしてみます。
このランタイム保護は、コンテナ内に元々存在しないファイルの実行を防ぐ機能です。
例えば、コンテナの中にシェルでログインし、「Hello World」と表示させるシェルを新たに作成し実行すると、「Permission denied」と出力され、シェルを実行することができなくなります。
「Drift Prevention」はデフォルトで有効化されているため、特に設定の作業をする必要はありません。
しかし、Aqua Platformはデプロイしたばかりのデフォルトの状態では、EnforceModeが「Audit」となっており、そのままではランタイム保護の機能を使用することができないため、EnforceModeを「Enforce」に設定をして、ランタイム保護を有効化させてからテストを行いたいと思います。
Aqua Platform上でランタイム保護を設定する
この項では、Aqua Platform上でランタイム保護を設定する手順を紹介します。
ECS-Fargate上で動作しているAqua Platformにログインして、「Policies」-「Runtime Policies」をクリックします。
「Aqua default runtime policies」のポリシーをクリックします。
「Enforcement Mode」が「Audit」になっているので、「Enforce」をクリックします。
画面右上の「Save」をクリックします。
確認用のポップアップが表示されるため、「OK」をクリックし、設定を保存します。
ECS-Fargate上のコンテナにシェルログインしてコマンドをテストする
この項では、コンテナにシェルでログインして、ランタイム保護が実際に動作している様子を紹介します。
まず、あらかじめECS Exec機能を実行できる状態になっていることを確認してから、手順に取り掛かってください。
作業環境上で、ECS Execで対象コンテナにログインします。
コンテナ上にログインできたら、/bin/pwdをコピーしてpodというコマンドを作成します。
$ cp -p /bin/pwd /bin/pod
その後コンテナ上で「/bin/pod」を実行すると、「permission denied」と表示され、コマンドを実行できなくなることが確認できます。
ランタイム保護の履歴は、Aqua Platformの画面から見ることができます。
「Security Report」-「Audit」をクリックします。
Auditの画面が開くので、画面左上の「Block」をクリックします。
監査ログより、「/bin/pod」がDrift Preventionによりブロックされたことが分かると思います。
まとめ
本稿ではECS-Fargate上にAqua Platformをデプロイし、MicroEnforcerが動作するコンテナをデプロイして、実際にコンテナの中に入って動作検証を行いました。
ECS-Fargate上に環境をデプロイすることで、EC2にデプロイする場合と比べて、リソースの見積もりやインスタンスタイプの選定、必要な台数の計算などの下回りの作業が削減され、管理にかかるコストを少なくすることができ、アプリケーションの開発に集中することができます。
また、Cloudformationを使ってECS-Fargate上にデプロイすることは、Aquaを構築するうえで負担の少ないやり方ですので、Aquaの導入を検討している方は是非、参考にして頂けたら幸いです。
今回はMicroEnforcerを埋め込みタイプでデプロイしましたが、次回は、サイドカータイプでデプロイする手順について紹介したいと思います。