Skip to content

RUN AS-IF-FOSS Deploy keys for protected branches - BE

Etienne Baqué requested to merge 30769-keys-on-protected-branch-be into master

What does this MR do?

This is MR is part of selecting Deploy Keys when creating Protected Branches. This related issue is here.

This backend MR modifies the part of the code that checks whether a user can push to a repository. This is now made a bit more permissive as deploy keys can be selected when defining a protected branch. As written in the issue proposal:

Deploy keys are able to push to protected branch if the owner does not have permission to do, but does have access to the project.

This is the 4th MR related to this issue (out of a total of 6). The MR summary can be seen here.

This feature hides behind the deploy_keys_on_protected_branches feature flag.

Relates to #30769 (closed)

Manual testing and screenshots

Let's take the following scenario: here's Project A's .gitlab-ci.yml file:

stages:
  - test

test git commands:
  stage: test
  before_script:
    - apk update && apk add git openssh
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
    - git config --global user.email "user@example.com"
    - git config --global user.name "User name"
  script:
    - cd ~
    - GIT_SSH_COMMAND="ssh -p 2222" git clone etienne@192.168.1.11:gnuwget/wget2.git
    - cd ~/wget2
    - git checkout test-job
    - echo 'hello' >> README.md
    - git commit -am "Added hello"
    - GIT_SSH_COMMAND="ssh -p 2222" git push origin test-job

As shown above, the job stage will pull the wget2 project, update the README.md file, commit and push to the wget2 repo. The private key of a user (called Lucius) as well as the wget project's host are added as env. variables.

Example 1: The user does not have read-access to the wget2 project (not a member and visibility is private)

private_repo

Example 2: The user has read-access to the wget2 project but their deploy key is not selected as part of the protected branch.

Screenshot_from_2020-10-05_11-43-33

Example 3: The user has read-access to the wget2 project, is not a member of it but their deploy key is added to the project and selected in the protected branch.

Screenshot_from_2020-10-05_11-34-09

Screenshot_from_2020-10-05_11-28-21

Import/Export testing

Let's say that we have a test-job branch, that has 1 role and 1 deploy key for the Allowed to push level.

Screenshot_from_2020-10-16_14-22-32

After running ::Projects::ImportExport::ExportService.new(project, user).execute and downloading the created tar.gz file, here's what we get:

# tree/project/protected_branches.ndjson

{
  "id":94,
    "project_id":3,
    "name":"test-job",
    "created_at":"2020-09-24T09:09:56.025Z",
    "updated_at":"2020-09-24T09:09:56.025Z",
    "code_owner_approval_required":false,
    "push_access_levels":[{"id":265,
      "access_level":0,
      "created_at":"2020-10-05T13:26:41.306Z",
      "updated_at":"2020-10-05T13:26:41.306Z",
      "user_id":null,
      "group_id":null,
      "deploy_key_id":null},
    {"id":275,
      "access_level":40,
      "created_at":"2020-10-16T12:18:33.086Z",
      "updated_at":"2020-10-16T12:18:33.086Z",
      "user_id":null,
      "group_id":null,
      "deploy_key_id":30,
      "deploy_key":{"id":30,
        "user_id":11,
        "created_at":"2020-07-10T16:29:01.710Z",
        "updated_at":"2020-10-05T09:32:57.017Z",
        "key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCuJxu+R4Lf9MJOdMVR8cVm0GtSfkJpiBEWDN/ZOVhUMUgElJdMI58vo0aTaY4nqGswOjWkjer+hlkjfBBLhs5ibY17exx6OyZ+ZAmQd3wCvJvOpzphiharEi4ZqmuUleRh9bSXix9Le9BXg8+Es/2j8cjHLXRnZjOptbAOBC6F/h+vU4FYI1hOrx4nR1fXt+wGQYAaK1tvp97ykB00lOz36StHIbYVZfp51C+DhnzGLEupkw/+2/bKOum1jBb7aiZoPO4DFo7Ph+PoPAqsNljOWOqcF+Q5VkTmsdLnCRWMJX69aKQXef3XfngIgZ7sIfpju3H/aAxtvtfLEapoFDuMDTvhDXi51jggAsAnDEuszIxzKPtNKJwGcpLfU+gXtIQyDjznZy8HzQOOhcWiaail7Ybik0O4V7A94d7TefWxpFKhTaVTRTOasyMpTdVNE7MJKSubYnPMPvMGG7wXL2sG1kvHGuNwPptZHSLyRja0KUqaILGxUQxUq0sQXCH4HJvHsn6nEtnQXBuF2fDq1zz6lFBWy1rfHXt6Xy8wAGGzHk9Oopt4mVX6jgUD45ZT66aroYXJEyiHDllfglxxA3+S/akKlRxm4YXuGhrjoXxkrzydTUIISiNqoJ8Hnt2hsC3e4r6BMfMmIJnrdpFDfv0DS0lkFp1WRB6PuXuQihayCw== lucius.huel@hagenesmitchell.info",
        "title":"Lucius's key",
        "fingerprint":"c9:6b:e6:d6:15:14:a3:a6:4a:88:c9:54:4f:e6:12:49",
        "public":false,
        "last_used_at":"2020-10-16T10:12:30.480Z",
        "fingerprint_sha256":"Qz2ZiDG0Km3W7hK9/BgnjtUFcIyELI+SQ3vGMOHQ8hU",
        "expires_at":null}}],
    "merge_access_levels":[{"id":124,
      "access_level":40,
      "created_at":"2020-09-24T09:09:56.028Z",
      "updated_at":"2020-09-24T09:09:56.028Z",
      "user_id":null,
      "group_id":null}],
    "unprotect_access_levels":[]
}

