Terraform loop処理の応用編(4) - Lambda

今日のTerraform loopネタはLambda関数作成。ログ監視の一貫なので、CloudWatchLogsのロググループとサブスクリプションフィルタ作成も一緒にやる。 この例でのディレクトリ構成は以下の通り。lambda/upload配下のzipファイルはTerraformにより生成されたもので、初回は空である。 work_dir ├── config.tf #初期化ファイル ├── lambda │ ├── code │ │ ├── func001 │ │ │ └── lambda-func001.py │ │ ├── func002 │ │ │ └── lambda-func002.py │ │ └── func003 │ │ └── lambda-func003.py │ └── upload │ ├── lambda-func001.zip │ ├── lambda-func002.zip │ └── lambda-func003.zip ├── lambda.auto.tfvars ├── lambda_cwl.tf ├── terraform.tfvars #regionのみ定義 └── variables.tf 最初に、すべて定数で記述したパターン。 lambda_logs.tf(定数バージョン) ################################################# # Lambda archive data ################################################# data "archive_file" "data-lambda-func001" { type = "zip" source_dir = "lambda/code/func001" output_path = "lambda/upload/lambda-func001....

December 12, 2021

AWSイベント監視 - CloudTrail + EventBridge + Lambdaでメールカスタマイズ(2)

以下過去記事の続き。この時はメール本文がJSON生データで送信された。これを、人間が状況を判別可能な状態までもっていきたい。 AWSイベント監視 - CloudTrail + EventBridge + Lambdaでメールカスタマイズ とういことで、再度検証。使用したAWS各種サービスのリソースは前回と同様で、Lambda関数のコードだけ入れ替え。何度も同じようなことをやっていて何がなんだか分からなくなっているがもうヤケクソ。 lambda_function.py (イベント監視メール通知用) import boto3 import json import os import re from botocore.exceptions import ClientError from datetime import datetime, timezone, timedelta from dateutil import parser print('Loading function') sns_arn = os.environ['SNS_TOPIC_ARN'] def lambda_handler(event, context): data = event s = json.dumps(data) e = json.loads(s) print(e) # eventから項目を抽出 dtl = e['detail'] #詳細(detail)を定義 e_type = e['detail-type'] # イベントタイプ 例:'AWS API Call via CloudTrail' t = e['time'] # 発生時刻 evt_name = dtl['eventName'] # イベント名 例:DeleteBucket evt_src = dtl['eventSource'] # イベントソース 例:s3....

November 21, 2021

CloudWatchアラーム + SNSからのメール本文をカスタマイズする(3)

表題のテーマ、過去にもCloudWatchアラーム通知メールのカスタマイズについて書いたが、表示時刻がUTCなのでJSTに変換しようと考えた。 過去記事 CloudWatchアラーム + SNSからのメール本文をカスタマイズする(2) CloudWatchアラーム + SNSからのメール件名をカスタマイズする CloudWatchアラームから渡されるeventの、元データの時刻表示は例えば'2021-10-24T09:35:10Z’となっている。これをJSTにするのに手っ取り早いのはpytzを使う方法だが、諸事情により標準ライブラリの範囲でやる必要がある。 で、試行錯誤。当初datetime型にしてからJSTに変換しようとしたがいいやり方が見つからなかったため「unixタイムスタンプに変換後、JSTに変換」とすることにした。 from datetime import datetime, timezone, timedelta from dateutil import parser JST = timezone(timedelta(hours=+9), 'JST') utcstr = '2021-10-24T09:35:10Z' utcstr_parsed = parser.parse(utcstr) #UNIXタイムスタンプに変換 ux_time = utcstr_parsed.timestamp() #int型にする epoch = int(ux_time) #JSTに変換 dt = datetime.fromtimestamp(epoch).replace(tzinfo=timezone.utc).astimezone(tz=JST) print(dt) 2021-10-25 03:35:10+09:00 当初JSTに変換した後の時間が変だ+18時間になってる何故だ、と悩んだが、拠点にした時間から+18時間になるのはおそらく実行環境がJSTだから。UTCの環境でやれば+9時間になるんだろう。くそ、こんなことで数時間週末を無駄にした。俺の休息時間はいつなんだ? ともあれ、修正したのが以下。コメントの「時刻変換」と、「件名に投入するアラーム名を抽出」を追加した。前回はメール件名規則を「任意の文字列 + 発生契機 + 対象リソース(dimention)」としていたが、発生契機はいらないから代わりにアラーム名にした。 lambda_function.py (時刻表示JSTバージョン) import boto3 import json import os import re from botocore.exceptions import ClientError from datetime import datetime, timezone, timedelta from dateutil import parser print('Loading function') sns_arn = os....

