feat: audit git ssh key regeneration (#4544)

This commit is contained in:
Colin Adler
2022-10-14 16:25:46 -05:00
committed by GitHub
parent dd8ebf10db
commit 7ec88bf841
8 changed files with 63 additions and 22 deletions

View File

@ -221,10 +221,18 @@ func convertAuditLog(dblog database.GetAuditLogsOffsetRow) codersdk.AuditLog {
}
func auditLogDescription(alog database.GetAuditLogsOffsetRow) string {
return fmt.Sprintf("{user} %s %s {target}",
str := fmt.Sprintf("{user} %s %s",
codersdk.AuditAction(alog.Action).FriendlyString(),
codersdk.ResourceType(alog.ResourceType).FriendlyString(),
)
// We don't display the name for git ssh keys. It's fairly long and doesn't
// make too much sense to display.
if alog.ResourceType != database.ResourceTypeGitSshKey {
str += " {target}"
}
return str
}
// auditSearchQuery takes a query string and returns the auditLog filter.

View File

@ -2676,7 +2676,7 @@ func (q *fakeQuerier) GetGitSSHKey(_ context.Context, userID uuid.UUID) (databas
return database.GitSSHKey{}, sql.ErrNoRows
}
func (q *fakeQuerier) UpdateGitSSHKey(_ context.Context, arg database.UpdateGitSSHKeyParams) error {
func (q *fakeQuerier) UpdateGitSSHKey(_ context.Context, arg database.UpdateGitSSHKeyParams) (database.GitSSHKey, error) {
q.mutex.Lock()
defer q.mutex.Unlock()
@ -2688,9 +2688,9 @@ func (q *fakeQuerier) UpdateGitSSHKey(_ context.Context, arg database.UpdateGitS
key.PrivateKey = arg.PrivateKey
key.PublicKey = arg.PublicKey
q.gitSSHKey[index] = key
return nil
return key, nil
}
return sql.ErrNoRows
return database.GitSSHKey{}, sql.ErrNoRows
}
func (q *fakeQuerier) InsertGroupMember(_ context.Context, arg database.InsertGroupMemberParams) error {

View File

@ -148,7 +148,7 @@ type sqlcQuerier interface {
ParameterValue(ctx context.Context, id uuid.UUID) (ParameterValue, error)
ParameterValues(ctx context.Context, arg ParameterValuesParams) ([]ParameterValue, error)
UpdateAPIKeyByID(ctx context.Context, arg UpdateAPIKeyByIDParams) error
UpdateGitSSHKey(ctx context.Context, arg UpdateGitSSHKeyParams) error
UpdateGitSSHKey(ctx context.Context, arg UpdateGitSSHKeyParams) (GitSSHKey, error)
UpdateGroupByID(ctx context.Context, arg UpdateGroupByIDParams) (Group, error)
UpdateMemberRoles(ctx context.Context, arg UpdateMemberRolesParams) (OrganizationMember, error)
UpdateProvisionerDaemonByID(ctx context.Context, arg UpdateProvisionerDaemonByIDParams) error

View File

@ -815,7 +815,7 @@ func (q *sqlQuerier) InsertGitSSHKey(ctx context.Context, arg InsertGitSSHKeyPar
return i, err
}
const updateGitSSHKey = `-- name: UpdateGitSSHKey :exec
const updateGitSSHKey = `-- name: UpdateGitSSHKey :one
UPDATE
gitsshkeys
SET
@ -824,6 +824,8 @@ SET
public_key = $4
WHERE
user_id = $1
RETURNING
user_id, created_at, updated_at, private_key, public_key
`
type UpdateGitSSHKeyParams struct {
@ -833,14 +835,22 @@ type UpdateGitSSHKeyParams struct {
PublicKey string `db:"public_key" json:"public_key"`
}
func (q *sqlQuerier) UpdateGitSSHKey(ctx context.Context, arg UpdateGitSSHKeyParams) error {
_, err := q.db.ExecContext(ctx, updateGitSSHKey,
func (q *sqlQuerier) UpdateGitSSHKey(ctx context.Context, arg UpdateGitSSHKeyParams) (GitSSHKey, error) {
row := q.db.QueryRowContext(ctx, updateGitSSHKey,
arg.UserID,
arg.UpdatedAt,
arg.PrivateKey,
arg.PublicKey,
)
return err
var i GitSSHKey
err := row.Scan(
&i.UserID,
&i.CreatedAt,
&i.UpdatedAt,
&i.PrivateKey,
&i.PublicKey,
)
return i, err
}
const deleteGroupByID = `-- name: DeleteGroupByID :exec

View File

@ -18,7 +18,7 @@ FROM
WHERE
user_id = $1;
-- name: UpdateGitSSHKey :exec
-- name: UpdateGitSSHKey :one
UPDATE
gitsshkeys
SET
@ -26,7 +26,9 @@ SET
private_key = $3,
public_key = $4
WHERE
user_id = $1;
user_id = $1
RETURNING
*;
-- name: DeleteGitSSHKey :exec
DELETE FROM

View File

@ -3,6 +3,7 @@ package coderd
import (
"net/http"
"github.com/coder/coder/coderd/audit"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/gitsshkey"
"github.com/coder/coder/coderd/httpapi"
@ -12,14 +13,32 @@ import (
)
func (api *API) regenerateGitSSHKey(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.GitSSHKey](rw, &audit.RequestParams{
Audit: *auditor,
Log: api.Logger,
Request: r,
Action: database.AuditActionWrite,
})
)
defer commitAudit()
if !api.Authorize(r, rbac.ActionUpdate, rbac.ResourceUserData.WithOwner(user.ID.String())) {
httpapi.ResourceNotFound(rw)
return
}
oldKey, err := api.Database.GetGitSSHKey(ctx, user.ID)
if err != nil {
httpapi.InternalServerError(rw, err)
return
}
aReq.Old = oldKey
privateKey, publicKey, err := gitsshkey.Generate(api.SSHKeygenAlgorithm)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
@ -29,7 +48,7 @@ func (api *API) regenerateGitSSHKey(rw http.ResponseWriter, r *http.Request) {
return
}
err = api.Database.UpdateGitSSHKey(ctx, database.UpdateGitSSHKeyParams{
newKey, err := api.Database.UpdateGitSSHKey(ctx, database.UpdateGitSSHKeyParams{
UserID: user.ID,
UpdatedAt: database.Now(),
PrivateKey: privateKey,
@ -43,14 +62,7 @@ func (api *API) regenerateGitSSHKey(rw http.ResponseWriter, r *http.Request) {
return
}
newKey, err := api.Database.GetGitSSHKey(ctx, user.ID)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching user's git SSH key.",
Detail: err.Error(),
})
return
}
aReq.New = newKey
httpapi.Write(ctx, rw, http.StatusOK, codersdk.GitSSHKey{
UserID: newKey.UserID,

View File

@ -5,9 +5,12 @@ import (
"testing"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/coder/coder/coderd/audit"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/gitsshkey"
"github.com/coder/coder/codersdk"
"github.com/coder/coder/provisioner/echo"
@ -73,8 +76,10 @@ func TestGitSSHKey(t *testing.T) {
})
t.Run("Regenerate", func(t *testing.T) {
t.Parallel()
auditor := audit.NewMock()
client := coderdtest.New(t, &coderdtest.Options{
SSHKeygenAlgorithm: gitsshkey.AlgorithmEd25519,
Auditor: auditor,
})
res := coderdtest.CreateFirstUser(t, client)
@ -89,6 +94,9 @@ func TestGitSSHKey(t *testing.T) {
require.GreaterOrEqual(t, key2.UpdatedAt, key1.UpdatedAt)
require.NotEmpty(t, key2.PublicKey)
require.NotEqual(t, key2.PublicKey, key1.PublicKey)
require.Len(t, auditor.AuditLogs, 1)
assert.Equal(t, database.AuditActionWrite, auditor.AuditLogs[0].Action)
})
}