【AWS】CloudWatch LogsとLambdaで特定文字を検出しSlackにアラートを送る【ubuntu】

こんにちは!株式会社Smallitの橋本です。

9月からAWSを使用した学習を始めて、早1か月半がたちました!
AWSの基本的な使い方を理解してきたこともあり、最近環境構築を任されました。
うれしいです( ;∀;)

この記事ではその時の備忘録と復習の意味を込めて、「CloudWatch LogsとLambda、CloudWatch Agentを利用して、ログファイルに特定文字があった場合にSlackにログを送信する」という環境構築について紹介します。

ちなみに今回は、パブリックサブネットのUbuntuサーバーのログをCloudWatchに転送しています。プライベートサブネットのEC2のログを取得したい場合は、もう一段階何か挟まないといけないと思います。

システムの概要

システムの概要を簡単に説明します。

  1. EC2の設定を行います。IAMロールを設定し、CloudWatchにアクセスできるようにします。

  2. CloudWatch AgentをEC2(今回はubuntuOSですが、LinuxOSでも基本的に設定は同じかと思います。)にインストールし、どのファイルをどういったロググループ名でCloudWatch logsに転送するかを設定します。

  3. Lambdaを作成します。ログに特定文字の文字があった場合に起動するように設定します。

  4. Lambdaが起動したら、特定文字があったログをSlackにそのまま転送するように設定します。

この4手順を行うことで、例えばエラーが起こったときに出力されるログをSlackに通知できます。
いち早くシステムの復旧ができるようになるはずです。

EC2の設定

まずはEC2の設定を行います。

STEP1 AMI:OSはubuntu 20.04 LTS – Focalを選択しました。今回業務で使用したのが、ubuntuOSだっただけでLinuxOSでも同じ手順で実装できるはずです。

STEP2 インスタンスタイプの選択:t2.microを選択します。

STEP3 インスタンスの詳細の設定:事前に作成しておいたネットワーク、パブリックサブネットを選択します。自動割り当てパブリックIPも有効にします。他はデフォルトでOKです。

STEP4 ストレージの追加:デフォルトでOKです。

STEP5 タグの追加:分かりやすい名前を付けましょう!私は、キーにName、値にhashimoto-log-alert-practiceにしました。

STEP6 セキュリティグループの設定:分かりやすいセキュリティグループの名前を付けます。自分のPCから接続できれば十分ですので、マイIPを選択します。

STEP7 SSH Keyを作成します。

STEP8 IAMロール作成:次にIAMロールを作成します。

STEP9 上記の赤枠をクリックします。

STEP10 Attach アクセス権限ポリシー:CloudWatchAgentServerPolicyのみでOKです。

STEP11 タグの追加:分かりやすい名前を付けましょう。私の場合は、キー:Name 値:hashimoto-log-alert-practice-ec2-roleにしました。

STEP12 ロールの作成:ロール名にhashimoto-log-alert-practice-ec2-roleと入力し、ロールの作成を押します。

STEP13 IAMロールの割り当て:EC2のダッシュボードに戻り、作成したEC2インスタンスを右クリックし、セキュリティ → IAMロールを変更を押します。

STEP14 IAMロールを変更:作成したIAMロールを選択し保存を押します。

これでEC2の設定は完了です。

CloudWatch Agentの設定

次にCloudWatch Agentの設定を行います。以下のコマンドを順番に実行します。

  1. sudo apt update

    バージョン管理ツールをアップロードするコマンドです。

  2. wget https://s3.ap-northeast-1.amazonaws.com/amazoncloudwatch-agent-ap-northeast-
    1/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb

    URLを指定してファイルをダウンロードするコマンドです。CloudWatch Agentをダウンロードします。

  3. sudo apt install /home/ubuntu/amazon-cloudwatch-agent.deb

    ダウンロードしたCloudWatch Agentをインストールします。

  4. sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard
    

    CloudWatch Agentの設定ファイルを作成します。CloudWatch Agentの設定ファイルを作成するには、amazon-cloudwatch-agent-config-wizardを起動し、質問に回答することで「/opt/aws/amazon-cloudwatch-agent/bin/config.json」に作成されます。以下は質問の設定です。

