クラウドセキュリティエンジニアブログ

ニューリジェンセキュリティのクラウドセキュリティエンジニアチームが AWSなどのクラウドセキュリティについて気になることや調べたことを書くブログ

Amazon InspectorがEC2インスタンスのdeep inspectionをサポートしたので、パターン別に検証してみた

こんにちは、クラウドセキュリティアーキテクトの大島悠司です。
Amazon Inspectorが、EC2インスタンスのdeep inspectionをサポートするようになりました。
従来は、OS標準搭載のパッケージマネージャーである yum や apt でインストールしたパッケージしか検知できませんでした。
今回のアップデートにより、プログラミング言語のパッケージマネージャーである pip や nmp でインストールしたパッケージも検知できるようになりました。

以前、InspectorがLambdaの診断対象をパターン別に検証したことがあり、今回も同様にパターン別に検証してみました。

devblog.nuligen.com

まずは結論から

時間が無い方用に結論を述べます。
Amazon Inspectorは、EC2インスタンスのdeep inspection機能を使うことで、任意のパスにあるパッケージの脆弱性を診断することができます。
ただし、Lambdaに対する診断と同じようなアーティファクトを使用しているため、メタファイル名やパッケージ内のファイルパスを変更するなどした場合、アーティファクトから外れてしまい、検知できないと考えられます。

アップデート概要

  • プログラミング言語のパッケージマネージャーからインストールしたパッケージも診断可能
  • デフォルトのディレクトリパスだけだけでなく、カスタムディレクトリパスを追加することで、より柔軟なパッケージ検出可能
    デフォルトディレクトリパスは以下
/usr/lib
/usr/lib64
/usr/local/lib
/usr/local/lib64
  • 2023 年 4 月 17 日以降にInspectorを有効化した場合は、deep inspectionも自動的に有効化される
  • 追加料金なしで利用可能

aws.amazon.com

docs.aws.amazon.com

Deep Inspectionの有効化

Inspectorの「設定」→「アカウント管理」を見ると、Amazon EC2スキャンの欄に「Deep inspection deactivated」と表示されています。
画面上部にある「Activate the deep inspection」ボタンがあるので押下します。

これで、有効化されました。

また、Organaization環境の場合、管理アカウントあるいはInspectorの委任先アカウントで、画面上部にある「Activate the deep inspection for your organization」ボタンから、全アカウントに対して一括で有効化ができます。

AWS System Manager ステートマネージャー を確認

Deep inspectionを有効化すると、AWS System Manager ステートマネージャーで以下の関連付けが作成されます。

  • InspectorLinuxDistributor-do-not-delete
  • InvokeInspectorLinuxSsmPlugin-do-not-delete

それぞれの関連付けドキュメントを確認してみます。

関連付け:InspectorLinuxDistributor-do-not-delete

ドキュメント:AmazonInspector2-InvokeInspectorSsmPluginLinux

InspectorのSSMプラグインをインストール/アンインストールしているようです。

{
  "schemaVersion": "2.2",
  "description": "Install or uninstall a Distributor package.",
  "parameters": {
    "action": {
      "description": "(Required) Specify whether or not to install or uninstall the package.",
      "type": "String",
      "allowedValues": [
        "Install",
        "Uninstall"
      ]
    },
    "installationType": {
      "description": "(Optional) Specify the type of installation. Uninstall and reinstall: The application is taken offline until the reinstallation process completes. In-place update: The application is available while new or updated files are added to the installation.",
      "type": "String",
      "allowedValues": [
        "Uninstall and reinstall",
        "In-place update"
      ],
      "default": "Uninstall and reinstall"
    },
    "name": {
      "description": "(Required) The package to install/uninstall.",
      "type": "String",
      "allowedPattern": "^arn:[a-z0-9][-.a-z0-9]{0,62}:[a-z0-9][-.a-z0-9]{0,62}:([a-z0-9][-.a-z0-9]{0,62})?:([a-z0-9][-.a-z0-9]{0,62})?:(package|document)\\/[a-zA-Z0-9/:.\\-_]{1,128}$|^[a-zA-Z0-9/:.\\-_]{1,128}$"
    },
    "version": {
      "description": "(Optional) The version of the package to install or uninstall. If you don't specify a version, the system installs the latest published version by default. The system will only attempt to uninstall the version that is currently installed. If no version of the package is installed, the system returns an error.",
      "type": "String",
      "default": ""
    },
    "additionalArguments": {
      "description": "(Optional) The additional parameters to provide to your install, uninstall, or update scripts.",
      "type": "StringMap",
      "displayType": "textarea",
      "default": {},
      "maxChars": 4096
    }
  },
  "mainSteps": [
    {
      "action": "aws:configurePackage",
      "precondition": {
        "StringEquals": [
          "platformType",
          "Linux"
        ]
      },
      "name": "configurePackage",
      "inputs": {
        "name": "{{ name }}",
        "action": "{{ action }}",
        "installationType": "{{installationType}}",
        "version": "{{ version }}",
        "additionalArguments": "{{ additionalArguments }}"
      }
    }
  ]
}

