Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1b65d08

Browse files
committed
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.
1 parent 91bf863 commit 1b65d08

39 files changed

+707
-254
lines changed

.vscode/settings.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@
3636
"gossh",
3737
"hashicorp",
3838
"httpmw",
39+
"idtoken",
3940
"isatty",
4041
"Jobf",
4142
"kirsle",
4243
"manifoldco",
4344
"mattn",
45+
"mitchellh",
4446
"moby",
4547
"nhooyr",
4648
"nolint",

cli/clitest/clitest_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func TestMain(m *testing.M) {
1818
func TestCli(t *testing.T) {
1919
t.Parallel()
2020
clitest.CreateProjectVersionSource(t, nil)
21-
client := coderdtest.New(t)
21+
client := coderdtest.New(t, nil)
2222
cmd, config := clitest.New(t)
2323
clitest.SetupConfig(t, client, config)
2424
pty := ptytest.New(t)

cli/login_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ func TestLogin(t *testing.T) {
1616
t.Parallel()
1717
t.Run("InitialUserNoTTY", func(t *testing.T) {
1818
t.Parallel()
19-
client := coderdtest.New(t)
19+
client := coderdtest.New(t, nil)
2020
root, _ := clitest.New(t, "login", client.URL.String())
2121
err := root.Execute()
2222
require.Error(t, err)
2323
})
2424

2525
t.Run("InitialUserTTY", func(t *testing.T) {
2626
t.Parallel()
27-
client := coderdtest.New(t)
27+
client := coderdtest.New(t, nil)
2828
// The --force-tty flag is required on Windows, because the `isatty` library does not
2929
// accurately detect Windows ptys when they are not attached to a process:
3030
// https://github.com/mattn/go-isatty/issues/59
@@ -55,7 +55,7 @@ func TestLogin(t *testing.T) {
5555

5656
t.Run("ExistingUserValidTokenTTY", func(t *testing.T) {
5757
t.Parallel()
58-
client := coderdtest.New(t)
58+
client := coderdtest.New(t, nil)
5959
_, err := client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{
6060
Username: "test-user",
6161
@@ -85,7 +85,7 @@ func TestLogin(t *testing.T) {
8585

8686
t.Run("ExistingUserInvalidTokenTTY", func(t *testing.T) {
8787
t.Parallel()
88-
client := coderdtest.New(t)
88+
client := coderdtest.New(t, nil)
8989
_, err := client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{
9090
Username: "test-user",
9191

cli/projectcreate_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func TestProjectCreate(t *testing.T) {
1717
t.Parallel()
1818
t.Run("NoParameters", func(t *testing.T) {
1919
t.Parallel()
20-
client := coderdtest.New(t)
20+
client := coderdtest.New(t, nil)
2121
coderdtest.CreateInitialUser(t, client)
2222
source := clitest.CreateProjectVersionSource(t, &echo.Responses{
2323
Parse: echo.ParseComplete,
@@ -53,7 +53,7 @@ func TestProjectCreate(t *testing.T) {
5353

5454
t.Run("Parameter", func(t *testing.T) {
5555
t.Parallel()
56-
client := coderdtest.New(t)
56+
client := coderdtest.New(t, nil)
5757
coderdtest.CreateInitialUser(t, client)
5858
source := clitest.CreateProjectVersionSource(t, &echo.Responses{
5959
Parse: []*proto.Parse_Response{{

cli/workspacecreate_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ func TestWorkspaceCreate(t *testing.T) {
1616
t.Parallel()
1717
t.Run("Create", func(t *testing.T) {
1818
t.Parallel()
19-
client := coderdtest.New(t)
19+
client := coderdtest.New(t, nil)
2020
user := coderdtest.CreateInitialUser(t, client)
2121
_ = coderdtest.NewProvisionerDaemon(t, client)
2222
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, &echo.Responses{

coderd/coderd.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"net/http"
55

66
"github.com/go-chi/chi/v5"
7+
"google.golang.org/api/idtoken"
78

89
"cdr.dev/slog"
910
"github.com/coder/coder/database"
@@ -17,14 +18,14 @@ type Options struct {
1718
Logger slog.Logger
1819
Database database.Store
1920
Pubsub database.Pubsub
21+
22+
GoogleTokenValidator *idtoken.Validator
2023
}
2124

2225
// New constructs the Coder API into an HTTP handler.
2326
func New(options *Options) http.Handler {
2427
api := &api{
25-
Database: options.Database,
26-
Logger: options.Logger,
27-
Pubsub: options.Pubsub,
28+
Options: options,
2829
}
2930

3031
r := chi.NewRouter()
@@ -105,6 +106,12 @@ func New(options *Options) http.Handler {
105106
})
106107
})
107108

109+
r.Route("/workspaceagent", func(r chi.Router) {
110+
r.Route("/authenticate", func(r chi.Router) {
111+
r.Post("/google-instance-identity", api.postWorkspaceAgentAuthenticateGoogleInstanceIdentity)
112+
})
113+
})
114+
108115
r.Route("/files", func(r chi.Router) {
109116
r.Use(httpmw.ExtractAPIKey(options.Database, nil))
110117
r.Post("/", api.postFiles)
@@ -150,7 +157,5 @@ func New(options *Options) http.Handler {
150157
// API contains all route handlers. Only HTTP handlers should
151158
// be added to this struct for code clarity.
152159
type api struct {
153-
Database database.Store
154-
Logger slog.Logger
155-
Pubsub database.Pubsub
160+
*Options
156161
}

coderd/coderdtest/coderdtest.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import (
1515
"github.com/google/uuid"
1616
"github.com/moby/moby/pkg/namesgenerator"
1717
"github.com/stretchr/testify/require"
18+
"go.opencensus.io/stats/view"
19+
"google.golang.org/api/idtoken"
20+
"google.golang.org/api/option"
1821

1922
"cdr.dev/slog"
2023
"cdr.dev/slog/sloggers/slogtest"
@@ -29,9 +32,31 @@ import (
2932
"github.com/coder/coder/provisionersdk/proto"
3033
)
3134

35+
type Options struct {
36+
GoogleTokenValidator *idtoken.Validator
37+
}
38+
3239
// New constructs an in-memory coderd instance and returns
3340
// the connected client.
34-
func New(t *testing.T) *codersdk.Client {
41+
func New(t *testing.T, options *Options) *codersdk.Client {
42+
// Stops the opencensus.io worker from leaking a goroutine.
43+
// The worker isn't used anyways, and is an indirect dependency
44+
// of the Google Cloud SDK.
45+
t.Cleanup(func() {
46+
view.Stop()
47+
})
48+
49+
if options == nil {
50+
options = &Options{}
51+
}
52+
if options.GoogleTokenValidator == nil {
53+
ctx, cancelFunc := context.WithCancel(context.Background())
54+
t.Cleanup(cancelFunc)
55+
var err error
56+
options.GoogleTokenValidator, err = idtoken.NewValidator(ctx, option.WithoutAuthentication())
57+
require.NoError(t, err)
58+
}
59+
3560
// This can be hotswapped for a live database instance.
3661
db := databasefake.New()
3762
pubsub := database.NewPubsubInMemory()
@@ -59,6 +84,8 @@ func New(t *testing.T) *codersdk.Client {
5984
Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
6085
Database: db,
6186
Pubsub: pubsub,
87+
88+
GoogleTokenValidator: options.GoogleTokenValidator,
6289
})
6390
srv := httptest.NewUnstartedServer(handler)
6491
srv.Config.BaseContext = func(_ net.Listener) context.Context {

coderd/coderdtest/coderdtest_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestMain(m *testing.M) {
1919

2020
func TestNew(t *testing.T) {
2121
t.Parallel()
22-
client := coderdtest.New(t)
22+
client := coderdtest.New(t, nil)
2323
user := coderdtest.CreateInitialUser(t, client)
2424
closer := coderdtest.NewProvisionerDaemon(t, client)
2525
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)

coderd/files_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,23 @@ func TestPostFiles(t *testing.T) {
1414
t.Parallel()
1515
t.Run("BadContentType", func(t *testing.T) {
1616
t.Parallel()
17-
client := coderdtest.New(t)
17+
client := coderdtest.New(t, nil)
1818
_ = coderdtest.CreateInitialUser(t, client)
1919
_, err := client.UploadFile(context.Background(), "bad", []byte{'a'})
2020
require.Error(t, err)
2121
})
2222

2323
t.Run("Insert", func(t *testing.T) {
2424
t.Parallel()
25-
client := coderdtest.New(t)
25+
client := coderdtest.New(t, nil)
2626
_ = coderdtest.CreateInitialUser(t, client)
2727
_, err := client.UploadFile(context.Background(), codersdk.ContentTypeTar, make([]byte, 1024))
2828
require.NoError(t, err)
2929
})
3030

3131
t.Run("InsertAlreadyExists", func(t *testing.T) {
3232
t.Parallel()
33-
client := coderdtest.New(t)
33+
client := coderdtest.New(t, nil)
3434
_ = coderdtest.CreateInitialUser(t, client)
3535
data := make([]byte, 1024)
3636
_, err := client.UploadFile(context.Background(), codersdk.ContentTypeTar, data)

coderd/projectimport_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestPostProjectImportByOrganization(t *testing.T) {
1919
t.Parallel()
2020
t.Run("FileNotFound", func(t *testing.T) {
2121
t.Parallel()
22-
client := coderdtest.New(t)
22+
client := coderdtest.New(t, nil)
2323
user := coderdtest.CreateInitialUser(t, client)
2424
_, err := client.CreateProjectImportJob(context.Background(), user.Organization, coderd.CreateProjectImportJobRequest{
2525
StorageMethod: database.ProvisionerStorageMethodFile,
@@ -30,7 +30,7 @@ func TestPostProjectImportByOrganization(t *testing.T) {
3030
})
3131
t.Run("Create", func(t *testing.T) {
3232
t.Parallel()
33-
client := coderdtest.New(t)
33+
client := coderdtest.New(t, nil)
3434
user := coderdtest.CreateInitialUser(t, client)
3535
_ = coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
3636
})
@@ -40,7 +40,7 @@ func TestProjectImportJobSchemasByID(t *testing.T) {
4040
t.Parallel()
4141
t.Run("ListRunning", func(t *testing.T) {
4242
t.Parallel()
43-
client := coderdtest.New(t)
43+
client := coderdtest.New(t, nil)
4444
user := coderdtest.CreateInitialUser(t, client)
4545
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
4646
_, err := client.ProjectImportJobSchemas(context.Background(), user.Organization, job.ID)
@@ -50,7 +50,7 @@ func TestProjectImportJobSchemasByID(t *testing.T) {
5050
})
5151
t.Run("List", func(t *testing.T) {
5252
t.Parallel()
53-
client := coderdtest.New(t)
53+
client := coderdtest.New(t, nil)
5454
user := coderdtest.CreateInitialUser(t, client)
5555
coderdtest.NewProvisionerDaemon(t, client)
5656
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, &echo.Responses{
@@ -80,7 +80,7 @@ func TestProjectImportJobParametersByID(t *testing.T) {
8080
t.Parallel()
8181
t.Run("ListRunning", func(t *testing.T) {
8282
t.Parallel()
83-
client := coderdtest.New(t)
83+
client := coderdtest.New(t, nil)
8484
user := coderdtest.CreateInitialUser(t, client)
8585
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
8686
_, err := client.ProjectImportJobSchemas(context.Background(), user.Organization, job.ID)
@@ -90,7 +90,7 @@ func TestProjectImportJobParametersByID(t *testing.T) {
9090
})
9191
t.Run("List", func(t *testing.T) {
9292
t.Parallel()
93-
client := coderdtest.New(t)
93+
client := coderdtest.New(t, nil)
9494
user := coderdtest.CreateInitialUser(t, client)
9595
coderdtest.NewProvisionerDaemon(t, client)
9696
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, &echo.Responses{
@@ -126,7 +126,7 @@ func TestProjectImportJobResourcesByID(t *testing.T) {
126126
t.Parallel()
127127
t.Run("ListRunning", func(t *testing.T) {
128128
t.Parallel()
129-
client := coderdtest.New(t)
129+
client := coderdtest.New(t, nil)
130130
user := coderdtest.CreateInitialUser(t, client)
131131
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
132132
_, err := client.ProjectImportJobResources(context.Background(), user.Organization, job.ID)
@@ -136,7 +136,7 @@ func TestProjectImportJobResourcesByID(t *testing.T) {
136136
})
137137
t.Run("List", func(t *testing.T) {
138138
t.Parallel()
139-
client := coderdtest.New(t)
139+
client := coderdtest.New(t, nil)
140140
user := coderdtest.CreateInitialUser(t, client)
141141
coderdtest.NewProvisionerDaemon(t, client)
142142
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, &echo.Responses{

coderd/projects_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func TestProjects(t *testing.T) {
1818

1919
t.Run("ListEmpty", func(t *testing.T) {
2020
t.Parallel()
21-
client := coderdtest.New(t)
21+
client := coderdtest.New(t, nil)
2222
_ = coderdtest.CreateInitialUser(t, client)
2323
projects, err := client.Projects(context.Background(), "")
2424
require.NoError(t, err)
@@ -28,7 +28,7 @@ func TestProjects(t *testing.T) {
2828

2929
t.Run("List", func(t *testing.T) {
3030
t.Parallel()
31-
client := coderdtest.New(t)
31+
client := coderdtest.New(t, nil)
3232
user := coderdtest.CreateInitialUser(t, client)
3333
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
3434
_ = coderdtest.CreateProject(t, client, user.Organization, job.ID)
@@ -42,7 +42,7 @@ func TestProjectsByOrganization(t *testing.T) {
4242
t.Parallel()
4343
t.Run("ListEmpty", func(t *testing.T) {
4444
t.Parallel()
45-
client := coderdtest.New(t)
45+
client := coderdtest.New(t, nil)
4646
user := coderdtest.CreateInitialUser(t, client)
4747
projects, err := client.Projects(context.Background(), user.Organization)
4848
require.NoError(t, err)
@@ -52,7 +52,7 @@ func TestProjectsByOrganization(t *testing.T) {
5252

5353
t.Run("List", func(t *testing.T) {
5454
t.Parallel()
55-
client := coderdtest.New(t)
55+
client := coderdtest.New(t, nil)
5656
user := coderdtest.CreateInitialUser(t, client)
5757
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
5858
_ = coderdtest.CreateProject(t, client, user.Organization, job.ID)
@@ -66,15 +66,15 @@ func TestPostProjectsByOrganization(t *testing.T) {
6666
t.Parallel()
6767
t.Run("Create", func(t *testing.T) {
6868
t.Parallel()
69-
client := coderdtest.New(t)
69+
client := coderdtest.New(t, nil)
7070
user := coderdtest.CreateInitialUser(t, client)
7171
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
7272
_ = coderdtest.CreateProject(t, client, user.Organization, job.ID)
7373
})
7474

7575
t.Run("AlreadyExists", func(t *testing.T) {
7676
t.Parallel()
77-
client := coderdtest.New(t)
77+
client := coderdtest.New(t, nil)
7878
user := coderdtest.CreateInitialUser(t, client)
7979
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
8080
project := coderdtest.CreateProject(t, client, user.Organization, job.ID)
@@ -92,7 +92,7 @@ func TestProjectByOrganization(t *testing.T) {
9292
t.Parallel()
9393
t.Run("Get", func(t *testing.T) {
9494
t.Parallel()
95-
client := coderdtest.New(t)
95+
client := coderdtest.New(t, nil)
9696
user := coderdtest.CreateInitialUser(t, client)
9797
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
9898
project := coderdtest.CreateProject(t, client, user.Organization, job.ID)
@@ -105,7 +105,7 @@ func TestPostParametersByProject(t *testing.T) {
105105
t.Parallel()
106106
t.Run("Create", func(t *testing.T) {
107107
t.Parallel()
108-
client := coderdtest.New(t)
108+
client := coderdtest.New(t, nil)
109109
user := coderdtest.CreateInitialUser(t, client)
110110
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
111111
project := coderdtest.CreateProject(t, client, user.Organization, job.ID)
@@ -123,7 +123,7 @@ func TestParametersByProject(t *testing.T) {
123123
t.Parallel()
124124
t.Run("ListEmpty", func(t *testing.T) {
125125
t.Parallel()
126-
client := coderdtest.New(t)
126+
client := coderdtest.New(t, nil)
127127
user := coderdtest.CreateInitialUser(t, client)
128128
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
129129
project := coderdtest.CreateProject(t, client, user.Organization, job.ID)
@@ -134,7 +134,7 @@ func TestParametersByProject(t *testing.T) {
134134

135135
t.Run("List", func(t *testing.T) {
136136
t.Parallel()
137-
client := coderdtest.New(t)
137+
client := coderdtest.New(t, nil)
138138
user := coderdtest.CreateInitialUser(t, client)
139139
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
140140
project := coderdtest.CreateProject(t, client, user.Organization, job.ID)

0 commit comments

Comments
 (0)