November 20, 2021

CloudWatchアラーム + SNSからのメール本文をカスタマイズする(2)

表題の件、過去記事ではメール件名カスタマイズが主題だったが、メール本文を人間が判読可能なフォーマットにすべく、Lambdaコードを改良してみた。これがSNSに渡り、整形された本文がメール送信される想定である。前回はメール件名を環境変数にしたが今回はコード内から値を取り出している。 類似の過去記事 CloudWatchアラーム + SNSからのメール件名をカスタマイズする lambda_function.py import boto3 import json import os import re from botocore.exceptions import ClientError print('Loading function') sns_arn = os.environ['SNS_TOPIC_ARN'] def lambda_handler(event, context): data = event s = json.dumps(data) e = json.loads(s) print(e) # eventから項目を抽出 t = e['time'] trig = e['detail-type'] alarm = e['resources'] #これはリスト。文字列にするにはalarm[0] # 「理由」となる詳細抽出 reason = e['detail']['state']['reason'] # リソース(ここではインスタンスID)を抽出し、文字列整形 resource = e['detail']['configuration']['metrics'][0]['metricStat']['metric']['dimensions'] res_str = json.dumps(resource) res = re.sub(r"[{}\"]", "", res_str) # 件名整形 subject_str = "本番環境 - アラーム " + trig + " - " + res # メッセージ本文整形 fix_msg = "以下のアラームが発生しました" + "\n" trig_msg = "発生契機:" + "\n" + trig time_msg = "発生時刻:" + "\n" + t alm_msg = "アラーム:" + "\n" + alarm[0] res_msg ="対象リソース:" "\n" + res dtl_msg ="理由:" "\n" + reason msg = fix_msg + "\n\n" + trig_msg + "\n\n" + time_msg + "\n\n" + alm_msg + "\n\n" + res_msg + "\n\n" + dtl_msg try: sns = boto3....

November 14, 2021

CloudWatchLogsのログ監視 - サブスクリプションフィルタ + Lambdaでメール送信(2)

表題の件、以下の過去記事に書いたが、この時点では送信される本文ががログメッセージだけとなっていて、通知メールとしては不十分なため本文もカスタマイズしてみた。 CloudWatchLogsのログ監視 - サブスクリプションフィルタ + Lambdaでメール送信 各種設定は冒頭の過去記事と同様のため割愛するとして、コードは変更前・後両方載せておく。 変更前:lambda_function.py(1) import base64 import json import zlib import datetime import os import boto3 from botocore.exceptions import ClientError print('Loading function') def lambda_handler(event, context): data = zlib.decompress(base64.b64decode(event['awslogs']['data']), 16+zlib.MAX_WBITS) data_json = json.loads(data) log_entire_json = json.loads(json.dumps(data_json["logEvents"], ensure_ascii=False)) log_entire_len = len(log_entire_json) print(log_entire_json) for i in range(log_entire_len): log_json = json.loads(json.dumps(data_json["logEvents"][i], ensure_ascii=False)) try: sns = boto3.client('sns') #SNS Publish publishResponse = sns.publish( TopicArn = os.environ['SNS_TOPIC_ARN'], Message = log_json['message'], Subject = os.environ['ALARM_SUBJECT'] ) except Exception as e: print(e) 参考...

November 14, 2021

CloudWatchアラーム + SNSからのメール件名をカスタマイズする