関連付け:InvokeInspectorLinuxSsmPlugin-do-not-delete

ドキュメント:AmazonInspector2-InvokeInspectorSsmPluginLinux

Linux用のInspectorのSSMプラグインを呼び出しているようです。

{
  "schemaVersion": "2.2",
  "description": "Invokes inspector ssm plugin for linux",
  "parameters": {
    "Timeout": {
      "type": "String",
      "description": "Timeout in seconds for inspector ssm plugin",
      "default": "900",
      "allowedPattern": "^([0-9]|[1-9][0-9]+)$"
    },
    "CpuLimit": {
      "type": "String",
      "description": "Cpu usage limit in percentage for inspector ssm plugin",
      "default": "65",
      "allowedPattern": "^([1-9]|[1-9][0-9])$|^(100)$"
    }
  },
  "mainSteps": [
    {
      "action": "aws:runShellScript",
      "name": "invokeInspectorSsmPluginLinux",
      "precondition": {
        "StringEquals": [
          "platformType",
          "Linux"
        ]
      },
      "inputs": {
        "runCommand": [
          "#!/bin/bash",
          "#",
          "# Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.",
          "#",
          "",
          "set -x",
          "",
          "function fail {",
          "  echo $1",
          "  echo $1 >&2",
          "  exit 1",
          "}",
          "",
          "function retry {",
          "  local attempt=0",
          "  local max_attempts=5",
          "  local delay=60",
          "  while",
          "    \"$1\" && break || {",
          "        ((attempt++))",
          "        echo \"Waiting for $delay second(s) before retrying...\"",
          "        sleep $delay;",
          "    }",
          "    [[ $attempt -lt $max_attempts ]]",
          "  do :; done",
          "  if [[ $attempt -eq $max_attempts ]]; then",
          "    echo \"Retries completed after $attempt attempts.\"",
          "    fail \"$2\"",
          "  fi",
          "}",
          "",
          "INSPECTOR_ROOT_DIR=\"/opt/aws/inspector\"",
          "INSPECTOR_SSM_PLUGIN=\"$INSPECTOR_ROOT_DIR/bin/inspectorssmplugin\"",
          "INSPECTOR_OUTPUT_DIR=\"$INSPECTOR_ROOT_DIR/var/output\"",
          "",
          "TIMEOUT=\"{{Timeout}}\"",
          "CPU_LIMIT=\"{{CpuLimit}}\"",
          "",
          "function is_installed {",
          "  if [[ ! -f $INSPECTOR_SSM_PLUGIN ]]; then",
          "    echo \"$INSPECTOR_SSM_PLUGIN does not exist\"",
          "    (exit 1)",
          "  else",
          "    echo \"$INSPECTOR_SSM_PLUGIN exist\"",
          "  fi",
          "}",
          "",
          "echo \"Checking the installation of inspector ssm plugin...\"",
          "retry is_installed \"Inspector ssm plugin is not installed. Exiting...\"",
          "echo \"Inspector ssm plugin is installed.\"",
          "",
          "echo \"Starting evaluation using inspector ssm plugin\"",
          "cmd=\"$INSPECTOR_SSM_PLUGIN -mode bpm -read-params-store -report-ssm-inventory -report-metrics-via-ssm-inventory -save-findings-as $INSPECTOR_OUTPUT_DIR/packages.txt -format text -timeout $(($TIMEOUT)) -cpulimit $(($CPU_LIMIT))\"",
          "$cmd",
          "status=$?",
          "if [ $status -eq 0 ]",
          "then",
          "  echo \"Inspector ssm plugin linux ran successfully\"",
          "  exit 0",
          "else",
          "  fail \"Inspector ssm plugin did not run successfully\"",
          "fi"
        ]
      }
    }
  ]
}

