From 11d49b995a9e6f47b16a07309950b5db01603f81 Mon Sep 17 00:00:00 2001 From: Hinam Mehra Date: Tue, 29 Oct 2024 22:23:38 +1100 Subject: [PATCH] Add audit event for when job token policies are updated - Creates a new audit event, secure_ci_job_token_policies_updated - Extends service UpdatePoliciesService to EE, which will log an audit event when CI job token policies are updated EE: true --- .../update_policies_service.rb | 2 + .../secure_ci_job_token_policies_updated.yml | 10 +++ doc/user/compliance/audit_event_types.md | 6 ++ .../update_policies_service.rb | 37 ++++++++++ .../update_policies_service_spec.rb | 67 +++++++++++++++++++ 5 files changed, 122 insertions(+) create mode 100644 config/audit_events/types/secure_ci_job_token_policies_updated.yml create mode 100644 ee/app/services/ee/ci/job_token_scope/update_policies_service.rb create mode 100644 ee/spec/services/ee/ci/job_token_scope/update_policies_service_spec.rb diff --git a/app/services/ci/job_token_scope/update_policies_service.rb b/app/services/ci/job_token_scope/update_policies_service.rb index b55c259f2e9b04..8cad91deb0de03 100644 --- a/app/services/ci/job_token_scope/update_policies_service.rb +++ b/app/services/ci/job_token_scope/update_policies_service.rb @@ -71,3 +71,5 @@ def find_link_using_source_and_target(target) end end end + +Ci::JobTokenScope::UpdatePoliciesService.prepend_mod_with('Ci::JobTokenScope::UpdatePoliciesService') diff --git a/config/audit_events/types/secure_ci_job_token_policies_updated.yml b/config/audit_events/types/secure_ci_job_token_policies_updated.yml new file mode 100644 index 00000000000000..7bb2108405e2b2 --- /dev/null +++ b/config/audit_events/types/secure_ci_job_token_policies_updated.yml @@ -0,0 +1,10 @@ +--- +name: secure_ci_job_token_policies_updated +description: Event triggered when permissions are updated for a CI_JOB_TOKEN scope +introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/495144 +introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/170930 +feature_category: authorization +milestone: '17.6' +saved_to_database: true +streamed: true +scope: [Project] diff --git a/doc/user/compliance/audit_event_types.md b/doc/user/compliance/audit_event_types.md index 723e6d429d72c4..3653d485c61aeb 100644 --- a/doc/user/compliance/audit_event_types.md +++ b/doc/user/compliance/audit_event_types.md @@ -92,6 +92,12 @@ Audit event types belong to the following product categories. | [`updated_group_audit_event_streaming_destination`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/148388) | Event triggered when an external audit event destination for a top-level group is updated. | **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.11](https://gitlab.com/gitlab-org/gitlab/-/issues/436610) | Group | | [`updated_instance_audit_event_streaming_destination`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/149104) | Event triggered when an external audit event destination for a GitLab instance is updated. | **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.11](https://gitlab.com/gitlab-org/gitlab/-/issues/436615) | Instance | +### Authorization + +| Name | Description | Saved to database | Streamed | Introduced in | Scope | +|:------------|:------------|:------------------|:---------|:--------------|:--------------| +| [`secure_ci_job_token_policies_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/170930) | Event triggered when permissions are updated for a CI_JOB_TOKEN scope | **{check-circle}** Yes | **{check-circle}** Yes | GitLab [17.6](https://gitlab.com/gitlab-org/gitlab/-/issues/495144) | Project | + ### Build artifacts | Name | Description | Saved to database | Streamed | Introduced in | Scope | diff --git a/ee/app/services/ee/ci/job_token_scope/update_policies_service.rb b/ee/app/services/ee/ci/job_token_scope/update_policies_service.rb new file mode 100644 index 00000000000000..6f0544e59fb6c5 --- /dev/null +++ b/ee/app/services/ee/ci/job_token_scope/update_policies_service.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module EE + module Ci + module JobTokenScope + module UpdatePoliciesService + extend ::Gitlab::Utils::Override + + override :execute + def execute(target, policies) + super.tap do |response| + audit(project, target, current_user, policies) if response.success? + end + end + + private + + def audit(scope, target, author, policies) + audit_message = + "CI job token policies updated to: #{policies.join(', ')}" + + event_name = 'secure_ci_job_token_policies_updated' + + audit_context = { + name: event_name, + author: author, + scope: scope, + target: target, + message: audit_message + } + + ::Gitlab::Audit::Auditor.audit(audit_context) + end + end + end + end +end diff --git a/ee/spec/services/ee/ci/job_token_scope/update_policies_service_spec.rb b/ee/spec/services/ee/ci/job_token_scope/update_policies_service_spec.rb new file mode 100644 index 00000000000000..9319968e10b317 --- /dev/null +++ b/ee/spec/services/ee/ci/job_token_scope/update_policies_service_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::JobTokenScope::UpdatePoliciesService, feature_category: :continuous_integration do + let_it_be(:project) { create(:project) } + let_it_be(:target_project) { create(:project) } + + let_it_be(:current_user) { create(:user, maintainer_of: project, developer_of: target_project) } + + let(:policies) { %w[read_project read_container_image] } + + subject(:service_result) do + described_class.new(project, current_user).execute(target_project, policies) + end + + describe '#execute' do + context 'when the link to update exists' do + before_all do + create(:ci_job_token_project_scope_link, + source_project: project, + target_project: target_project, + job_token_policies: %w[read_project read_package], + direction: :inbound + ) + end + + let(:audit_event) do + { + name: 'secure_ci_job_token_policies_updated', + author: current_user, + scope: project, + target: target_project, + message: 'CI job token policies updated to: read_project, read_container_image' + } + end + + it 'returns a success response', :aggregate_failures do + expect(service_result).to be_success + + link = service_result.payload + + expect(link.source_project).to eq(project) + expect(link.target_project).to eq(target_project) + expect(link.job_token_policies).to eq(policies) + end + + it 'audits the event' do + expect(::Gitlab::Audit::Auditor).to receive(:audit).with(audit_event) + + service_result + end + end + + context 'when the link to update does not exist' do + it 'returns an error response' do + expect(service_result).to be_error + end + + it 'does not audit the event' do + expect(::Gitlab::Audit::Auditor).not_to receive(:audit) + + service_result + end + end + end +end -- GitLab