-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
184 lines (148 loc) · 4.27 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// Copyright (c) 2016 Niklas Wolber
// This file is licensed under the MIT license.
// See the LICENSE file for more information.
package main
import (
"flag"
"log"
"os"
"strings"
"time"
influx "github.com/influxdata/influxdb/client/v2"
)
func main() {
var err error
host, influxHost, username, password, db, measurement, authLog := config()
if host == "" {
host, err = os.Hostname()
if err != nil {
log.Fatalln("Hostname not provided and failed to get hostname from system", err)
}
log.Println("Using hostname", host)
}
client, err := influx.NewHTTPClient(influx.HTTPConfig{
Addr: influxHost,
Username: username,
Password: password,
UserAgent: "loginmonitor",
})
if err != nil {
log.Fatalln("Failed to create InfluxDB client", err)
}
c := make(chan struct{})
go func() {
if _, _, err = client.Ping(time.Second); err != nil {
log.Fatalln("Error connecting to InfluxDB", err)
}
c <- struct{}{}
}()
select {
case <-c:
case <-time.Tick(5 * time.Second):
log.Fatalln("InfluxDB failed to respond in time")
}
log.Println("Connected to InfluxDB at", influxHost)
s := &eventStore{
c: client,
hostname: host,
db: db,
measurement: measurement,
}
closer := make(chan struct{})
go func() {
monitorAuthLog(authLog, s)
closer <- struct{}{}
}()
go func() {
monitorDocker(s)
closer <- struct{}{}
}()
<-closer
}
func config() (host, influx, username, password, db, measurement, authLog string) {
const (
defaultHost = ""
defaultInfluxDb = "http://localhost:8086"
defaultUsername = ""
defaultPassword = ""
defaultDb = ""
defaultMeasurement = "events"
defaultAuthLog = "/var/log/auth.log"
)
flag.StringVar(&host, "host", defaultHost, "String to use in the 'hostname' tag, if empty the system will be queried")
flag.StringVar(&influx, "influxdb", defaultInfluxDb, "InfluxDB HTTP endpoint")
flag.StringVar(&username, "username", defaultUsername, "Username for InfluxDB")
flag.StringVar(&password, "password", defaultPassword, "Password for InfluxDB")
flag.StringVar(&db, "db", defaultDb, "Database where events are written to")
flag.StringVar(&measurement, "measurement", defaultMeasurement, "Measurement where events are written to")
flag.StringVar(&authLog, "authlog", defaultAuthLog, "The PAM authentication log to watch for login/logout messages")
help := flag.Bool("help", false, "Print this help message")
c := flag.Bool("config", false, "Print config")
flag.Parse()
if *help {
flag.PrintDefaults()
os.Exit(1)
// Not reached
}
if *c {
log.Println("host =", host)
log.Println("influxdb =", influx)
log.Println("username =", username)
log.Println("password =", password)
log.Println("db =", db)
log.Println("measurement =", measurement)
log.Println("authLog =", authLog)
}
return
}
type eventStore struct {
c influx.Client
hostname, db, measurement string
}
func (s *eventStore) storeUserEvent(typ, user, msg string, timestamp time.Time) {
s.store("auth", typ, msg, map[string]string{
"user": user,
}, timestamp)
}
func (s *eventStore) storeDockerEvent(typ, service, container, image, msg string, timestamp time.Time) {
tags := make(map[string]string)
tags["container"] = container
tags["image"] = image
if service != "" {
tags["service"] = service
}
s.store("docker", typ, msg, tags, timestamp)
}
func (s *eventStore) store(provider, event, msg string, tags map[string]string, timestamp time.Time) {
t := make(map[string]string)
t["hostname"] = s.hostname
t["event"] = event
for k, v := range tags {
if _, ok := t[k]; ok {
log.Println(k, "is a reserved tag. Won't store", event, "event.")
return
}
t[k] = v
}
fields := make(map[string]interface{})
fields["description"] = msg
measurement := provider + strings.Title(s.measurement)
p, err := influx.NewPoint(measurement, t, fields, timestamp)
if err != nil {
log.Println("Error creating event", msg, err)
return
}
bp, err := influx.NewBatchPoints(influx.BatchPointsConfig{
Database: s.db,
})
if err != nil {
log.Println("Error creating batch points", err)
return
}
bp.AddPoint(p)
if err := s.c.Write(bp); err != nil {
log.Println("Error writing batch point", err)
return
}
log.Println("Message written")
}