Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
60 changes: 31 additions & 29 deletions internal/collector/otel_collector_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ func (oc *Collector) updateNginxAppProtectTcplogReceivers(
oc.config.Collector.Receivers.TcplogReceivers = make(map[string]*config.TcplogReceiver)
}

napSysLogServer := oc.findAvailableSyslogServers(ctx, nginxConfigContext.NAPSysLogServers)
napSysLogServer := oc.findAvailableSyslogServer(ctx, nginxConfigContext.NAPSysLogServer)

if napSysLogServer != "" {
if !oc.doesTcplogReceiverAlreadyExist(napSysLogServer) {
Expand Down Expand Up @@ -705,40 +705,29 @@ func (oc *Collector) updateResourceAttributes(
return actionUpdated
}

func (oc *Collector) findAvailableSyslogServers(ctx context.Context, napSyslogServers []string) string {
napSyslogServersMap := make(map[string]bool)
for _, server := range napSyslogServers {
napSyslogServersMap[server] = true
}

if oc.previousNAPSysLogServer != "" {
if _, ok := napSyslogServersMap[oc.previousNAPSysLogServer]; ok {
return oc.previousNAPSysLogServer
}
func (oc *Collector) findAvailableSyslogServer(ctx context.Context, napSyslogServer string) string {
if oc.previousNAPSysLogServer != "" &&
normaliseAddress(oc.previousNAPSysLogServer) == normaliseAddress(napSyslogServer) {
return napSyslogServer
}

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

continue
}
closeError := ln.Close()
if closeError != nil {
slog.DebugContext(ctx, "Failed to close syslog server", "address", napSyslogServer, "error", closeError)
}

slog.DebugContext(ctx, "Found valid NAP syslog server", "address", napSyslogServer)
listenConfig := &net.ListenConfig{}
ln, err := listenConfig.Listen(ctx, "tcp", napSyslogServer)
if err != nil {
slog.DebugContext(ctx, "NAP syslog server is not reachable", "address", napSyslogServer,
"error", err)

oc.previousNAPSysLogServer = napSyslogServer
return ""
}

return napSyslogServer
closeError := ln.Close()
if closeError != nil {
slog.DebugContext(ctx, "Failed to close syslog server", "address", napSyslogServer, "error", closeError)
}

return ""
oc.previousNAPSysLogServer = napSyslogServer

return napSyslogServer
}

func isOSSReceiverChanged(nginxReceiver config.NginxReceiver, nginxConfigContext *model.NginxConfigContext) bool {
Expand Down Expand Up @@ -824,3 +813,16 @@ func setProxyWithBasicAuth(ctx context.Context, proxy *config.Proxy, parsedProxy
proxyURL := parsedProxyURL.String()
setProxyEnvs(ctx, proxyURL, "Setting Proxy with basic auth")
}

func normaliseAddress(address string) string {
host, port, err := net.SplitHostPort(address)
if err != nil {
return address
}

if host == "localhost" {
host = "127.0.0.1"
}

return net.JoinHostPort(host, port)
}
30 changes: 15 additions & 15 deletions internal/collector/otel_collector_plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ func TestCollector_updateNginxAppProtectTcplogReceivers(t *testing.T) {
require.NoError(t, err)

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

assert.Empty(t, conf.Collector.Receivers.TcplogReceivers)
Expand Down Expand Up @@ -777,7 +777,7 @@ func TestCollector_updateNginxAppProtectTcplogReceivers(t *testing.T) {
t.Run("Test 4: NewCollector tcplogReceiver added and deleted another", func(tt *testing.T) {
tcplogReceiverDeleted := collector.updateNginxAppProtectTcplogReceivers(ctx,
&model.NginxConfigContext{
NAPSysLogServers: []string{"localhost:1555"},
NAPSysLogServer: "localhost:1555",
},
)

Expand Down Expand Up @@ -927,49 +927,49 @@ func TestCollector_findAvailableSyslogServers(t *testing.T) {
name string
expectedSyslogServer string
previousNAPSysLogServer string
syslogServers []string
syslogServers string
portInUse bool
}{
{
name: "Test 1: port available",
expectedSyslogServer: "localhost:15632",
previousNAPSysLogServer: "",
syslogServers: []string{"localhost:15632"},
syslogServers: "localhost:15632",
portInUse: false,
},
{
name: "Test 2: port in use",
expectedSyslogServer: "",
previousNAPSysLogServer: "",
syslogServers: []string{"localhost:15632"},
syslogServers: "localhost:15632",
portInUse: true,
},
{
name: "Test 3: syslog server already configured",
expectedSyslogServer: "localhost:15632",
previousNAPSysLogServer: "localhost:15632",
syslogServers: []string{"localhost:15632"},
syslogServers: "localhost:15632",
portInUse: false,
},
{
name: "Test 4: new syslog server",
expectedSyslogServer: "localhost:15632",
previousNAPSysLogServer: "localhost:1122",
syslogServers: []string{"localhost:15632"},
syslogServers: "localhost:15632",
portInUse: false,
},
{
name: "Test 5: port in use find next server",
name: "Test 6: port hasn't changed",
expectedSyslogServer: "localhost:1122",
previousNAPSysLogServer: "",
syslogServers: []string{"localhost:15632", "localhost:1122"},
previousNAPSysLogServer: "localhost:1122",
syslogServers: "localhost:1122",
portInUse: true,
},
{
name: "Test 6: port hasn't changed",
name: "Test 7: port hasn't changed, but is now localhost",
expectedSyslogServer: "localhost:1122",
previousNAPSysLogServer: "localhost:1122",
syslogServers: []string{"localhost:1122"},
previousNAPSysLogServer: "127.0.0.1:1122",
syslogServers: "localhost:1122",
portInUse: true,
},
}
Expand All @@ -983,12 +983,12 @@ func TestCollector_findAvailableSyslogServers(t *testing.T) {

if test.portInUse {
listenConfig := &net.ListenConfig{}
ln, listenError := listenConfig.Listen(ctx, "tcp", "localhost:15632")
ln, listenError := listenConfig.Listen(ctx, "tcp", test.syslogServers)
require.NoError(t, listenError)
defer ln.Close()
}

actual := collector.findAvailableSyslogServers(ctx, test.syslogServers)
actual := collector.findAvailableSyslogServer(ctx, test.syslogServers)
assert.Equal(tt, test.expectedSyslogServer, actual)
})
}
Expand Down
13 changes: 13 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ func ResolveConfig() (*Config, error) {
Features: viperInstance.GetStringSlice(FeaturesKey),
Labels: resolveLabels(),
LibDir: viperInstance.GetString(LibDirPathKey),
SyslogServer: resolveSyslogServer(),
}

defaultCollector(collector, config)
Expand Down Expand Up @@ -420,6 +421,12 @@ func registerFlags() {
"A comma-separated list of features enabled for the agent.",
)

fs.String(
SyslogServerPort,
DefSyslogServerPort,
"The port Agent will start the syslog server on for logs collection",
)

registerCommonFlags(fs)
registerCommandFlags(fs)
registerAuxiliaryCommandFlags(fs)
Expand Down Expand Up @@ -897,6 +904,12 @@ func resolveLog() *Log {
}
}

func resolveSyslogServer() *SyslogServer {
return &SyslogServer{
Port: viperInstance.GetString(SyslogServerPort),
}
}

func resolveLabels() map[string]interface{} {
input := viperInstance.GetStringMapString(LabelsRootKey)

Expand Down
3 changes: 3 additions & 0 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,9 @@ func createConfig() *Config {
Level: "debug",
Path: "./test-path",
},
SyslogServer: &SyslogServer{
Port: "1512",
},
Client: &Client{
HTTP: &HTTP{
Timeout: 15 * time.Second,
Expand Down
2 changes: 2 additions & 0 deletions internal/config/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const (
DefNginxReloadBackoffMaxInterval = 3 * time.Second
DefNginxReloadBackoffMaxElapsedTime = 10 * time.Second

DefSyslogServerPort = "1514"

DefCommandServerHostKey = ""
DefCommandServerPortKey = 0
DefCommandServerTypeKey = "grpc"
Expand Down
2 changes: 2 additions & 0 deletions internal/config/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ var (
NginxExcludeLogsKey = pre(DataPlaneConfigRootKey, "nginx") + "exclude_logs"
NginxApiTlsCa = pre(DataPlaneConfigRootKey, "nginx") + "api_tls_ca"

SyslogServerPort = pre("syslog_server") + "port"

FileWatcherMonitoringFrequencyKey = pre(FileWatcherKey) + "monitoring_frequency"
NginxExcludeFilesKey = pre(FileWatcherKey) + "exclude_files"
)
Expand Down
6 changes: 5 additions & 1 deletion internal/config/testdata/nginx-agent.conf
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ features:
- metrics
- api-action
- logs-nap



syslog_server:
port: 1512

data_plane_config:
nginx:
reload_monitoring_period: 30s
Expand Down
4 changes: 4 additions & 0 deletions internal/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type (
Client *Client `yaml:"client" mapstructure:"client"`
Collector *Collector `yaml:"collector" mapstructure:"collector"`
Watchers *Watchers `yaml:"watchers" mapstructure:"watchers"`
SyslogServer *SyslogServer `yaml:"syslog_server" mapstructure:"syslog_server"`
Labels map[string]any `yaml:"labels" mapstructure:"labels"`
Version string `yaml:"-"`
Path string `yaml:"-"`
Expand All @@ -61,6 +62,9 @@ type (
Nginx *NginxDataPlaneConfig `yaml:"nginx" mapstructure:"nginx"`
}

SyslogServer struct {
Port string `yaml:"port" mapstructure:"port"`
}
NginxDataPlaneConfig struct {
ReloadBackoff *BackOff `yaml:"reload_backoff" mapstructure:"reload_backoff"`
APITls TLSConfig `yaml:"api_tls" mapstructure:"api_tls"`
Expand Down
33 changes: 17 additions & 16 deletions internal/datasource/config/nginx_config_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
payload *crossplane.Payload,
configPath string,
) (*model.NginxConfigContext, error) {
napSyslogServersFound := make(map[string]bool)
napEnabled := false

nginxConfigContext := &model.NginxConfigContext{
Expand All @@ -167,7 +166,7 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
Listen: "",
Location: "",
},
NAPSysLogServers: make([]string, 0),
NAPSysLogServer: "",
}

rootDir := filepath.Dir(instance.GetInstanceRuntime().GetConfigPath())
Expand Down Expand Up @@ -223,8 +222,8 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
if len(directive.Args) > 1 {
napEnabled = true
sysLogServer := ncp.findLocalSysLogServers(directive.Args[1])
if sysLogServer != "" && !napSyslogServersFound[sysLogServer] {
napSyslogServersFound[sysLogServer] = true
if sysLogServer != "" {
nginxConfigContext.NAPSysLogServer = sysLogServer
slog.DebugContext(ctx, "Found NAP syslog server", "address", sysLogServer)
}
}
Expand All @@ -251,17 +250,6 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
nginxConfigContext.PlusAPIs = append(nginxConfigContext.PlusAPIs, plusAPIs...)
}

if len(napSyslogServersFound) > 0 {
var napSyslogServer []string
for server := range napSyslogServersFound {
napSyslogServer = append(napSyslogServer, server)
}
nginxConfigContext.NAPSysLogServers = napSyslogServer
} else if napEnabled {
slog.WarnContext(ctx, "Could not find available local NGINX App Protect syslog server. "+
"Security violations will not be collected.")
}

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 @@ -270,6 +258,15 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
}
}

if napEnabled && nginxConfigContext.NAPSysLogServer == "" {
slog.WarnContext(ctx, fmt.Sprintf("Could not find available local NGINX App Protect syslog"+
" server configured on port %s. Security violations will not be collected.",
ncp.agentConfig.SyslogServer.Port))
} else {
slog.InfoContext(ctx, fmt.Sprintf("Found available local NGINX App Protect syslog"+
"server configured on port %s", ncp.agentConfig.SyslogServer.Port))
}

nginxConfigContext.StubStatus = ncp.FindStubStatusAPI(ctx, nginxConfigContext)
nginxConfigContext.PlusAPI = ncp.FindPlusAPI(ctx, nginxConfigContext)

Expand All @@ -280,11 +277,15 @@ func (ncp *NginxConfigParser) findLocalSysLogServers(sysLogServer string) string
re := regexp.MustCompile(`syslog:server=([\S]+)`)
matches := re.FindStringSubmatch(sysLogServer)
if len(matches) > 1 {
host, _, err := net.SplitHostPort(matches[1])
host, port, err := net.SplitHostPort(matches[1])
if err != nil {
return ""
}

if port != ncp.agentConfig.SyslogServer.Port {
return ""
}

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