feat: Add agent authentication based on instance ID (#336)

* feat: Add agent authentication based on instance ID

Each cloud has it's own unique instance identity signatures, which
can be used for zero-token authentication. This change adds support
for tracking by "instance_id", and automatically authenticating
with Google Cloud.

* Add test for CLI

* Fix workspace agent request name

* Fix race with adding to wait group

* Fix name of instance identity token
This commit is contained in:
Kyle Carberry
2022-02-21 20:36:29 +00:00
committed by GitHub
parent 67613da86d
commit 8958b641e9
41 changed files with 752 additions and 251 deletions
+13
View File
@@ -195,6 +195,18 @@ func (q *fakeQuerier) GetWorkspaceByUserIDAndName(_ context.Context, arg databas
return database.Workspace{}, sql.ErrNoRows
}
func (q *fakeQuerier) GetWorkspaceResourceByInstanceID(_ context.Context, instanceID string) (database.WorkspaceResource, error) {
q.mutex.Lock()
defer q.mutex.Unlock()
for _, workspaceResource := range q.workspaceResource {
if workspaceResource.InstanceID.String == instanceID {
return workspaceResource, nil
}
}
return database.WorkspaceResource{}, sql.ErrNoRows
}
func (q *fakeQuerier) GetWorkspaceOwnerCountsByProjectIDs(_ context.Context, projectIDs []uuid.UUID) ([]database.GetWorkspaceOwnerCountsByProjectIDsRow, error) {
counts := map[string]map[string]struct{}{}
for _, projectID := range projectIDs {
@@ -916,6 +928,7 @@ func (q *fakeQuerier) InsertWorkspaceResource(_ context.Context, arg database.In
ID: arg.ID,
CreatedAt: arg.CreatedAt,
WorkspaceHistoryID: arg.WorkspaceHistoryID,
InstanceID: arg.InstanceID,
Type: arg.Type,
Name: arg.Name,
WorkspaceAgentToken: arg.WorkspaceAgentToken,
+1
View File
@@ -276,6 +276,7 @@ CREATE TABLE workspace_resource (
id uuid NOT NULL,
created_at timestamp with time zone NOT NULL,
workspace_history_id uuid NOT NULL,
instance_id character varying(64),
type character varying(256) NOT NULL,
name character varying(64) NOT NULL,
workspace_agent_token character varying(128) NOT NULL,
@@ -38,6 +38,9 @@ CREATE TABLE workspace_resource (
id uuid NOT NULL UNIQUE,
created_at timestamptz NOT NULL,
workspace_history_id uuid NOT NULL REFERENCES workspace_history (id) ON DELETE CASCADE,
-- A unique identifier for the resource. This can be used
-- to exchange for an agent token with various providers.
instance_id varchar(64),
-- Resource type produced by a provisioner.
-- eg. "google_compute_instance"
type varchar(256) NOT NULL,
+8 -7
View File
@@ -452,11 +452,12 @@ type WorkspaceHistory struct {
}
type WorkspaceResource struct {
ID uuid.UUID `db:"id" json:"id"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
WorkspaceHistoryID uuid.UUID `db:"workspace_history_id" json:"workspace_history_id"`
Type string `db:"type" json:"type"`
Name string `db:"name" json:"name"`
WorkspaceAgentToken string `db:"workspace_agent_token" json:"workspace_agent_token"`
WorkspaceAgentID uuid.NullUUID `db:"workspace_agent_id" json:"workspace_agent_id"`
ID uuid.UUID `db:"id" json:"id"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
WorkspaceHistoryID uuid.UUID `db:"workspace_history_id" json:"workspace_history_id"`
InstanceID sql.NullString `db:"instance_id" json:"instance_id"`
Type string `db:"type" json:"type"`
Name string `db:"name" json:"name"`
WorkspaceAgentToken string `db:"workspace_agent_token" json:"workspace_agent_token"`
WorkspaceAgentID uuid.NullUUID `db:"workspace_agent_id" json:"workspace_agent_id"`
}
+1
View File
@@ -40,6 +40,7 @@ type querier interface {
GetWorkspaceHistoryByWorkspaceIDAndName(ctx context.Context, arg GetWorkspaceHistoryByWorkspaceIDAndNameParams) (WorkspaceHistory, error)
GetWorkspaceHistoryByWorkspaceIDWithoutAfter(ctx context.Context, workspaceID uuid.UUID) (WorkspaceHistory, error)
GetWorkspaceOwnerCountsByProjectIDs(ctx context.Context, ids []uuid.UUID) ([]GetWorkspaceOwnerCountsByProjectIDsRow, error)
GetWorkspaceResourceByInstanceID(ctx context.Context, instanceID string) (WorkspaceResource, error)
GetWorkspaceResourcesByHistoryID(ctx context.Context, workspaceHistoryID uuid.UUID) ([]WorkspaceResource, error)
GetWorkspacesByProjectAndUserID(ctx context.Context, arg GetWorkspacesByProjectAndUserIDParams) ([]Workspace, error)
GetWorkspacesByUserID(ctx context.Context, ownerID string) ([]Workspace, error)
+12 -1
View File
@@ -328,6 +328,16 @@ WHERE
LIMIT
1;
-- name: GetWorkspaceResourceByInstanceID :one
SELECT
*
FROM
workspace_resource
WHERE
instance_id = @instance_id :: text
ORDER BY
created_at;
-- name: GetWorkspaceResourcesByHistoryID :many
SELECT
*
@@ -596,12 +606,13 @@ INSERT INTO
id,
created_at,
workspace_history_id,
instance_id,
type,
name,
workspace_agent_token
)
VALUES
($1, $2, $3, $4, $5, $6) RETURNING *;
($1, $2, $3, $4, $5, $6, $7) RETURNING *;
-- name: UpdateAPIKeyByID :exec
UPDATE
+40 -8
View File
@@ -1111,9 +1111,36 @@ func (q *sqlQuerier) GetWorkspaceOwnerCountsByProjectIDs(ctx context.Context, id
return items, nil
}
const getWorkspaceResourceByInstanceID = `-- name: GetWorkspaceResourceByInstanceID :one
SELECT
id, created_at, workspace_history_id, instance_id, type, name, workspace_agent_token, workspace_agent_id
FROM
workspace_resource
WHERE
instance_id = $1 :: text
ORDER BY
created_at
`
func (q *sqlQuerier) GetWorkspaceResourceByInstanceID(ctx context.Context, instanceID string) (WorkspaceResource, error) {
row := q.db.QueryRowContext(ctx, getWorkspaceResourceByInstanceID, instanceID)
var i WorkspaceResource
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.WorkspaceHistoryID,
&i.InstanceID,
&i.Type,
&i.Name,
&i.WorkspaceAgentToken,
&i.WorkspaceAgentID,
)
return i, err
}
const getWorkspaceResourcesByHistoryID = `-- name: GetWorkspaceResourcesByHistoryID :many
SELECT
id, created_at, workspace_history_id, type, name, workspace_agent_token, workspace_agent_id
id, created_at, workspace_history_id, instance_id, type, name, workspace_agent_token, workspace_agent_id
FROM
workspace_resource
WHERE
@@ -1133,6 +1160,7 @@ func (q *sqlQuerier) GetWorkspaceResourcesByHistoryID(ctx context.Context, works
&i.ID,
&i.CreatedAt,
&i.WorkspaceHistoryID,
&i.InstanceID,
&i.Type,
&i.Name,
&i.WorkspaceAgentToken,
@@ -2112,21 +2140,23 @@ INSERT INTO
id,
created_at,
workspace_history_id,
instance_id,
type,
name,
workspace_agent_token
)
VALUES
($1, $2, $3, $4, $5, $6) RETURNING id, created_at, workspace_history_id, type, name, workspace_agent_token, workspace_agent_id
($1, $2, $3, $4, $5, $6, $7) RETURNING id, created_at, workspace_history_id, instance_id, type, name, workspace_agent_token, workspace_agent_id
`
type InsertWorkspaceResourceParams struct {
ID uuid.UUID `db:"id" json:"id"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
WorkspaceHistoryID uuid.UUID `db:"workspace_history_id" json:"workspace_history_id"`
Type string `db:"type" json:"type"`
Name string `db:"name" json:"name"`
WorkspaceAgentToken string `db:"workspace_agent_token" json:"workspace_agent_token"`
ID uuid.UUID `db:"id" json:"id"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
WorkspaceHistoryID uuid.UUID `db:"workspace_history_id" json:"workspace_history_id"`
InstanceID sql.NullString `db:"instance_id" json:"instance_id"`
Type string `db:"type" json:"type"`
Name string `db:"name" json:"name"`
WorkspaceAgentToken string `db:"workspace_agent_token" json:"workspace_agent_token"`
}
func (q *sqlQuerier) InsertWorkspaceResource(ctx context.Context, arg InsertWorkspaceResourceParams) (WorkspaceResource, error) {
@@ -2134,6 +2164,7 @@ func (q *sqlQuerier) InsertWorkspaceResource(ctx context.Context, arg InsertWork
arg.ID,
arg.CreatedAt,
arg.WorkspaceHistoryID,
arg.InstanceID,
arg.Type,
arg.Name,
arg.WorkspaceAgentToken,
@@ -2143,6 +2174,7 @@ func (q *sqlQuerier) InsertWorkspaceResource(ctx context.Context, arg InsertWork
&i.ID,
&i.CreatedAt,
&i.WorkspaceHistoryID,
&i.InstanceID,
&i.Type,
&i.Name,
&i.WorkspaceAgentToken,