Slack/Teams GuardDuty에 대한 위협 탐지 결과 알림
개시하다
나는 생산기술부에서 제품 검사 공정을 책임지는 엔지니어다.AWS의 보안에 대응하기 위해 GuardDuty를 사용했습니다.GuardDuty를 사용하면 악의적인 활동과 비정상적인 동작을 지속적으로 모니터링할 수 있습니다.하지만 검출된 결과에 주의하지 않으면 의미가 없다.결과를 메신저에 전달함으로써 조속히 대응하는 체제를 목표로 한다.
Slack/Teams에 대한 알림 방법
위협이 감지된 결과는 자동으로 이벤트브릿지(구 Amazon CloudWatch Events)로 전송되기 때문에 이벤트브릿지로 이벤트를 트리거합니다.
Slack 사용 시 Cloudformation
GuardDuty는 클라우드 트레일, Kubernetes, VPC 프로세스 로그, DNS 로그 등에 따라 위협 검사를 한다.그러나 이러한 설정은 필요하지 않습니다. GuardDuty를 사용하면 위협 탐지가 자동으로 시작됩니다.EventBridge는 다음 이벤트에 대한 규칙을 설정하고 Target에서 SNS 주제를 지정합니다.
SNS의 끝점은 Chatbot의 API
https://global.sns-api.chatbot.amazonaws.com
를 지정합니다.ChatBot은 AWS 콘솔에서 Slack과 사전에 연결합니다.Cloudformation의 ChatBot에서 다음을 설정합니다.https://sample.slack.com/archives/XXXXXXXXXXX
AWSTemplateFormatVersion: "2010-09-09"
Description: Guard Duty
# ------------------------------------------------------------------------------
# Resources
# ------------------------------------------------------------------------------
Resources:
GuardDuty:
Type: AWS::GuardDuty::Detector
Properties:
Enable: True
FindingPublishingFrequency: FIFTEEN_MINUTES
EventRule:
Type: AWS::Events::Rule
Properties:
Description: guardduty notification
Name: guardduty-notification
EventPattern:
source:
- aws.guardduty
detail-type:
- GuardDuty Finding
State: ENABLED
Targets:
- Arn: !Ref Topic
Id: sns-topic
Topic:
Type: AWS::SNS::Topic
Subscription:
Type: AWS::SNS::Subscription
Properties:
Protocol: https
TopicArn: !Ref Topic
Endpoint: "https://global.sns-api.chatbot.amazonaws.com"
ChatBot:
Type: AWS::Chatbot::SlackChannelConfiguration
Properties:
ConfigurationName: GuardDutyNotification
GuardrailPolicies:
- "arn:aws:iam::aws:policy/ReadOnlyAccess"
IamRoleArn: !GetAtt ChatBotRole.Arn
LoggingLevel: NONE
SlackChannelId: "{{resolve:ssm:GuardDutySlackChannelId:1}}"
SlackWorkspaceId: "{{resolve:ssm:GuardDutySlackWorkspaceId:1}}"
SnsTopicArns:
- !Ref Topic
UserRoleRequired: false
ChatBotRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: chatbot.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/ReadOnlyAccess
Slack에 대한 알림 확인
Chatbot과 Slack 사이의 소통은ChatAWS 콘솔에서'테스트 메시지 보내기'를 클릭하면 확인할 수 있다.Slack에서 다음 메시지를 보냅니다.
GuardDuty에서 Slack까지의 소통은 GuardDuty의AWS 콘솔에서 설정한'결과 샘플의 생성'을 클릭하면 결과의 샘플을 자동으로 생성하고 확인할 수 있다.Slack에서 다음 메시지를 보냅니다.새로운 결과는 5분 이내에 EventBridge에 전송됩니다.
Teams 사용 시 Cloudformation
슬랙에 알릴 때와 달리 이벤트 브릿지의 목표는 람바다로 설정됩니다.
AWSTemplateFormatVersion: "2010-09-09"
Description: Guard Duty
# ------------------------------------------------------------------------------
# Resources
# ------------------------------------------------------------------------------
Resources:
GuardDuty:
Type: AWS::GuardDuty::Detector
Properties:
Enable: True
FindingPublishingFrequency: FIFTEEN_MINUTES
EventRule:
Type: AWS::Events::Rule
Properties:
Description: guardduty notification
Name: guardduty-notification
EventPattern:
source:
- aws.guardduty
detail-type:
- GuardDuty Finding
State: ENABLED
Targets:
- Arn: !GetAtt Function.Arn
Id: lambda
EventPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref Function
Principal: events.amazonaws.com
SourceAccount: !Ref AWS::AccountId
SourceArn: !GetAtt EventRule.Arn
Function:
Type: AWS::Lambda::Function
Properties:
Handler: guardduty-notification
Role: !GetAtt LambdaRole.Arn
Code:
S3Bucket: "{{resolve:ssm:S3BacketLambda:1}}"
S3Key: guardduty-notification.zip
Runtime: go1.x
ReservedConcurrentExecutions: 1
Timeout: 5
TracingConfig:
Mode: Active
Environment:
Variables:
TeamsUrl: "{{resolve:ssm:TeamsUrl:1}}"
LambdaRole:
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Condition: {}
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Version: 2012-10-17
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Tags:
- Key: f-iot.service.name
Value: lambda
Type: AWS::IAM::Role
Teams 사용 시 Lambda
Event Bridge에서 받은 이벤트를 처리하고 환경 변수에서 TeamsUrl로 필요한 정보를 읽어 보냅니다.구현 단계는 GuardDuty에서 EventBridge에 전송된 이벤트의 샘플 제작 구조체를 참조하여 필요한 데이터를 추출하는 것입니다.Teams의 Webhook 데이터 형식으로 가공하여 POST를 진행하면 완성됩니다.
/// main GuardDutyが脅威検出した結果を通知します。
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"os"
"strconv"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
type Service struct {
EventFirstSeen string `json:"eventFirstSeen"`
EventLastSeen string `json:"eventLastSeen"`
Count int `json:"count"`
}
type GuardDutyEvent struct {
AccountId string `json:"accountId"`
Id string `json:"id"`
Type string `json:"type"`
Region string `json:"region"`
Service Service `json:"service"`
Severity float32 `json:"severity"`
Description string `json:"description"`
}
type Fact struct {
Name string `json:"name"`
Value string `json:"value"`
}
type Section struct {
Facts []Fact `json:"facts"`
}
type Target struct {
Os string `json:"os"`
Uri string `json:"uri"`
}
type Link struct {
Type string `json:"@type"`
Name string `json:"name"`
Targets []Target `json:"targets"`
}
func HandleLambdaEvent(_ context.Context, event events.CloudWatchEvent) {
var guardDutyEvent GuardDutyEvent
if err := json.Unmarshal(event.Detail, &guardDutyEvent); err != nil {
os.Exit(1)
}
TeamsUrl := os.Getenv("TeamsUrl")
var color string
var servirityCategory string
if guardDutyEvent.Severity >= 7.0 {
color = "#ff0000"
servirityCategory = "High"
} else if guardDutyEvent.Severity >= 4.0 {
color = "#fd7e00"
servirityCategory = "MEDIUM"
} else {
color = "#0000ff"
servirityCategory = "LOW"
}
facts := []Fact{
{Name: "Finding type", Value: guardDutyEvent.Type},
{Name: "Description", Value: guardDutyEvent.Description},
{Name: "Severity", Value: servirityCategory},
{Name: "First Seen", Value: guardDutyEvent.Service.EventFirstSeen},
{Name: "Last Seen", Value: guardDutyEvent.Service.EventLastSeen},
{Name: "Threat Count", Value: strconv.Itoa(guardDutyEvent.Service.Count)},
}
sections := []Section{{Facts: facts}}
guarddutyURL := "https://console.aws.amazon.com/guardduty/home?region=" + guardDutyEvent.Region + "#/findings?search=id=" + guardDutyEvent.Id
targets := []Target{{Os: "default", Uri: guarddutyURL}}
links := []Link{{Type: "OpenUri", Name: "Jump To GuardDuty", Targets: targets}}
payload, err := json.Marshal(struct {
Summary string `json:"summary"`
Type string `json:"@type"`
ThemeColor string `json:"themeColor"`
Title string `json:"title"`
Sections []Section `json:"sections"`
PotentialAction []Link `json:"potentialAction"`
}{
Summary: "Summary",
Type: "MessageCard",
ThemeColor: color,
Title: "GuardDuty Finding | " + guardDutyEvent.Region + " | Account: " + guardDutyEvent.AccountId,
Sections: sections,
PotentialAction: links,
})
if err != nil {
fmt.Println(err)
return
}
resp, err := http.Post(TeamsUrl, "application/json; charset=UTF-8", bytes.NewReader(payload))
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Printf("HTTP: %v\n", resp.StatusCode)
}
}
func main() {
lambda.Start(HandleLambdaEvent)
}
Teams 알림 확인
람바다와 팀스 간 소통은 람바다의 AWS 콘솔에서 테스트 이벤트를 만들어'테스트'를 클릭해 확인할 수 있다.테스트 이벤트 JSON은 이벤트브릿지의 AWS 콘솔에서 샌드박스로 이동해 샘플 이벤트를'GuardDuty Finding'으로 설정하면 샘플을 쉽게 얻을 수 있다.취득한 샘플에 따라 람다를 실행하면 팀스는 다음과 같은 정보를 보낸다.
GuardDuty에서 Teams까지의 소통은 슬랙과 마찬가지로'결과 샘플 생성'을 누르면 확인할 수 있다.
최후
GuardDuty에서 Slack/Teams에 위협 검출 결과를 보내는 메커니즘을 실현했다.채트봇이면 편하고 람바다면 자유롭게 맞춤 제작이 가능하니 어디든 괜찮은 것 같아요.GuardDuty의 결과뿐만 아니라 CodePipeline의 실행 결과 등도 같은 방법으로 메신저에 알릴 수 있으니 꼭 시도해 보세요.
Reference
이 문제에 관하여(Slack/Teams GuardDuty에 대한 위협 탐지 결과 알림), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/s_tomoyuki/articles/0004-aws-guardduty-notification텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)