diff --git a/lib/auth/auth.go b/lib/auth/auth.go index f53eaee43a885..c34d5bf7012ff 100644 --- a/lib/auth/auth.go +++ b/lib/auth/auth.go @@ -4536,6 +4536,16 @@ func (a *Server) CreateAccessRequestV2(ctx context.Context, req types.AccessRequ if _, err := a.Services.CreateAccessRequestV2(ctx, req); err != nil { return nil, trace.Wrap(err) } + + var annotations *apievents.Struct + if sa := req.GetSystemAnnotations(); len(sa) > 0 { + var err error + annotations, err = apievents.EncodeMapStrings(sa) + if err != nil { + log.WithError(err).Debug("Failed to encode access request annotations.") + } + } + err := a.emitter.EmitAuditEvent(a.closeCtx, &apievents.AccessRequestCreate{ Metadata: apievents.Metadata{ Type: events.AccessRequestCreateEvent, @@ -4551,6 +4561,7 @@ func (a *Server) CreateAccessRequestV2(ctx context.Context, req types.AccessRequ RequestState: req.GetState().String(), Reason: req.GetRequestReason(), MaxDuration: req.GetMaxDuration(), + Annotations: annotations, }) if err != nil { log.WithError(err).Warn("Failed to emit access request create event.") @@ -4651,6 +4662,13 @@ func (a *Server) SetAccessRequestState(ctx context.Context, params types.AccessR Roles: params.Roles, AssumeStartTime: params.AssumeStartTime, } + if sa := req.GetSystemAnnotations(); len(sa) > 0 { + var err error + event.Annotations, err = apievents.EncodeMapStrings(sa) + if err != nil { + log.WithError(err).Debug("Failed to encode access request annotations.") + } + } if delegator := apiutils.GetDelegator(ctx); delegator != "" { event.Delegator = delegator diff --git a/lib/auth/auth_test.go b/lib/auth/auth_test.go index a1c8aebff419f..5dafa65db2dbd 100644 --- a/lib/auth/auth_test.go +++ b/lib/auth/auth_test.go @@ -3252,3 +3252,61 @@ func TestGetTokens(t *testing.T) { _, err = s.a.GetTokens(ctx) require.NoError(t, err) } + +func TestAccessRequestAuditLog(t *testing.T) { + t.Parallel() + ctx := context.Background() + + p, err := newTestPack(ctx, t.TempDir()) + require.NoError(t, err) + + requester, _, _ := createSessionTestUsers(t, p.a) + + paymentsRole, err := types.NewRole("paymentsRole", types.RoleSpecV6{ + Allow: types.RoleConditions{ + Request: &types.AccessRequestConditions{ + Roles: []string{"requestRole"}, + Annotations: map[string][]string{ + "pagerduty_services": {"payments"}, + }, + }, + }, + }) + require.NoError(t, err) + + requestRole, err := types.NewRole("requestRole", types.RoleSpecV6{}) + require.NoError(t, err) + + p.a.CreateRole(ctx, requestRole) + p.a.CreateRole(ctx, paymentsRole) + + user, err := p.a.GetUser(requester, true) + require.NoError(t, err) + user.AddRole(paymentsRole.GetName()) + err = p.a.UpsertUser(user) + require.NoError(t, err) + + accessRequest, err := types.NewAccessRequest(uuid.NewString(), requester, "requestRole") + require.NoError(t, err) + req, err := p.a.CreateAccessRequestV2(ctx, accessRequest, TestUser(requester).I.GetIdentity()) + require.NoError(t, err) + + expectedAnnotations, err := apievents.EncodeMapStrings(paymentsRole.GetAccessRequestConditions(types.Allow).Annotations) + require.NoError(t, err) + + arc, ok := p.mockEmitter.LastEvent().(*apievents.AccessRequestCreate) + require.True(t, ok) + require.Equal(t, expectedAnnotations, arc.Annotations) + require.Equal(t, "PENDING", arc.RequestState) + + err = p.a.SetAccessRequestState(ctx, types.AccessRequestUpdate{ + RequestID: req.GetName(), + State: types.RequestState_APPROVED, + }) + require.NoError(t, err) + + arc, ok = p.mockEmitter.LastEvent().(*apievents.AccessRequestCreate) + require.True(t, ok) + require.Equal(t, expectedAnnotations, arc.Annotations) + require.Equal(t, "APPROVED", arc.RequestState) +}