[アップデート] Amazon OpenSearch Service の取り込みパイプラインが Amazon Security Lake からのイベント取り込みをサポートしました

2023.06.27

いわさです。

AWS 上でセキュリティ情報を管理する際に、Amazon OpenSearch Service で分析や可視化出来るようにすることがあります。
また、それを実装したソリューションである SIEM on Amazon OpenSearch Service というものも提供されています。

このソリューションでは個別に S3 や Kinesis を介してセキュリティデータを収集し、Lambda で ETL 処理を行うことで OpenSearch Service 上へ取り込み、ダッシュボードで可視化出来るようなものになっています。

一方で、直近ではセキュリティデータ用のデータレイクを簡単に構築出来る Amazon Security Lake や、OpenSearch Service への取り込みパイプラインを構築出来る Amazon OpenSearch Ingestion というものも登場しています。

本日のアップデートで Amazon OpenSearch Ingestion は、Apache Parquet 形式でのデータの取り込みをサポートするようになりました。
これによって、Amazon OpenSearch Ingestion を使って Amazon Security Lake からリアルタイムでイベントを取り込めるようになりました。

Amazon Security Lake と Amazon OpenSearch Service を簡単に統合することが出来るようになるので、非常に興味深いアップデートですね。
本日は Security Lake を有効化し、OpenSearch Serverless 上でセキュリティログの確認までを行ってみましたので構築方法などの流れを紹介します。

はじめに概念をおさらい

実は私がまだ Security Lake も OpenSearch Ingestion も構築したことがなく、アップデート情報をちょっと眺めていた程度だったので、概念を先におさらいしておきたいと思います。

Amazon Security Lake とは

Amazon Security Lake は先月 GA を迎えた、セキュリティ向けのデータレイクサービスです。

デフォルトで基本的な AWS サービスのログは一通りサポートされており、さらにカスタムソース機能から外部からのログ取り込みも可能です。
Security Lake を有効化するだけで、これらを一元化したデータレイクを簡単に構築することが出来ます。

さらに、Security Lake にはサブスクライバーという機能があり、Security Lake のデータを外部サービスやアカウントから参照させるための機能もあります。
今回はこちらを使って Amazon OpenSearch Service から Security Lake のデータを取り込むような挙動となっています。

サブスクライバーはデータアクセスとクエリアクセスの概念があり、今回はデータアクセスの機能を使います。(上記ブログはクエリアクセス)
これは、データが Security Lake の S3 バケットに書き込まれると、HTTPS エンドポイントまたは Amazon SQS キューを介して、サブスクライバーが新しいオブジェクトについて通知を受けることができる仕組みです。

後述する OpenSearch Service の Ingestion で構成するパイプラインで、この SQS キューを選択することで、OpenSearch Service 側に新しいイベントデータが取り込まれるという仕組みになっています。

取り込みパイプラインとは

続いて Amazon OpenSearch Ingestion のパイプラインについてです。
パイプラインとは、Amazon OpenSearch Ingestion がデータをソース (データの取得元) からシンク (データの移動先) に移動するために使用する機能で、2 ヶ月前にリリースされました。

冒頭のアーキテクチャーでは Lambda で ETL 部分を構成していましたが、今回 Ingestion パイプラインを使って Security Lake との統合を行うことが出来るようになっています。

Amazon OpenSearch Ingestion - Amazon OpenSearch Service より引用

やってみよう

今回は Security Lake も OpenSearch Service も使っていない環境で新規構築を行ってみました。
流れとしては次のような感じです。

  • Security Lake を有効化する
  • Security Lake でサブスクライバーを作成する
  • OpenSearch Serverless のコレクションを作成する
  • OpenSearch Ingestion のパイプラインを作成する

Security Lake 有効化 + サブスクライバー作成

委任管理アカウントを選択して有効化するだけです。
対象ソースやアカウントなどはデフォルト状態で構成しました。Security Lake として少しオプションがある部分ですが、今回のアップデートには影響しないので割愛します。

Security Lake が有効化できたら、次にサブスクライバーを作成します。

データアクセス方法は S3 を、通知の詳細は SQS キューを選択しました。
OpenSearch Service Ingestion パイプラインでブループリントを使うのですが、SQS キューを指定する形になっているので併せて SQS キューを選択しています。

ここで、IAM ロールが自動作成されまして、そちらにはインラインポリシーが 2 つ設定されています。
後ほどこのポリシーを組み合わせたものを作る必要があるので、ポリシー内容を確認しておきましょう。

OpenSearch Serverless のコレクションを作成

続いて OpenSearch Serverless のコレクションを作成します。
ちなみに、今回は Serverless を選択しましたが、非 Serverless なドメイン環境にも取り込みは可能です。

