Skip to content

Commit d2c3597

Browse files
committed
feat(actions): Isolate action
With the isolate action it is possible to block all inbound/outbound traffic to the host except for loopback address and the list of allowed IP addresses specified in the action parameter.
1 parent eab4790 commit d2c3597

File tree

10 files changed

+351
-47
lines changed

10 files changed

+351
-47
lines changed

go.mod

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ require (
2828
github.com/spf13/viper v1.6.2
2929
github.com/streadway/amqp v1.0.0
3030
github.com/stretchr/testify v1.8.1
31+
github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6
3132
github.com/valyala/bytebufferpool v1.0.0
3233
github.com/valyala/gozstd v1.11.0
3334
github.com/xeipuuv/gojsonschema v1.2.0
@@ -44,9 +45,16 @@ require (
4445
)
4546

4647
require (
48+
github.com/BurntSushi/toml v0.4.1 // indirect
4749
github.com/rivo/uniseg v0.4.2 // indirect
4850
github.com/rogpeppe/go-internal v1.11.0 // indirect
4951
github.com/secDre4mer/pkcs7 v0.0.0-20240322103146-665324a4461d // indirect
52+
go4.org/netipx v0.0.0-20220725152314-7e7bdc8411bf // indirect
53+
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect
54+
golang.org/x/mod v0.17.0 // indirect
55+
golang.org/x/sync v0.10.0 // indirect
56+
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
57+
honnef.co/go/tools v0.3.2 // indirect
5058
)
5159

5260
require (

go.sum

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2-
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
32
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
3+
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
4+
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
45
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
56
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
67
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
@@ -77,8 +78,9 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
7778
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
7879
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
7980
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
80-
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
8181
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
82+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
83+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
8284
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
8385
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
8486
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
@@ -230,6 +232,8 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs
230232
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
231233
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
232234
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
235+
github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6 h1:l10Gi6w9jxvinoiq15g8OToDdASBni4CyJOdHY1Hr8M=
236+
github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6/go.mod h1:ZXRML051h7o4OcI0d3AaILDIad/Xw0IkXaHM17dic1Y=
233237
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
234238
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
235239
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
@@ -254,6 +258,12 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
254258
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
255259
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
256260
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
261+
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE=
262+
go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA=
263+
go4.org/netipx v0.0.0-20220725152314-7e7bdc8411bf h1:IdwJUzqoIo5lkr2EOyKoe5qipUaEjbOKKY5+fzPBZ3A=
264+
go4.org/netipx v0.0.0-20220725152314-7e7bdc8411bf/go.mod h1:+QXzaoURFd0rGDIjDNpyIkv+F9R7EmeKorvlKRnhqgA=
265+
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 h1:FyBZqvoA/jbNzuAWLQE2kG820zMAkcilx6BMjGbL/E4=
266+
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
257267
golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc=
258268
golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
259269
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -263,10 +273,14 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
263273
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
264274
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
265275
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
276+
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e h1:qyrTQ++p1afMkO4DPEeLGq/3oTsdlvdH4vqZUBWzUKM=
277+
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
266278
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
267279
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
268280
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
269281
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
282+
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
283+
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
270284
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
271285
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
272286
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -289,6 +303,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
289303
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
290304
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
291305
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
306+
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
307+
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
292308
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
293309
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
294310
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -330,6 +346,8 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
330346
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
331347
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
332348
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
349+
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
350+
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
333351
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
334352
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
335353
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -363,5 +381,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
363381
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
364382
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
365383
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
384+
honnef.co/go/tools v0.3.2 h1:ytYb4rOqyp1TSa2EPvNVwtPQJctSELKaMyLfqNP4+34=
385+
honnef.co/go/tools v0.3.2/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw=
366386
www.velocidex.com/golang/go-ntfs v0.2.1-0.20240818145200-04736de821dc h1:eeL+RUEGr6/lYL8hJEbvugrF88I6W4pBaVtFa1falj4=
367387
www.velocidex.com/golang/go-ntfs v0.2.1-0.20240818145200-04736de821dc/go.mod h1:itvbHQcnLdTVIDY6fI3lR0zeBwXwBYBdUFtswE0x1vc=

pkg/config/_fixtures/filters/default.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ output: >
99
`%ps.exe` attempted to reach out to `%net.sip` IP address
1010
action:
1111
- name: kill
12+
- name: isolate
13+
whitelist:
14+
- 127.0.0.1
15+
- 8.8.8.8
1216
min-engine-version: 2.0.0
1317
tags:
1418
- TE

pkg/config/decoder.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818

1919
package config
2020

21-
import "github.com/mitchellh/mapstructure"
21+
import (
22+
"github.com/mitchellh/mapstructure"
23+
"net"
24+
"reflect"
25+
)
2226

2327
func decode(input, output interface{}) error {
2428
var decoderConfig = &mapstructure.DecoderConfig{
@@ -28,6 +32,7 @@ func decode(input, output interface{}) error {
2832
DecodeHook: mapstructure.ComposeDecodeHookFunc(
2933
mapstructure.StringToTimeDurationHookFunc(),
3034
mapstructure.StringToSliceHookFunc(","),
35+
ipSliceDecodeHook(),
3136
),
3237
}
3338
decoder, err := mapstructure.NewDecoder(decoderConfig)
@@ -36,3 +41,25 @@ func decode(input, output interface{}) error {
3641
}
3742
return decoder.Decode(input)
3843
}
44+
45+
func ipSliceDecodeHook() mapstructure.DecodeHookFunc {
46+
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
47+
if to.Kind() == reflect.Slice && to.Elem() == reflect.TypeOf(net.IP(nil)) {
48+
49+
switch v := data.(type) {
50+
case []interface{}:
51+
var ips []net.IP
52+
for _, s := range v {
53+
ip, ok := s.(string)
54+
if !ok {
55+
continue
56+
}
57+
ips = append(ips, net.ParseIP(ip))
58+
}
59+
return ips, nil
60+
}
61+
}
62+
63+
return data, nil
64+
}
65+
}

pkg/config/filters.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/spf13/viper"
3131
"gopkg.in/yaml.v3"
3232
"io"
33+
"net"
3334
"net/http"
3435
u "net/url"
3536
"os"
@@ -64,6 +65,13 @@ type FilterAction any
6465
// indicates by the filter field expression.
6566
type KillAction struct{}
6667

68+
// IsolateAction defines an action for isolating the host
69+
// via firewall rules.
70+
type IsolateAction struct {
71+
// Whitelist contains IP addresses that should remain accessible.
72+
Whitelist []net.IP `mapstructure:"whitelist"`
73+
}
74+
6775
// DecodeActions converts raw YAML map to
6876
// typed action structures.
6977
func (f FilterConfig) DecodeActions() ([]any, error) {
@@ -89,8 +97,14 @@ func (f FilterConfig) DecodeActions() ([]any, error) {
8997
if err := dec(m, kill); err != nil {
9098
return nil, err
9199
}
100+
case "isolate":
101+
var isolate IsolateAction
102+
if err := dec(m, isolate); err != nil {
103+
return nil, err
104+
}
92105
}
93106
}
107+
94108
return actions, nil
95109
}
96110

pkg/config/filters_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ func TestLoadRulesFromPaths(t *testing.T) {
6161
acts, err := f1.DecodeActions()
6262
require.NoError(t, err)
6363
require.IsType(t, KillAction{}, acts[0])
64+
require.IsType(t, IsolateAction{}, acts[1])
65+
66+
isolate := acts[1].(IsolateAction)
67+
require.Len(t, isolate.Whitelist, 2)
68+
require.Contains(t, isolate.Whitelist, net.ParseIP("127.0.0.1"))
6469

6570
assert.Equal(t, "2.0.0", f1.MinEngineVersion)
6671

pkg/config/schema_windows.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -507,12 +507,12 @@ var rulesSchema = `
507507
"$schema": "http://json-schema.org/draft-07/schema#",
508508
"type": "object",
509509
"properties": {
510-
"id": {"type": "string", "minLength": 36, "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"},
510+
"id": {"type": "string", "minLength": 36, "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"},
511511
"version": {"type": "string", "minLength": 5, "pattern": "^([0-9]+.)([0-9]+.)([0-9]+)$"},
512-
"name": {"type": "string", "minLength": 3},
513-
"description": {"type": "string"},
512+
"name": {"type": "string", "minLength": 3},
513+
"description": {"type": "string"},
514514
"output": {"type": "string", "minLength": 5},
515-
"notes": {"type": "string"},
515+
"notes": {"type": "string"},
516516
"severity": {"type": "string", "enum": ["low", "medium", "high", "critical"]},
517517
"min-engine-version": {"type": "string", "minLength": 5, "pattern": "^([0-9]+.)([0-9]+.)([0-9]+)$"},
518518
"enabled": {"type": "boolean"},
@@ -521,17 +521,32 @@ var rulesSchema = `
521521
"type": "object",
522522
"additionalProperties": { "type": "string"}
523523
},
524-
"tags": {"type": "array", "items": [{"type": "string", "minLength": 1}]},
524+
"tags": {"type": "array", "items": [{"type": "string", "minLength": 1}]},
525525
"references": {"type": "array", "items": [{"type": "string", "minLength": 1}]},
526526
"action": {
527527
"type": "array",
528528
"items": {
529529
"type": "object",
530+
"additionalProperties": false,
530531
"properties": {
531-
"name": {"type": "string", "enum": ["kill"]}
532+
"name": {"type": "string", "enum": ["kill", "isolate"]},
533+
"whitelist": true
532534
},
533535
"required": ["name"],
534-
"additionalProperties": false
536+
"if": {
537+
"properties": {"name": {"const": "isolate"}}
538+
},
539+
"then": {
540+
"properties": {
541+
"whitelist": {"type": "array", "minItems": 1, "items": {"type": "string", "format": "ipv4"}}
542+
}
543+
},
544+
"else": {
545+
"properties": {
546+
"name": {"type": "string", "enum": ["kill", "isolate"]}
547+
},
548+
"additionalProperties": false
549+
}
535550
}
536551
}
537552
},

0 commit comments

Comments
 (0)