Skip to content

Commit

Permalink
Add NGINX App Protect instance type
Browse files Browse the repository at this point in the history
  • Loading branch information
dhurley committed Dec 6, 2024
1 parent 653c907 commit a24ce79
Show file tree
Hide file tree
Showing 9 changed files with 739 additions and 187 deletions.
479 changes: 293 additions & 186 deletions api/grpc/mpi/v1/command.pb.go

Large diffs are not rendered by default.

149 changes: 149 additions & 0 deletions api/grpc/mpi/v1/command.pb.validate.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions api/grpc/mpi/v1/command.proto
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ message InstanceMeta {
INSTANCE_TYPE_NGINX_PLUS = 3;
// NGINX Unit
INSTANCE_TYPE_UNIT = 4;
// NGINX App Protect
INSTANCE_TYPE_NGINX_APP_PROTECT = 5;
}
// the types of instances possible
InstanceType instance_type = 2;
Expand Down Expand Up @@ -252,6 +254,8 @@ message InstanceRuntime {
NGINXRuntimeInfo nginx_runtime_info = 4;
// NGINX Plus runtime configuration settings like api value, usually read from the NGINX config, NGINX process or NGINX Plus API
NGINXPlusRuntimeInfo nginx_plus_runtime_info = 5;
// NGINX App Protect runtime information
NGINXAppProtectRuntimeInfo nginx_app_protect_runtime_info = 7;
}
// List of worker processes
repeated InstanceChild instance_children = 6;
Expand Down Expand Up @@ -304,6 +308,16 @@ message NGINXPlusRuntimeInfo {
}];
}

// A set of runtime NGINX App Protect settings
message NGINXAppProtectRuntimeInfo {
// NGINX App Protect Release
string release = 1;
// Attack signature version
string attack_signature_version = 2;
// Threat campaign version
string threat_campaign_version = 3;
}

// A set of actions that can be performed on an instance
message InstanceAction {}

