def main_function(event, context): name = kms_decrypted("IGNORE_QUEUE") region = kms_decrypted("REGION", "ap-northeast-1") sqs = boto3.client('sqs', region_name=region) url = sqs.get_queue_url(QueueName=name) url = url["QueueUrl"] print_json({"type": "SQS", "message": "Search Message", "queue": name}) while (True): result = sqs.receive_message(QueueUrl=url, MaxNumberOfMessages=10, VisibilityTimeout=30, WaitTimeSeconds=20, AttributeNames=["All"], MessageAttributeNames=["SystemAlertId"]) if "Messages" not in result: break if len(result["Messages"]) == 0: break print_json({ "type": "lambda", "message": "Lambdaを再帰呼出しします", "payload": result }) if lambda_tools.aws_request_id == "debug": lambda_handler(result, context) else: invoke(result)
def set_ignore_queue(message): body = json.loads(message) name = kms_decrypted("IGNORE_QUEUE") system_alert_id = body["SystemAlertId"] region = kms_decrypted("REGION", "ap-northeast-1") sqs = boto3.resource('sqs', region_name=region) try: queue = sqs.get_queue_by_name(QueueName=name) except Exception as e: queue = sqs.create_queue(QueueName=name) queue.set_attributes(Attributes={ 'ReceiveMessageWaitTimeSeconds': '20', 'VisibilityTimeout': '30' }) print_json({ "type": "SQS", "message": "Send Message", "queue": name, "payload": message }) result = queue.send_message(MessageBody=message, MessageAttributes={ "SystemAlertId": { "StringValue": system_alert_id, 'DataType': 'String' } }) message_id = result["MessageId"] return message_id
def remove_message(message_id, system_alert_id): """ @brief 指定したMessageIdとSystemAlertIdに合致するSQSメッセージの削除 @params[in] message_id SQSのメッセージId @params[in] system_alert_id Azure SentinelのアラートID """ name = kms_decrypted("IGNORE_QUEUE") region = kms_decrypted("REGION", "ap-northeast-1") sqs = boto3.resource('sqs', region_name=region) queue = sqs.get_queue_by_name(QueueName=name) id = None recipt_handle = None print_json({ "type": "SQS", "message": "Search Message", "queue": name, "message_id": message_id, }) while(True): result = queue.receive_messages( MaxNumberOfMessages=10, VisibilityTimeout=3, WaitTimeSeconds=20, MessageAttributeNames=["SystemAlertId"] ) if len(result) == 0: break for msg in result: if message_id != msg.message_id: continue said = msg.message_attributes.get("SystemAlertId", None) if said is None: continue if system_alert_id != said["StringValue"]: continue receipt_handle = msg.receipt_handle print_json({ "type": "SQS", "message": "Delete Message", 'message_id': message_id, 'receipt_handle': receipt_handle }) response = queue.delete_messages(Entries=[{ 'Id': message_id, 'ReceiptHandle': receipt_handle }]) return True return False
def answer_false(event, action): value = action["value"] value = json.loads(value) print_json({ "type": "Slack", "message": "Interactive Event Value", "value": value, }) message = event["message"] alert_id = value["SystemAlertId"] user = event["user"], channel_id = event["container"]["channel_id"] blocks = message["blocks"] blocks[2] = { "type": "section", "block_id": "reason", "fields": [ {"type": "mrkdwn", "text": "*応答*"}, {"type": "mrkdwn", "text": "心当たりがない"}, {"type": "mrkdwn", "text": "*応答ユーザー*"}, {"type": "mrkdwn", "text": user[0]["username"]} ] } set_status(alert_id, False) slack_api_token = kms_decrypted("SLACK_API_TOKEN") slack_chat = Slack.Chat(token=slack_api_token) post_args = { "channel": channel_id, "text": message["text"], "ts": message["ts"], "blocks": blocks, } slack_chat.update_message(**post_args)
def box_create_user_folder(name: str): box_folder_id = kms_decrypted("BOX_FOLDER_ID") response = box_folder.items(folder_id=box_folder_id, fields=["name"]) tree = objectpath.Tree(response) query = '$..entries[@.type is "folder" and @.name is "{}"].id' query = query.format(name) dt = list(tree.execute(query)) if len(dt) > 0: return dt.pop() else: response = box_folder.create(name, box_folder_id, fields=["id"]) return response["id"]
def google_uploader(file, stream, length, event): name = file["name"] mime = file["mimetype"] buf = io.BytesIO(stream.read()) # Google Drive用メタデータ作成 metadata = GSuite.Drive.Metadata() metadata.name = name metadata.writersCanShare = True parent_id = kms_decrypted("GSUITE_PARENT_ID") metadata.parents = [parent_id] print_json({ "type": "lambda", "message": "Slack上のFileをGoogle Driveにアップロードします", "name": name, "size": length }) # Google Driveにアップロード file = gdrive.insert( metadata=metadata, file_stream=buf, original_mime_type=mime, fields='id, webViewLink, permissions' ) print_json({ "type": "lambda", "message": "Slack上のFileをGoogle Driveにアップロードしました", "name": name, "size": length }) link = file.get("webViewLink") id = file.get("id") pids = file["permissions"] perm = {} perm["type"] = "domain" perm['role'] = 'reader' perm['domain'] = kms_decrypted("GSUITE_DOMAIN") gdrive_permission.create(file_id=id, permission=perm) link = file.get("webViewLink") return id, name, link
def set_status(system_alert_id, status, message: str = None): """ @brief Logic Appにステータスを送信 @params[in] system_alert_id Azure SentinelのSystem Alert Id @params[in] status ユーザー応答結果 @n True : 意図している @n False: 覚えがない @params[in] message 理由テキスト """ url = kms_decrypted("LOGIC_APP_URL") method = "POST" headers = {"Content-Type": "application/json"} data = { "SystemAlertId": system_alert_id, "UserResult": 0 if status else 1, } if message is not None: data["UserMessage"] = message ret = { "type": "Logic App", "id": system_alert_id, "payload": data, "status": status } data = json.dumps(data).encode("utf-8") request = urllib.request.Request( url, data=data, method=method, headers=headers ) with urllib.request.urlopen(request) as response: result = False ret["result"] = { "status": response.status, "reason": response.reason, "message": response.msg } if response.status == 200: result = True expires = response.getheader("Expires") if expires == "-1": ret["message"] = "Send Status(System Alert Id was Expired)" else: result = True else: ret["message"] = "Send Status({})".format(response.msg) ret["result"] = { "status": response.status, "reason": response.reason, "message": response.msg } print_json(ret) return result
def view_submission(event): """ @brief 入力用Modal ViewからSubmitssion Callbackの受け取り @params[in] event イベントペイロード @details 入力値を取得しprivate_metadataから呼出元メッセージを特定し @n chat.update APIにて入力値を呼び出し元に反映します """ view = event["view"] private_metadata = json.loads(view["private_metadata"]) container = private_metadata["container"] message = private_metadata["message"] channel_id = container["channel_id"] blocks = message["blocks"] user = private_metadata["user"] action_value = private_metadata["action_value"] reason = view["state"]["values"]["reason_input"]["reason_text"]["value"] status = action_value["Status"] alert_id = action_value["SystemAlertId"] message_id = action_value["MessageId"] blocks[2] = { "type": "section", "block_id": "reason", "fields": [ {"type": "mrkdwn", "text": "*応答*"}, {"type": "mrkdwn", "text": "意図している"}, {"type": "mrkdwn", "text": "*応答ユーザー*"}, {"type": "mrkdwn", "text": user["username"]}, {"type": "mrkdwn", "text": "*理由*"}, {"type": "mrkdwn", "text": reason} ] } reason = "[{}]{}".format(user["username"], reason) result = set_status(alert_id, status, reason) if result: slack_api_token = kms_decrypted("SLACK_API_TOKEN") slack_chat = Slack.Chat(token=slack_api_token) post_args = { "channel": channel_id, "text": message["text"], "ts": message["ts"], "blocks": blocks, } print_json({ "type": "Slack", "message": "Update Message", "metadata": post_args }) slack_chat.update_message(**post_args) remove_message(message_id, alert_id)
def credential_setting(): # Box用設定 if "box" == upload_type: global box_file global box_folder logging.getLogger('boxsdk').setLevel(logging.CRITICAL) key_name = "/SlackUploadFileTransfer/Box" box_setting = lambda_tools.ssm_get_parameter(name=key_name) box_setting = json.loads(box_setting) settings = box_setting["boxAppSettings"] box_user = kms_decrypted("BOX_USER") box_folder = Box.Folder( client_id=settings["clientID"], client_secret=settings["clientSecret"], enterprise_id=box_setting["enterpriseID"], jwt_key_id=settings["appAuth"]["publicKeyID"], rsa_private_key_data=settings["appAuth"]["privateKey"] ) box_folder.login(box_user) box_file = Box.File( client_id=settings["clientID"], client_secret=settings["clientSecret"], enterprise_id=box_setting["enterpriseID"], jwt_key_id=settings["appAuth"]["publicKeyID"], rsa_private_key_data=settings["appAuth"]["privateKey"] ) box_file.login(box_user) # Google用設定 if "google" == upload_type: global gdrive global gdrive_permission key_name = "/SlackUploadFileTransfer/GSuite" credential = lambda_tools.ssm_get_parameter(name=key_name) credential = json.loads(credential) gdrive = GSuite.Drive.Files( credential=credential, scopes=GSuite.Drive.SCOPES_MANAGE, delegate_user=credential["client_email"] ) gdrive_permission = GSuite.Drive.Permissions( credential=credential, scopes=GSuite.Drive.SCOPES_MANAGE, delegate_user=credential["client_email"] )
def call_modal(event): """ @brief 入力用Modal Viewの表示 @params[in] event イベントペイロード @details メッセージ上のBlocksに表示されたボタンのaction_idが @n answer_trueである場合に呼び出されます。 @n 呼出元のBlocksのチャンネル情報とメッセージ情報を @n private_metadataに格納しModal Viewを画面上に表示されます。 """ slack_api_token = kms_decrypted("SLACK_API_TOKEN") trigger_id = event["trigger_id"] action = event["actions"][0] action_value = action["value"] action_value = json.loads(action_value) data = json.dumps({ "container": event["container"], "channel": event["channel"], "message": event["message"], "user": event["user"], "action_value": action_value }) slack_views = Slack.Views(token=slack_api_token) view = { "type": "modal", "private_metadata": data, "callback_id": "modal_reason", "title": {"type": "plain_text", "text": "Azure Sentinel 通知"}, "submit": {"type": "plain_text", "text": "Submit"}, "close": {"type": "plain_text", "text": "Cancel"}, "blocks": [{ "type": "input", "block_id": "reason_input", "element": { "type": "plain_text_input", "multiline": True, "action_id": "reason_text" }, "label": {"type": "plain_text", "text": "理由"} }] } slack_views.open(trigger_id, view)
def set_status(system_alert_id): """ @brief Logic Appにステータスを送信 @params[in] system_alert_id Azure SentinelのSystem Alert Id """ url = kms_decrypted("LOGIC_APP_URL") method = "POST" headers = {"Content-Type": "application/json"} data = json.dumps({ "SystemAlertId": system_alert_id, }).encode("utf-8") request = urllib.request.Request(url, data=data, method=method, headers=headers) with urllib.request.urlopen(request) as response: result = False ret = { "type": "Logic App", "id": system_alert_id, } if response.status == 200: expires = response.getheader("Expires") if expires == "-1": ret["message"] = "Send Status(System Alert Id was Expired)" else: ret["message"] = "Send Status({})".format(response.msg) result = True else: ret["message"] = "Send Status({})".format(response.msg) ret["result"] = { "status": response.status, "reason": response.reason, "message": response.msg } print_json(ret) return result
def main_function(events): slack_api_token = kms_decrypted("SLACK_API_TOKEN") slack_bot_token = kms_decrypted("SLACK_BOT_TOKEN") channel_id = kms_decrypted("SLACK_CHANNEL_ID") slack_chat = Slack.Chat(token=slack_api_token) for event in events: body = event.get("body", None) if body is None: continue id = set_ignore_queue(body) body = json.loads(body) username = body["Name"].replace('assumed-role/sso/', '') body["MessageId"] = id blocks = [] blocks.append({ "type": "section", "block_id": "alert", "text": { "type": "mrkdwn", "text": "@{}\nAzure Sentinel 警告通知".format(username) }, "fields": [ { "type": "mrkdwn", "text": "*アラート名*" }, { "type": "mrkdwn", "text": body["AlertName"] }, { "type": "mrkdwn", "text": "*アラート概要*" }, { "type": "mrkdwn", "text": body["Description"] }, ] }) blocks.append({"type": "divider"}) elements = [] body["Status"] = True elements.append({ "action_id": "answer_true", "type": "button", "text": { "type": "plain_text", "text": "意図している" }, "value": json.dumps(body) }) body["Status"] = False elements.append({ "action_id": "answer_false", "type": "button", "text": { "type": "plain_text", "text": "心当たりがない" }, "value": json.dumps(body) }) blocks.append({ "block_id": "answer", "type": "actions", "elements": elements }) post_args = { "channel": channel_id, "text": "Azure Sentinel 警告通知", "blocks": blocks, "link_names": True, "mrkdwn": True } print_json({ "type": "Slack", "message": "メッセージ送信", "channel-id": channel_id, "payload": post_args, }) result = slack_chat.post_message(**post_args)
import objectpath import Slack import Box import GSuite import urllib.request import logging from urllib.parse import parse_qs import lambda_tools from lambda_tools import invoke from lambda_tools import print_json from lambda_tools import kms_decrypted from lambda_tools import get_lambda_info from lambda_tools import slack_verification slack_token = kms_decrypted("SLACK_TOKEN") slack_bot_token = kms_decrypted("SLACK_BOT_TOKEN") slack_user = Slack.User(token=slack_bot_token) slack_channel_ids = kms_decrypted("SLACK_CHANNEL_IDS", None) if not (slack_channel_ids is None or slack_channel_ids == ""): slack_channel_ids = slack_channel_ids.split(",") box_folder = None box_file = None gdrive = None gdrive_permission = None upload_type = kms_decrypted("UPLOAD_TYPE").lower() def credential_setting(): # Box用設定