5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CloudWatchLogsのサブスクリプションフィルタをAWSCLIから設定する

Last updated at Posted at 2024-02-24

はじめに

前回の記事でAWS CLIコマンドを利用してCloudWatchAlermを設定する方法を調査・検証した。
せっかくなので、Alermと一緒に大量に設定する必要のあるCloudWatchLogsのロググループと
サブスクリプションフィルタをAWS CLIから設定する方法を調査・検証した。

環境

CloudShellからの実行を想定。記事作成時点のCloudShell上でのバージョンは以下の通り。

  • AWS CLI:2.15.21
  • jq:1.6(設定確認時に利用)

準備:SNS連携用Lambda作成

なんでもよいのでサブスクリプションフィルタの送信先となるLambda関数を作っておく。
今回はログ監視を想定し、サブスクリプションフィルタに指定した文字列を検知した場合、
メール整形用Lambdaへ連携、LmabdaからSNSのトピックを呼びメールを送信するLambda関数を用意する。

Lambda関数作成にあたり参考にさせていただいた記事

下記のコードを利用する場合は環境変数SNS_TOPIC_ARNにメール通知先となるSNSのARNを設定すること。
また、LambdaのIAMロールにsns:Publishの許可があること。

lambda
import json
import logging
import base64
import gzip
import os
from datetime import datetime, timezone, timedelta
import boto3

# logger初期化
logger = logging.getLogger()
logger.setLevel(logging.INFO)

# タイムスタンプ時刻変換
def convert_time(timestamp_unix):
    # UNIXミリ秒から秒への変換
    timestamp_sec = timestamp_unix / 1000
    dt = datetime.fromtimestamp(timestamp_sec, timezone(timedelta(hours=9)))
    # ISO:8601形式に変換
    timestamp_jst = dt.isoformat()

    return timestamp_jst

# SNSへの連携
def publish_sns(loggroup, logstream, logfiltername, logtimestamp, message):
    sns_client = boto3.client('sns')
    sns_topic_arn = os.environ['SNS_TOPIC_ARN']

    sns_client.publish (
        TopicArn = sns_topic_arn,
        Subject = "【HOGEHOGEシステム】ログ監視アラーム",
        Message =(
            "========================================" + "\n" +
            "ログ グループ名: " + loggroup + "\n" +
            "ログ ストリーム名: " + logstream + "\n" +
            "ログ フィルタ名: " + logfiltername + "\n" +
            "ログ 検知日時(JST): " + logtimestamp + "\n" +
            "ログ 内容: " + message + "\n" +
            "========================================"
        )
    )

def lambda_handler(event, context):
    # CWlogsサブスクリプションフィルタ連携データからJSONデータ取り出し
    logger.info("LOAD Function: " + context.function_name)
    decode_data = base64.b64decode(event['awslogs']['data'])
    json_data = json.loads(gzip.decompress(decode_data))

    # データ取得
    log_group = json_data['logGroup']
    log_stream = json_data['logStream']
    log_filtername = json_data['subscriptionFilters'][0]
    log_timestamp = json_data['logEvents'][0]['timestamp']
    log_message = json_data['logEvents'][0]['message']

    # タイムスタンプ時刻変換
    log_timestamp = convert_time(log_timestamp)

    # SNSへの連携
    publish_sns(log_group, log_stream, log_filtername, log_timestamp, log_message)

    logger.info("END Function: " + context.function_name)

設定コマンド

aws logs put-subscription-filterを利用すればサブスクリプションフィルタを設定できる。

aws logs put-subscription-filter \
--log-group-name <ロググループ名> \
--filter-name <フィルタ名> \
--filter-pattern <フィルタパターン> \
--destination-arn <連携先>

注意点

GUI上からサブスクリプションフィルタを設定する場合はAWS側で自動的にやってくれるため意識しなかったが、
Lambda側のリソースポリシーでCloudWatchLogsからアクセスできるように設定しておかないと以下のエラーが出る。

An error occurred (InvalidParameterException) when calling the PutSubscriptionFilter operation: Could not execute the lambda function. Make sure you have given CloudWatch Logs permission to execute your function.

以下のようにCloudWatchLogsからのlambda:InvokeFunctionを許可しておくこと。

image.png

コマンドサンプル

aws logs put-subscription-filter \
--log-group-name "messages" \
--filter-name "gp-dev-log-messages" \
--filter-pattern "?\".err>\" ?\".crit>\" ?\".alert>\" ?\".emerg>\"" \
--destination-arn "arn:aws:lambda:ap-northeast-1:xxxxxxxxxx"

--filter-pattern内でダブルクォーテーション使う場合はエスケープしないとエラーになる点は注意

動作確認

EC2から/var/log/messagesをロググループに出力しているため、
今回はloggerコマンドでsyslogにエラーを出力する。
AWS CLIからaws log put-log-eventsでロググループにログを送信しても良い。

設定コマンド実行後GUI確認

image.png

メール受信確認

image.png

サブスクリプションフィルタ設定確認

aws logs describe-subscription-filtersを利用すればサブスクリプションフィルタ設定を取得できる。

オプションとして--log-group-nameの指定が必須となる。
CloudWatchAlermの時と違い、AWS CLIコマンド単体では全てのロググループと
それに紐づくサブスクリプションフィルタを一括で取得できないのは残念。
一気に取得する場合はロググループ名を読み込んでループさせる
シェルスクリプトを作る必要がありそう。
JSON形式で取得できるので、jqに渡して成形・出力する。

コマンドサンプル

aws logs describe-subscription-filters --log-group-name "messages" | jq -c '.subscriptionFilters[] | [.logGroupName, .filterName, .filterPattern, .destinationArn]'

実行結果サンプル

["messages","gp-dev-log-messages","?\".err>\" ?\".crit>\" ?\".alert>\" ?\".emerg>\"","arn:aws:lambda:ap-northeast-1:xxxxxxxxxx"]

以上。
CLIでの設定より連携先Lambdaの中身を書く方が大変でした。

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?