Skip to content

Commit 0ba96ad

Browse files
authored
Merge pull request #3 from ncode/juliano/messaging
Support for notification
2 parents 376f960 + 166c8a7 commit 0ba96ad

File tree

17 files changed

+3353
-125
lines changed

17 files changed

+3353
-125
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ go.work.sum
2727
# idea
2828
.idea
2929

30-
# ignore the log directory
30+
# .DS_Store
31+
.DS_Store
3132

33+
# ignore the log directory
3234
configs/development/logs/

README.md

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
- **Dynamic Logging**: Log audit events to specified files with log rotation and size limits.
1414
- **Supports Multiple Operations**: Filters common Vault operations, including KV operations, metadata updates, and deletion events.
1515
- **Performance-Oriented**: Built with `gnet` to handle high concurrency.
16+
- **Flexible Forwarding**: Forward filtered audit logs to specified UDP addresses for further processing or monitoring.
17+
- **Messaging Integration**: Send notifications about matched audit logs to messaging platforms like Mattermost.
1618

1719
## Table of Contents
1820

@@ -30,7 +32,7 @@ These instructions will help you set up and run `vault-audit-filter` on your loc
3032

3133
### Prerequisites
3234

33-
- **Go**: Ensure you have Go 1.21 or later installed. You can download it here: <https://golang.org/dl/>
35+
- **Go**: Ensure you have Go 1.22.3 or later installed. You can download it here: <https://golang.org/dl/>
3436
- **Vault**: You should have HashiCorp Vault installed and configured. Instructions can be found here: <https://www.vaultproject.io/docs/install>
3537

3638
### Installation
@@ -54,7 +56,7 @@ Once you have built the project, you can run the `vault-audit-filter` executable
5456

5557
## Configuration
5658

57-
`vault-audit-filter` uses a YAML-based configuration file that allows you to define rule groups, specify logging files, and configure Vault settings.
59+
`vault-audit-filter` uses a YAML-based configuration file that allows you to define rule groups, specify logging files, configure Vault settings, set up forwarding options, and configure messaging integration.
5860

5961
### Sample Configuration (`config.yaml`)
6062

@@ -75,6 +77,12 @@ Once you have built the project, you can run the `vault-audit-filter` executable
7577
max_backups: 5 # Max number of backup files
7678
max_age: 30 # Max age in days
7779
compress: true # Compress rotated files
80+
forwarding:
81+
enabled: true
82+
address: "127.0.0.1:9001"
83+
messaging:
84+
type: "mattermost_webhook"
85+
webhook_url: "https://your-mattermost-instance.com/hooks/your-webhook-id"
7886

7987
- name: "critical_events"
8088
rules:
@@ -86,6 +94,14 @@ Once you have built the project, you can run the `vault-audit-filter` executable
8694
max_backups: 5
8795
max_age: 30
8896
compress: true
97+
forwarding:
98+
enabled: true
99+
address: "127.0.0.1:9002"
100+
messaging:
101+
type: "mattermost"
102+
url: "https://your-mattermost-instance.com"
103+
token: "your-bot-token"
104+
channel: "your-channel-id"
89105

90106
### Configuration Parameters
91107

@@ -104,6 +120,13 @@ Once you have built the project, you can run the `vault-audit-filter` executable
104120
- `log_file.max_backups`: The number of backup logs to keep.
105121
- `log_file.max_age`: The maximum number of days to retain logs.
106122
- `log_file.compress`: Whether to compress the old log files.
123+
- `forwarding.enabled`: Whether to enable forwarding for this rule group.
124+
- `forwarding.address`: The UDP address to forward matching audit logs to.
125+
- `messaging.type`: The type of messaging integration ("mattermost" or "mattermost_webhook").
126+
- `messaging.webhook_url`: The webhook URL for Mattermost (when using "mattermost_webhook" type).
127+
- `messaging.url`: The Mattermost server URL (when using "mattermost" type).
128+
- `messaging.token`: The bot token for Mattermost (when using "mattermost" type).
129+
- `messaging.channel`: The channel ID for Mattermost messages (when using "mattermost" type).
107130

108131
### Rule Syntax
109132

@@ -139,6 +162,33 @@ $ export VAULT_ADDRESS="http://127.0.0.1:8200"
139162
$ export VAULT_TOKEN="your-vault-token"
140163
```
141164

165+
## Testing
166+
167+
To run the test suite for `vault-audit-filter`, use the following command:
168+
169+
```bash
170+
go test -v ./...
171+
```
172+
173+
For running tests with race condition detection:
174+
175+
```bash
176+
go test -race -v ./...
177+
```
178+
179+
To run a specific test, such as the concurrent forwarding test:
180+
181+
```bash
182+
go test -v -run TestUDPForwarder_ConcurrentForwarding ./pkg/forwarder
183+
```
184+
185+
To generate a test coverage report:
186+
187+
```bash
188+
go test -v -coverprofile=coverage.out ./...
189+
go tool cover -html=coverage.out
190+
```
191+
142192
### Development
143193

144194
For development purposes, you can use the provided Makefile located at `configs/development/Makefile` to build and run the project using Docker and Docker Compose. This is how I test my changes and have a playground of sorts.
@@ -151,6 +201,7 @@ Before submitting a pull request, ensure that:
151201
- The code compiles without errors.
152202
- All tests pass.
153203
- Your changes are well-documented.
204+
- You've added or updated tests to cover your changes.
154205

155206
## License
156207

cmd/auditServer.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ package cmd
1717

1818
import (
1919
"fmt"
20+
"log"
21+
2022
"github.com/ncode/vault-audit-filter/pkg/auditserver"
2123
"github.com/panjf2000/gnet"
2224
"github.com/spf13/viper"
23-
"log"
2425

2526
"github.com/spf13/cobra"
2627
)
@@ -37,7 +38,10 @@ This application is a tool to generate the needed files
3738
to quickly create a Cobra application.`,
3839
Run: func(cmd *cobra.Command, args []string) {
3940
addr := fmt.Sprintf("udp://%s", viper.GetString("vault.audit_address"))
40-
server := auditserver.New(nil)
41+
server, err := auditserver.New(nil)
42+
if err != nil {
43+
logger.Error(err.Error())
44+
}
4145
log.Fatal(gnet.Serve(server, addr, gnet.WithMulticore(true)))
4246
},
4347
}

cmd/root.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,6 @@ func initConfig() {
104104
fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
105105
}
106106

107-
if viper.GetString("vault.token") == "" {
108-
logger.Error("vault.token is required")
109-
os.Exit(1)
110-
}
111-
112107
if !viper.IsSet("rule_groups") || len(viper.GetStringSlice("rule_groups")) == 0 {
113108
logger.Info("No rules defined in configuration; all audit logs will be printed")
114109
}

