Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add client metadata to PostgreSQL database session start event #50711

Merged
Merged
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
6 changes: 6 additions & 0 deletions api/proto/teleport/legacy/types/events/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3150,6 +3150,12 @@ message DatabaseSessionStart {
// connection. This can be useful for backend process cancellation or
// termination and it is not a sensitive or secret value.
uint32 PostgresPID = 8 [(gogoproto.jsontag) = "postgres_pid,omitempty"];
// Client is the common client event metadata.
ClientMetadata Client = 9 [
(gogoproto.nullable) = false,
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];
}

// DatabaseSessionQuery is emitted when a user executes a database query.
Expand Down
1,725 changes: 886 additions & 839 deletions api/types/events/events.pb.go

Large diffs are not rendered by default.

16 changes: 11 additions & 5 deletions lib/srv/db/access_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1629,13 +1629,13 @@ func (c *testContext) startHandlingConnections() {

// postgresClient connects to test Postgres through database access as a
// specified Teleport user and database account.
func (c *testContext) postgresClient(ctx context.Context, teleportUser, dbService, dbUser, dbName string) (*pgconn.PgConn, error) {
return c.postgresClientWithAddr(ctx, c.mux.DB().Addr().String(), teleportUser, dbService, dbUser, dbName)
func (c *testContext) postgresClient(ctx context.Context, teleportUser, dbService, dbUser, dbName string, opts ...common.ClientOption) (*pgconn.PgConn, error) {
return c.postgresClientWithAddr(ctx, c.mux.DB().Addr().String(), teleportUser, dbService, dbUser, dbName, opts...)
}

// postgresClientWithAddr is like postgresClient but allows to override connection address.
func (c *testContext) postgresClientWithAddr(ctx context.Context, address, teleportUser, dbService, dbUser, dbName string) (*pgconn.PgConn, error) {
return postgres.MakeTestClient(ctx, common.TestClientConfig{
func (c *testContext) postgresClientWithAddr(ctx context.Context, address, teleportUser, dbService, dbUser, dbName string, opts ...common.ClientOption) (*pgconn.PgConn, error) {
cfg := common.TestClientConfig{
AuthClient: c.authClient,
AuthServer: c.authServer,
Address: address,
Expand All @@ -1647,7 +1647,13 @@ func (c *testContext) postgresClientWithAddr(ctx context.Context, address, telep
Username: dbUser,
Database: dbName,
},
})
}

for _, opt := range opts {
opt(&cfg)
}

return postgres.MakeTestClient(ctx, cfg)
}

// postgresClientLocalProxy connects to test Postgres through local ALPN proxy.
Expand Down
5 changes: 4 additions & 1 deletion lib/srv/db/audit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/gravitational/teleport/lib/defaults"
libevents "github.com/gravitational/teleport/lib/events"
"github.com/gravitational/teleport/lib/events/eventstest"
"github.com/gravitational/teleport/lib/srv/db/common"
"github.com/gravitational/teleport/lib/srv/db/postgres"
"github.com/gravitational/teleport/lib/srv/db/redis"
)
Expand All @@ -59,12 +60,14 @@ func TestAuditPostgres(t *testing.T) {
requireEvent(t, testCtx, libevents.DatabaseSessionStartFailureCode)

// Connect should trigger successful session start event.
psql, err := testCtx.postgresClient(ctx, "alice", "postgres", "postgres", "postgres")
userAgent := "psql"
psql, err := testCtx.postgresClient(ctx, "alice", "postgres", "postgres", "postgres", common.WithUserAgent(userAgent))
require.NoError(t, err)
startEvt, ok := requireEvent(t, testCtx, libevents.DatabaseSessionStartCode).(*events.DatabaseSessionStart)
require.True(t, ok)
require.NotNil(t, startEvt)
require.NotZero(t, startEvt.PostgresPID)
require.Equal(t, userAgent, startEvt.ClientMetadata.UserAgent)

// Simple query should trigger the query event.
_, err = psql.Exec(ctx, "select 1").ReadAll()
Expand Down
3 changes: 3 additions & 0 deletions lib/srv/db/common/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ func (a *audit) OnSessionStart(ctx context.Context, session *Session, sessionErr
Success: true,
},
PostgresPID: session.PostgresPID,
ClientMetadata: events.ClientMetadata{
UserAgent: session.UserAgent,
},
}
event.SetTime(session.StartTime)

Expand Down
2 changes: 2 additions & 0 deletions lib/srv/db/common/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ type Session struct {
StartTime time.Time
// PostgresPID is the Postgres backend PID for the session.
PostgresPID uint32
// UserAgent identifies the type of client used on the session.
UserAgent string
}

// String returns string representation of the session parameters.
Expand Down
12 changes: 12 additions & 0 deletions lib/srv/db/common/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,16 @@ func MakeTestServerTLSConfig(config TestServerConfig) (*tls.Config, error) {
}, nil
}

// ClientOption represents a database client config option.
type ClientOption func(config *TestClientConfig)

// WithUserAgent set client user agent.
func WithUserAgent(userAgent string) ClientOption {
return func(config *TestClientConfig) {
config.UserAgent = userAgent
}
}

// TestClientConfig combines parameters for a test Postgres/MySQL client.
type TestClientConfig struct {
// AuthClient will be used to retrieve trusted CA.
Expand All @@ -176,6 +186,8 @@ type TestClientConfig struct {
PinnedIP string
// RouteToDatabase contains database routing information.
RouteToDatabase tlsca.RouteToDatabase
// UserAgent contains the client user agent.
UserAgent string
}

// MakeTestClientTLSCert returns TLS certificate suitable for configuring test
Expand Down
3 changes: 3 additions & 0 deletions lib/srv/db/postgres/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ func (e *Engine) handleStartup(client *pgproto3.Backend, sessionCtx *common.Sess
sessionCtx.DatabaseName = value
case "user":
sessionCtx.DatabaseUser = value
// https://www.postgresql.org/docs/17/libpq-connect.html#LIBPQ-CONNECT-APPLICATION-NAME
case "application_name":
sessionCtx.UserAgent = value
default:
sessionCtx.StartupParameters[key] = value
}
Expand Down
3 changes: 3 additions & 0 deletions lib/srv/db/postgres/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ func MakeTestClient(ctx context.Context, config common.TestClientConfig) (*pgcon
if err != nil {
return nil, trace.Wrap(err)
}
if config.UserAgent != "" {
pgconnConfig.RuntimeParams["application_name"] = config.UserAgent
}
pgConn, err := pgconn.ConnectConfig(ctx, pgconnConfig)
if err != nil {
return nil, trace.Wrap(err)
Expand Down
Loading