diff options
-rw-r--r-- | app/policies/project_policy.rb | 2 | ||||
-rw-r--r-- | doc/ci/jobs/ci_job_token.md | 13 | ||||
-rw-r--r-- | doc/update/index.md | 15 | ||||
-rw-r--r-- | spec/policies/project_policy_spec.rb | 46 | ||||
-rw-r--r-- | spec/requests/api/npm_project_packages_spec.rb | 4 | ||||
-rw-r--r-- | spec/requests/lfs_http_spec.rb | 6 |
6 files changed, 48 insertions, 38 deletions
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index cdb7c3eca46..c70dc288710 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -670,7 +670,7 @@ class ProjectPolicy < BasePolicy enable :read_project_for_iids end - rule { ~project_allowed_for_job_token }.prevent_all + rule { ~public_project & ~internal_access & ~project_allowed_for_job_token }.prevent_all rule { can?(:public_access) }.policy do enable :read_package diff --git a/doc/ci/jobs/ci_job_token.md b/doc/ci/jobs/ci_job_token.md index fa1ba4be2ec..a60aaa04ea1 100644 --- a/doc/ci/jobs/ci_job_token.md +++ b/doc/ci/jobs/ci_job_token.md @@ -67,10 +67,12 @@ tries to steal tokens from other jobs. You can control what projects a CI/CD job token can access to increase the job token's security. A job token might give extra permissions that aren't necessary -to access specific resources. +to access specific private resources. The job token scope only controls access +to private projects. If an accessed project is public or internal, token scoping does +not apply. If a job token is leaked, it could potentially be used to access private data -to the job token's user. By limiting the job token access scope, project data cannot +to the job token's user. By limiting the job token access scope, private data cannot be accessed unless projects are explicitly authorized. There is a proposal to add more strategic control of the access permissions, @@ -90,7 +92,8 @@ their `CI_JOB_TOKEN`. For example, project `A` can add project `B` to the allowlist. CI/CD jobs in project `B` (the "allowed project") can now use their CI/CD job token to -authenticate API calls to access project `A`. +authenticate API calls to access project `A`. If project `A` is public or internal, +the project can be accessed by project `B` without adding it to the allowlist. By default, the allowlist of any project only includes itself. @@ -165,7 +168,9 @@ limited only by the user's access permissions. For example, when the setting is enabled, jobs in a pipeline in project `A` have a `CI_JOB_TOKEN` scope limited to project `A`. If the job needs to use the token -to make an API request to project `B`, then `B` must be added to the allowlist for `A`. +to make an API request to a private project `B`, then `B` must be added to the allowlist for `A`. +If project `B` is public or internal, you do not need to add +`B` to the allowlist to grant access. ### Configure the job token scope diff --git a/doc/update/index.md b/doc/update/index.md index 7bcbc32a0e9..0380f1a69ef 100644 --- a/doc/update/index.md +++ b/doc/update/index.md @@ -270,11 +270,6 @@ NOTE: Specific information that follow related to Ruby and Git versions do not apply to [Omnibus installations](https://docs.gitlab.com/omnibus/) and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with appropriate Ruby and Git versions and are not using system binaries for Ruby and Git. There is no need to install Ruby or Git when utilizing these two approaches. -### 16.1.1 - -- Accessing a public or internal project with a [CI/CD job token](../ci/jobs/ci_job_token.md) - now needs explicit authorization in the target project's allowlist. - ### 16.1.0 - A `MigrateHumanUserType` background migration will be finalized with @@ -290,11 +285,6 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap migration may take multiple days to complete on larger GitLab instances. Make sure the migration has completed successfully before upgrading to 16.1.0. -### 16.0.6 - -- Accessing a public or internal project with a [CI/CD job token](../ci/jobs/ci_job_token.md) - now needs explicit authorization in the target project's allowlist. - ### 16.0.0 - Sidekiq crashes if there are non-ASCII characters in the GitLab.rb file. You can fix this @@ -305,11 +295,6 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap - Docker 20.10.10 or later is required to run the GitLab Docker image. Older versions [throw errors on startup](../install/docker.md#threaderror-cant-create-thread-operation-not-permitted). -### 15.11.10 - -- Accessing a public or internal project with a [CI/CD job token](../ci/jobs/ci_job_token.md) - now needs explicit authorization in the target project's allowlist. - ### 15.11.1 - Many [project importers](../user/project/import/index.md) and [group importers](../user/group/import/index.md) now diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index 200e2025517..ee8d811971a 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -2552,24 +2552,42 @@ RSpec.describe ProjectPolicy, feature_category: :system_access do describe 'when user is authenticated via CI_JOB_TOKEN', :request_store do using RSpec::Parameterized::TableSyntax - where(:user_role, :external_user, :scope_project_type, :token_scope_enabled, :result) do - :reporter | false | :same | true | true - :reporter | true | :same | true | true - :reporter | false | :same | false | true - :reporter | false | :different | true | false - :reporter | true | :different | true | false - :reporter | false | :different | false | true - :guest | false | :same | true | true - :guest | true | :same | true | true - :guest | false | :same | false | true - :guest | false | :different | true | false - :guest | true | :different | true | false - :guest | false | :different | false | true + where(:project_visibility, :user_role, :external_user, :scope_project_type, :token_scope_enabled, :result) do + :private | :reporter | false | :same | true | true + :private | :reporter | false | :same | false | true + :private | :reporter | false | :different | true | false + :private | :reporter | false | :different | false | true + :private | :guest | false | :same | true | true + :private | :guest | false | :same | false | true + :private | :guest | false | :different | true | false + :private | :guest | false | :different | false | true + + :internal | :reporter | false | :same | true | true + :internal | :reporter | true | :same | true | true + :internal | :reporter | false | :same | false | true + :internal | :reporter | false | :different | true | true + :internal | :reporter | true | :different | true | false + :internal | :reporter | false | :different | false | true + :internal | :guest | false | :same | true | true + :internal | :guest | true | :same | true | true + :internal | :guest | false | :same | false | true + :internal | :guest | false | :different | true | true + :internal | :guest | true | :different | true | false + :internal | :guest | false | :different | false | true + + :public | :reporter | false | :same | true | true + :public | :reporter | false | :same | false | true + :public | :reporter | false | :different | true | true + :public | :reporter | false | :different | false | true + :public | :guest | false | :same | true | true + :public | :guest | false | :same | false | true + :public | :guest | false | :different | true | true + :public | :guest | false | :different | false | true end with_them do let(:current_user) { public_send(user_role) } - let(:project) { public_project } + let(:project) { public_send("#{project_visibility}_project") } let(:job) { build_stubbed(:ci_build, project: scope_project, user: current_user) } let(:scope_project) do diff --git a/spec/requests/api/npm_project_packages_spec.rb b/spec/requests/api/npm_project_packages_spec.rb index b18d99ca884..60d4bddc502 100644 --- a/spec/requests/api/npm_project_packages_spec.rb +++ b/spec/requests/api/npm_project_packages_spec.rb @@ -111,7 +111,7 @@ RSpec.describe API::NpmProjectPackages, feature_category: :package_registry do context 'with a job token for a different user' do let_it_be(:other_user) { create(:user) } - let_it_be_with_reload(:other_job) { create(:ci_build, :running, user: other_user, project: project) } + let_it_be_with_reload(:other_job) { create(:ci_build, :running, user: other_user) } let(:headers) { build_token_auth_header(other_job.token) } @@ -160,7 +160,7 @@ RSpec.describe API::NpmProjectPackages, feature_category: :package_registry do context 'with a job token for a different user' do let_it_be(:other_user) { create(:user) } - let_it_be_with_reload(:other_job) { create(:ci_build, :running, user: other_user, project: project) } + let_it_be_with_reload(:other_job) { create(:ci_build, :running, user: other_user) } let(:headers) { build_token_auth_header(other_job.token) } diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb index 81d6b5465e3..b07296a0df2 100644 --- a/spec/requests/lfs_http_spec.rb +++ b/spec/requests/lfs_http_spec.rb @@ -677,7 +677,8 @@ RSpec.describe 'Git LFS API and storage', feature_category: :source_code_managem context 'tries to push to other project' do let(:pipeline) { create(:ci_empty_pipeline, project: other_project) } - it_behaves_like 'LFS http 404 response' + # I'm not sure what this tests that is different from the previous test + it_behaves_like 'LFS http 403 response' end end @@ -1197,7 +1198,8 @@ RSpec.describe 'Git LFS API and storage', feature_category: :source_code_managem context 'tries to push to other project' do let(:pipeline) { create(:ci_empty_pipeline, project: other_project) } - it_behaves_like 'LFS http 404 response' + # I'm not sure what this tests that is different from the previous test + it_behaves_like 'LFS http 403 response' end end |