kiwiki

主にセキュリティ関連の技術メモブログです。

CloudWatch Logs で JSON 形式のログデータをフィルタリングする際のフィルターパターン構文

目次

フィルターパターンとは?

CloudWatch Logs に集約されたログデータにフィルターパターンを適用すると、集約した各ログデータ内からパターンにマッチしたログデータを抽出することができ、ログデータをフィルタリングすることができます。また、フィルターパターンを設定したメトリクスフィルターを作成することで、AWS 全体のモニタリングに活用することも可能です。フィルターパターンは、ログデータをフィルタリングするための条件(パターン)となります。 例えば、フィルターパターンを活用することで、「MFA を利用していないユーザーのコンソールログイン」をモニタリングするといったことが可能となり、該当する IAM ユーザーに MFA を設定するように管理者が促すことで AWS 全体のセキュリティ向上に繋げることができます。

フィルターパターンの構文を確認してみる

AWS 公式ドキュメント(※1)を確認すると、JSON 形式のログデータに利用できるフィルターパターンは下記のような構文になります。

{ PropertySelector EqualityOperator String }

■ Property selector ドル記号の後にピリオド (「$.」) が付いたプロパティセレクタをオフに設定します。プロパティセレクタは英数字の文字列であり、ハイフン (「-」) およびアンダースコア (「_」) をサポートします。文字列は科学表記をサポートしていません。プロパティセレクタは、JSON ログイベントの値ノードを指します。値ノードには、文字列または数値を指定できます。プロパティセレクタの後に配列を配置します。配列には、0 から始まる順序付けシステム (0 = 1、1 = 2 など) に従う要素が含まれます。要素を角かっこ (「[]」) で囲みます。プロパティセレクタで配列またはオブジェクトを指定しても、メトリクスフィルターはログ形式を照合しません。

■ EqualityOperator(等値演算子) 等しい (「=」) または等しくない (「!=」) の記号のいずれかを使用して、等価演算子を区切ります。等値演算子は、ブール値 (true または false) を返します。

■ String 文字列は、二重引用符 ("") で囲むことができます。英数字とアンダースコア記号以外の種類を含む文字列は、二重引用符で囲む必要があります。アスタリスク (「*」) をワイルドカードとして使用して、テキストを照合します。

フィルターとパターンの構文
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html

上記の他にも NumericOperator(数値演算子)や複数の条件を組み合わせた複合式などが使用できます。これらについては AWS 公式ドキュメントをご確認ください。

下記の JSON 形式のログデータは、「IAM ユーザのコンソールログイン」が記録されたものです。「Property selector」は ":" の左側の文字列(例えば、"eventVersion")、「String」は ":" の右側(例えば、"1.08")が該当します。 例えば、下記のログデータをもとに「"eventSource" が "signin.amazonaws.com" である」という条件をフィルターバターンに落とし込むと、{ $.eventSource = "signin.amazonaws.com" } となります。

{
    "eventVersion": "1.08",
    "userIdentity": {
        "type": "IAMUser",
        "principalId": "XXXXXXXXXXXXXXXXXXXXX",
        "arn": "arn:aws:iam::xxxxxxxxxxxx:user/readonly-user",
        "accountId": "xxxxxxxxxx",
        "userName": "readonly-user"
    },
    "eventTime": "2022-09-06T05:38:01Z",
    "eventSource": "signin.amazonaws.com",
    "eventName": "ConsoleLogin",
    "awsRegion": "us-west-2",
    "sourceIPAddress": "xxx.xxx.xxx.xxx",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:104.0) Gecko/20100101 Firefox/104.0",
    "requestParameters": null,
    "responseElements": {
        "ConsoleLogin": "Success"
    },
    "additionalEventData": {
        "LoginTo": "https://console.aws.amazon.com/console/home?...",
        "MobileVersion": "No",
        "MFAUsed": "No"
    },
    "eventID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "readOnly": false,
    "eventType": "AwsConsoleSignIn",
    "managementEvent": true,
    "recipientAccountId": "xxxxxxxxxx",
    "eventCategory": "Management",
    "tlsDetails": {
        "tlsVersion": "TLSv1.2",
        "cipherSuite": "ECDHE-RSA-AES128-GCM-SHA256",
        "clientProvidedHostHeader": "us-west-2.signin.aws.amazon.com"
    }
}

MFA を設定していない IAM ユーザをフィルタリングするためのフィルターパターンを作成してみる

