diff --git a/doc/administration/audit_event_streaming/audit_event_types.md b/doc/administration/audit_event_streaming/audit_event_types.md
index 01523e173546bae82f18c5736f292c1c91fbc9e4..79f92cb74aedbda1e027cc49993dabc9324c3e43 100644
--- a/doc/administration/audit_event_streaming/audit_event_types.md
+++ b/doc/administration/audit_event_streaming/audit_event_types.md
@@ -149,6 +149,7 @@ Every audit event is associated with an event type. The association with the eve
| [`incident_closed_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an incident is closed using a project access token | **{check-circle}** Yes | **{check-circle}** Yes | `incident_management` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
| [`incident_created_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an incident is created using a project access token | **{check-circle}** Yes | **{check-circle}** Yes | `incident_management` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
| [`incident_reopened_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an incident is reopened using a project access token | **{check-circle}** Yes | **{check-circle}** Yes | `incident_management` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
+| [`instance_google_cloud_logging_configuration_deleted`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131752) | Triggered when instance level Google Cloud Logging configuration is deleted. | **{check-circle}** Yes | **{check-circle}** Yes | `audit_events` | GitLab [16.5](https://gitlab.com/gitlab-org/gitlab/-/issues/423040) |
| [`ip_restrictions_changed`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86037) | Event triggered on any changes in the IP AllowList | **{check-circle}** Yes | **{check-circle}** Yes | `system_access` | GitLab [15.0](https://gitlab.com/gitlab-org/gitlab/-/issues/358986) |
| [`issue_closed_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an issue is closed using a project access token | **{check-circle}** Yes | **{check-circle}** Yes | `team_planning` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
| [`issue_created_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an issue is created using a project access token | **{check-circle}** Yes | **{check-circle}** Yes | `team_planning` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 78f2f584a8a0a6cdce7410cca50ade91a6743c6d..a413ef0ac3109692fb47e2f79f048a2c55636551 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -4085,6 +4085,24 @@ Input type: `InstanceExternalAuditEventDestinationUpdateInput`
| `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| `instanceExternalAuditEventDestination` | [`InstanceExternalAuditEventDestination`](#instanceexternalauditeventdestination) | Updated destination. |
+### `Mutation.instanceGoogleCloudLoggingConfigurationDestroy`
+
+Input type: `InstanceGoogleCloudLoggingConfigurationDestroyInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| `id` | [`AuditEventsInstanceGoogleCloudLoggingConfigurationID!`](#auditeventsinstancegooglecloudloggingconfigurationid) | ID of the Google Cloud logging configuration to destroy. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+
### `Mutation.issuableResourceLinkCreate`
Input type: `IssuableResourceLinkCreateInput`
@@ -29218,6 +29236,12 @@ A `AuditEventsInstanceExternalAuditEventDestinationID` is a global ID. It is enc
An example `AuditEventsInstanceExternalAuditEventDestinationID` is: `"gid://gitlab/AuditEvents::InstanceExternalAuditEventDestination/1"`.
+### `AuditEventsInstanceGoogleCloudLoggingConfigurationID`
+
+A `AuditEventsInstanceGoogleCloudLoggingConfigurationID` is a global ID. It is encoded as a string.
+
+An example `AuditEventsInstanceGoogleCloudLoggingConfigurationID` is: `"gid://gitlab/AuditEvents::Instance::GoogleCloudLoggingConfiguration/1"`.
+
### `AuditEventsStreamingHeaderID`
A `AuditEventsStreamingHeaderID` is a global ID. It is encoded as a string.
diff --git a/ee/app/graphql/ee/types/mutation_type.rb b/ee/app/graphql/ee/types/mutation_type.rb
index 6fa6ee1ae077b63befa7cd4249024e948f262ede..9467532e3d452fce92a89654826e98efb506846b 100644
--- a/ee/app/graphql/ee/types/mutation_type.rb
+++ b/ee/app/graphql/ee/types/mutation_type.rb
@@ -129,6 +129,7 @@ module MutationType
mount_mutation ::Mutations::AuditEvents::Streaming::InstanceEventTypeFilters::Create
mount_mutation ::Mutations::AuditEvents::Streaming::InstanceEventTypeFilters::Destroy
mount_mutation ::Mutations::Security::CiConfiguration::ProjectSetContinuousVulnerabilityScanning
+ mount_mutation ::Mutations::AuditEvents::Instance::GoogleCloudLoggingConfigurations::Destroy
prepend(Types::DeprecatedMutations)
end
diff --git a/ee/app/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/base.rb b/ee/app/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/base.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1b10b196f5202d355c0d225de172e40730ec7ab7
--- /dev/null
+++ b/ee/app/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/base.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+module Mutations
+ module AuditEvents
+ module Instance
+ module GoogleCloudLoggingConfigurations
+ class Base < BaseMutation
+ authorize :admin_instance_external_audit_events
+
+ def ready?(**args)
+ raise_resource_not_available_error! unless current_user&.can?(:admin_instance_external_audit_events)
+
+ super
+ end
+
+ private
+
+ def find_object(config_gid)
+ destination = GitlabSchema.object_from_id(
+ config_gid,
+ expected_type: ::AuditEvents::Instance::GoogleCloudLoggingConfiguration).sync
+
+ raise_resource_not_available_error! if destination.blank?
+
+ destination
+ end
+
+ def audit(config, action:)
+ audit_context = {
+ name: "instance_google_cloud_logging_configuration_#{action}",
+ author: current_user,
+ scope: Gitlab::Audit::InstanceScope.new,
+ target: config,
+ message: "#{action.capitalize} Instance Google Cloud logging configuration with name: #{config.name} " \
+ "project id: #{config.google_project_id_name} and log id: #{config.log_id_name}"
+ }
+
+ ::Gitlab::Audit::Auditor.audit(audit_context)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/ee/app/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/destroy.rb b/ee/app/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/destroy.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ebf7b98794146c8b5da601edbbdb48bb6b9db7d9
--- /dev/null
+++ b/ee/app/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/destroy.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Mutations
+ module AuditEvents
+ module Instance
+ module GoogleCloudLoggingConfigurations
+ class Destroy < Base
+ graphql_name 'InstanceGoogleCloudLoggingConfigurationDestroy'
+
+ argument :id, ::Types::GlobalIDType[::AuditEvents::Instance::GoogleCloudLoggingConfiguration],
+ required: true,
+ description: 'ID of the Google Cloud logging configuration to destroy.'
+
+ def resolve(id:)
+ config = authorized_find!(id)
+
+ audit(config, action: :deleted) if config.destroy
+
+ { errors: Array(config.errors) }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/ee/config/audit_events/types/instance_google_cloud_logging_configuration_deleted.yml b/ee/config/audit_events/types/instance_google_cloud_logging_configuration_deleted.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5ef3f8908ffedeab1df3442ed39e07886f792bd9
--- /dev/null
+++ b/ee/config/audit_events/types/instance_google_cloud_logging_configuration_deleted.yml
@@ -0,0 +1,9 @@
+---
+name: instance_google_cloud_logging_configuration_deleted
+description: Triggered when instance level Google Cloud Logging configuration is deleted.
+introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/423040
+introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131752
+milestone: '16.5'
+feature_category: audit_events
+saved_to_database: true
+streamed: true
diff --git a/ee/spec/requests/api/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/destroy_spec.rb b/ee/spec/requests/api/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/destroy_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d3853463dfedd6600afdfbbbaf346005e9d4ad7c
--- /dev/null
+++ b/ee/spec/requests/api/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/destroy_spec.rb
@@ -0,0 +1,96 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Destroy Instance Google Cloud logging configuration', feature_category: :audit_events do
+ include GraphqlHelpers
+
+ let_it_be(:config) { create(:instance_google_cloud_logging_configuration) }
+ let_it_be(:admin) { create(:admin) }
+
+ let(:current_user) { admin }
+ let(:mutation) { graphql_mutation(:instance_google_cloud_logging_configuration_destroy, id: global_id_of(config)) }
+ let(:mutation_response) { graphql_mutation_response(:instance_google_cloud_logging_configuration_destroy) }
+
+ subject(:mutate) { post_graphql_mutation(mutation, current_user: current_user) }
+
+ shared_examples 'a mutation that does not destroy a configuration' do
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+
+ it 'does not destroy the configuration' do
+ expect { mutate }
+ .not_to change { AuditEvents::Instance::GoogleCloudLoggingConfiguration.count }
+ end
+
+ it 'does not create audit event' do
+ expect { mutate }.not_to change { AuditEvent.count }
+ end
+ end
+
+ context 'when feature is licensed' do
+ before do
+ stub_licensed_features(external_audit_events: true)
+ end
+
+ context 'when current user is instance admin' do
+ before do
+ allow(Gitlab::Audit::Auditor).to receive(:audit)
+ end
+
+ it 'destroys the configuration' do
+ expect { mutate }
+ .to change { AuditEvents::Instance::GoogleCloudLoggingConfiguration.count }.by(-1)
+ end
+
+ it 'audits the deletion' do
+ subject
+
+ expect(Gitlab::Audit::Auditor).to have_received(:audit) do |args|
+ expect(args[:name]).to eq('instance_google_cloud_logging_configuration_deleted')
+ expect(args[:author]).to eq(current_user)
+ expect(args[:scope]).to be_an_instance_of(Gitlab::Audit::InstanceScope)
+ expect(args[:target]).to eq(config)
+ expect(args[:message])
+ .to eq("Deleted Instance Google Cloud logging configuration with name: #{config.name} " \
+ "project id: #{config.google_project_id_name} and log id: #{config.log_id_name}")
+ end
+ end
+
+ context 'when there is an error during destroy' do
+ before do
+ allow_next_instance_of(
+ Mutations::AuditEvents::Instance::GoogleCloudLoggingConfigurations::Destroy) do |mutation|
+ allow(mutation).to receive(:authorized_find!).and_return(config)
+ end
+
+ allow(config).to receive(:destroy).and_return(false)
+
+ errors = ActiveModel::Errors.new(config).tap { |e| e.add(:base, 'error message') }
+ allow(config).to receive(:errors).and_return(errors)
+ end
+
+ it 'does not destroy the configuration and returns the error' do
+ expect { mutate }
+ .not_to change { AuditEvents::Instance::GoogleCloudLoggingConfiguration.count }
+
+ expect(mutation_response).to include('errors' => ['error message'])
+ end
+ end
+ end
+
+ context 'when current user is not instance admin' do
+ let_it_be(:current_user) { create(:user) }
+
+ it_behaves_like 'a mutation that does not destroy a configuration'
+ end
+ end
+
+ context 'when feature is unlicensed' do
+ before do
+ stub_licensed_features(external_audit_events: false)
+ end
+
+ it_behaves_like 'a mutation that does not destroy a configuration'
+ end
+end