Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
fix(coderd): add audit log on creating a new session key
  • Loading branch information
johnstcn committed Sep 2, 2025
commit 8386d4491ab8106e8a411cd94ef30ac001953085
18 changes: 15 additions & 3 deletions coderd/apikey.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,19 @@ func (api *API) postToken(rw http.ResponseWriter, r *http.Request) {
// @Success 201 {object} codersdk.GenerateAPIKeyResponse
// @Router /users/{user}/keys [post]
func (api *API) postAPIKey(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
user := httpmw.UserParam(r)
var (
ctx = r.Context()
user = httpmw.UserParam(r)
auditor = api.Auditor.Load()
aReq, commitAudit = audit.InitRequest[database.APIKey](rw, &audit.RequestParams{
Audit: *auditor,
Log: api.Logger,
Request: r,
Action: database.AuditActionCreate,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't be visible in the UI if filter will specify action:login

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, typically that gets logged when users authenticate via the Web UI.

})
)
aReq.Old = database.APIKey{}
defer commitAudit()

// TODO(Cian): System users technically just have the 'member' role
// and we don't want to disallow all members from creating API keys.
Expand All @@ -142,7 +153,7 @@ func (api *API) postAPIKey(rw http.ResponseWriter, r *http.Request) {
return
}

cookie, _, err := api.createAPIKey(ctx, apikey.CreateParams{
cookie, key, err := api.createAPIKey(ctx, apikey.CreateParams{
UserID: user.ID,
DefaultLifetime: api.DeploymentValues.Sessions.DefaultTokenDuration.Value(),
LoginType: database.LoginTypePassword,
Expand All @@ -156,6 +167,7 @@ func (api *API) postAPIKey(rw http.ResponseWriter, r *http.Request) {
return
}

aReq.New = *key
// We intentionally do not set the cookie on the response here.
// Setting the cookie will couple the browser session to the API
// key we return here, meaning logging out of the website would
Expand Down
11 changes: 9 additions & 2 deletions coderd/apikey_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,12 +305,19 @@ func TestAPIKey_OK(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
_ = coderdtest.CreateFirstUser(t, client)
auditor := audit.NewMock()
client := coderdtest.New(t, &coderdtest.Options{Auditor: auditor})
owner := coderdtest.CreateFirstUser(t, client)

auditor.ResetLogs()
res, err := client.CreateAPIKey(ctx, codersdk.Me)
require.NoError(t, err)
require.Greater(t, len(res.Key), 2)
require.True(t, auditor.Contains(t, database.AuditLog{
UserID: owner.UserID,
Action: database.AuditActionCreate,
ResourceType: database.ResourceTypeApiKey,
}))
}

func TestAPIKey_Deleted(t *testing.T) {
Expand Down
Loading