Skip to content

Commit dbf8fcd

Browse files
Add client metadata to PostgreSQL database session start event (#50711)
* feat: add client metadata to database session start event * refactor(test): update option to WithUserAgent
1 parent c5b4101 commit dbf8fcd

File tree

9 files changed

+930
-845
lines changed

9 files changed

+930
-845
lines changed

api/proto/teleport/legacy/types/events/events.proto

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3150,6 +3150,12 @@ message DatabaseSessionStart {
31503150
// connection. This can be useful for backend process cancellation or
31513151
// termination and it is not a sensitive or secret value.
31523152
uint32 PostgresPID = 8 [(gogoproto.jsontag) = "postgres_pid,omitempty"];
3153+
// Client is the common client event metadata.
3154+
ClientMetadata Client = 9 [
3155+
(gogoproto.nullable) = false,
3156+
(gogoproto.embed) = true,
3157+
(gogoproto.jsontag) = ""
3158+
];
31533159
}
31543160

31553161
// DatabaseSessionQuery is emitted when a user executes a database query.

api/types/events/events.pb.go

Lines changed: 886 additions & 839 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/srv/db/access_test.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,13 +1629,13 @@ func (c *testContext) startHandlingConnections() {
16291629

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

16361636
// postgresClientWithAddr is like postgresClient but allows to override connection address.
1637-
func (c *testContext) postgresClientWithAddr(ctx context.Context, address, teleportUser, dbService, dbUser, dbName string) (*pgconn.PgConn, error) {
1638-
return postgres.MakeTestClient(ctx, common.TestClientConfig{
1637+
func (c *testContext) postgresClientWithAddr(ctx context.Context, address, teleportUser, dbService, dbUser, dbName string, opts ...common.ClientOption) (*pgconn.PgConn, error) {
1638+
cfg := common.TestClientConfig{
16391639
AuthClient: c.authClient,
16401640
AuthServer: c.authServer,
16411641
Address: address,
@@ -1647,7 +1647,13 @@ func (c *testContext) postgresClientWithAddr(ctx context.Context, address, telep
16471647
Username: dbUser,
16481648
Database: dbName,
16491649
},
1650-
})
1650+
}
1651+
1652+
for _, opt := range opts {
1653+
opt(&cfg)
1654+
}
1655+
1656+
return postgres.MakeTestClient(ctx, cfg)
16511657
}
16521658

16531659
// postgresClientLocalProxy connects to test Postgres through local ALPN proxy.

lib/srv/db/audit_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/gravitational/teleport/lib/defaults"
3636
libevents "github.com/gravitational/teleport/lib/events"
3737
"github.com/gravitational/teleport/lib/events/eventstest"
38+
"github.com/gravitational/teleport/lib/srv/db/common"
3839
"github.com/gravitational/teleport/lib/srv/db/postgres"
3940
"github.com/gravitational/teleport/lib/srv/db/redis"
4041
)
@@ -59,12 +60,14 @@ func TestAuditPostgres(t *testing.T) {
5960
requireEvent(t, testCtx, libevents.DatabaseSessionStartFailureCode)
6061

6162
// Connect should trigger successful session start event.
62-
psql, err := testCtx.postgresClient(ctx, "alice", "postgres", "postgres", "postgres")
63+
userAgent := "psql"
64+
psql, err := testCtx.postgresClient(ctx, "alice", "postgres", "postgres", "postgres", common.WithUserAgent(userAgent))
6365
require.NoError(t, err)
6466
startEvt, ok := requireEvent(t, testCtx, libevents.DatabaseSessionStartCode).(*events.DatabaseSessionStart)
6567
require.True(t, ok)
6668
require.NotNil(t, startEvt)
6769
require.NotZero(t, startEvt.PostgresPID)
70+
require.Equal(t, userAgent, startEvt.ClientMetadata.UserAgent)
6871

6972
// Simple query should trigger the query event.
7073
_, err = psql.Exec(ctx, "select 1").ReadAll()

lib/srv/db/common/audit.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ func (a *audit) OnSessionStart(ctx context.Context, session *Session, sessionErr
146146
Success: true,
147147
},
148148
PostgresPID: session.PostgresPID,
149+
ClientMetadata: events.ClientMetadata{
150+
UserAgent: session.UserAgent,
151+
},
149152
}
150153
event.SetTime(session.StartTime)
151154

lib/srv/db/common/session.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ type Session struct {
6868
StartTime time.Time
6969
// PostgresPID is the Postgres backend PID for the session.
7070
PostgresPID uint32
71+
// UserAgent identifies the type of client used on the session.
72+
UserAgent string
7173
}
7274

7375
// String returns string representation of the session parameters.

lib/srv/db/common/test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,16 @@ func MakeTestServerTLSConfig(config TestServerConfig) (*tls.Config, error) {
160160
}, nil
161161
}
162162

163+
// ClientOption represents a database client config option.
164+
type ClientOption func(config *TestClientConfig)
165+
166+
// WithUserAgent set client user agent.
167+
func WithUserAgent(userAgent string) ClientOption {
168+
return func(config *TestClientConfig) {
169+
config.UserAgent = userAgent
170+
}
171+
}
172+
163173
// TestClientConfig combines parameters for a test Postgres/MySQL client.
164174
type TestClientConfig struct {
165175
// AuthClient will be used to retrieve trusted CA.
@@ -176,6 +186,8 @@ type TestClientConfig struct {
176186
PinnedIP string
177187
// RouteToDatabase contains database routing information.
178188
RouteToDatabase tlsca.RouteToDatabase
189+
// UserAgent contains the client user agent.
190+
UserAgent string
179191
}
180192

181193
// MakeTestClientTLSCert returns TLS certificate suitable for configuring test

lib/srv/db/postgres/engine.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ func (e *Engine) handleStartup(client *pgproto3.Backend, sessionCtx *common.Sess
213213
sessionCtx.DatabaseName = value
214214
case "user":
215215
sessionCtx.DatabaseUser = value
216+
// https://www.postgresql.org/docs/17/libpq-connect.html#LIBPQ-CONNECT-APPLICATION-NAME
217+
case "application_name":
218+
sessionCtx.UserAgent = value
216219
default:
217220
sessionCtx.StartupParameters[key] = value
218221
}

lib/srv/db/postgres/test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ func MakeTestClient(ctx context.Context, config common.TestClientConfig) (*pgcon
5858
if err != nil {
5959
return nil, trace.Wrap(err)
6060
}
61+
if config.UserAgent != "" {
62+
pgconnConfig.RuntimeParams["application_name"] = config.UserAgent
63+
}
6164
pgConn, err := pgconn.ConnectConfig(ctx, pgconnConfig)
6265
if err != nil {
6366
return nil, trace.Wrap(err)

0 commit comments

Comments
 (0)