一般的によくありそうな状況を仮定してフィルターパターンを作成してみたいと思います。今回は「MFA を設定していない IAM ユーザのコンソールログイン」をフィルタリングするフィルターパターンを作成してみます。再度、上記のログデータと同じもの(IAM ユーザーのコンソールログイン)を下記に記載しました。

{
    "eventVersion": "1.08",
    "userIdentity": {
        "type": "IAMUser",
        "principalId": "XXXXXXXXXXXXXXXXXXXXX",
        "arn": "arn:aws:iam::xxxxxxxxxxxx:user/readonly-user",
        "accountId": "xxxxxxxxxx",
        "userName": "readonly-user"
    },
    "eventTime": "2022-09-06T05:38:01Z",
    "eventSource": "signin.amazonaws.com",
    "eventName": "ConsoleLogin",
    "awsRegion": "us-west-2",
    "sourceIPAddress": "xxx.xxx.xxx.xxx",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:104.0) Gecko/20100101 Firefox/104.0",
    "requestParameters": null,
    "responseElements": {
        "ConsoleLogin": "Success"
    },
    "additionalEventData": {
        "LoginTo": "https://console.aws.amazon.com/console/home?...",
        "MobileVersion": "No",
        "MFAUsed": "No"
    },
    "eventID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "readOnly": false,
    "eventType": "AwsConsoleSignIn",
    "managementEvent": true,
    "recipientAccountId": "xxxxxxxxxx",
    "eventCategory": "Management",
    "tlsDetails": {
        "tlsVersion": "TLSv1.2",
        "cipherSuite": "ECDHE-RSA-AES128-GCM-SHA256",
        "clientProvidedHostHeader": "us-west-2.signin.aws.amazon.com"
    }
}

上記のログデータの "eventName" と "additionalEventData.MFAUsed" を活用することで実現できます。具体的には「"eventName" が "ConsoleLogin" かつ "additionalEventData.MFAUsed" が "Yes" ではない」という条件になります。フィルターパターンに落とし込むと下記のようになります。

{($.eventName = "ConsoleLogin") && ($.additionalEventData.MFAUsed != "Yes")}

どんなフィルターパターンを活用すれば良いのか?

AWS セキュリティガイドラインとして CIS Benchmark(※2)があります。CIS Benchmark によると、CloudTrail ログを CloudWatch Logs に転送して、CloudWatch Logs で下記のようなフィルターパターンを設定したメトリクスフィルターとアラームを作成することが推奨されています。

※ CIS Benchmark の推奨項目は 15 ありますが、3 つを抜粋して記載します。

■ 4.1 Ensure a log metric filter and alarm exist for unauthorized API calls (認証されていない API コールに対するメトリクスフィルターとアラームを確認する)

{(($.errorCode="*UnauthorizedOperation") || ($.errorCode="AccessDenied*")) && (($.sourceIPAddress!="delivery.logs.amazonaws.com") && ($.eventName!="HeadBucket"))}

■ 4.3 Ensure a log metric filter and alarm exist for usage of 'root' account (root アカウントの使用に対するメトリクスフィルターとアラームを確認する)

{$.userIdentity.type = "Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != "AwsServiceEvent"} 

■ 4.4 Ensure a log metric filter and alarm exist for IAM policy changes (IAM ポリシーの変更に対するメトリクスフィルターとアラームを確認する)

{($.eventName=DeleteGroupPolicy)||($.eventName=DeleteRolePolicy)||($.eventName=DeleteUserPolicy)||($.eventName=PutGroupPolicy)||($.eventName=PutRolePolicy)||($.eventName=PutUserPolicy)||($.eventName=CreatePolicy)||($.eventName=DeletePolicy)||($.eventName=CreatePolicyVersion)||($.eventName=DeletePolicyVersion)||($.eventName=AttachRolePolicy)||($.eventName=DetachRolePolicy)||($.eventName=AttachUserPolicy)||($.eventName=DetachUserPolicy)||($.eventName=AttachGroupPolicy)||($.eventName=DetachGroupPolicy)}

まとめ

  • フィルターパターンに詳しくなると、より高度な CloudWatch Logs ログデータのフィルタリングやメトリクスフィルターを使用したモニタリングが可能になる(と思う)。
  • どのようなフィルターパターンを適用したら良いのか迷う場合、まずは CIS Benchmark などの AWS セキュリティガイドラインに記載されているものを参考にしてみると良いかも。

参考文献