console:

Screenshot_from_2020-10-16_14-25-22

Manual testing with GitLab Shell v13.11.0

Following the release of this fix, some more manual testing is needed:

  • FOSS - Protected Branch with only "No one" as access level -> Can't push to repo.
  • FOSS - Protected Branch with "No one" and deploy key. Use of deploy key in CI -> Can push to repo.
  • EE - Protected Branch with only "No one" as access level -> Can't push to repo.
  • EE - Protected Branch with "No one" and deploy key. Use of deploy key in CI -> Can push to repo.
  • EE - Protected Branch with that deploy key's owner selected only (deploy key is not selected). User is added to project as member -> Can push to repo.

2020-10-23: More manual testing about excluding PushAccessLevel records with deploy_key_id

Original project - 1 branch defined with one user, one deploy key and one role:

2020-10-23_12-32

Screenshot_from_2020-10-23_13-42-12

Export JSON snippet about protected branches (for test-job branch):

{
  "id":106,
    "project_id":3,
    "name":"test-job",
    "created_at":"2020-10-20T12:20:38.880Z",
    "updated_at":"2020-10-20T12:20:38.880Z",
    "code_owner_approval_required":false,
    "merge_access_levels":[{"id":143,
      "access_level":40,
      "created_at":"2020-10-20T12:20:38.882Z",
      "updated_at":"2020-10-20T12:20:38.882Z",
      "user_id":null,
      "group_id":null}],
    "push_access_levels":[{"id":301,
      "access_level":40,
      "created_at":"2020-10-23T10:30:01.716Z",
      "updated_at":"2020-10-23T10:30:01.716Z",
      "user_id":3,
      "group_id":null,
      "deploy_key_id":null},
    {"id":289,
      "access_level":0,
      "created_at":"2020-10-20T12:20:38.885Z",
      "updated_at":"2020-10-20T12:20:38.885Z",
      "user_id":null,
      "group_id":null,
      "deploy_key_id":null}],
    "unprotect_access_levels":[]
}

Imported project:

2020-10-23_13-37

Screenshot_from_2020-10-23_13-42-58

Does this MR meet the acceptance criteria?

Conformity

Availability and Testing

Security

If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:

  • Label as security and @ mention @gitlab-com/gl-security/appsec
  • The MR includes necessary changes to maintain consistency between UI, API, email, or other methods
  • Security reports checked/validated by a reviewer from the AppSec team

Relates to #30769 (closed)

Edited by Etienne Baqué

Merge request reports