diff --git a/doc/administration/audit_event_streaming/audit_event_types.md b/doc/administration/audit_event_streaming/audit_event_types.md
index e9f2a4a611df90672b4e96e293c6789617a99909..5c27dabe378649354fab452f2d51de72fd3411da 100644
--- a/doc/administration/audit_event_streaming/audit_event_types.md
+++ b/doc/administration/audit_event_streaming/audit_event_types.md
@@ -152,6 +152,7 @@ audit events to external destinations.
| [`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_created`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130663) | Triggered when Instance level Google Cloud Logging configuration is created | **{check-circle}** Yes | **{check-circle}** Yes | `audit_events` | GitLab [16.4](https://gitlab.com/gitlab-org/gitlab/-/issues/423038) |
| [`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) |
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 12688851fb1fe279a48f2d3553634fcb0763548f..ef60be92ee274d65b7b462fdad397aa6c35baf1f 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -4096,6 +4096,29 @@ Input type: `InstanceExternalAuditEventDestinationUpdateInput`
| `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| `instanceExternalAuditEventDestination` | [`InstanceExternalAuditEventDestination`](#instanceexternalauditeventdestination) | Updated destination. |
+### `Mutation.instanceGoogleCloudLoggingConfigurationCreate`
+
+Input type: `InstanceGoogleCloudLoggingConfigurationCreateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `clientEmail` | [`String!`](#string) | Email address associated with the service account that will be used to authenticate and interact with the Google Cloud Logging service. This is part of the IAM credentials. |
+| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| `googleProjectIdName` | [`String!`](#string) | Unique identifier of the Google Cloud project to which the logging configuration belongs. |
+| `logIdName` | [`String`](#string) | Unique identifier used to distinguish and manage different logs within the same Google Cloud project.(defaults to `audit_events`). |
+| `name` | [`String`](#string) | Destination name. |
+| `privateKey` | [`String!`](#string) | Private Key associated with the service account. This key is used to authenticate the service account and authorize it to interact with the Google Cloud Logging service. |
+
+#### 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. |
+| `instanceGoogleCloudLoggingConfiguration` | [`InstanceGoogleCloudLoggingConfigurationType`](#instancegooglecloudloggingconfigurationtype) | configuration created. |
+
### `Mutation.instanceGoogleCloudLoggingConfigurationDestroy`
Input type: `InstanceGoogleCloudLoggingConfigurationDestroyInput`
diff --git a/ee/app/graphql/ee/types/mutation_type.rb b/ee/app/graphql/ee/types/mutation_type.rb
index 9467532e3d452fce92a89654826e98efb506846b..5332505397e41b9141e706a65d4d7e303850899c 100644
--- a/ee/app/graphql/ee/types/mutation_type.rb
+++ b/ee/app/graphql/ee/types/mutation_type.rb
@@ -122,6 +122,7 @@ module MutationType
mount_mutation ::Mutations::AuditEvents::GoogleCloudLoggingConfigurations::Create
mount_mutation ::Mutations::AuditEvents::GoogleCloudLoggingConfigurations::Destroy
mount_mutation ::Mutations::AuditEvents::GoogleCloudLoggingConfigurations::Update
+ mount_mutation ::Mutations::AuditEvents::Instance::GoogleCloudLoggingConfigurations::Create
mount_mutation ::Mutations::Forecasting::BuildForecast, alpha: { milestone: '16.0' }
mount_mutation ::Mutations::AuditEvents::Streaming::InstanceHeaders::Create
mount_mutation ::Mutations::AuditEvents::Streaming::InstanceHeaders::Update
diff --git a/ee/app/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/create.rb b/ee/app/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/create.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5e782db6188e0e97319f923ade0faf15111787eb
--- /dev/null
+++ b/ee/app/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/create.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+module Mutations
+ module AuditEvents
+ module Instance
+ module GoogleCloudLoggingConfigurations
+ class Create < Base
+ graphql_name 'InstanceGoogleCloudLoggingConfigurationCreate'
+
+ argument :name, GraphQL::Types::String,
+ required: false,
+ description: 'Destination name.'
+
+ argument :google_project_id_name, GraphQL::Types::String,
+ required: true,
+ description: 'Unique identifier of the Google Cloud project ' \
+ 'to which the logging configuration belongs.'
+
+ argument :client_email, GraphQL::Types::String,
+ required: true,
+ description: 'Email address associated with the service account ' \
+ 'that will be used to authenticate and interact with the ' \
+ 'Google Cloud Logging service. This is part of the IAM credentials.'
+
+ argument :log_id_name, GraphQL::Types::String,
+ required: false,
+ description: 'Unique identifier used to distinguish and manage ' \
+ 'different logs within the same Google Cloud project.' \
+ '(defaults to `audit_events`).',
+ default_value: 'audit_events'
+
+ argument :private_key, GraphQL::Types::String,
+ required: true,
+ description: 'Private Key associated with the service account. This key ' \
+ 'is used to authenticate the service account and authorize it ' \
+ 'to interact with the Google Cloud Logging service.'
+
+ field :instance_google_cloud_logging_configuration,
+ ::Types::AuditEvents::Instance::GoogleCloudLoggingConfigurationType,
+ null: true,
+ description: 'configuration created.'
+
+ def resolve(google_project_id_name:, client_email:, private_key:, log_id_name: nil, name: nil)
+ config_attributes = {
+ google_project_id_name: google_project_id_name,
+ client_email: client_email,
+ private_key: private_key,
+ name: name
+ }
+
+ config_attributes[:log_id_name] = log_id_name if log_id_name.present?
+
+ config = ::AuditEvents::Instance::GoogleCloudLoggingConfiguration.new(config_attributes)
+
+ if config.save
+ audit(config, action: :created)
+
+ { instance_google_cloud_logging_configuration: config, errors: [] }
+ else
+ { instance_google_cloud_logging_configuration: nil, errors: Array(config.errors) }
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/ee/config/audit_events/types/instance_google_cloud_logging_configuration_created.yml b/ee/config/audit_events/types/instance_google_cloud_logging_configuration_created.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2af527cc80cd37c0cbfc01291f2658529063426b
--- /dev/null
+++ b/ee/config/audit_events/types/instance_google_cloud_logging_configuration_created.yml
@@ -0,0 +1,9 @@
+---
+name: instance_google_cloud_logging_configuration_created
+description: Triggered when Instance level Google Cloud Logging configuration is created
+introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/423038
+introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130663
+milestone: '16.4'
+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/create_spec.rb b/ee/spec/requests/api/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/create_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a3bb728e370e5dbd411c1be4f7b7fd00eb28aaa0
--- /dev/null
+++ b/ee/spec/requests/api/graphql/mutations/audit_events/instance/google_cloud_logging_configurations/create_spec.rb
@@ -0,0 +1,162 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Create Instance level Google Cloud logging configuration', feature_category: :audit_events do
+ include GraphqlHelpers
+
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:destination_name) { 'my_google_destination' }
+ let_it_be(:google_project_id_name) { 'test-project' }
+ let_it_be(:client_email) { 'test-email@example.com' }
+ let_it_be(:private_key) { OpenSSL::PKey::RSA.new(4096).to_pem }
+ let_it_be(:log_id_name) { 'audit_events' }
+
+ let(:current_user) { admin }
+ let(:mutation) { graphql_mutation(:instance_google_cloud_logging_configuration_create, input) }
+ let(:mutation_response) { graphql_mutation_response(:instance_google_cloud_logging_configuration_create) }
+
+ let(:input) do
+ {
+ name: destination_name,
+ googleProjectIdName: google_project_id_name,
+ clientEmail: client_email,
+ privateKey: private_key
+ }
+ end
+
+ subject(:mutate) { post_graphql_mutation(mutation, current_user: current_user) }
+
+ shared_examples 'creates an audit event' do
+ before do
+ allow(Gitlab::Audit::Auditor).to receive(:audit)
+ end
+
+ it 'audits the creation' do
+ subject
+
+ config = AuditEvents::Instance::GoogleCloudLoggingConfiguration.last
+ expect(Gitlab::Audit::Auditor).to have_received(:audit) do |args|
+ expect(args[:name]).to eq('instance_google_cloud_logging_configuration_created')
+ 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("Created Instance Google Cloud logging configuration with name: #{destination_name} " \
+ "project id: #{google_project_id_name} and log id: #{log_id_name}")
+ end
+ end
+ end
+
+ shared_examples 'a mutation that does not create a configuration' do
+ it 'does not create 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
+
+ shared_examples 'an unauthorized mutation that does not create a configuration' do
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+
+ it_behaves_like 'a mutation that does not create a configuration'
+ end
+
+ context 'when feature is licensed' do
+ before do
+ stub_licensed_features(external_audit_events: true)
+ end
+
+ context 'when current user is an admin' do
+ it 'creates the configuration' do
+ expect { mutate }
+ .to change { AuditEvents::Instance::GoogleCloudLoggingConfiguration.count }.by(1)
+
+ config = AuditEvents::Instance::GoogleCloudLoggingConfiguration.last
+ expect(config.name).to eq(destination_name)
+ expect(config.google_project_id_name).to eq(google_project_id_name)
+ expect(config.client_email).to eq(client_email)
+ expect(config.log_id_name).to eq(log_id_name)
+ expect(config.private_key).to eq(private_key)
+
+ expect(mutation_response['errors']).to be_empty
+ expect(mutation_response['instanceGoogleCloudLoggingConfiguration']['googleProjectIdName'])
+ .to eq(google_project_id_name)
+ expect(mutation_response['instanceGoogleCloudLoggingConfiguration']['id']).not_to be_empty
+ expect(mutation_response['instanceGoogleCloudLoggingConfiguration']['name']).to eq(destination_name)
+ expect(mutation_response['instanceGoogleCloudLoggingConfiguration']['clientEmail']).to eq(client_email)
+ expect(mutation_response['instanceGoogleCloudLoggingConfiguration']['logIdName']).to eq(log_id_name)
+ end
+
+ it_behaves_like 'creates an audit event', 'audit_events'
+
+ context 'when overriding log id name' do
+ let_it_be(:log_id_name) { 'test-log-id' }
+
+ let(:input) do
+ {
+ name: destination_name,
+ googleProjectIdName: google_project_id_name,
+ clientEmail: client_email,
+ privateKey: private_key,
+ logIdName: log_id_name
+ }
+ end
+
+ it 'creates the configuration' do
+ expect { mutate }
+ .to change { AuditEvents::Instance::GoogleCloudLoggingConfiguration.count }.by(1)
+
+ config = AuditEvents::Instance::GoogleCloudLoggingConfiguration.last
+ expect(config.name).to eq(destination_name)
+ expect(config.google_project_id_name).to eq(google_project_id_name)
+ expect(config.client_email).to eq(client_email)
+ expect(config.log_id_name).to eq(log_id_name)
+ expect(config.private_key).to eq(private_key)
+ end
+
+ it_behaves_like 'creates an audit event'
+ end
+
+ context 'when there is error while saving' do
+ before do
+ allow_next_instance_of(AuditEvents::Instance::GoogleCloudLoggingConfiguration) do |instance|
+ allow(instance).to receive(:save).and_return(false)
+
+ errors = ActiveModel::Errors.new(instance).tap { |e| e.add(:log_id_name, 'error message') }
+ allow(instance).to receive(:errors).and_return(errors)
+ end
+ end
+
+ it 'does not create the configuration and returns the error' do
+ expect { mutate }
+ .not_to change { AuditEvents::Instance::GoogleCloudLoggingConfiguration.count }
+
+ expect(mutation_response).to include(
+ 'instanceGoogleCloudLoggingConfiguration' => nil,
+ 'errors' => ["Log id name error message"]
+ )
+ end
+ end
+ end
+
+ context 'when current user is not an admin' do
+ let_it_be(:current_user) { user }
+
+ it_behaves_like 'an unauthorized mutation that does not create a configuration'
+ end
+ end
+
+ context 'when feature is unlicensed' do
+ before do
+ stub_licensed_features(external_audit_events: false)
+ end
+
+ it_behaves_like 'an unauthorized mutation that does not create a configuration'
+ end
+end