コレクションタイプはログ分析などの場合は時系列タイプを選択します。
コレクションタイプは後ほど変更出来ないのでご注意ください。

ネットワークはパブリックを選択しました。
検証用なので単純化したくてパブリックにしたのですが、VPC を選択する場合はいくつか考慮事項が増えそうな気がしますね。

データアクセスの設定を行うことでエンドポイントやダッシュボードへアクセス出来るようになるのですが、設定にはパイプライン用の IAM ロール ARN が必要で、かつパイプライン用の IAM ロールのポリシーではコレクションの ARN を指定する必要があります。
ちょっと面倒なのですが、コレクション作成 → IAM ロール作成 → コレクションにデータアクセスポリシーを設定という順で設定していきたいと思います。

作成するとコレクションの ARN が取得出来るのでこちらを使った IAM ロールを構成したいと思います。

パイプライン用の IAM ロール作成

次の公式ドキュメントの手順に従ってパイプライン用ロールを作成します。

サービスを信頼したロールを作成出来たら、上記ドキュメントに記載の基本ポリシーに加えて、先程 Security Lake のサブスクライバー作成によって自動作成されたロールのインラインポリシーを組み合わせたものもポリシーとして付与しておきます。
内容としては SQS を受信して S3 からデータを取得出来るポリシーになっています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:ListBucket",
                "s3:ListBucketVersions"
            ],
            "Resource": [
                "arn:aws:s3:::aws-security-data-lake-ap-northeast-1-igmvpzos9ssddeoli9mlklqx2/aws/CLOUD_TRAIL_MGMT/1.0/*",
                "arn:aws:s3:::aws-security-data-lake-ap-northeast-1-igmvpzos9ssddeoli9mlklqx2/aws/LAMBDA_EXECUTION/1.0/*",
                "arn:aws:s3:::aws-security-data-lake-ap-northeast-1-igmvpzos9ssddeoli9mlklqx2/aws/S3_DATA/1.0/*",
                "arn:aws:s3:::aws-security-data-lake-ap-northeast-1-igmvpzos9ssddeoli9mlklqx2/aws/VPC_FLOW/1.0/*",
                "arn:aws:s3:::aws-security-data-lake-ap-northeast-1-igmvpzos9ssddeoli9mlklqx2/aws/ROUTE53/1.0/*",
                "arn:aws:s3:::aws-security-data-lake-ap-northeast-1-igmvpzos9ssddeoli9mlklqx2/aws/SH_FINDINGS/1.0/*",
                "arn:aws:s3:::aws-security-data-lake-ap-northeast-1-igmvpzos9ssddeoli9mlklqx2"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "sqs:GetQueueUrl",
                "sqs:ReceiveMessage",
                "sqs:SendMessage",
                "sqs:DeleteMessage",
                "sqs:GetQueueAttributes",
                "sqs:ChangeMessageVisibility",
                "sqs:ListQueues"
            ],
            "Resource": [
                "arn:aws:sqs:ap-northeast-1:123456789012:AmazonSecurityLake-36c3d217-38c1-46c2-b991-3b663050fe4a-Main-Queue",
                "arn:aws:sqs:ap-northeast-1:123456789012:AmazonSecurityLake-36c3d217-38c1-46c2-b991-3b663050fe4a-DLQ"
            ]
        }
    ]
}

今回は上記ポリシーを外したパターンを試していないですが、公式ドキュメントには Security Lake のサブスクライバーによってパイプライン用のポリシーは自動作成されないと明記されていたので、おそらく必須だと思います。

IAM ロールが作成出来たら、OpenSearch Serverless コレクション側のデータアクセスポリシーでロールのアクセスを許可しておきます。

パイプライン作成

下準備が終わったので、最後にパイプラインを作成して動作確認しましょう。
OpenSearch Service のサイドメニューから、新規パイプラインの作成を開始します。

パイプラインの構成を行う必要がありますが、今回のアップデートに伴って Security Lake から取り込むためのブループリントが提供されています。
設定のブループリントからAWS-SecurityLakeS3ParquetOCSFPipelineを選択します。

OpenSearch Serverless のエンドポイントが必要なので事前に確認しておきます。

また、Security Lake サブスクライバーで自動作成される SQS キューの URL も必要です。

デフォルトではいくつかコメントアウトされていますが、以下ハイライト部分をブループリントから変更しています。

###
  ## Relevant Documentation for this blueprint
    # https://docs.aws.amazon.com/opensearch-service/latest/developerguide/use-cases-overview.html
    # https://docs.aws.amazon.com/opensearch-service/latest/developerguide/configure-client.html#configure-client-s3
    # https://docs.aws.amazon.com/opensearch-service/latest/developerguide/pipeline-domain-access.html
  ##
