예제 #1
0
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
예제 #2
0
def check_messages(event):
    ja = pytz.timezone("Asia/Tokyo")
    nt = datetime.datetime.now(ja)
    nt = nt.timestamp() * 1000
    for message in event:
        body = json.loads(message['Body'])
        alert_id = message["MessageAttributes"]["SystemAlertId"]["StringValue"]
        sent_timestamp = int(message["Attributes"]["SentTimestamp"])
        stime = datetime.datetime.fromtimestamp(sent_timestamp / 1000, ja)
        stime = "{0:%Y-%m-%d %H:%M:%S}".format(stime)
        lapsed_time = nt - sent_timestamp
        msg = None

        if lapsed_time < 86400000:
            msg = "24時間未満"
        # 24時間以上48時間以下
        elif lapsed_time < 172800000:
            msg = "24時間経過"
            repost(message)
        # 48時間以上72時間以下
        elif lapsed_time < 259200000:
            msg = "48時間経過"
            repost(message)
        # 72時間以上
        else:
            msg = "72時間経過"
            set_status(alert_id)
        print_json({
            "type": "Lambda",
            "message": msg,
            "send_time": stime,
            "alert": body
        })
예제 #3
0
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)
예제 #4
0
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)
예제 #5
0
def main_function(event):
    print_json({
        "type": "Slack",
        "message": "Interactive Event",
        "payload": event,
    })
    type = event["type"]
    if type == "view_submission":
        view_submission(event)
    elif type == "block_actions":
        block_actions(event)
예제 #6
0
def block_actions(event):
    for action in event["actions"]:
        print_json({
            "type": "Slack",
            "message": "Interactive Event",
            "action": action
        })
        action_id = action["action_id"]
        if (action_id == "answer_true"):
            call_modal(event)
        elif (action_id == "answer_false"):
            answer_false(event, action)
예제 #7
0
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
예제 #8
0
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)
예제 #9
0
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
예제 #10
0
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
예제 #11
0
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
예제 #12
0
def lambda_handler(event, context):
    get_lambda_info(context, "sentinel-alert-crawler")
    print_json({
        "type": "lambda",
        "message": "イベント受信",
        "payload": event,
    })
    response_url = None
    try:
        if 'Messages' in event:
            check_messages(event["Messages"])
        else:
            main_function(event, context)
        return {
            "isBase64Encoded": False,
            "statusCode": 200,
            "headers": {},
            "body": json.dumps({})
        }
    except Exception as e:
        print_json({
            "type": "lambda",
            "level": "error",
            "request-id": lambda_tools.aws_request_id,
            "message": str(e),
            "reason": error.exception_fail(e)
        })
        return {
            "isBase64Encoded": False,
            "statusCode": 502,
            "headers": {},
            "body": json.dumps({
                "text": str(e),
                "response_type": "in_channel"
            })
        }
예제 #13
0
def lambda_handler(event, context):
    get_lambda_info(context, "sentinel-alert-answer")
    print_json({
        "type": "lambda",
        "message": "イベント受信",
        "payload": event,
    })
    try:
        if 'body' in event:
            if lambda_tools.aws_request_id != "debug":
                verify_slack_signature(event)
            params = parse_qs(event['body'])
            print_json({
                "type": "lambda",
                "message": "Lambdaを再帰呼出しします",
                "payload": params,
            })
            if lambda_tools.aws_request_id == "debug":
                return lambda_handler(params, context)
            else:
                invoke(params)
        elif 'payload' in event:
            payload = event["payload"]
            payload = json.loads(payload[0])
            main_function(payload)
        return {
            "isBase64Encoded": False,
            "statusCode": 200,
            "headers": {
                'content-type': 'application/json'
            },
            "body": ""
        }
    except Exception as e:
        print_json({
            "type": "lambda",
            "level": "error",
            "request-id": lambda_tools.aws_request_id,
            "message": str(e),
            "reason": error.exception_fail(e)
        })
        return {
            "isBase64Encoded": False,
            "statusCode": 502,
            "headers": {
                'content-type': 'application/json'
            },
            "body": json.dumps({
                "text": str(e),
                "response_type": "in_channel"
            })
        }