(1)pipコマンドで古いパッケージを取得(deep inspection設定前)

以下のインスタンスを用意しました。
以降の検証も全て同じインスタンスを利用します。

pipでnumpy1.21.3をインストールします。

$ pip install numpy==1.21.3
Defaulting to user installation because normal site-packages is not writeable
Collecting numpy==1.21.3
  Downloading numpy-1.21.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (15.7 MB)
     |████████████████████████████████| 15.7 MB 5.6 MB/s
Installing collected packages: numpy
Successfully installed numpy-1.21.3

インストールパスを確認すると、「/home/ssm-user」配下にインストールされているようです。

Name: numpy
Version: 1.21.3
Summary: NumPy is the fundamental package for array computing with Python.
Home-page: https://www.numpy.org
Author: Travis E. Oliphant et al.
Author-email:
License: BSD
Location: /home/ssm-user/.local/lib/python3.9/site-packages
Requires:
Required-by:

Inspectorを確認すると、検知結果がないことが確認できます。

これは、先ほどnumpyのインストールパスを確認した通り、Inspectorがデフォルトで検査する以下のパスにnumpyが存在しないためです。

/usr/lib
/usr/lib64
/usr/local/lib
/usr/local/lib64

(2)pipコマンドで古いパッケージを取得(deep inspection設定後)

Inspectorの「全般設定」→「EC2スキャン設定」から、カスタムパスの「編集」を押下します。

先ほどの確認で、numpyは「/home/ssm-user」に存在することが分かっているので、そのパスを入力して「保存」を押下します。

deep inspectionのためのアプリケーションインベントリの収集は6時間毎に行われる仕様です。
今回は検証のため手動で実行します。
InvokeInspectorLinuxSsmPlugin-do-not-delete の関連付けが、Linux用のInspectorのSSMプラグインを呼び出すものなので、これを再適用します。
AWS System Manager ステートマネージャーで InvokeInspectorLinuxSsmPlugin-do-not-delete を選択し、「関連付けを今すぐ適用」を押下します。
以降の検証もこの再適用を繰り返し実施します。

すると、Inspectorの検出結果でnumpyの脆弱性が検知されています。

検知されたパッケージが存在するファイルパスも、deep inspectionで設定したパス配下であることが確認できます。

このファイルパスにあるMETADATAは、numpyのバージョンやライセンスなどの情報が書かれており、Inspectorはこのファイルを見て脆弱か否かを判定しているようです。

$ pwd
/home/ssm-user/.local/lib/python3.9/site-packages/numpy-1.21.3.dist-info
$ cat METADATA
Metadata-Version: 2.1
Name: numpy
Version: 1.21.3
Summary: NumPy is the fundamental package for array computing with Python.
Home-page: https://www.numpy.org
Author: Travis E. Oliphant et al.
Maintainer: NumPy Developers
Maintainer-email: numpy-discussion@python.org
License: BSD
Download-URL: https://pypi.python.org/pypi/numpy
Project-URL: Bug Tracker, https://github.com/numpy/numpy/issues
Project-URL: Documentation, https://numpy.org/doc/1.21
Project-URL: Source Code, https://github.com/numpy/numpy
Platform: Windows
Platform: Linux
Platform: Solaris
Platform: Mac OS-X
Platform: Unix
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: C
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Software Development
Classifier: Topic :: Scientific/Engineering
Classifier: Typing :: Typed
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX
Classifier: Operating System :: Unix
Classifier: Operating System :: MacOS
Requires-Python: >=3.7,<3.11

It provides:

- a powerful N-dimensional array object
- sophisticated (broadcasting) functions
- tools for integrating C/C++ and Fortran code
- useful linear algebra, Fourier transform, and random number capabilities
- and much more

Besides its obvious scientific uses, NumPy can also be used as an efficient
multi-dimensional container of generic data. Arbitrary data-types can be
defined. This allows NumPy to seamlessly and speedily integrate with a wide
variety of databases.

All NumPy wheels distributed on PyPI are BSD licensed.

以降、このMETADATAファイルに対して様々な変更を加え、Inspectorが検知できるのかを見ていきます。

(2-2)METADATAファイル名を変更

mvコマンドでファイル名を「METADATA」から「METADATAtest」に変更します。

