Add audit event for service account creation

What does this MR do and why?

Adds a new service_account_created audit event that fires whenever a service account is successfully created at the instance, group, or project level.

Currently, service account creation only triggers the generic user_created audit event (via the EE Users::CreateService prepend chain), which provides no service-account-specific context. This makes it difficult for administrators and SIEM integrations to distinguish service account creation from regular user creation — a gap in audit coverage given that service accounts have elevated access.

Changes

  • New audit event type (ee/config/audit_events/types/service_account_created.yml): Defines service_account_created with scope [User, Group, Project], saved_to_database: true, and streamed: true.
  • Audit call in base service (ee/app/services/users/service_accounts/create_service.rb): Added log_service_account_audit_event after successful creation in execute. Uses a polymorphic audit_scope method that returns the created user (instance-level).
  • Scope override in namespace service (ee/app/services/namespaces/service_accounts/create_service.rb): Overrides audit_scope to return the group or project resource.
  • Tests: Covers instance/group/project-level creation, scope correctness, dual event verification (user_created + service_account_created), skip_owner_check path, and failure scenarios.

Note on duplicate audit events

Both user_created and service_account_created will fire on successful service account creation. This is intentional — they serve different purposes:

  • user_created is a generic user lifecycle event
  • service_account_created is a security-specific event with the correct scope (group/project) for SIEM filtering

References

Screenshots or screen recordings

Not applicable — no UI changes. This is a backend-only audit event addition.

How to set up and validate locally

  1. Ensure you have an Ultimate license (audit events require it)
  2. Create an instance-level service account via the API:
    curl --request POST --header "PRIVATE-TOKEN: <admin_token>" \
      "http://localhost:3000/api/v4/service_accounts"
  3. Check audit events in rails console:
    AuditEvent.where(event_name: 'service_account_created').last
  4. Verify the event has the correct scope, target, and message
  5. Repeat for group-level and project-level service accounts:
    # Group-level
    curl --request POST --header "PRIVATE-TOKEN: <token>" \
      "http://localhost:3000/api/v4/groups/<group_id>/service_accounts"
    
    # Project-level
    curl --request POST --header "PRIVATE-TOKEN: <token>" \
      "http://localhost:3000/api/v4/projects/<project_id>/service_accounts"

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by ŁUKASZ KORBASIEWICZ

Merge request reports

Loading