###
###
  # s3-log-pipeline:
  # This pipeline can receive AWS Security Lake logs in either parquet or avro format (depending on which is configured in s3.codec parameter) from an SQS queue,
  # and then writes them to an OpenSearch index name generated by <service_name>-<class_name>-ocsf-cuid-<class_uid>-%{yyyy.MM.dd} (i.e. cloudtrail-api_activity-ocsf-cuid-3005-2023.06.23)
###

version: "2"
s3-log-pipeline:
  source:
    s3:
      # Prevent data loss by only considering logs to be processed successfully after they are received by the opensearch sink
      acknowledgments: true
      notification_type: "sqs"
      compression: "none"
      notification_source: "eventbridge"
      codec:
        parquet:
      sqs:
        # Provide a SQS Queue URL to read from
        queue_url: "https://sqs.ap-northeast-1.amazonaws.com/123456789012/AmazonSecurityLake-36c3d217-38c1-46c2-b991-3b663050fe4a-Main-Queue"
        # Modify the visibility_timeout of the sqs messages depending on the size of your parquet or avro S3 objects.
        # Objects that are small (< 0.5 GB) and evenly distributed in size will result in the best performance
        # It is recommended to allocate a minimum of 30 seconds, and to add 30 seconds for every 0.25 GB of data in each S3 Object
        visibility_timeout: "60s"
      aws:
        # Provide the region to use for aws credentials
        region: "ap-northeast-1"
        # Provide the role to assume for requests to SQS and S3
        sts_role_arn: "arn:aws:iam::123456789012:role/hoge0627pipelinerole"
  processor:
    - lowercase_string:
        with_keys: [ "/metadata/product/name", "/class_name" ]
    - substitute_string:
        entries:
          - source: "/metadata/product/name"
            from: "\\s"
            to: "_"
          - source: "/class_name"
            from: "\\s"
            to: "_"
    - delete_entries:
        with_keys: [ "s3" ]
  sink:
    - opensearch:
        # Provide an AWS OpenSearch Service domain endpoint
        hosts: [ "https://55fvhz0qkr11bfax2ura.ap-northeast-1.aoss.amazonaws.com" ]
        aws:
          # Provide a Role ARN with access to the domain. This role should have a trust relationship with osis-pipelines.amazonaws.com
          sts_role_arn: "arn:aws:iam::123456789012:role/hoge0627pipelinerole"
          # Provide the region of the domain.
          region: "ap-northeast-1"
          # Enable the 'serverless' flag if the sink is an Amazon OpenSearch Serverless collection
          serverless: true
        index: "${/metadata/product/name}-${/class_name}-ocsf-cuid-${/class_uid}-%{yyyy.MM.dd}"
        # Enable the S3 DLQ to capture any failed requests in an S3 bucket
        # dlq:
          # s3:
            # Provide an S3 bucket
            # bucket: "your-dlq-bucket-name"
            # Provide a key path prefix for the failed requests
            # key_path_prefix: "s3-log-pipeline/dlq"
            # Provide the region of the bucket.
            # region: "us-east-1"
            # Provide a Role ARN with access to the bucket. This role should have a trust relationship with osis-pipelines.amazonaws.com
            # sts_role_arn: "arn:aws:iam::123456789012:role/Example-Role"

要は送信元と送信先の情報を上記で構築しています。
構成後に検証ボタンから検証を行うことが出来ます。問題なければ次のようになります。

パイプラインが作成されてしばらくするとステータスが Active になると思います。
Active になったらパイプラインが開始されている状態なので、インデックスが作成されているか確認してみましょう。

インデックス作られた

OpenSearch Serverless コレクションからインデックスがいくつか作成されていそうなことがわかります。

実際に OpenSearch Dashboard にアクセスしてインデックスパターンを適当に作成しようとすると、対象のインデックスが検出されていることがわかると思います。

かなり適当なインデックスパターンですが、次のように OpenSearch 側でログが確認出来ていますね。

さいごに

本日は Amazon OpenSearch Service の取り込みパイプラインが Amazon Security Lake からのイベント取り込みをサポートしたので試してみました。

Security Lake も OpenSearch Serveless も OpenSearch Ingestion も全部初めて触ったもので、調べながら構築してみましたので時間はかかってしまったのですが、おそらく実際にスムーズに構築できれば数分で終わりそうです。

マネージドな機能で Security Lake から OpenSearch まで統合できるのはかなり良いですね。
せっかく分析環境が作れたので、少し Security Lake と OpenSearch で遊んでみたいと思います。