예제 #14
0
def lambda_handler(event, context):
    get_lambda_info(context, "sentinel-alert-receiver")
    print_json({
        "type": "lambda",
        "message": "イベント受信",
        "payload": event,
    })
    response_url = None
    try:
        if 'Records' in event:
            params = event['Records']
            print_json({
                "type": "lambda",
                "message": "Lambdaを再帰呼出しします",
                "payload": params,
            })
            if lambda_tools.aws_request_id == "debug":
                return lambda_handler(params, context)
            else:
                invoke(params)
        else:
            main_function(event)
        return {
            "isBase64Encoded": False,
            "statusCode": 200,
            "headers": {},
            "body": json.dumps({"response_type": "in_channel"})
        }
    except Exception as e:
        print_json({
            "type": "lambda",
            "level": "error",
            "request-id": lambda_tools.aws_request_id,
            "message": str(e),
            "reason": error.exception_fail(e)
        })
        return {
            "isBase64Encoded": False,
            "statusCode": 502,
            "headers": {},
            "body": json.dumps({
                "text": str(e),
                "response_type": "in_channel"
            })
        }
예제 #15
0
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)
예제 #16
0
def lambda_handler(event, context):
    get_lambda_info(context, "SlackUploadFileTransfer-Receiver")
    print_json({
        "type": "lambda", "message": "イベント受信",
        "payload": event
    })
    if "X-Slack-Retry-Reason" in event["headers"]:
        if event["headers"]["X-Slack-Retry-Reason"] == "http_timeout":
            return {
                "statusCode": 200,
                "headers": {
                    "Content-Type": "application/json"
                },
                "body": "OK"
            }
    try:
        if isinstance(event["body"], str):
            slack_verification(event)
            event["body"] = json.loads(event["body"])
            if "challenge" in event["body"]:
                print_json({
                    "type": "lambda", "message": "チャレンジイベント受信",
                    "payload": event
                })
                return {
                    'statusCode': '200',
                    'body': event["body"]["challenge"]
                }
            subtype = event["body"]["event"].get("subtype", None)
            channel = event["body"]["event"].get("channel", None)
            if slack_channel_ids is not None:
                if channel not in slack_channel_ids:
                    return {
                        "statusCode": 200,
                        "headers": {"Content-Type": "application/json"},
                        "body": "OK"
                    }
            if subtype == "file_share":
                print_json({
                    "type": "lambda", "message": "FileShareイベント受信",
                    "payload": event
                })
                print_json({
                    "type": "lambda",
                    "message": "Lambdaを再帰呼出しします"
                })
                if lambda_tools.aws_request_id == "debug":
                    return lambda_handler(event, context)
                else:
                    invoke(event)
        else:
            main_function(event, context)
        return {
            "statusCode": 200,
            "headers": {
                "Content-Type": "application/json"
            },
            "body": "OK"
        }
    except Exception as e:
        print_json({
            "type": "lambda",
            "level": "error",
            "request-id": lambda_tools.aws_request_id,
            "message": str(e),
            "event": event,
            "reason": lambda_tools.exception_fail(e)
        })
        return {
            "statusCode": 502,
            "headers": {},
            "body": json.dumps({
                "text": str(e)
            })
        }
