diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-19 18:44:42 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-19 18:44:42 +0300 |
commit | 4555e1b21c365ed8303ffb7a3325d773c9b8bf31 (patch) | |
tree | 5423a1c7516cffe36384133ade12572cf709398d /doc/development/audit_event_guide | |
parent | e570267f2f6b326480d284e0164a6464ba4081bc (diff) |
Add latest changes from gitlab-org/gitlab@13-12-stable-eev13.12.0-rc42
Diffstat (limited to 'doc/development/audit_event_guide')
-rw-r--r-- | doc/development/audit_event_guide/index.md | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/doc/development/audit_event_guide/index.md b/doc/development/audit_event_guide/index.md new file mode 100644 index 00000000000..0bff297f2a0 --- /dev/null +++ b/doc/development/audit_event_guide/index.md @@ -0,0 +1,181 @@ +--- +stage: Manage +group: Compliance +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +--- + +# Audit Event Guide + +This guide provides an overview of how Audit Events work, and how to instrument +new audit events. + +## What are Audit Events? + +Audit Events are a tool for GitLab owners and administrators to view records of important +actions performed across the application. + +## Audit Event Schemas + +To instrument an audit event, the following attributes should be provided: + +| Attribute | Type | Required? | Description | +|:-------------|:---------------------|:----------|:----------------------------------------------------| +| `name` | string | false | Action name to be audited. Used for error tracking | +| `author` | User | true | User who authors the change | +| `scope` | User, Project, Group | true | Scope which the audit event belongs to | +| `target` | Object | true | Target object being audited | +| `ip_address` | IPAddr | false | Request IP address | +| `message` | string | true | Message describing the action | + +## How to instrument new Audit Events + +There are three ways of instrumenting audit events: + +- Create a new class in `ee/lib/ee/audit/` and extend `AuditEventService` +- Call `AuditEventService` after a successful action +- Call `Gitlab::Audit::Auditor.audit` passing an action block + +This inconsistency leads to unexpected bugs, increases maintainer effort, and worsens the +developer experience. Therefore, we suggest you use `Gitlab::Audit::Auditor` to +instrument new audit events. + +With new service, we can instrument audit events in two ways: + +- Using block for multiple events. +- Using standard method call for single events. + +### Using block to record multiple events + +This method is useful when events are emitted deep in the call stack. + +For example, we can record multiple audit events when the user updates a merge +request approval rule. As part of this user flow, we would like to audit changes +to both approvers and approval groups. In the initiating service +(for example, `MergeRequestRuleUpdateService`), we can wrap the `execute` call as follows: + +```ruby +# in the initiating service +audit_context = { + name: 'merge_approval_rule_updated', + author: current_user, + scope: project_alpha, + target: merge_approval_rule, + ip_address: request.remote_ip, + message: 'Attempted to update an approval rule' +} + +Gitlab::Audit::Auditor.audit(audit_context) do + service.execute +end +``` + +In the model (for example, `ApprovalProjectRule`), we can push audit events on model +callbacks (for example, `after_save` or `after_add`). + +```ruby +# in the model +include Auditable + +def audit_add(model) + push_audit_event('Added an approver on Security rule') +end + +def audit_remove(model) + push_audit_event('Removed an approver on Security rule') +end +``` + +Please note that this method does not support actions that are asynchronous, or +span across multiple processes (for example, background jobs). + +### Using standard method call to record single event + +This method allows recording single audit event and involves fewer moving parts. + +```ruby +if merge_approval_rule.save + audit_context = { + name: 'merge_approval_rule_created', + author: current_user, + scope: project_alpha, + target: merge_approval_rule, + ip_address: request.remote_ip, + message: 'Created a new approval rule' + } + + Gitlab::Audit::Auditor.audit(audit_context) +end +``` + +## Audit Event instrumentation flows + +The two ways we can instrument audit events have different flows. + +### Using block to record multiple events + +We wrap the operation block in a `Gitlab::Audit::Auditor` which captures the +initial audit context (that is, `author`, `scope`, `target`, `ip_address`) object that are +available at the time the operation is initiated. + +Extra instrumentation is required in the interacted classes in the chain with +`Auditable` mixin to add audit events to the Audit Event queue via `Gitlab::Audit::EventQueue`. + +The `EventQueue` is stored in a local thread via `SafeRequestStore` and then later +extracted when we record an audit event in `Gitlab::Audit::Auditor`. + +```plantuml +skinparam shadowing false +skinparam BoxPadding 10 +skinparam ParticipantPadding 20 + +participant "Instrumented Class" as A +participant "Audit::Auditor" as A1 #LightBlue +participant "Audit::EventQueue" as B #LightBlue +participant "Interacted Class" as C +participant "AuditEvent" as D + +A->A1: audit <b>{ block } +activate A1 +A1->B: begin! +A1->C: <b>block.call +activate A1 #FFBBBB +activate C +C-->B: push [ message ] +C-->A1: true +deactivate A1 +deactivate C +A1->B: read +activate A1 #FFBBBB +activate B +B-->A1: [ messages ] +deactivate B +A1->D: bulk_insert! +deactivate A1 +A1->B: end! +A1-->A: +deactivate A1 +``` + +### Using standard method call to record single event + +This method has a more straight-forward flow, and does not rely on `EventQueue` +and local thread. + +```plantuml +skinparam shadowing false +skinparam BoxPadding 10 +skinparam ParticipantPadding 20 + +participant "Instrumented Class" as A +participant "Audit::Auditor" as B #LightBlue +participant "AuditEvent" as C + +A->B: audit +activate B +B->C: bulk_insert! +B-->A: +deactivate B +``` + +In addition to recording to the database, we also write these events to +[a log file](../../administration/logs.md#audit_jsonlog). |