【CloudWatch Agentの設定質問】

4-1. On which OS are you plannning to use the agent?
(どのOSでエージェントを使用する予定ですか?)
1を選択します。ubuntuは、Linuxとその他ソフトウェア群を1つにまとめたものです。

4-2. Trying to fetch the default region based on ec2 metadata … Are you useing EC2 or On-Premises hosts?
(EC2上でメタデータをフェッチ(データの読み取り)しようとしてますが、ホストはEC2ですか?オンプレミスですか?)
1を選択します。EC2を利用しているためです。

4-3. Which user are you plannning to run the agent?
(CloudWatch Agentをどのユーザーとして動作させますか?)
1を選択します。ログファイルの権限次第ですが、rootユーザーで動かします。

4-4. Do you wamt to turn on StatsD deamon?
(StatsDを有効にしますか?)
2を選択します。StatsDとは、アプリケーションの計測ツールのことです。何を計測するかは使ったことが無いのでわかりません・・・。気になる方は調べてみてください!

4-5. Do you want to monitor metrics from CollectD?
(CollectDのメトリクスをモニタリングしますか?)
2を選択します。CollectDとは、サーバの統計情報を収集するためのオープンソースソフトウェアです。統計情報は今回不要なので、2を選択しています。

4-6. Do you want to monitor any host metrics? e.g CPU, memory, etc.
(ホストメトリックを監視しますか? 例:CPU、メモリなど)
2を選択します。CPUやメモリの監視は、今回不要なので2を選択します。

4-7. Do you have any existing CloudWatch Log Agent (http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AgentReference.html)configuration file to import for migration?
(既存の設定ファイルがありますか?)
新規作成なので、2を選択します。

4-8. Do you want to monitor any log files?
(モニタリングしたいログファイルはありますか?)
1を選択します。ログファイルの監視を実装したいので1を選択します。

4-9. Log file path:
(モニタリングしたいログファイルの場所を指定してください。)
「/var/log/syslog」を指定します。ubuntuのシステムログファイルの場所です。ubuntuに関する主なログファイルの場所は[メモ]Linuxの主なログファイル – Qiitaを参考にしてください。

4-10. Log group name:
(ロググループ名を指定してください。)
「hashimoto-log-alert-practice-system.log」にします。

4-11. Log stream name:
デフォルトでEnterを押します。ログストリームが何のことなのかを調べましたがいまいちよく分からなかったので、気になる方は調べてください。

4-12. Do you want to specify any additional log files to monitor?
(他にもモニタリングしたいファイルはありますか?)
モニタリングしたいファイルが1つならここで2を選択します。2を選択した場合 4-13 の質問に移行します。ここでは練習のため1を指定します。1を指定した場合 、4-12で2を選択するまで、4-9 ~ 4-12 の質問が繰り返されます。

2回目の質問では以下のように選択します。
4-9(2回目). 「/var/log/auth.log」(システムへのログイン履歴情報を格納しているログファイル)
4-10(2回目). 「hashimoto-log-alert-practice-auth.log」
4-11(2回目). デフォルトでEnterを押します。

4-13. Do you want to store the config in the SSM parameter store?
(設定をSSMパラメータストアに保存しますか?)
2を指定します。SSMパラメータストアとは、AWS Systems Manager の一機能である Parameter Storeのことです。設定データの管理を提供します。設定ファイルを保存しておくと、他のEC2でCloudWatch Agentを設定するときに、この保存したファイルを使用できます。今回は保存不要なので2を選択します。

設定ファイルの設定はこれで完了です。

5.

sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s 
-c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json

CloudWatch agentを起動するコマンドです。config.jsonをCloudWatch logsに連携します。

これでCloudWatch Agentの設定は終了で、この段階でCloudWatch logsに指定したファイルが、以下のように連携されています。

AWS Lambdaの設定

次にLambdaの作成を行います。

STEP1 赤枠の部分を設定します。一から作成を選択します。関数名を入力します。私の場合は、「hashimoto-log-alert-practice-lambda」にしました。ランタイムにPythonを選択します。あとはデフォルトのまま、関数の作成を押します。

STEP2 トリガーを追加:トリガーを追加をクリックし、以下のように設定します。

【STEP2での設定項目】

  1. トリガーの設定:CloudWatch Logsを選択します。

  2. ロググループ:CloudWatch agentの設定 4-9で設定したロググループ名を指定します。

  3. フィルターの名前:分かりやすいフィルター名を付けます。ここでは、hashimoto-log-alert-practice-auth-filterを指定します。

  4. フィルターパターン(検出したい文字列):ログファイルにどの文字が検出されたら、Lambdaを実行するかを指定します。ここでは「error」という文字列がログファイルに書かれたらLambdaが実行されるようにします。

1つのログファイルを監視したい場合は、ここまでの設定でOKです。もし2つ目のファイルを監視したい場合はもう1つ同様に設定します。

import logging
import json
import urllib.request
import base64
import gzip

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def post_slack(argStr):
notify = "<!channel> "
message = argStr

send_data = {
"username": "dev-hashimoto-Lambda",
"icon_emoji": ":bell:",
"text": notify + message,
}

send_text = "payload=" + json.dumps(send_data)

# URLにはご自分のWebhook URLを入力してください
request = urllib.request.Request(
"https://hooks.slack.com/services/T02J9888Y8Z/B02HWLSDG10/tmaOtG",
data=send_text.encode("utf-8"),
method="POST"
)

with urllib.request.urlopen(request) as response:
response_body = response.read().decode("utf-8")

def lambda_handler(event, context):

# CloudWatchLogsからのデータはbase64エンコードされているのでデコード
decoded_data = base64.b64decode(event['awslogs']['data'])

# バイナリに圧縮されているため展開
json_data = json.loads(gzip.decompress(decoded_data))

# ログデータ取得
error_log = json_data['logEvents'][0]['message']

post_slack(error_log)

STEP3 Lambdaのコードを作成(24行目だけURLを変える):上記のコードをlambda_functionにコピペします。Slackに通知を送るためウェブフックURLを発行します。24行目のコードのみ以下のサイトで取得し、ウェブフックURLを張り替えます

https://slack.com/services/new/incoming-webhook

Slackにログインした状態でチャンネルを選択し、赤枠をクリックするとlambdaが実行されたときに、そのチャンネルに通知を送ることができるURLが発行されます。

STEP4 詳細な設定:この設定は行わなくても実行はできますが、slackでの通知名などを変更できます。
15行目:「dev-hashimoto-Lambda」という名前でslackに通知が来ます。変更したい場合はここを変更します。

16行目:「:bell:」は上記のようなアイコンになります。変更したい場合は、https://belltree.life/slack-emoji-object-symbol/ を参考にしてください。

STEP5 Deploy:Deployボタンを押して、コードを適用します。

実際に動かしてみる

動作確認を行うために、以下のコードを入力します。

  1. sudo chmod 777 /var/log/syslog
    

    権限を変更するためのコマンドです。テストのために一時的に権限を変更します。

  2. sudo echo error_log_test >> /var/log/syslog
    

    指定したログファイルに、「error_log_test」という文字列を書き込みます。以下のように通知が来ます。書き込んだ文字と同じ通知が来ていることが確認できます。
    他にログ監視を設定したファイルがあれば同様に確認します。

  3. sudo chmod 640 /var/log/syslog
    

    権限を戻しておきます。

これでテストは完了です。

まとめ

今回は、CloudWatch Agentを利用してログファイルを監視し、特定の文字が検出された場合にSlackに通知するシステムを構築しました。手順を振り返ると以下のようになります。

  1. EC2の設定(CloudWatchにアクセスできる権限を付ける)

  2. CloudWatch Agentの設定

  3. Lambdaの設定(Slackのwebhookなどを設定する)

  4. 権限を変更してテスト、最後に元に戻す

実装してみた感想としては、システムはシンプルでも実装するのは大変だな・・・ということです。

実際に自分が構築したときは、CloudWatch Agentやロールの設定が難しく時間がかかりました。初めて構築するときは、質問しながら3日くらいは掛かりました(´・ω・`)

この記事が参考になって、これからシステムを構築する人が簡単にアラートシステムを実装できればうれしいです。

Smallitのサービス