$ pwd
/home/ssm-user/.local/lib/python3.9/site-packages/numpy-1.21.3.dist-info
$ mv METADATA METADATAtest
$ ls
INSTALLER  LICENSE.txt  LICENSES_bundled.txt  METADATAtest  RECORD  REQUESTED  WHEEL  entry_points.txt  top_level.txt

AWS System Manager ステートマネージャーで InvokeInspectorLinuxSsmPlugin-do-not-delete をの関連付けを再適用します。
すると、Inspectorで検知されませんでした。

(2-3)METADATAファイルパスを変更

mvコマンドでファイル名を「METADATAtest」から「METADATA」に戻します。
そして、mvコマンドで1つ上の階層に移動させます。

$ mv METADATAtest METADATA
$ mv METADATA ..
$ pwd
/home/ssm-user/.local/lib/python3.9/site-packages/numpy-1.21.3.dist-info
$ ls
INSTALLER  LICENSE.txt  LICENSES_bundled.txt  RECORD  REQUESTED  WHEEL  entry_points.txt  top_level.txt
$ cd ..
$ ls
METADATA  numpy  numpy-1.21.3.dist-info  numpy.libs

AWS System Manager ステートマネージャーで InvokeInspectorLinuxSsmPlugin-do-not-delete をの関連付けを再適用します。
すると、先ほどと同様にInspectorで検知されませんでした。

(2-4)METADATAファイルを削除

mvコマンドで「METADATA」を /tmp 配下に移動します。

$ pwd
/home/ssm-user/.local/lib/python3.9/site-packages
$ mv  METADATA /tmp/
$ ls
numpy  numpy-1.21.3.dist-info  numpy.libs
$ ls /tmp/
METADATA

AWS System Manager ステートマネージャーで InvokeInspectorLinuxSsmPlugin-do-not-delete をの関連付けを再適用します。
すると、先ほどと同様にInspectorで検知されませんでした。

(2-5)METADATAファイルを書き換える

まずは、mvコマンドで「METADATA」を元のパスに移動します。

$ mv /tmp/METADATA numpy-1.21.3.dist-info/
$ cd numpy-1.21.3.dist-info/
$ ls
INSTALLER  LICENSE.txt  LICENSES_bundled.txt  METADATA  RECORD  REQUESTED  WHEEL  entry_points.txt  top_level.txt

適当なエディタで「METADATA」を開き、Versionを「1.21.3」から「1.21.0」に書き換えます。

$ vim METADATA
Metadata-Version: 2.1
Name: numpy
Version: 1.21.0
Summary: NumPy is the fundamental package for array computing with Python.
Home-page: https://www.numpy.org
Author: Travis E. Oliphant et al.
Maintainer: NumPy Developers
(省略)

ファイル「METADATA」に記載のバージョン情報が書き換わっていることを確認します。

$ cat METADATA | grep ^Version
Version: 1.21.0

AWS System Manager ステートマネージャーで InvokeInspectorLinuxSsmPlugin-do-not-delete をの関連付けを再適用します。
すると、Inspectorで検知されました。

Inspectorで詳細を確認すると、インストール済バージョンが書き換えた「1.21.0」で検知されていることが確認できます。

まとめ

以上の検証をまとめると、以下の表のようになります。

Amazon Inspectorのdeep inspectionを使って、EC2にインストールされたnumpyを様々なパターンで診断させた場合の結果

検証番号 条件 結果
(1) pipコマンドで古いパッケージを取得(deep inspection設定前) METADATAで検知
(2) pipコマンドで古いパッケージを取得(deep inspection設定後) METADATAで検知
(2-2) METADATAファイル名を変更 検知無し
(2-3) METADATAファイルパスを変更 検知無し
(2-4) METADATAファイルを削除 検知無し
(2-5) METADATAファイルを書き換える METADATAで書き換えたバージョンとして検知

Inspectorのdeep inspection機能を使って、ユーザがパスを明示することで、pip や nmp でインストールしたパッケージであっても検知することができました。
ただし、メタファイル名やパッケージ内のファイルパスを変更するなどした場合、アーティファクトから外れてしまい、検知できないと考えられます。
冒頭にも紹介した通り、以前のブログでLambdaに対する診断も同様のパターン別検証をしており、その時と同様の結果になっています。
deep inspectionは便利な機能ですが、Inspectorのこのような特性を理解したうえで活用していければと思います。