[Backend] Add audit events on change in instance level external audit event destinations
With APIs added in !115157 (merged) instance level external audit events destinations can be added, updated and destroyed. We need to log audit events for such operations.
Implementation plan
- Currently the only scopes supported for audit events are
user, group and project
refer https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/audit/auditor.rb#L17. - For audit events for changes made on instance level, we can consider creating a new abstract scope
instance_scope
, it will be similar to https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/audit/unauthenticated_author.rb. - For this we can create a new class
InstanceScope
, which will have some required attributes and methods for a scope such asid, name, full_path and licensed_feature_available?()
. - We can provide dummy values to attributes
id, name and full_path
. - For
licensed_feature_available?
, we can simply consider whether the license is supported for instance or not. - This method handles the instance scope without involving any database queries.
Alternate Implementation plan
- Currently the only scopes supported for audit events are
user, group and project
refer https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/audit/auditor.rb#L17. - For supporting changes made on instance level, which means to application settings. We can consider a new scope
application_settings
which is unique to an instance. - In AuditEvent, the scope is stored in polymorphic form under parameter
entity
for which the attributesentity_id
andentity_type
are stored in theaudit_events
table. Since we have an entity forapplication_settings
, it would fit perfectly under thisentity
reference. - Even though all instance level changes need not to be in
application_settings
table but they will be in other tables representing instance/application, so I think using theapplication_settings
as scope is justified. Similar thing is done for group and project settings, where changes are actually made in some other tables but scope isgroup
orproject
. - The audit event context could be something like as created in !123335 (diffs).
module Audit
class InstanceAuditEventsHelper
def self.log_audit_event(user, event_type, message, target = nil)
application_setting = ApplicationSetting.current
target = application_setting if target.nil?
audit_context = {
name: event_type,
author: user,
scope: application_setting,
target: target,
message: message
}
::Gitlab::Audit::Auditor.audit(audit_context)
end
end
end
- Regarding the method
audit_enabled?
in https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/ee/gitlab/audit/auditor.rb#L35, we can add a check for::License.feature_available?(:audit_events)
if scope isApplicationSetting
. This was not necessary as we already have a check::License.feature_available?(:extended_audit_events)
which will be true for premium and ultimate customer, but to maintain consistency I am adding this check.
Verification steps:
- For this you need to have Ultimate license for the gitlab instance and instance admin access.
- Since this requires instance admin access, I am using staging-ref environment here.
- Login as instance admin on https://staging-ref.gitlab.com/.
- Visit https://staging-ref.gitlab.com/admin/audit_logs?tab=streams.
- Add a new streaming destination by clicking on "Add streaming destination" button and then select "HTTP endpoint".
- Add a streaming destination url, for example "https://www.example.com", then click on "Add" button.
- Visit https://staging-ref.gitlab.com/admin/audit_logs?tab=log and refresh the page and you will see a new audit event for this destination being added in the logs.
- Now for update, we can't do it from UI, so lets do it via API.
- Open https://staging-ref.gitlab.com/-/graphql-explorer for running graphql queries and mutations.
- Run following query in graphql explorer for listing down all the destinations and note down the gid of the destination you want to update:
query {
instanceExternalAuditEventDestinations {
nodes {
id
destinationUrl
verificationToken
headers {
nodes {
id
key
value
}
}
}
}
}
- Run following mutation to update the destination, replace the gid with one obtained in step 5
mutation {
instanceExternalAuditEventDestinationUpdate(input: {
id: "gid://gitlab/AuditEvents::InstanceExternalAuditEventDestination/<id>",
destinationUrl: "https://www.newexample.com"
}) {
errors
instanceExternalAuditEventDestination {
destinationUrl
id
verificationToken
}
}
}
- Visit https://staging-ref.gitlab.com/admin/audit_logs?tab=log and refresh the page, there will be a new audit event related to destination update.
- Visit https://staging-ref.gitlab.com/admin/audit_logs?tab=streams again for deleting the destination.
- Click on the destination and then click the
Delete destination
button. - Again visit https://staging-ref.gitlab.com/admin/audit_logs?tab=log and refresh the page, there should be an audit event for deletion of the destination.
Edited by Hitesh Raghuvanshi