cmd/setup.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ var setupCmd = &cobra.Command{
2929
Short: "Setup vault audit device",
3030
Long: ``,
3131
Run: func(cmd *cobra.Command, args []string) {
32+
if viper.GetString("vault.token") == "" {
33+
logger.Error("vault.token is required")
34+
os.Exit(1)
35+
}
36+
3237
client, err := vault.NewVaultClient(viper.GetString("vault.address"), vault.TokenAuth{Token: viper.GetString("vault.token")})
3338
if err != nil {
3439
logger.Error("setup", "unable to setup vault client", err.Error())

configs/development/config/config.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,6 @@ rule_groups:
2020
max_backups: 5
2121
max_age: 30
2222
compress: true
23+
forwarding:
24+
enabled: true
25+
address: "udp_receiver:9001"

configs/development/docker-compose.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,11 @@ services:
4242
- IPC_LOCK
4343
entrypoint: "/scripts/writer.sh"
4444

45+
udp_receiver:
46+
image: oraclelinux:9
47+
container_name: udp_receiver
48+
volumes:
49+
- ./scripts:/scripts:ro
50+
entrypoint: "/scripts/udp-receiver.sh"
51+
ports:
52+
- "9001:9001/udp"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/sh
2+
3+
set -x
4+
5+
dnf -y install nc
6+
7+
while true ; do
8+
nc -lu -p 9001
9+
done
10+
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
#!/bin/sh
22

3-
sleep 5
4-
53
set -x
4+
while true ; do
5+
sleep 5
66

7-
vault kv put secret/data/myapp/config api_key=12345 environment=production
8-
vault kv metadata put -custom-metadata="replicate_to=vault_replica" secret/metadata/myapp/config
9-
vault kv metadata get secret/metadata/myapp/config
10-
11-
vault kv put secret/data/myapp/database username=dbuser password=supersecret host=db.example.com port=5432
7+
vault kv put secret/data/myapp/config api_key=12345 environment=production
8+
vault kv metadata put -custom-metadata="replicate_to=vault_replica" secret/metadata/myapp/config
9+
vault kv metadata get secret/metadata/myapp/config
1210

13-
vault kv get -field=api_key secret/data/myapp/config
14-
vault kv get -format=json secret/data/myapp/database
11+
vault kv put secret/data/myapp/database username=dbuser password=supersecret host=db.example.com port=5432
1512

16-
vault kv list secret/metadata/myapp/
17-
vault kv delete secret/data/myapp/config
13+
vault kv get -field=api_key secret/data/myapp/config
14+
vault kv get -format=json secret/data/myapp/database
1815

16+
vault kv list secret/metadata/myapp/
17+
vault kv delete secret/data/myapp/config
18+
done
1919

go.mod

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,28 @@ go 1.22.3
55
require (
66
github.com/expr-lang/expr v1.16.9
77
github.com/hashicorp/vault/api v1.14.0
8-
github.com/ncode/courier v0.0.0-20240805115708-0d51f4845b17
8+
github.com/mattermost/mattermost-server/v6 v6.7.2
99
github.com/panjf2000/gnet v1.6.7
10-
github.com/redis/go-redis/v9 v9.6.1
1110
github.com/spf13/cobra v1.8.0
1211
github.com/spf13/viper v1.18.2
1312
github.com/stretchr/testify v1.8.4
13+
gopkg.in/natefinch/lumberjack.v2 v2.0.0
1414
)
1515

1616
require (
17-
github.com/cespare/xxhash/v2 v2.2.0 // indirect
18-
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
19-
github.com/tidwall/btree v1.1.0 // indirect
20-
github.com/tidwall/match v1.1.1 // indirect
21-
)
22-
23-
require (
17+
github.com/blang/semver v3.5.1+incompatible // indirect
2418
github.com/cenkalti/backoff/v3 v3.0.0 // indirect
2519
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
20+
github.com/dustin/go-humanize v1.0.0 // indirect
21+
github.com/dyatlov/go-opengraph v0.0.0-20210112100619-dae8665a5b09 // indirect
22+
github.com/francoispqt/gojay v1.2.13 // indirect
2623
github.com/fsnotify/fsnotify v1.7.0 // indirect
24+
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
2725
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
26+
github.com/go-test/deep v1.0.4 // indirect
27+
github.com/google/uuid v1.4.0 // indirect
28+
github.com/gorilla/websocket v1.5.0 // indirect
29+
github.com/graph-gophers/graphql-go v1.3.0 // indirect
2830
github.com/hashicorp/errwrap v1.1.0 // indirect
2931
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
3032
github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -35,21 +37,44 @@ require (
3537
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
3638
github.com/hashicorp/hcl v1.0.0 // indirect
3739
github.com/inconshreveable/mousetrap v1.1.0 // indirect
40+
github.com/json-iterator/go v1.1.12 // indirect
41+
github.com/klauspost/compress v1.17.0 // indirect
42+
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
3843
github.com/magiconair/properties v1.8.7 // indirect
44+
github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 // indirect
45+
github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d // indirect
46+
github.com/mattermost/logr/v2 v2.0.15 // indirect
47+
github.com/minio/md5-simd v1.1.2 // indirect
48+
github.com/minio/minio-go/v7 v7.0.24 // indirect
49+
github.com/minio/sha256-simd v1.0.0 // indirect
3950
github.com/mitchellh/go-homedir v1.1.0 // indirect
4051
github.com/mitchellh/mapstructure v1.5.0 // indirect
52+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
53+
github.com/modern-go/reflect2 v1.0.2 // indirect
54+
github.com/opentracing/opentracing-go v1.2.0 // indirect
55+
github.com/pborman/uuid v1.2.1 // indirect
56+
github.com/pelletier/go-toml v1.9.4 // indirect
4157
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
58+
github.com/philhofer/fwd v1.1.1 // indirect
59+
github.com/pkg/errors v0.9.1 // indirect
4260
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
61+
github.com/rs/xid v1.4.0 // indirect
4362
github.com/ryanuber/go-glob v1.0.0 // indirect
4463
github.com/sagikazarmark/locafero v0.4.0 // indirect
4564
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
65+
github.com/sirupsen/logrus v1.8.1 // indirect
4666
github.com/sourcegraph/conc v0.3.0 // indirect
4767
github.com/spf13/afero v1.11.0 // indirect
4868
github.com/spf13/cast v1.6.0 // indirect
4969
github.com/spf13/pflag v1.0.5 // indirect
70+
github.com/stretchr/objx v0.5.0 // indirect
5071
github.com/subosito/gotenv v1.6.0 // indirect
51-
github.com/tidwall/redcon v1.6.2 // indirect
72+
github.com/tinylib/msgp v1.1.6 // indirect
5273
github.com/valyala/bytebufferpool v1.0.0 // indirect
74+
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
75+
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
76+
github.com/wiggin77/merror v1.0.3 // indirect
77+
github.com/wiggin77/srslog v1.0.1 // indirect
5378
go.uber.org/atomic v1.9.0 // indirect
5479
go.uber.org/multierr v1.9.0 // indirect
5580
go.uber.org/zap v1.21.0 // indirect
@@ -60,6 +85,6 @@ require (
6085
golang.org/x/text v0.15.0 // indirect
6186
golang.org/x/time v0.5.0 // indirect
6287
gopkg.in/ini.v1 v1.67.0 // indirect
63-
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
88+
gopkg.in/yaml.v2 v2.4.0 // indirect
6489
gopkg.in/yaml.v3 v3.0.1 // indirect
6590
)

0 commit comments

Comments
 (0)