mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add boundary log forwarding from agent to coderd (#21345)
Add agent forwarding of boundary audit logs from workspaces to coderd via agent API, and re-emission of boundary logs to coderd stderr. This change adds a server to the workspace agent that always listens on a unix socket for boundary to connect and send audit logs. coderd log format example: ``` [API] 2025-12-23 18:31:46.755 [info] coderd.agentrpc: boundary_request owner=.. workspace_name=.. agent_name=.. decision=.. workspace_id=.. http_method=.. http_url=.. event_time=.. request_id=.. ``` Corresponding boundary PR: https://github.com/coder/boundary/pull/124 RFC: https://www.notion.so/coderhq/Agent-Boundary-Logs-2afd579be59280f29629fc9823ac41ba https://github.com/coder/coder/issues/21280
This commit is contained in:
@@ -220,7 +220,10 @@ func New(opts Options, workspace database.Workspace) *API {
|
||||
Database: opts.Database,
|
||||
}
|
||||
|
||||
api.BoundaryLogsAPI = &BoundaryLogsAPI{}
|
||||
api.BoundaryLogsAPI = &BoundaryLogsAPI{
|
||||
Log: opts.Log,
|
||||
WorkspaceID: opts.WorkspaceID,
|
||||
}
|
||||
|
||||
// Start background cache refresh loop to handle workspace changes
|
||||
// like prebuild claims where owner_id and other fields may be modified in the DB.
|
||||
|
||||
@@ -2,14 +2,60 @@ package agentapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"cdr.dev/slog"
|
||||
|
||||
agentproto "github.com/coder/coder/v2/agent/proto"
|
||||
)
|
||||
|
||||
type BoundaryLogsAPI struct{}
|
||||
type BoundaryLogsAPI struct {
|
||||
Log slog.Logger
|
||||
WorkspaceID uuid.UUID
|
||||
}
|
||||
|
||||
func (*BoundaryLogsAPI) ReportBoundaryLogs(context.Context, *agentproto.ReportBoundaryLogsRequest) (*agentproto.ReportBoundaryLogsResponse, error) {
|
||||
return nil, xerrors.New("not implemented")
|
||||
func (a *BoundaryLogsAPI) ReportBoundaryLogs(ctx context.Context, req *agentproto.ReportBoundaryLogsRequest) (*agentproto.ReportBoundaryLogsResponse, error) {
|
||||
for _, l := range req.Logs {
|
||||
var logTime time.Time
|
||||
if l.Time != nil {
|
||||
logTime = l.Time.AsTime()
|
||||
}
|
||||
|
||||
switch r := l.Resource.(type) {
|
||||
case *agentproto.BoundaryLog_HttpRequest_:
|
||||
if r.HttpRequest == nil {
|
||||
a.Log.Warn(ctx, "empty http request resource",
|
||||
slog.F("workspace_id", a.WorkspaceID.String()))
|
||||
continue
|
||||
}
|
||||
|
||||
fields := []slog.Field{
|
||||
slog.F("decision", allowBoolToString(l.Allowed)),
|
||||
slog.F("workspace_id", a.WorkspaceID.String()),
|
||||
slog.F("http_method", r.HttpRequest.Method),
|
||||
slog.F("http_url", r.HttpRequest.Url),
|
||||
slog.F("event_time", logTime.Format(time.RFC3339Nano)),
|
||||
}
|
||||
if l.Allowed {
|
||||
fields = append(fields, slog.F("matched_rule", r.HttpRequest.MatchedRule))
|
||||
}
|
||||
|
||||
a.Log.With(fields...).Info(ctx, "boundary_request")
|
||||
default:
|
||||
a.Log.Warn(ctx, "unknown resource type",
|
||||
slog.F("workspace_id", a.WorkspaceID.String()))
|
||||
}
|
||||
}
|
||||
|
||||
return &agentproto.ReportBoundaryLogsResponse{}, nil
|
||||
}
|
||||
|
||||
//nolint:revive // This stringifies the boolean argument.
|
||||
func allowBoolToString(b bool) string {
|
||||
if b {
|
||||
return "allow"
|
||||
}
|
||||
return "deny"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user