Skip to content

Commit b01d1cb

Browse files
committed
auth tunnels via updater
1 parent 42ccc2c commit b01d1cb

File tree

7 files changed

+36
-38
lines changed

7 files changed

+36
-38
lines changed

coderd/workspaceagents.go

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,7 +1482,6 @@ func (api *API) workspaceAgentsExternalAuthListen(ctx context.Context, rw http.R
14821482
func (api *API) tailnet(rw http.ResponseWriter, r *http.Request) {
14831483
ctx := r.Context()
14841484
owner := httpmw.UserParam(r)
1485-
ownerRoles := httpmw.UserAuthorization(r)
14861485

14871486
// Check if the actor is allowed to access any workspace owned by the user.
14881487
if !api.Authorize(r, policy.ActionSSH, rbac.ResourceWorkspace.WithOwner(owner.ID.String())) {
@@ -1530,32 +1529,16 @@ func (api *API) tailnet(rw http.ResponseWriter, r *http.Request) {
15301529

15311530
go httpapi.Heartbeat(ctx, conn)
15321531
err = api.TailnetClientService.ServeUserClient(ctx, version, wsNetConn, tailnet.ServeUserClientOptions{
1533-
PeerID: peerID,
1534-
UserID: owner.ID,
1535-
AuthFn: authAgentFn(api.Database, api.Authorizer, &ownerRoles),
1532+
PeerID: peerID,
1533+
UserID: owner.ID,
1534+
UpdatesProvider: api.WorkspaceUpdatesProvider,
15361535
})
15371536
if err != nil && !xerrors.Is(err, io.EOF) && !xerrors.Is(err, context.Canceled) {
15381537
_ = conn.Close(websocket.StatusInternalError, err.Error())
15391538
return
15401539
}
15411540
}
15421541

1543-
// authAgentFn accepts a subject, and returns a closure that authorizes against
1544-
// passed agent IDs.
1545-
func authAgentFn(db database.Store, auth rbac.Authorizer, user *rbac.Subject) func(context.Context, uuid.UUID) error {
1546-
return func(ctx context.Context, agentID uuid.UUID) error {
1547-
ws, err := db.GetWorkspaceByAgentID(ctx, agentID)
1548-
if err != nil {
1549-
return xerrors.Errorf("get workspace by agent id: %w", err)
1550-
}
1551-
err = auth.Authorize(ctx, *user, policy.ActionSSH, ws.RBACObject())
1552-
if err != nil {
1553-
return xerrors.Errorf("workspace agent not found or you do not have permission: %w", sql.ErrNoRows)
1554-
}
1555-
return nil
1556-
}
1557-
}
1558-
15591542
// createExternalAuthResponse creates an ExternalAuthResponse based on the
15601543
// provider type. This is to support legacy `/workspaceagents/me/gitauth`
15611544
// which uses `Username` and `Password`.

coderd/workspaceupdates.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,24 @@ type updatesProvider struct {
9191
cancelFn func()
9292
}
9393

94+
func (u *updatesProvider) IsOwner(userID uuid.UUID, agentID uuid.UUID) error {
95+
u.mu.RLock()
96+
defer u.mu.RUnlock()
97+
98+
workspaces, exists := u.latest[userID]
99+
if !exists {
100+
return xerrors.Errorf("workspace agent not found or you do not have permission: %w", sql.ErrNoRows)
101+
}
102+
for _, workspace := range workspaces {
103+
for _, agent := range workspace.Agents {
104+
if agent.ID == agentID {
105+
return nil
106+
}
107+
}
108+
}
109+
return xerrors.Errorf("workspace agent not found or you do not have permission: %w", sql.ErrNoRows)
110+
}
111+
94112
var _ tailnet.WorkspaceUpdatesProvider = (*updatesProvider)(nil)
95113

96114
func NewUpdatesProvider(ctx context.Context, db UpdateQuerier, ps pubsub.Pubsub) (tailnet.WorkspaceUpdatesProvider, error) {

enterprise/tailnet/connio.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ var errDisconnect = xerrors.New("graceful disconnect")
133133

134134
func (c *connIO) handleRequest(req *proto.CoordinateRequest) error {
135135
c.logger.Debug(c.peerCtx, "got request")
136-
err := c.auth.Authorize(c.coordCtx, req)
136+
err := c.auth.Authorize(req)
137137
if err != nil {
138138
c.logger.Warn(c.peerCtx, "unauthorized request", slog.Error(err))
139139
return xerrors.Errorf("authorize request: %w", err)

tailnet/coordinator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ func (c *core) handleRequest(p *peer, req *proto.CoordinateRequest) error {
577577
return ErrAlreadyRemoved
578578
}
579579

580-
if err := pr.auth.Authorize(context.Background(), req); err != nil {
580+
if err := pr.auth.Authorize(req); err != nil {
581581
return xerrors.Errorf("authorize request: %w", err)
582582
}
583583

tailnet/service.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ type WorkspaceUpdatesProvider interface {
4343
Subscribe(peerID uuid.UUID, userID uuid.UUID) (<-chan *proto.WorkspaceUpdate, error)
4444
Unsubscribe(peerID uuid.UUID)
4545
Stop()
46+
IsOwner(userID uuid.UUID, agentID uuid.UUID) error
4647
}
4748

4849
type ClientServiceOptions struct {
@@ -119,11 +120,9 @@ func (s *ClientService) ServeClient(ctx context.Context, version string, conn ne
119120
}
120121

121122
type ServeUserClientOptions struct {
122-
PeerID uuid.UUID
123-
UserID uuid.UUID
124-
// AuthFn authorizes the user to `ActionSSH` against the workspace given
125-
// an agent ID.
126-
AuthFn func(context.Context, uuid.UUID) error
123+
PeerID uuid.UUID
124+
UserID uuid.UUID
125+
UpdatesProvider WorkspaceUpdatesProvider
127126
}
128127

129128
func (s *ClientService) ServeUserClient(ctx context.Context, version string, conn net.Conn, opts ServeUserClientOptions) error {
@@ -136,7 +135,6 @@ func (s *ClientService) ServeUserClient(ctx context.Context, version string, con
136135
case 2:
137136
auth := ClientUserCoordinateeAuth{
138137
UserID: opts.UserID,
139-
AuthFn: opts.AuthFn,
140138
}
141139
streamID := StreamID{
142140
Name: "client",

tailnet/service_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func TestClientService_ServeClient_V2(t *testing.T) {
7474
require.NotNil(t, call)
7575
require.Equal(t, call.ID, clientID)
7676
require.Equal(t, call.Name, "client")
77-
require.NoError(t, call.Auth.Authorize(ctx, &proto.CoordinateRequest{
77+
require.NoError(t, call.Auth.Authorize(&proto.CoordinateRequest{
7878
AddTunnel: &proto.CoordinateRequest_Tunnel{Id: agentID[:]},
7979
}))
8080
req := testutil.RequireRecvCtx(ctx, t, call.Reqs)

tailnet/tunnel.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package tailnet
22

33
import (
4-
"context"
54
"database/sql"
65
"net/netip"
76

@@ -14,13 +13,13 @@ import (
1413
var legacyWorkspaceAgentIP = netip.MustParseAddr("fd7a:115c:a1e0:49d6:b259:b7ac:b1b2:48f4")
1514

1615
type CoordinateeAuth interface {
17-
Authorize(ctx context.Context, req *proto.CoordinateRequest) error
16+
Authorize(req *proto.CoordinateRequest) error
1817
}
1918

2019
// SingleTailnetCoordinateeAuth allows all tunnels, since Coderd and wsproxy are allowed to initiate a tunnel to any agent
2120
type SingleTailnetCoordinateeAuth struct{}
2221

23-
func (SingleTailnetCoordinateeAuth) Authorize(context.Context, *proto.CoordinateRequest) error {
22+
func (SingleTailnetCoordinateeAuth) Authorize(*proto.CoordinateRequest) error {
2423
return nil
2524
}
2625

@@ -29,7 +28,7 @@ type ClientCoordinateeAuth struct {
2928
AgentID uuid.UUID
3029
}
3130

32-
func (c ClientCoordinateeAuth) Authorize(_ context.Context, req *proto.CoordinateRequest) error {
31+
func (c ClientCoordinateeAuth) Authorize(req *proto.CoordinateRequest) error {
3332
if tun := req.GetAddTunnel(); tun != nil {
3433
uid, err := uuid.FromBytes(tun.Id)
3534
if err != nil {
@@ -66,7 +65,7 @@ type AgentCoordinateeAuth struct {
6665
ID uuid.UUID
6766
}
6867

69-
func (a AgentCoordinateeAuth) Authorize(_ context.Context, req *proto.CoordinateRequest) error {
68+
func (a AgentCoordinateeAuth) Authorize(req *proto.CoordinateRequest) error {
7069
if tun := req.GetAddTunnel(); tun != nil {
7170
return xerrors.New("agents cannot open tunnels")
7271
}
@@ -93,17 +92,17 @@ func (a AgentCoordinateeAuth) Authorize(_ context.Context, req *proto.Coordinate
9392
}
9493

9594
type ClientUserCoordinateeAuth struct {
96-
UserID uuid.UUID
97-
AuthFn func(context.Context, uuid.UUID) error
95+
UserID uuid.UUID
96+
UpdatesProvider WorkspaceUpdatesProvider
9897
}
9998

100-
func (a ClientUserCoordinateeAuth) Authorize(ctx context.Context, req *proto.CoordinateRequest) error {
99+
func (a ClientUserCoordinateeAuth) Authorize(req *proto.CoordinateRequest) error {
101100
if tun := req.GetAddTunnel(); tun != nil {
102101
uid, err := uuid.FromBytes(tun.Id)
103102
if err != nil {
104103
return xerrors.Errorf("parse add tunnel id: %w", err)
105104
}
106-
err = a.AuthFn(ctx, uid)
105+
err = a.UpdatesProvider.IsOwner(a.UserID, uid)
107106
if err != nil {
108107
return xerrors.Errorf("workspace agent not found or you do not have permission: %w", sql.ErrNoRows)
109108
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy