mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: add requester IP to workspace build audit logs (#10242)
This commit is contained in:
+61
-6
@@ -11,6 +11,8 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/sqlc-dev/pqtype"
|
||||
"go.opentelemetry.io/otel/baggage"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"cdr.dev/slog"
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
@@ -54,6 +56,7 @@ type BuildAuditParams[T Auditable] struct {
|
||||
Status int
|
||||
Action database.AuditAction
|
||||
OrganizationID uuid.UUID
|
||||
IP string
|
||||
AdditionalFields json.RawMessage
|
||||
|
||||
New T
|
||||
@@ -248,9 +251,7 @@ func InitRequest[T Auditable](w http.ResponseWriter, p *RequestParams) (*Request
|
||||
// WorkspaceBuildAudit creates an audit log for a workspace build.
|
||||
// The audit log is committed upon invocation.
|
||||
func WorkspaceBuildAudit[T Auditable](ctx context.Context, p *BuildAuditParams[T]) {
|
||||
// As the audit request has not been initiated directly by a user, we omit
|
||||
// certain user details.
|
||||
ip := parseIP("")
|
||||
ip := parseIP(p.IP)
|
||||
|
||||
diff := Diff(p.Audit, p.Old, p.New)
|
||||
var err error
|
||||
@@ -280,16 +281,70 @@ func WorkspaceBuildAudit[T Auditable](ctx context.Context, p *BuildAuditParams[T
|
||||
RequestID: p.JobID,
|
||||
AdditionalFields: p.AdditionalFields,
|
||||
}
|
||||
exportErr := p.Audit.Export(ctx, auditLog)
|
||||
if exportErr != nil {
|
||||
err = p.Audit.Export(ctx, auditLog)
|
||||
if err != nil {
|
||||
p.Log.Error(ctx, "export audit log",
|
||||
slog.F("audit_log", auditLog),
|
||||
slog.Error(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type WorkspaceBuildBaggage struct {
|
||||
IP string
|
||||
}
|
||||
|
||||
func (b WorkspaceBuildBaggage) Props() ([]baggage.Property, error) {
|
||||
ipProp, err := baggage.NewKeyValueProperty("ip", b.IP)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("create ip kv property: %w", err)
|
||||
}
|
||||
|
||||
return []baggage.Property{ipProp}, nil
|
||||
}
|
||||
|
||||
func WorkspaceBuildBaggageFromRequest(r *http.Request) WorkspaceBuildBaggage {
|
||||
return WorkspaceBuildBaggage{IP: r.RemoteAddr}
|
||||
}
|
||||
|
||||
type Baggage interface {
|
||||
Props() ([]baggage.Property, error)
|
||||
}
|
||||
|
||||
func BaggageToContext(ctx context.Context, d Baggage) (context.Context, error) {
|
||||
props, err := d.Props()
|
||||
if err != nil {
|
||||
return ctx, xerrors.Errorf("create baggage properties: %w", err)
|
||||
}
|
||||
|
||||
m, err := baggage.NewMember("audit", "baggage", props...)
|
||||
if err != nil {
|
||||
return ctx, xerrors.Errorf("create new baggage member: %w", err)
|
||||
}
|
||||
|
||||
b, err := baggage.New(m)
|
||||
if err != nil {
|
||||
return ctx, xerrors.Errorf("create new baggage carrier: %w", err)
|
||||
}
|
||||
|
||||
return baggage.ContextWithBaggage(ctx, b), nil
|
||||
}
|
||||
|
||||
func BaggageFromContext(ctx context.Context) WorkspaceBuildBaggage {
|
||||
d := WorkspaceBuildBaggage{}
|
||||
b := baggage.FromContext(ctx)
|
||||
props := b.Member("audit").Properties()
|
||||
for _, prop := range props {
|
||||
switch prop.Key() {
|
||||
case "ip":
|
||||
d.IP, _ = prop.Value()
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
func either[T Auditable, R any](old, new T, fn func(T) R, auditAction database.AuditAction) R {
|
||||
if ResourceID(new) != uuid.Nil {
|
||||
return fn(new)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package audit_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/audit"
|
||||
)
|
||||
|
||||
func TestBaggage(t *testing.T) {
|
||||
t.Parallel()
|
||||
prop := propagation.NewCompositeTextMapPropagator(
|
||||
propagation.TraceContext{},
|
||||
propagation.Baggage{},
|
||||
)
|
||||
|
||||
expected := audit.WorkspaceBuildBaggage{
|
||||
IP: "127.0.0.1",
|
||||
}
|
||||
|
||||
ctx, err := audit.BaggageToContext(context.Background(), expected)
|
||||
require.NoError(t, err)
|
||||
|
||||
carrier := propagation.MapCarrier{}
|
||||
prop.Inject(ctx, carrier)
|
||||
bCtx := prop.Extract(ctx, carrier)
|
||||
got := audit.BaggageFromContext(bCtx)
|
||||
|
||||
require.Equal(t, expected, got)
|
||||
}
|
||||
Reference in New Issue
Block a user