Skip to content

Commit 13d9896

Browse files
committed
auth tunnels via updater
1 parent a694bb3 commit 13d9896

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
@@ -1491,7 +1491,6 @@ func (api *API) workspaceAgentsExternalAuthListen(ctx context.Context, rw http.R
14911491
func (api *API) tailnet(rw http.ResponseWriter, r *http.Request) {
14921492
ctx := r.Context()
14931493
owner := httpmw.UserParam(r)
1494-
ownerRoles := httpmw.UserAuthorization(r)
14951494

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

15401539
go httpapi.Heartbeat(ctx, conn)
15411540
err = api.TailnetClientService.ServeUserClient(ctx, version, wsNetConn, tailnet.ServeUserClientOptions{
1542-
PeerID: peerID,
1543-
UserID: owner.ID,
1544-
AuthFn: authAgentFn(api.Database, api.Authorizer, &ownerRoles),
1541+
PeerID: peerID,
1542+
UserID: owner.ID,
1543+
UpdatesProvider: api.WorkspaceUpdatesProvider,
15451544
})
15461545
if err != nil && !xerrors.Is(err, io.EOF) && !xerrors.Is(err, context.Canceled) {
15471546
_ = conn.Close(websocket.StatusInternalError, err.Error())
15481547
return
15491548
}
15501549
}
15511550

1552-
// authAgentFn accepts a subject, and returns a closure that authorizes against
1553-
// passed agent IDs.
1554-
func authAgentFn(db database.Store, auth rbac.Authorizer, user *rbac.Subject) func(context.Context, uuid.UUID) error {
1555-
return func(ctx context.Context, agentID uuid.UUID) error {
1556-
ws, err := db.GetWorkspaceByAgentID(ctx, agentID)
1557-
if err != nil {
1558-
return xerrors.Errorf("get workspace by agent id: %w", err)
1559-
}
1560-
err = auth.Authorize(ctx, *user, policy.ActionSSH, ws.RBACObject())
1561-
if err != nil {
1562-
return xerrors.Errorf("workspace agent not found or you do not have permission: %w", sql.ErrNoRows)
1563-
}
1564-
return nil
1565-
}
1566-
}
1567-
15681551
// createExternalAuthResponse creates an ExternalAuthResponse based on the
15691552
// provider type. This is to support legacy `/workspaceagents/me/gitauth`
15701553
// 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