Skip to content

Commit 478001a

Browse files
committed
feat: add session token to provisioner
1 parent a1853f2 commit 478001a

File tree

5 files changed

+100
-3
lines changed

5 files changed

+100
-3
lines changed

coderd/coderd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,7 @@ func (api *API) CreateInMemoryProvisionerDaemon(ctx context.Context, debounce ti
964964
TemplateScheduleStore: api.TemplateScheduleStore,
965965
AcquireJobDebounce: debounce,
966966
Logger: api.Logger.Named(fmt.Sprintf("provisionerd-%s", daemon.Name)),
967+
DeploymentValues: api.DeploymentValues,
967968
})
968969
if err != nil {
969970
return nil, err

coderd/provisionerdserver/provisionerdserver.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package provisionerdserver
22

33
import (
44
"context"
5+
"crypto/sha256"
56
"database/sql"
67
"encoding/json"
78
"errors"
89
"fmt"
10+
"net"
911
"net/http"
1012
"net/url"
1113
"reflect"
@@ -37,6 +39,7 @@ import (
3739
"github.com/coder/coder/coderd/telemetry"
3840
"github.com/coder/coder/coderd/tracing"
3941
"github.com/coder/coder/codersdk"
42+
"github.com/coder/coder/cryptorand"
4043
"github.com/coder/coder/provisioner"
4144
"github.com/coder/coder/provisionerd/proto"
4245
"github.com/coder/coder/provisionersdk"
@@ -62,6 +65,7 @@ type Server struct {
6265
QuotaCommitter *atomic.Pointer[proto.QuotaCommitter]
6366
Auditor *atomic.Pointer[audit.Auditor]
6467
TemplateScheduleStore *atomic.Pointer[schedule.TemplateScheduleStore]
68+
DeploymentValues *codersdk.DeploymentValues
6569

6670
AcquireJobDebounce time.Duration
6771
OIDCConfig httpmw.OAuth2Config
@@ -193,6 +197,11 @@ func (server *Server) AcquireJob(ctx context.Context, _ *proto.Empty) (*proto.Ac
193197
}
194198
}
195199

200+
sessionToken, err := server.regenerateSessionToken(ctx, owner, workspace)
201+
if err != nil {
202+
return nil, failJob(fmt.Sprintf("regenerate session token: %s", err))
203+
}
204+
196205
// Compute parameters for the workspace to consume.
197206
parameters, err := parameter.Compute(ctx, server.Database, parameter.ComputeScope{
198207
TemplateImportJobID: templateVersion.JobID,
@@ -286,6 +295,7 @@ func (server *Server) AcquireJob(ctx context.Context, _ *proto.Empty) (*proto.Ac
286295
WorkspaceOwnerId: owner.ID.String(),
287296
TemplateName: template.Name,
288297
TemplateVersion: templateVersion.Name,
298+
CoderSessionToken: sessionToken,
289299
},
290300
LogLevel: input.LogLevel,
291301
},
@@ -1410,6 +1420,79 @@ func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
14101420
return nil
14111421
}
14121422

1423+
func workspaceSessionTokenName(workspace database.Workspace) string {
1424+
return fmt.Sprintf("%s_%s_session_token", workspace.OwnerID, workspace.ID)
1425+
}
1426+
1427+
// Generates a new ID and secret for an API key.
1428+
// TODO put API key logic in separate package.
1429+
func GenerateAPIKeyIDSecret() (id string, secret string, err error) {
1430+
// Length of an API Key ID.
1431+
id, err = cryptorand.String(10)
1432+
if err != nil {
1433+
return "", "", err
1434+
}
1435+
// Length of an API Key secret.
1436+
secret, err = cryptorand.String(22)
1437+
if err != nil {
1438+
return "", "", err
1439+
}
1440+
return id, secret, nil
1441+
}
1442+
1443+
func (server *Server) regenerateSessionToken(ctx context.Context, user database.User, workspace database.Workspace) (string, error) {
1444+
id, secret, err := GenerateAPIKeyIDSecret()
1445+
if err != nil {
1446+
return "", xerrors.Errorf("generate API key: %w", err)
1447+
}
1448+
hashed := sha256.Sum256([]byte(secret))
1449+
1450+
err = server.Database.InTx(
1451+
func(tx database.Store) error {
1452+
key, err := tx.GetAPIKeyByName(ctx, database.GetAPIKeyByNameParams{
1453+
UserID: workspace.OwnerID,
1454+
TokenName: workspaceSessionTokenName(workspace),
1455+
})
1456+
if err == nil {
1457+
err = tx.DeleteAPIKeyByID(ctx, key.ID)
1458+
if err != nil {
1459+
return xerrors.Errorf("delete api key: %w", err)
1460+
}
1461+
}
1462+
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
1463+
return xerrors.Errorf("get api key by name: %w", err)
1464+
}
1465+
1466+
ip := net.IPv4(0, 0, 0, 0)
1467+
bitlen := len(ip) * 8
1468+
_, err = tx.InsertAPIKey(ctx, database.InsertAPIKeyParams{
1469+
ID: id,
1470+
UserID: workspace.OwnerID,
1471+
LifetimeSeconds: int64(server.DeploymentValues.SessionDuration.Value().Seconds()),
1472+
ExpiresAt: database.Now().Add(server.DeploymentValues.SessionDuration.Value()).UTC(),
1473+
IPAddress: pqtype.Inet{
1474+
IPNet: net.IPNet{
1475+
IP: ip,
1476+
Mask: net.CIDRMask(bitlen, bitlen),
1477+
},
1478+
Valid: true,
1479+
},
1480+
CreatedAt: database.Now(),
1481+
UpdatedAt: database.Now(),
1482+
HashedSecret: hashed[:],
1483+
LoginType: user.LoginType,
1484+
Scope: database.APIKeyScopeAll,
1485+
TokenName: workspaceSessionTokenName(workspace),
1486+
})
1487+
1488+
return nil
1489+
}, nil)
1490+
if err != nil {
1491+
return "", xerrors.Errorf("regenerate API key: %w", err)
1492+
}
1493+
return fmt.Sprintf("%s-%s", id, secret), nil
1494+
}
1495+
14131496
// obtainOIDCAccessToken returns a valid OpenID Connect access token
14141497
// for the user if it's able to obtain one, otherwise it returns an empty string.
14151498
func obtainOIDCAccessToken(ctx context.Context, db database.Store, oidcConfig httpmw.OAuth2Config, userID uuid.UUID) (string, error) {

provisioner/terraform/provision.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ func provisionEnv(config *proto.Provision_Config, params []*proto.ParameterValue
220220
"CODER_WORKSPACE_OWNER_OIDC_ACCESS_TOKEN="+config.Metadata.WorkspaceOwnerOidcAccessToken,
221221
"CODER_WORKSPACE_ID="+config.Metadata.WorkspaceId,
222222
"CODER_WORKSPACE_OWNER_ID="+config.Metadata.WorkspaceOwnerId,
223+
"CODER_SESSION_TOKEN="+config.Metadata.CoderSessionToken,
223224
)
224225
for key, value := range provisionersdk.AgentScriptEnv() {
225226
env = append(env, key+"="+value)

provisionersdk/proto/provisioner.pb.go

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

provisionersdk/proto/provisioner.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ message Provision {
241241
string template_name = 8;
242242
string template_version = 9;
243243
string workspace_owner_oidc_access_token = 10;
244+
string coder_session_token = 11;
244245
}
245246

246247
// Config represents execution configuration shared by both Plan and

0 commit comments

Comments
 (0)