CloudWatchアラーム + SNSトピックでメール飛ばす時の件名を変更したい。ということで、過去記事 AWS EventBridge + SNSからのメール件名をカスタマイズする でイベントからのメール通知でやったことを、アラームに変えてやってみた。アラームのトリガーはEC2インスタンスCPU使用率閾値超えとする。 ベースの参照は以下クラメソさんネタ。ただしこちらは本文のカスタマイズであり、件名は変えていない。またLambdaも使用していない。これに先の過去記事パターンを合体させてやってみた。 CloudWatch アラームの通知メールを少しでも読みやすくしたい 処理概要 CloudWatchアラームのステータスがALARMに変わる。 Lambda関数起動 SNSに連携される メール通知 作業概要 SNSトピック作成〜サブスクライブ CloudWatchアラーム作成 Lambda関数作成(Lambda用IAMロールは既存流用) EventBridgeルール作成 EventBridgeルールのターゲットに3.のLambda関数を設定する 対象EC2インスタンスのCPU負荷を上げてアラームステータスにする メール通知確認 検証に使用したアイテム アイテム 名称 SNSトピック alarm-notification-topic CloudWatchアラーム CPU_Utilization_Test Lambda関数 cw-alarm-sns-function EventBridgeルール cw-alarm-rule やったこと SNSトピック作成、Lambda関数作成は冒頭のリンク過去記事でもやったので省略。Lambda関数の環境変数でSNSトピック、メール件名を指定している。一応後半にスクショあり。 CLIよりCloudWatchアラーム作成。少ない負荷でもアラームステータスになるように閾値は10%にしてある。 $ aws cloudwatch put-metric-alarm --alarm-name "CPU_Utilization_Test" \ --metric-name "CPUUtilization" \ --namespace "AWS/EC2" \ --statistic "Maximum" \ --period 60 \ --evaluation-periods 1 \ --datapoints-to-alarm 1 \ --threshold 10 \ --comparison-operator "GreaterThanThreshold" \ --dimensions "Name=InstanceId,Value=i-0xxxxxxxxxxx9" EventBridgeルールの作成。以下の場合、“CPU_Utilization_“を含むアラームと関連付けられる...

November 3, 2021

CloudWatchLogsのログ監視 - サブスクリプションフィルタ + Lambdaでメール送信

AWSでのログ監視メール送信はサブスクリプションフィルタ + Lambda + SNSを使用するのがスタンダード。みんなやっていそうなことだが未経験だったのでやってみた。基本参考にしたのは王道クラメソさんの記事だったが、ちょっとわかりにくいところがあったので他の記事も合わせて参照して若干やり方変えつつ検証した。 今回はマネコン作業メインでやったが、CLIやTerraformなどAPI経由で実装する場合追加作業が発生するため注意が必要。(後述 補足事項に記載) 参考 CloudWatch Logs を文字列検知してログ内容をメールを送信してみた サブスクリプションフィルター版 【AWS】CloudWatch Logsからシステムログをメール通知する。 CloudWatch Logs のサブスクリプションフィルタを使って特定文字列を検知したログをEメール通知する ※CLI実装例 以下は今後の参考用 CloudWatchLogsの内容をフィルタリングしてLambdaで通知させたい ※除外キーワードをコードで記述する例 CloudWatchLogsからLambda経由でログメッセージを通知する ※Terraform実装例 処理概要 CWLにログが出力される CWLのサブスクリプションフィルタでキーワード検知 Lambda関数起動 SNSに連携される メール通知 作業概要 SNSトピック作成〜サブスクライブ Lambda用IAMロール作成 Lambda関数作成 ロググループ/ログストリーム作成 ロググループにサブスクリプションフィルタ作成 (配信先に3.のLambda関数を指定) テストログ送信〜メール通知確認 ※ログストリーム作成は検証時のみ。通常は自動生成される。 今回の検証に使用したアイテム(個人メモ) アイテム 名称 SNSトピック log-monitor-topic Lambda用IAMロール send-log-filter-role Lambda関数 send-log-filter-function サブスクリプションフィルタ send-log-filter やったこと SNSトピック作成〜サブスクライブ 過去記事:AWS EventBridge + SNSからのメール件名をカスタマイズするに書いたので省略。ここではCLIでやってるけどマネコンでも特にハマるところはない。アクセスポリシーはデフォルトにした。 Lambda用IAMロール作成 とりあえず以下のマネージドポリシーをアタッチ。 CloudEatchLogsFullAccess AmazonSNSFullAccess Lambda関数作成 (1) 参考ブログのコード貼り付け import base64 import json import zlib import datetime import os import boto3 from botocore....

October 31, 2021