mirror of
https://github.com/coder/coder.git
synced 2026-09-21 12:44:32 +08:00
feat: add template version ID to re-emitted boundary logs (#21636)
Adds template_version_id to re-emitted boundary audit logs to allow filtering and analysis by specific template versions iin addition to the existing template_id field. Since boundary policies are defined in the template, the template version is critical to figuring out which policy was responsible for boundaries decision in a workspace. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -79,10 +79,12 @@ func TestBoundaryLogs_EndToEnd(t *testing.T) {
|
||||
logger := slog.Make(sink)
|
||||
workspaceID := uuid.New()
|
||||
templateID := uuid.New()
|
||||
templateVersionID := uuid.New()
|
||||
reporter := &agentapi.BoundaryLogsAPI{
|
||||
Log: logger,
|
||||
WorkspaceID: workspaceID,
|
||||
TemplateID: templateID,
|
||||
Log: logger,
|
||||
WorkspaceID: workspaceID,
|
||||
TemplateID: templateID,
|
||||
TemplateVersionID: templateVersionID,
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
@@ -126,6 +128,7 @@ func TestBoundaryLogs_EndToEnd(t *testing.T) {
|
||||
require.Equal(t, "allow", getField(entry.Fields, "decision"))
|
||||
require.Equal(t, workspaceID.String(), getField(entry.Fields, "workspace_id"))
|
||||
require.Equal(t, templateID.String(), getField(entry.Fields, "template_id"))
|
||||
require.Equal(t, templateVersionID.String(), getField(entry.Fields, "template_version_id"))
|
||||
require.Equal(t, "GET", getField(entry.Fields, "http_method"))
|
||||
require.Equal(t, "https://example.com/allowed", getField(entry.Fields, "http_url"))
|
||||
require.Equal(t, "*.example.com", getField(entry.Fields, "matched_rule"))
|
||||
@@ -159,6 +162,7 @@ func TestBoundaryLogs_EndToEnd(t *testing.T) {
|
||||
require.Equal(t, "deny", getField(entry.Fields, "decision"))
|
||||
require.Equal(t, workspaceID.String(), getField(entry.Fields, "workspace_id"))
|
||||
require.Equal(t, templateID.String(), getField(entry.Fields, "template_id"))
|
||||
require.Equal(t, templateVersionID.String(), getField(entry.Fields, "template_version_id"))
|
||||
require.Equal(t, "POST", getField(entry.Fields, "http_method"))
|
||||
require.Equal(t, "https://blocked.com/denied", getField(entry.Fields, "http_url"))
|
||||
require.Equal(t, nil, getField(entry.Fields, "matched_rule"))
|
||||
|
||||
@@ -65,10 +65,11 @@ type API struct {
|
||||
var _ agentproto.DRPCAgentServer = &API{}
|
||||
|
||||
type Options struct {
|
||||
AgentID uuid.UUID
|
||||
OwnerID uuid.UUID
|
||||
WorkspaceID uuid.UUID
|
||||
OrganizationID uuid.UUID
|
||||
AgentID uuid.UUID
|
||||
OwnerID uuid.UUID
|
||||
WorkspaceID uuid.UUID
|
||||
OrganizationID uuid.UUID
|
||||
TemplateVersionID uuid.UUID
|
||||
|
||||
AuthenticatedCtx context.Context
|
||||
Log slog.Logger
|
||||
@@ -221,9 +222,10 @@ func New(opts Options, workspace database.Workspace) *API {
|
||||
}
|
||||
|
||||
api.BoundaryLogsAPI = &BoundaryLogsAPI{
|
||||
Log: opts.Log,
|
||||
WorkspaceID: opts.WorkspaceID,
|
||||
TemplateID: workspace.TemplateID,
|
||||
Log: opts.Log,
|
||||
WorkspaceID: opts.WorkspaceID,
|
||||
TemplateID: workspace.TemplateID,
|
||||
TemplateVersionID: opts.TemplateVersionID,
|
||||
}
|
||||
|
||||
// Start background cache refresh loop to handle workspace changes
|
||||
|
||||
@@ -11,9 +11,10 @@ import (
|
||||
)
|
||||
|
||||
type BoundaryLogsAPI struct {
|
||||
Log slog.Logger
|
||||
WorkspaceID uuid.UUID
|
||||
TemplateID uuid.UUID
|
||||
Log slog.Logger
|
||||
WorkspaceID uuid.UUID
|
||||
TemplateID uuid.UUID
|
||||
TemplateVersionID uuid.UUID
|
||||
}
|
||||
|
||||
func (a *BoundaryLogsAPI) ReportBoundaryLogs(ctx context.Context, req *agentproto.ReportBoundaryLogsRequest) (*agentproto.ReportBoundaryLogsResponse, error) {
|
||||
@@ -35,6 +36,7 @@ func (a *BoundaryLogsAPI) ReportBoundaryLogs(ctx context.Context, req *agentprot
|
||||
slog.F("decision", allowBoolToString(l.Allowed)),
|
||||
slog.F("workspace_id", a.WorkspaceID.String()),
|
||||
slog.F("template_id", a.TemplateID.String()),
|
||||
slog.F("template_version_id", a.TemplateVersionID.String()),
|
||||
slog.F("http_method", r.HttpRequest.Method),
|
||||
slog.F("http_url", r.HttpRequest.Url),
|
||||
slog.F("event_time", logTime.Format(time.RFC3339Nano)),
|
||||
|
||||
@@ -127,10 +127,11 @@ func (api *API) workspaceAgentRPC(rw http.ResponseWriter, r *http.Request) {
|
||||
defer monitor.close()
|
||||
|
||||
agentAPI := agentapi.New(agentapi.Options{
|
||||
AgentID: workspaceAgent.ID,
|
||||
OwnerID: workspace.OwnerID,
|
||||
WorkspaceID: workspace.ID,
|
||||
OrganizationID: workspace.OrganizationID,
|
||||
AgentID: workspaceAgent.ID,
|
||||
OwnerID: workspace.OwnerID,
|
||||
WorkspaceID: workspace.ID,
|
||||
OrganizationID: workspace.OrganizationID,
|
||||
TemplateVersionID: build.TemplateVersionID,
|
||||
|
||||
AuthenticatedCtx: ctx,
|
||||
Log: logger,
|
||||
|
||||
@@ -127,17 +127,18 @@ commands run with `boundary-run`.
|
||||
|
||||
Each boundary audit log entry includes:
|
||||
|
||||
| Field | Description |
|
||||
|------------------|-----------------------------------------------------------------------------------------|
|
||||
| `decision` | Whether the request was allowed (`allow`) or blocked (`deny`) |
|
||||
| `workspace_id` | The UUID of the workspace where the request originated |
|
||||
| `workspace_name` | The name of the workspace where the request originated |
|
||||
| `owner` | The owner of the workspace where the request originated |
|
||||
| `template_id` | The UUID of the template that the workspace was created from |
|
||||
| `http_method` | The HTTP method used (GET, POST, PUT, DELETE, etc.) |
|
||||
| `http_url` | The fully qualified URL that was requested |
|
||||
| `event_time` | Timestamp when boundary processed the request (RFC3339 format) |
|
||||
| `matched_rule` | The allowlist rule that permitted the request (only present when `decision` is `allow`) |
|
||||
| Field | Description |
|
||||
|-----------------------|-----------------------------------------------------------------------------------------|
|
||||
| `decision` | Whether the request was allowed (`allow`) or blocked (`deny`) |
|
||||
| `workspace_id` | The UUID of the workspace where the request originated |
|
||||
| `workspace_name` | The name of the workspace where the request originated |
|
||||
| `owner` | The owner of the workspace where the request originated |
|
||||
| `template_id` | The UUID of the template that the workspace was created from |
|
||||
| `template_version_id` | The UUID of the template version used by the current workspace build |
|
||||
| `http_method` | The HTTP method used (GET, POST, PUT, DELETE, etc.) |
|
||||
| `http_url` | The fully qualified URL that was requested |
|
||||
| `event_time` | Timestamp when boundary processed the request (RFC3339 format) |
|
||||
| `matched_rule` | The allowlist rule that permitted the request (only present when `decision` is `allow`) |
|
||||
|
||||
### Viewing Audit Logs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user