Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita518017

Browse files
authored
feat(coderd): add endpoint to fetch provisioner key details (#15505)
This PR is the first step aiming toresolve#15126 - Creating a new endpoint to return the details associated to aprovisioner key.This is an authenticated endpoints aiming to be used by the provisionerdaemons - using the provisioner key as authentication method.This endpoint is not ment to be used with PSK or User Sessions.
1 parent593d659 commita518017

File tree

7 files changed

+305
-8
lines changed

7 files changed

+305
-8
lines changed

‎coderd/apidoc/docs.go

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/apidoc/swagger.json

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎codersdk/provisionerdaemons.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,26 @@ func (c *Client) ListProvisionerKeys(ctx context.Context, organizationID uuid.UU
368368
returnresp,json.NewDecoder(res.Body).Decode(&resp)
369369
}
370370

371+
// GetProvisionerKey returns the provisioner key.
372+
func (c*Client)GetProvisionerKey(ctx context.Context,pkstring) (ProvisionerKey,error) {
373+
res,err:=c.Request(ctx,http.MethodGet,
374+
fmt.Sprintf("/api/v2/provisionerkeys/%s",pk),nil,
375+
func(req*http.Request) {
376+
req.Header.Add(ProvisionerDaemonKey,pk)
377+
},
378+
)
379+
iferr!=nil {
380+
returnProvisionerKey{},xerrors.Errorf("request to fetch provisioner key failed: %w",err)
381+
}
382+
deferres.Body.Close()
383+
384+
ifres.StatusCode!=http.StatusOK {
385+
returnProvisionerKey{},ReadBodyAsError(res)
386+
}
387+
varrespProvisionerKey
388+
returnresp,json.NewDecoder(res.Body).Decode(&resp)
389+
}
390+
371391
// ListProvisionerKeyDaemons lists all provisioner keys with their associated daemons for an organization.
372392
func (c*Client)ListProvisionerKeyDaemons(ctx context.Context,organizationID uuid.UUID) ([]ProvisionerKeyDaemons,error) {
373393
res,err:=c.Request(ctx,http.MethodGet,

‎docs/reference/api/enterprise.md

Lines changed: 44 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎enterprise/coderd/coderd.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,15 @@ func New(ctx context.Context, options *Options) (_ *API, err error) {
343343
r.Get("/",api.groupByOrganization)
344344
})
345345
})
346+
r.Route("/provisionerkeys",func(r chi.Router) {
347+
r.Use(
348+
httpmw.ExtractProvisionerDaemonAuthenticated(httpmw.ExtractProvisionerAuthConfig{
349+
DB:api.Database,
350+
Optional:false,
351+
}),
352+
)
353+
r.Get("/{provisionerkey}",api.fetchProvisionerKey)
354+
})
346355
r.Route("/organizations/{organization}/provisionerkeys",func(r chi.Router) {
347356
r.Use(
348357
apiKeyMiddleware,

‎enterprise/coderd/provisionerkeys.go

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -200,17 +200,44 @@ func (api *API) deleteProvisionerKey(rw http.ResponseWriter, r *http.Request) {
200200
httpapi.Write(ctx,rw,http.StatusNoContent,nil)
201201
}
202202

203+
// @Summary Fetch provisioner key details
204+
// @ID fetch-provisioner-key-details
205+
// @Security CoderSessionToken
206+
// @Produce json
207+
// @Tags Enterprise
208+
// @Param provisionerkey path string true "Provisioner Key"
209+
// @Success 200 {object} codersdk.ProvisionerKey
210+
// @Router /provisionerkeys/{provisionerkey} [get]
211+
func (*API)fetchProvisionerKey(rw http.ResponseWriter,r*http.Request) {
212+
ctx:=r.Context()
213+
214+
pk,ok:=httpmw.ProvisionerKeyAuthOptional(r)
215+
// extra check but this one should never happen as it is covered by the auth middleware
216+
if!ok {
217+
httpapi.Write(ctx,rw,http.StatusForbidden, codersdk.Response{
218+
Message:fmt.Sprintf("unable to auth: please provide the %s header",codersdk.ProvisionerDaemonKey),
219+
})
220+
return
221+
}
222+
223+
httpapi.Write(ctx,rw,http.StatusOK,convertProvisionerKey(pk))
224+
}
225+
226+
funcconvertProvisionerKey(dbKey database.ProvisionerKey) codersdk.ProvisionerKey {
227+
return codersdk.ProvisionerKey{
228+
ID:dbKey.ID,
229+
CreatedAt:dbKey.CreatedAt,
230+
OrganizationID:dbKey.OrganizationID,
231+
Name:dbKey.Name,
232+
Tags:codersdk.ProvisionerKeyTags(dbKey.Tags),
233+
// HashedSecret - never include the access token in the API response
234+
}
235+
}
236+
203237
funcconvertProvisionerKeys(dbKeys []database.ProvisionerKey) []codersdk.ProvisionerKey {
204238
keys:=make([]codersdk.ProvisionerKey,0,len(dbKeys))
205239
for_,dbKey:=rangedbKeys {
206-
keys=append(keys, codersdk.ProvisionerKey{
207-
ID:dbKey.ID,
208-
CreatedAt:dbKey.CreatedAt,
209-
OrganizationID:dbKey.OrganizationID,
210-
Name:dbKey.Name,
211-
Tags:codersdk.ProvisionerKeyTags(dbKey.Tags),
212-
// HashedSecret - never include the access token in the API response
213-
})
240+
keys=append(keys,convertProvisionerKey(dbKey))
214241
}
215242

216243
slices.SortFunc(keys,func(key1,key2 codersdk.ProvisionerKey)int {

‎enterprise/coderd/provisionerkeys_test.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,136 @@ func TestProvisionerKeys(t *testing.T) {
134134
err=orgAdmin.DeleteProvisionerKey(ctx,owner.OrganizationID,codersdk.ProvisionerKeyNamePSK)
135135
require.ErrorContains(t,err,"reserved")
136136
}
137+
138+
funcTestGetProvisionerKey(t*testing.T) {
139+
t.Parallel()
140+
141+
tests:= []struct {
142+
namestring
143+
useFakeKeybool
144+
fakeKeystring
145+
successbool
146+
expectedErrstring
147+
}{
148+
{
149+
name:"ok",
150+
success:true,
151+
expectedErr:"",
152+
},
153+
{
154+
name:"using unknown key",
155+
useFakeKey:true,
156+
fakeKey:"unknownKey",
157+
success:false,
158+
expectedErr:"provisioner daemon key invalid",
159+
},
160+
{
161+
name:"no key provided",
162+
useFakeKey:true,
163+
fakeKey:"",
164+
success:false,
165+
expectedErr:"provisioner daemon key required",
166+
},
167+
}
168+
169+
for_,tt:=rangetests {
170+
tt:=tt
171+
t.Run(tt.name,func(t*testing.T) {
172+
t.Parallel()
173+
174+
ctx:=testutil.Context(t,testutil.WaitShort)
175+
dv:=coderdtest.DeploymentValues(t)
176+
client,owner:=coderdenttest.New(t,&coderdenttest.Options{
177+
Options:&coderdtest.Options{
178+
DeploymentValues:dv,
179+
},
180+
LicenseOptions:&coderdenttest.LicenseOptions{
181+
Features: license.Features{
182+
codersdk.FeatureMultipleOrganizations:1,
183+
codersdk.FeatureExternalProvisionerDaemons:1,
184+
},
185+
},
186+
})
187+
188+
//nolint:gocritic // ignore This client is operating as the owner user, which has unrestricted permissions
189+
key,err:=client.CreateProvisionerKey(ctx,owner.OrganizationID, codersdk.CreateProvisionerKeyRequest{
190+
Name:"my-test-key",
191+
Tags:map[string]string{"key1":"value1","key2":"value2"},
192+
})
193+
require.NoError(t,err)
194+
195+
pk:=key.Key
196+
iftt.useFakeKey {
197+
pk=tt.fakeKey
198+
}
199+
200+
fetchedKey,err:=client.GetProvisionerKey(ctx,pk)
201+
if!tt.success {
202+
require.ErrorContains(t,err,tt.expectedErr)
203+
}else {
204+
require.NoError(t,err)
205+
require.Equal(t,fetchedKey.Name,"my-test-key")
206+
require.Equal(t,fetchedKey.Tags, codersdk.ProvisionerKeyTags{"key1":"value1","key2":"value2"})
207+
}
208+
})
209+
}
210+
211+
t.Run("TestPSK",func(t*testing.T) {
212+
t.Parallel()
213+
consttestPSK="psk-testing-purpose"
214+
ctx:=testutil.Context(t,testutil.WaitShort)
215+
dv:=coderdtest.DeploymentValues(t)
216+
client,owner:=coderdenttest.New(t,&coderdenttest.Options{
217+
ProvisionerDaemonPSK:testPSK,
218+
Options:&coderdtest.Options{
219+
DeploymentValues:dv,
220+
},
221+
LicenseOptions:&coderdenttest.LicenseOptions{
222+
Features: license.Features{
223+
codersdk.FeatureMultipleOrganizations:1,
224+
codersdk.FeatureExternalProvisionerDaemons:1,
225+
},
226+
},
227+
})
228+
229+
//nolint:gocritic // ignore This client is operating as the owner user, which has unrestricted permissions
230+
_,err:=client.CreateProvisionerKey(ctx,owner.OrganizationID, codersdk.CreateProvisionerKeyRequest{
231+
Name:"my-test-key",
232+
Tags:map[string]string{"key1":"value1","key2":"value2"},
233+
})
234+
require.NoError(t,err)
235+
236+
fetchedKey,err:=client.GetProvisionerKey(ctx,testPSK)
237+
require.ErrorContains(t,err,"provisioner daemon key invalid")
238+
require.Empty(t,fetchedKey)
239+
})
240+
241+
t.Run("TestSessionToken",func(t*testing.T) {
242+
t.Parallel()
243+
244+
ctx:=testutil.Context(t,testutil.WaitShort)
245+
dv:=coderdtest.DeploymentValues(t)
246+
client,owner:=coderdenttest.New(t,&coderdenttest.Options{
247+
Options:&coderdtest.Options{
248+
DeploymentValues:dv,
249+
},
250+
LicenseOptions:&coderdenttest.LicenseOptions{
251+
Features: license.Features{
252+
codersdk.FeatureMultipleOrganizations:1,
253+
codersdk.FeatureExternalProvisionerDaemons:1,
254+
},
255+
},
256+
})
257+
258+
//nolint:gocritic // ignore This client is operating as the owner user, which has unrestricted permissions
259+
_,err:=client.CreateProvisionerKey(ctx,owner.OrganizationID, codersdk.CreateProvisionerKeyRequest{
260+
Name:"my-test-key",
261+
Tags:map[string]string{"key1":"value1","key2":"value2"},
262+
})
263+
require.NoError(t,err)
264+
265+
fetchedKey,err:=client.GetProvisionerKey(ctx,client.SessionToken())
266+
require.ErrorContains(t,err,"provisioner daemon key invalid")
267+
require.Empty(t,fetchedKey)
268+
})
269+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp