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

Skip to content

Commit 8958b64

Browse files
authored
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
1 parent 67613da commit 8958b64

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+752
-251
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/projectlist_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func TestProjectList(t *testing.T) {
1414
t.Parallel()
1515
t.Run("None", func(t *testing.T) {
1616
t.Parallel()
17-
client := coderdtest.New(t)
17+
client := coderdtest.New(t, nil)
1818
coderdtest.CreateInitialUser(t, client)
1919
cmd, root := clitest.New(t, "projects", "list")
2020
clitest.SetupConfig(t, client, root)
@@ -32,7 +32,7 @@ func TestProjectList(t *testing.T) {
3232
})
3333
t.Run("List", func(t *testing.T) {
3434
t.Parallel()
35-
client := coderdtest.New(t)
35+
client := coderdtest.New(t, nil)
3636
user := coderdtest.CreateInitialUser(t, client)
3737
daemon := coderdtest.NewProvisionerDaemon(t, client)
3838
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)

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: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"sync"
66

77
"github.com/go-chi/chi/v5"
8+
"google.golang.org/api/idtoken"
89

910
"cdr.dev/slog"
1011
"github.com/coder/coder/database"
@@ -18,6 +19,8 @@ type Options struct {
1819
Logger slog.Logger
1920
Database database.Store
2021
Pubsub database.Pubsub
22+
23+
GoogleTokenValidator *idtoken.Validator
2124
}
2225

2326
// New constructs the Coder API into an HTTP handler.
@@ -107,6 +110,12 @@ func New(options *Options) (http.Handler, func()) {
107110
})
108111
})
109112

113+
r.Route("/workspaceagent", func(r chi.Router) {
114+
r.Route("/authenticate", func(r chi.Router) {
115+
r.Post("/google-instance-identity", api.postAuthenticateWorkspaceAgentUsingGoogleInstanceIdentity)
116+
})
117+
})
118+
110119
r.Route("/files", func(r chi.Router) {
111120
r.Use(httpmw.ExtractAPIKey(options.Database, nil))
112121
r.Post("/", api.postFiles)

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: 11 additions & 11 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)
@@ -39,7 +39,7 @@ func TestProjects(t *testing.T) {
3939

4040
t.Run("ListWorkspaceOwnerCount", func(t *testing.T) {
4141
t.Parallel()
42-
client := coderdtest.New(t)
42+
client := coderdtest.New(t, nil)
4343
user := coderdtest.CreateInitialUser(t, client)
4444
coderdtest.NewProvisionerDaemon(t, client)
4545
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
@@ -58,7 +58,7 @@ func TestProjectsByOrganization(t *testing.T) {
5858
t.Parallel()
5959
t.Run("ListEmpty", func(t *testing.T) {
6060
t.Parallel()
61-
client := coderdtest.New(t)
61+
client := coderdtest.New(t, nil)
6262
user := coderdtest.CreateInitialUser(t, client)
6363
projects, err := client.Projects(context.Background(), user.Organization)
6464
require.NoError(t, err)
@@ -68,7 +68,7 @@ func TestProjectsByOrganization(t *testing.T) {
6868

6969
t.Run("List", func(t *testing.T) {
7070
t.Parallel()
71-
client := coderdtest.New(t)
71+
client := coderdtest.New(t, nil)
7272
user := coderdtest.CreateInitialUser(t, client)
7373
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
7474
_ = coderdtest.CreateProject(t, client, user.Organization, job.ID)
@@ -82,15 +82,15 @@ func TestPostProjectsByOrganization(t *testing.T) {
8282
t.Parallel()
8383
t.Run("Create", func(t *testing.T) {
8484
t.Parallel()
85-
client := coderdtest.New(t)
85+
client := coderdtest.New(t, nil)
8686
user := coderdtest.CreateInitialUser(t, client)
8787
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
8888
_ = coderdtest.CreateProject(t, client, user.Organization, job.ID)
8989
})
9090

9191
t.Run("AlreadyExists", 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
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
9696
project := coderdtest.CreateProject(t, client, user.Organization, job.ID)
@@ -108,7 +108,7 @@ func TestProjectByOrganization(t *testing.T) {
108108
t.Parallel()
109109
t.Run("Get", func(t *testing.T) {
110110
t.Parallel()
111-
client := coderdtest.New(t)
111+
client := coderdtest.New(t, nil)
112112
user := coderdtest.CreateInitialUser(t, client)
113113
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
114114
project := coderdtest.CreateProject(t, client, user.Organization, job.ID)
@@ -121,7 +121,7 @@ func TestPostParametersByProject(t *testing.T) {
121121
t.Parallel()
122122
t.Run("Create", func(t *testing.T) {
123123
t.Parallel()
124-
client := coderdtest.New(t)
124+
client := coderdtest.New(t, nil)
125125
user := coderdtest.CreateInitialUser(t, client)
126126
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
127127
project := coderdtest.CreateProject(t, client, user.Organization, job.ID)
@@ -139,7 +139,7 @@ func TestParametersByProject(t *testing.T) {
139139
t.Parallel()
140140
t.Run("ListEmpty", func(t *testing.T) {
141141
t.Parallel()
142-
client := coderdtest.New(t)
142+
client := coderdtest.New(t, nil)
143143
user := coderdtest.CreateInitialUser(t, client)
144144
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
145145
project := coderdtest.CreateProject(t, client, user.Organization, job.ID)
@@ -150,7 +150,7 @@ func TestParametersByProject(t *testing.T) {
150150

151151
t.Run("List", func(t *testing.T) {
152152
t.Parallel()
153-
client := coderdtest.New(t)
153+
client := coderdtest.New(t, nil)
154154
user := coderdtest.CreateInitialUser(t, client)
155155
job := coderdtest.CreateProjectImportJob(t, client, user.Organization, nil)
156156
project := coderdtest.CreateProject(t, client, user.Organization, job.ID)

0 commit comments

Comments
 (0)