예제 #17
0
def main_function(data, context):
    credential_setting()
    body = data.get("body", {})
    event = body.get("event", {})
    text = event.get("text", None)
    channel_id = event.get("channel", None)
    channel_type = event.get("channel_type", None)
    ts = event.get("ts", None)
    files = event.get("files", [])
    user_id = event.get("user")
    thread_ts = event.get("thread_ts", None)
    blocks = event.get("blocks", None)

    links = []
    for file in files:
        try:
            id, name, link = transfer(file, event)
            links.append(link)
        except urllib.error.HTTPError as e:
            if e.code == 404:
                print_json({
                    "level": "warning",
                    "type": "Slack",
                    "message": "Slack上にFileが存在しません",
                    "id": file["id"],
                    "name": file["name"]
                })
                continue
            raise e
        except Exception as e:
            raise e
    if len(links) == 0:
        return
    # Slack処理
    user_info = slack_user.info(user_id)
    profile = user_info["user"]["profile"]
    user_icon = profile.get("image_original", profile["image_192"])
    user_name = profile.get("display_name")
    if user_name == "":
        user_name = profile.get("real_name")
    if channel_type == "im":
        channel_id = user_id
    try:
        slack_chat = Slack.Chat(token=slack_bot_token)
        message = {
            "channel": channel_id,
            "text": "{}\n{}".format(text, "\n".join(links)),
            "link_names": True,
            "username": user_name,
            "icon_url": user_icon,
            "thread_ts": thread_ts
        }
        print_json({
            "type": "Slack",
            "message": "Slack上にメッセージをPostします",
            "data": message
        })
        slack_chat.post_message(**message)
    except Exception as e:
        raise e
    # 古いメッセージを削除
    try:
        print_json({
            "type": "Slack",
            "message": "Slack上の古いメッセージを削除します",
            "channel": channel_id,
            "ts": ts
        })
        slack_chat = Slack.Chat(token=slack_token)
        slack_chat.delete(channel=channel_id, ts=ts, as_user=True)
    except Exception as e:
        print_json({
            "type": "Slac",
            "level": "error",
            "request-id": lambda_tools.aws_request_id,
            "channel": channel_id,
            "ts": ts,
            "message": "メッセージ削除に失敗しました[{}]".format(str(e))
        })
    # Slack上のファイルを削除
    slack_file = Slack.File(token=slack_token)
    for file in files:
        try:
            print_json({
                "type": "Slack",
                "message": "Slack上のファイルを削除します",
                "file": file["id"],
                "name": file["name"]
            })
            slack_file.delete(file=file["id"])
        except Exception as e:
            print_json({
                "type": "lambda",
                "level": "error",
                "request-id": lambda_tools.aws_request_id,
                "message": "ファイル削除に失敗しました[{}]".format(str(e)),
                "file": file["id"],
                "name": file["name"]
            })
예제 #18
0
def box_uploader(file, stream, length, event):
    user_info = slack_user.info(event["user"])
    user_name = user_info["user"]["profile"]["display_name"]
    if user_name == "":
        user_name = user_info["user"]["name"]

    parent_id = box_create_user_folder(user_name)
    name = file["name"].split(".")
    base = name[0]
    ext = name[1]

    # Boxにアップロードが可能かPreFlightCheck
    name = "{}.{}".format(base, ext)
    try:
        box_file.preflight(name, parent_id, file["size"])
    except Exception as e:
        if e.code == "item_name_in_use":
            name = "{} ({}).{}".format(base, event["ts"], ext)
        else:
            raise e
    print_json({
        "type": "Box",
        "message": "Slack上のFileをBoxにアップロードします",
        "name": name,
        "size": length
    })
    # Upload
    try:
        if length <= 20000000:
            uploaded_file = box_file.upload(
                folder_id=parent_id, stream=io.BytesIO(stream.read()),
                name=name, overwrite=True
            )
        else:
            # Chunk upload
            session = box_file.client.folder(
                folder_id=parent_id
            ).create_upload_session(file_size=length, file_name=name)
            parts = []
            sha1 = hashlib.sha1()
            for part_index in range(session.total_parts):
                copied_length = 0
                chunk = b''
                while copied_length < session.part_size:
                    buffer = stream.read(session.part_size - copied_length)
                    if buffer is None:
                        continue
                    if len(buffer) == 0:
                        break
                    chunk += buffer
                    copied_length += len(buffer)
                    uploaded_part = session.upload_part_bytes(
                        chunk, part_index*session.part_size, length)
                    parts.append(uploaded_part)
                    updated_sha1 = sha1.update(chunk)
            content_sha1 = sha1.digest()
            uploaded_file = session.commit(
                content_sha1=content_sha1, parts=parts)
        link = uploaded_file.get_shared_link()
        print_json({
            "type": "Box",
            "message": "Slack上のFileをBoxにアップロードしました",
            "name": uploaded_file.name,
            "id": uploaded_file.id,
            "link": link
        })
        return uploaded_file.id, uploaded_file.name, link
    except Exception as e:
        raise e