Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions internal/collector/otel_collector_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,18 +543,31 @@ func (oc *Collector) updateExistingNginxOSSReceiver(

func (oc *Collector) updateTcplogReceivers(nginxConfigContext *model.NginxConfigContext) bool {
newTcplogReceiverAdded := false
if nginxConfigContext.NAPSysLogServers != nil {
napLoop:
for _, napSysLogServer := range nginxConfigContext.NAPSysLogServers {
if oc.doesTcplogReceiverAlreadyExist(napSysLogServer) {
continue napLoop
}

if nginxConfigContext.NAPSysLogServer != "" {
if !oc.doesTcplogReceiverAlreadyExist(nginxConfigContext.NAPSysLogServer) {
oc.config.Collector.Receivers.TcplogReceivers = append(
oc.config.Collector.Receivers.TcplogReceivers,
config.TcplogReceiver{
ListenAddress: napSysLogServer,
ListenAddress: nginxConfigContext.NAPSysLogServer,
Operators: []config.Operator{
// regex captures the priority number from the log line
{
Type: "regex_parser",
Fields: map[string]string{
"regex": "^<(?P<priority>\\d+)>",
"parse_from": "body",
"parse_to": "attributes",
},
},
// filter drops all logs that have a severity above 4
// https://docs.secureauth.com/0902/en/how-to-read-a-syslog-message.html#severity-code-table
{
Type: "filter",
Fields: map[string]string{
"expr": "'int(attributes.priority) % 8 > 4'",
"drop_ratio": "1.0",
},
},
{
Type: "add",
Fields: map[string]string{
Expand Down Expand Up @@ -621,12 +634,10 @@ func (oc *Collector) configDeletedNapReceivers(nginxConfigContext *model.NginxCo
elements[tcplogReceiver.ListenAddress] = true
}

if nginxConfigContext.NAPSysLogServers != nil {
if nginxConfigContext.NAPSysLogServer != "" {
addressesToDelete := make(map[string]bool)
for _, napAddress := range nginxConfigContext.NAPSysLogServers {
if !elements[napAddress] {
addressesToDelete[napAddress] = true
}
if !elements[nginxConfigContext.NAPSysLogServer] {
addressesToDelete[nginxConfigContext.NAPSysLogServer] = true
}

return addressesToDelete
Expand Down
15 changes: 6 additions & 9 deletions internal/collector/otel_collector_plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -733,9 +733,7 @@ func TestCollector_updateTcplogReceivers(t *testing.T) {
require.NoError(t, err)

nginxConfigContext := &model.NginxConfigContext{
NAPSysLogServers: []string{
"localhost:151",
},
NAPSysLogServer: "localhost:151",
}

assert.Empty(t, conf.Collector.Receivers.TcplogReceivers)
Expand All @@ -746,7 +744,7 @@ func TestCollector_updateTcplogReceivers(t *testing.T) {
assert.True(tt, tcplogReceiverAdded)
assert.Len(tt, conf.Collector.Receivers.TcplogReceivers, 1)
assert.Equal(tt, "localhost:151", conf.Collector.Receivers.TcplogReceivers[0].ListenAddress)
assert.Len(tt, conf.Collector.Receivers.TcplogReceivers[0].Operators, 4)
assert.Len(tt, conf.Collector.Receivers.TcplogReceivers[0].Operators, 6)
})

// Calling updateTcplogReceivers shouldn't update the TcplogReceivers slice
Expand All @@ -756,7 +754,7 @@ func TestCollector_updateTcplogReceivers(t *testing.T) {
assert.False(t, tcplogReceiverAdded)
assert.Len(t, conf.Collector.Receivers.TcplogReceivers, 1)
assert.Equal(t, "localhost:151", conf.Collector.Receivers.TcplogReceivers[0].ListenAddress)
assert.Len(t, conf.Collector.Receivers.TcplogReceivers[0].Operators, 4)
assert.Len(t, conf.Collector.Receivers.TcplogReceivers[0].Operators, 6)
})

t.Run("Test 3: TcplogReceiver deleted", func(tt *testing.T) {
Expand All @@ -766,13 +764,12 @@ func TestCollector_updateTcplogReceivers(t *testing.T) {
})

t.Run("Test 4: New tcplogReceiver added and deleted another", func(tt *testing.T) {
tcplogReceiverDeleted := collector.updateTcplogReceivers(&model.NginxConfigContext{NAPSysLogServers: []string{
"localhost:152",
}})
tcplogReceiverDeleted := collector.
updateTcplogReceivers(&model.NginxConfigContext{NAPSysLogServer: "localhost:152"})
assert.True(t, tcplogReceiverDeleted)
assert.Len(t, conf.Collector.Receivers.TcplogReceivers, 1)
assert.Equal(t, "localhost:152", conf.Collector.Receivers.TcplogReceivers[0].ListenAddress)
assert.Len(t, conf.Collector.Receivers.TcplogReceivers[0].Operators, 4)
assert.Len(t, conf.Collector.Receivers.TcplogReceivers[0].Operators, 6)
})
}

Expand Down
79 changes: 64 additions & 15 deletions internal/datasource/config/nginx_config_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ const (

type (
NginxConfigParser struct {
agentConfig *config.Config
agentConfig *config.Config
previousNAPSysLogServer string
}
)

Expand All @@ -65,7 +66,8 @@ type (

func NewNginxConfigParser(agentConfig *config.Config) *NginxConfigParser {
return &NginxConfigParser{
agentConfig: agentConfig,
agentConfig: agentConfig,
previousNAPSysLogServer: "",
}
}

Expand Down Expand Up @@ -107,6 +109,7 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
payload *crossplane.Payload,
) (*model.NginxConfigContext, error) {
napSyslogServersFound := make(map[string]bool)
napEnabled := false

nginxConfigContext := &model.NginxConfigContext{
InstanceID: instance.GetInstanceMeta().GetInstanceId(),
Expand Down Expand Up @@ -173,19 +176,11 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
}
case "app_protect_security_log":
if len(directive.Args) > 1 {
syslogArg := directive.Args[1]
re := regexp.MustCompile(`syslog:server=([\S]+)`)
matches := re.FindStringSubmatch(syslogArg)
if len(matches) > 1 {
syslogServer := matches[1]
if !napSyslogServersFound[syslogServer] {
nginxConfigContext.NAPSysLogServers = append(
nginxConfigContext.NAPSysLogServers,
syslogServer,
)
napSyslogServersFound[syslogServer] = true
slog.DebugContext(ctx, "Found NAP syslog server", "address", syslogServer)
}
napEnabled = true
sysLogServer := ncp.findValidSysLogServers(directive.Args[1])
if sysLogServer != "" && !napSyslogServersFound[sysLogServer] {
napSyslogServersFound[sysLogServer] = true
slog.DebugContext(ctx, "Found NAP syslog server", "address", sysLogServer)
}
}
}
Expand All @@ -207,6 +202,17 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
nginxConfigContext.PlusAPI = plusAPI
}

if len(napSyslogServersFound) > 0 {
syslogServer := ncp.parseSyslogDirective(ctx, napSyslogServersFound)
if syslogServer != "" {
nginxConfigContext.NAPSysLogServer = syslogServer
ncp.previousNAPSysLogServer = syslogServer
}
} else if napEnabled {
slog.WarnContext(ctx, "Could not find usable NAP syslog server, "+
"security violations will be unavailable")
}

fileMeta, err := files.FileMeta(conf.File)
if err != nil {
slog.WarnContext(ctx, "Unable to get file metadata", "file_name", conf.File, "error", err)
Expand All @@ -218,6 +224,49 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
return nginxConfigContext, nil
}

func (ncp *NginxConfigParser) parseSyslogDirective(ctx context.Context, napSyslogServers map[string]bool) string {
if ncp.previousNAPSysLogServer != "" {
if _, ok := napSyslogServers[ncp.previousNAPSysLogServer]; ok {
return ncp.previousNAPSysLogServer
}
}

for napSyslogServer := range napSyslogServers {
ln, err := net.Listen("tcp", napSyslogServer)
if err != nil {
slog.DebugContext(ctx, "NAP syslog server is not reachable", "address", napSyslogServer,
"error", err)

continue
}
ln.Close()

slog.DebugContext(ctx, "Found valid NAP syslog server", "address", napSyslogServer)

return napSyslogServer
}

return ""
}

func (ncp *NginxConfigParser) findValidSysLogServers(sysLogServer string) string {
re := regexp.MustCompile(`syslog:server=([\S]+)`)
matches := re.FindStringSubmatch(sysLogServer)
if len(matches) > 1 {
host, _, err := net.SplitHostPort(matches[1])
if err != nil {
return ""
}

ip := net.ParseIP(host)
if ip.IsLoopback() || strings.EqualFold(host, "localhost") {
return matches[1]
}
}

return ""
}

func (ncp *NginxConfigParser) parseIncludeDirective(directive *crossplane.Directive) string {
var include string
if filepath.IsAbs(directive.Args[0]) {
Expand Down
Loading