Cảnh báo đăng nhập bằng Golang

Dạo gần đây mình đang theo học một môn võ công mới. Môn võ công này kinh dị đến nỗi mới theo được vài ngày đã bị tàu hỏa nhập ma. Cấu trúc thì xấu kinh dị, thuật ngữ thì khó, Nhưng cuộc sống mà không có gì là tươi đẹp. Cuộc đời xô đẩy dẫn đến mình phải luyện nó thôi.

Golang hay còn gọi là Go được ông anh gồ phát triển vào năm 2007 sau đó được công bố vào năm 2009. Với tốc độ thực thi mã lệnh cực nhanh và xử lý các tác vụ hoàn hảo, không gì tuyệt vời hơn nếu sử dụng nó để làm 1 vài Microservices bằng Go

Xây dựng hệ thống cảnh báo đăng nhập linux

Ý tưởng: Khi người dùng đăng nhập hệ thống linux, Server sẽ tự call đến 1 service, Service này có nhiệm vụ gửi 1 thông điệp notification đến các kênh thông báo như SMS, email, slack, chatwork, vv...

Xây dựng Lên kế hoạch thôi Hãy chắc chắn rằng linux của bạn đã install go B1. tạo file config.json

{
  "SMTP_EMAIL": "",
  "SMTP_PASSWORD": "",
  "SMTP_SERVER": "",
  "SMTP_PORT": 25,
  "SLACK_WEBHOOK": "token",
  "CHATWORK_TOKEN": "token",
  "ROOM_ID": "room_id",
  "LISTEN": ":8000"
}

Ở đây mình sẽ ví dụ gửi đến 2 kênh thông báo slack và chatwork

B2. Xây dựng go notification.go

Để Notification tới chatwork chắc chắn các bạn phải sử dụng đến api chatwork rồi api chatwork. Hãy tạo 1 em boot sau đó request lấy api token nhét vào config.jon là ok rồi

Import thư viện cần thiết

import (
  "encoding/json"
  "fmt"
  "io/ioutil"
  "net/http"
)

struct lưu trữ thông tin cấu hình

type Config struct {
  SMTP_EMAIL      string
  SMTP_PASSWORD   string
  SMTP_SERVER     string
  SMTP_PORT       int
  SLACK_WEBHOOK   string
  CHATWORK_TOKEN  string
  ROOM_ID         string
  LISTEN          string
}

Đọc file từ config.jon và nạp vào struct Config

func loadConfig() *Config {
  conf := Config{}
  content, e := ioutil.ReadFile("./config.json")
  checkErr(e)
  err := json.Unmarshal(content, &conf)
  checkErr(err)
  return &conf
}

checkErr() Method này dùng để check lỗi chương trình

Send notification tới chatwork

func doSendChatwork(body string) []byte {
  client := &http.Client{}
  req, requestErr := http.NewRequest("POST", "https://api.chatwork.com/v2/rooms/"+config.ROOM_ID+"/messages?body="+body, nil)
  checkErr(requestErr)
  req.Header.Add("X-ChatWorkToken", config.CHATWORK_TOKEN)
  resp, responseErr := client.Do(req)
  checkErr(responseErr)
  
  return parseBody(resp)
}

Method thực thi

func notifyLogin(w http.ResponseWriter, r *http.Request) {
  response := doSendChatwork("Warning%21%20Logged")
  fmt.Println(response)
}

Hàm main chính

func main() {
  config = loadConfig()
  http.HandleFunc("/notify/login", notifyLogin)
  err := http.ListenAndServe(config.LISTEN, nil)
  checkErr(err)
}

Service tự tạo 1 webserver chạy ở port trong config. Để build thành file scripts trên linux sử dụng với lệnh sau

$ go build notification.go

Run scripts $ ./notification

Tạo Trigger trên các server Agent

Khi người dùng đăng nhập vào hệ thống các scripts trong /etc/profile.d/ sẽ được thực thi. Lợi dụng điều này ta sẽ tạo 1 scripts với nội dung như sau

#!/usr/bin/env bash
if [ -n "$SSH_CLIENT" ];then 
    LOGIN_NOTIFY_HOST="localhost:8000"
    REMOTE_IP=`echo $SSH_CLIENT|awk '{print $1}'`
    LOGIN_NOTIFY_API="http://${LOGIN_NOTIFY_HOST}/notify/login?user=${USER}&remoteip=$REMOTE_IP"
    /usr/bin/curl "$LOGIN_NOTIFY_API" &> /dev/null
fi

Scripts sẽ call đến service kèm theo thông tin User và địa chỉ IP đăng nhập. Ngay lập tức services sẽ gửi 1 thông điệp tới chatwork "Attacked by xxx"

Toàn bộ source code được lưu tại https://github.com/dung13890/go-notification