Expand Down
20 changes: 20 additions & 0 deletions docs/proto/protos.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
- [InstanceRuntime](#mpi-v1-InstanceRuntime)
- [ManagementPlaneRequest](#mpi-v1-ManagementPlaneRequest)
- [MetricsServer](#mpi-v1-MetricsServer)
- [NGINXAppProtectRuntimeInfo](#mpi-v1-NGINXAppProtectRuntimeInfo)
- [NGINXPlusRuntimeInfo](#mpi-v1-NGINXPlusRuntimeInfo)
- [NGINXRuntimeInfo](#mpi-v1-NGINXRuntimeInfo)
- [ReleaseInfo](#mpi-v1-ReleaseInfo)
Expand Down Expand Up @@ -813,6 +814,7 @@ Meta-information relating to the reported instance
| config_path | [string](#string) | | the config path location |
| nginx_runtime_info | [NGINXRuntimeInfo](#mpi-v1-NGINXRuntimeInfo) | | NGINX runtime configuration settings like stub_status, usually read from the NGINX config or NGINX process |
| nginx_plus_runtime_info | [NGINXPlusRuntimeInfo](#mpi-v1-NGINXPlusRuntimeInfo) | | NGINX Plus runtime configuration settings like api value, usually read from the NGINX config, NGINX process or NGINX Plus API |
| nginx_app_protect_runtime_info | [NGINXAppProtectRuntimeInfo](#mpi-v1-NGINXAppProtectRuntimeInfo) | | NGINX App Protect runtime information |
| instance_children | [InstanceChild](#mpi-v1-InstanceChild) | repeated | List of worker processes |


Expand Down Expand Up @@ -851,6 +853,23 @@ The metrics settings associated with origins (sources) of the metrics and destin



<a name="mpi-v1-NGINXAppProtectRuntimeInfo"></a>

### NGINXAppProtectRuntimeInfo
A set of runtime NGINX App Protect settings


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| release | [string](#string) | | NGINX App Protect Release |
| attack_signature_version | [string](#string) | | Attack signature version |
| threat_campaign_version | [string](#string) | | Threat campaign version |






<a name="mpi-v1-NGINXPlusRuntimeInfo"></a>

### NGINXPlusRuntimeInfo
Expand Down Expand Up @@ -1017,6 +1036,7 @@ the types of instances possible
| INSTANCE_TYPE_NGINX | 2 | NGINX |
| INSTANCE_TYPE_NGINX_PLUS | 3 | NGINX Plus |
| INSTANCE_TYPE_UNIT | 4 | NGINX Unit |
| INSTANCE_TYPE_NGINX_APP_PROTECT | 5 | NGINX App Protect |



Expand Down
3 changes: 2 additions & 1 deletion internal/watcher/health/health_watcher_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ func (hw *HealthWatcherService) AddHealthWatcher(instances []*mpi.Instance) {
hw.watchers[instance.GetInstanceMeta().GetInstanceId()] = watcher
case mpi.InstanceMeta_INSTANCE_TYPE_AGENT:
case mpi.InstanceMeta_INSTANCE_TYPE_UNSPECIFIED,
mpi.InstanceMeta_INSTANCE_TYPE_UNIT:
mpi.InstanceMeta_INSTANCE_TYPE_UNIT,
mpi.InstanceMeta_INSTANCE_TYPE_NGINX_APP_PROTECT:
fallthrough
default:
slog.Warn("Health watcher not implemented", "instance_type",
Expand Down
1 change: 1 addition & 0 deletions internal/watcher/instance/instance_watcher_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func NewInstanceWatcherService(agentConfig *config.Config) *InstanceWatcherServi
processOperator: process.NewProcessOperator(),
processParsers: []processParser{
NewNginxProcessParser(),
NewNginxAppProtectProcessParser(),
},
nginxConfigParser: NewNginxConfigParser(agentConfig),
instanceCache: make(map[string]*mpi.Instance),
Expand Down
135 changes: 135 additions & 0 deletions internal/watcher/instance/nginx_app_protect_process_parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright (c) F5, Inc.
//
// This source code is licensed under the Apache License, Version 2.0 license found in the
// LICENSE file in the root directory of this source tree.

package instance

import (
"context"
"log/slog"
"os"
"strings"

mpi "github.com/nginx/agent/v3/api/grpc/mpi/v1"
"github.com/nginx/agent/v3/internal/model"
"github.com/nginx/agent/v3/pkg/uuid"
)

const (
versionFilePath = "/opt/app_protect/VERSION"
releaseFilePath = "/opt/app_protect/RELEASE"
processName = "bd-socket-plugin"
attackSignatureVersionFilePath = "/opt/app_protect/var/update_files/signatures/version"
threatCampaignVersionFilePath = "/opt/app_protect/var/update_files/threat_campaigns/version"
)

type (
NginxAppProtectProcessParser struct {
versionFilePath string
releaseFilePath string
attackSignatureVersionFilePath string
threatCampaignVersionFilePath string
}
)

var _ processParser = (*NginxAppProtectProcessParser)(nil)

func NewNginxAppProtectProcessParser() *NginxAppProtectProcessParser {
return &NginxAppProtectProcessParser{
versionFilePath: versionFilePath,
releaseFilePath: releaseFilePath,
attackSignatureVersionFilePath: attackSignatureVersionFilePath,
threatCampaignVersionFilePath: threatCampaignVersionFilePath,
}
}

func (n NginxAppProtectProcessParser) Parse(ctx context.Context, processes []*model.Process) map[string]*mpi.Instance {
instanceMap := make(map[string]*mpi.Instance) // key is instanceID

for _, process := range processes {
if process.Name == processName {
instanceID := n.instanceID(process)

instanceMap[instanceID] = &mpi.Instance{
InstanceMeta: &mpi.InstanceMeta{
InstanceId: instanceID,
InstanceType: mpi.InstanceMeta_INSTANCE_TYPE_NGINX_APP_PROTECT,
Version: n.instanceVersion(ctx),
},
InstanceConfig: &mpi.InstanceConfig{},
InstanceRuntime: &mpi.InstanceRuntime{
ProcessId: process.PID,
BinaryPath: process.Exe,
ConfigPath: "",
Details: &mpi.InstanceRuntime_NginxAppProtectRuntimeInfo{
NginxAppProtectRuntimeInfo: &mpi.NGINXAppProtectRuntimeInfo{
Release: n.release(ctx),
AttackSignatureVersion: n.attackSignatureVersion(ctx),
ThreatCampaignVersion: n.threatCampaignVersion(ctx),
},
},
InstanceChildren: make([]*mpi.InstanceChild, 0),
},
}
}
}

return instanceMap
}

func (n NginxAppProtectProcessParser) instanceID(process *model.Process) string {
return uuid.Generate("%s", process.Exe)
}

func (n NginxAppProtectProcessParser) instanceVersion(ctx context.Context) string {
version, err := os.ReadFile(n.versionFilePath)
if err != nil {
slog.WarnContext(ctx, "Unable to read NAP version file", "file_path", n.versionFilePath, "error", err)
return ""
}

return strings.TrimSuffix(string(version), "\n")
}

func (n NginxAppProtectProcessParser) release(ctx context.Context) string {
release, err := os.ReadFile(n.releaseFilePath)
if err != nil {
slog.WarnContext(ctx, "Unable to read NAP release file", "file_path", n.releaseFilePath, "error", err)
return ""
}

return strings.TrimSuffix(string(release), "\n")
}

func (n NginxAppProtectProcessParser) attackSignatureVersion(ctx context.Context) string {
attackSignatureVersion, err := os.ReadFile(n.attackSignatureVersionFilePath)
if err != nil {
slog.WarnContext(
ctx,
"Unable to read NAP attack signature version file",
"file_path", n.attackSignatureVersionFilePath,
"error", err,
)

return ""
}

return string(attackSignatureVersion)
}

func (n NginxAppProtectProcessParser) threatCampaignVersion(ctx context.Context) string {
threatCampaignVersion, err := os.ReadFile(n.threatCampaignVersionFilePath)
if err != nil {
slog.WarnContext(
ctx,
"Unable to read NAP threat campaign version file",
"file_path", n.threatCampaignVersionFilePath,
"error", err,
)

return ""
}

return string(threatCampaignVersion)
}
Loading

0 comments on commit a24ce79

Please sign in to comment.