Skip to content

Add authentication to merge request external status checks

Release Post

External status checks can now be configured with HMAC (Hash-based Message Authentication Code) authentication. This will provide a more secure way to verify the authenticity of requests from GitLab to external services.

When enabled for your status check, a shared secret will be used to generate a unique signature for each request. The signature will be sent in the X-Gitlab-Signature header, using SHA256 as the hash algorithm.

  • Improved Security: HMAC authentication prevents tampering with requests and ensures they come from a legitimate source.
  • Compliance: This feature is particularly valuable for regulated industries, such as banking, where security is paramount.
  • Backwards Compatibility: The feature will be optional and backwards compatible. Users can choose to enable HMAC authentication for new or existing checks, but existing external status checks will continue to function without changes.

In a future iteration, GitLab plans to add options for verifying HTTPS and potentially blocking HTTP requests when HMAC is enabled.

Why are we doing this work

Problem

Merge request external status checks currently have no way of checking the authenticity of the request from GitLab in the external service. This could lead to spoofing of the GitLab request to the external status check.

Proposals

💡 Basic auth (we decided to go with HMAC (see below))

Add header parameter that is defined on creation of the external status check and can not be changed. Similar to audit event streaming authenticity. The external service can then verify the header parameter to ensure authenticity.

💡 HMAC implementation (thread)
  1. Implement with HMAC.
  2. Ensure that it's backwards compatible such that no existing un-authenticated checks are broken (and that this is very well tested and monitored during any rollout).
  3. Allow users to configure with HMAC, at which point we conditionally block HTTP.

Relevant links

Non-functional requirements

  • Documentation:
  • Feature flag:
  • Performance:
  • Testing:

Implementation plan

  encrypted_shared_secret character varying,
  encrypted_shared_secret_iv character varying,
  • backend MR2: extend ee/app/models/merge_requests/external_status_check.rb to with attr_encrypted
  attr_encrypted :shared_secret,
    mode: :per_attribute_iv,
    algorithm: 'aes-256-gcm',
    key: Settings.attr_encrypted_db_key_base_32
  • backend MR3: extend ee/app/graphql/mutations/branch_rules/external_status_checks mutations (create only) to include argument with shared_secret, extend related services to store these values, extend ee/app/graphql/types/branch_rules/external_status_check_type.rb to return information that HMAC is enabled or not,
  • backend MR4: modify ee/app/services/external_status_checks/dispatch_service.rb to send webhook with HMAC (if shared secret is set for external status check, if it is not provided send it without any updates),
  • frontend MR5: add to the modal ability to configure shared secret for external status check:

image

Verification steps

  1. Create new project in Ultimate group
  2. Go to Settings -> Merge Requests -> Status checks
  3. Click Add status check, provide URL, Service name, Target branch and specify shared secret. Save the check.
  4. Create new MR with same target branch as defined in the external status check.
  5. Verify that request sent to the server included HMAC.
Edited by Grant Hickman