Skip to content

Commit 8d7f74c

Browse files
authored
Parse NGINX Config for Valid NAP Syslog Server (#1165)
1 parent b29108e commit 8d7f74c

File tree

9 files changed

+356
-75
lines changed

9 files changed

+356
-75
lines changed

internal/collector/otel_collector_plugin.go

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -543,17 +543,12 @@ func (oc *Collector) updateExistingNginxOSSReceiver(
543543

544544
func (oc *Collector) updateTcplogReceivers(nginxConfigContext *model.NginxConfigContext) bool {
545545
newTcplogReceiverAdded := false
546-
if nginxConfigContext.NAPSysLogServers != nil {
547-
napLoop:
548-
for _, napSysLogServer := range nginxConfigContext.NAPSysLogServers {
549-
if oc.doesTcplogReceiverAlreadyExist(napSysLogServer) {
550-
continue napLoop
551-
}
552-
546+
if nginxConfigContext.NAPSysLogServer != "" {
547+
if !oc.doesTcplogReceiverAlreadyExist(nginxConfigContext.NAPSysLogServer) {
553548
oc.config.Collector.Receivers.TcplogReceivers = append(
554549
oc.config.Collector.Receivers.TcplogReceivers,
555550
config.TcplogReceiver{
556-
ListenAddress: napSysLogServer,
551+
ListenAddress: nginxConfigContext.NAPSysLogServer,
557552
Operators: []config.Operator{
558553
{
559554
Type: "add",
@@ -621,12 +616,10 @@ func (oc *Collector) configDeletedNapReceivers(nginxConfigContext *model.NginxCo
621616
elements[tcplogReceiver.ListenAddress] = true
622617
}
623618

624-
if nginxConfigContext.NAPSysLogServers != nil {
619+
if nginxConfigContext.NAPSysLogServer != "" {
625620
addressesToDelete := make(map[string]bool)
626-
for _, napAddress := range nginxConfigContext.NAPSysLogServers {
627-
if !elements[napAddress] {
628-
addressesToDelete[napAddress] = true
629-
}
621+
if !elements[nginxConfigContext.NAPSysLogServer] {
622+
addressesToDelete[nginxConfigContext.NAPSysLogServer] = true
630623
}
631624

632625
return addressesToDelete

internal/collector/otel_collector_plugin_test.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -733,9 +733,7 @@ func TestCollector_updateTcplogReceivers(t *testing.T) {
733733
require.NoError(t, err)
734734

735735
nginxConfigContext := &model.NginxConfigContext{
736-
NAPSysLogServers: []string{
737-
"localhost:151",
738-
},
736+
NAPSysLogServer: "localhost:151",
739737
}
740738

741739
assert.Empty(t, conf.Collector.Receivers.TcplogReceivers)
@@ -766,9 +764,8 @@ func TestCollector_updateTcplogReceivers(t *testing.T) {
766764
})
767765

768766
t.Run("Test 4: New tcplogReceiver added and deleted another", func(tt *testing.T) {
769-
tcplogReceiverDeleted := collector.updateTcplogReceivers(&model.NginxConfigContext{NAPSysLogServers: []string{
770-
"localhost:152",
771-
}})
767+
tcplogReceiverDeleted := collector.
768+
updateTcplogReceivers(&model.NginxConfigContext{NAPSysLogServer: "localhost:152"})
772769
assert.True(t, tcplogReceiverDeleted)
773770
assert.Len(t, conf.Collector.Receivers.TcplogReceivers, 1)
774771
assert.Equal(t, "localhost:152", conf.Collector.Receivers.TcplogReceivers[0].ListenAddress)

internal/datasource/config/nginx_config_parser.go

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ const (
4747

4848
type (
4949
NginxConfigParser struct {
50-
agentConfig *config.Config
50+
agentConfig *config.Config
51+
previousNAPSysLogServer string
5152
}
5253
)
5354

@@ -65,7 +66,8 @@ type (
6566

6667
func NewNginxConfigParser(agentConfig *config.Config) *NginxConfigParser {
6768
return &NginxConfigParser{
68-
agentConfig: agentConfig,
69+
agentConfig: agentConfig,
70+
previousNAPSysLogServer: "",
6971
}
7072
}
7173

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

111114
nginxConfigContext := &model.NginxConfigContext{
112115
InstanceID: instance.GetInstanceMeta().GetInstanceId(),
@@ -173,19 +176,11 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
173176
}
174177
case "app_protect_security_log":
175178
if len(directive.Args) > 1 {
176-
syslogArg := directive.Args[1]
177-
re := regexp.MustCompile(`syslog:server=([\S]+)`)
178-
matches := re.FindStringSubmatch(syslogArg)
179-
if len(matches) > 1 {
180-
syslogServer := matches[1]
181-
if !napSyslogServersFound[syslogServer] {
182-
nginxConfigContext.NAPSysLogServers = append(
183-
nginxConfigContext.NAPSysLogServers,
184-
syslogServer,
185-
)
186-
napSyslogServersFound[syslogServer] = true
187-
slog.DebugContext(ctx, "Found NAP syslog server", "address", syslogServer)
188-
}
179+
napEnabled = true
180+
sysLogServer := ncp.findLocalSysLogServers(directive.Args[1])
181+
if sysLogServer != "" && !napSyslogServersFound[sysLogServer] {
182+
napSyslogServersFound[sysLogServer] = true
183+
slog.DebugContext(ctx, "Found NAP syslog server", "address", sysLogServer)
189184
}
190185
}
191186
}
@@ -207,6 +202,17 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
207202
nginxConfigContext.PlusAPI = plusAPI
208203
}
209204

205+
if len(napSyslogServersFound) > 0 {
206+
syslogServer := ncp.findAvailableSyslogServers(ctx, napSyslogServersFound)
207+
if syslogServer != "" {
208+
nginxConfigContext.NAPSysLogServer = syslogServer
209+
ncp.previousNAPSysLogServer = syslogServer
210+
}
211+
} else if napEnabled {
212+
slog.WarnContext(ctx, "Could not find available local NGINX App Protect syslog server. "+
213+
"Security violations will not be collected.")
214+
}
215+
210216
fileMeta, err := files.FileMeta(conf.File)
211217
if err != nil {
212218
slog.WarnContext(ctx, "Unable to get file metadata", "file_name", conf.File, "error", err)
@@ -218,6 +224,49 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
218224
return nginxConfigContext, nil
219225
}
220226

227+
func (ncp *NginxConfigParser) findAvailableSyslogServers(ctx context.Context, napSyslogServers map[string]bool) string {
228+
if ncp.previousNAPSysLogServer != "" {
229+
if _, ok := napSyslogServers[ncp.previousNAPSysLogServer]; ok {
230+
return ncp.previousNAPSysLogServer
231+
}
232+
}
233+
234+
for napSyslogServer := range napSyslogServers {
235+
ln, err := net.Listen("tcp", napSyslogServer)
236+
if err != nil {
237+
slog.DebugContext(ctx, "NAP syslog server is not reachable", "address", napSyslogServer,
238+
"error", err)
239+
240+
continue
241+
}
242+
ln.Close()
243+
244+
slog.DebugContext(ctx, "Found valid NAP syslog server", "address", napSyslogServer)
245+
246+
return napSyslogServer
247+
}
248+
249+
return ""
250+
}
251+
252+
func (ncp *NginxConfigParser) findLocalSysLogServers(sysLogServer string) string {
253+
re := regexp.MustCompile(`syslog:server=([\S]+)`)
254+
matches := re.FindStringSubmatch(sysLogServer)
255+
if len(matches) > 1 {
256+
host, _, err := net.SplitHostPort(matches[1])
257+
if err != nil {
258+
return ""
259+
}
260+
261+
ip := net.ParseIP(host)
262+
if ip.IsLoopback() || strings.EqualFold(host, "localhost") {
263+
return matches[1]
264+
}
265+
}
266+
267+
return ""
268+
}
269+
221270
func (ncp *NginxConfigParser) parseIncludeDirective(directive *crossplane.Directive) string {
222271
var include string
223272
if filepath.IsAbs(directive.Args[0]) {

0 commit comments

Comments
 (0)