Skip to content

GraphQL: Add ephemeral_authentication_token field to CiRunner

What does this MR do and why?

Describe in detail what your merge request does and why.

This MR adds an ephemeral_authentication_token field to the CiRunner GraphQL type. This field is required so that if for some reason (e.g. temporary network failure) the user is not able to receive the response of the mutation that creates a new runner, they can still access the runner authentication token that will be required to register the runner through the runner ID present on the URL of the follow-up page.

For security reasons, we put some measures in place to reduce the exposure of the token:

  • The token can only be seen by the user that created the runner (creator).
  • Only glrt- prefixed tokens are made available here;
  • The token can only be seen for a period of 3 hours after the creation of the runner;
  • The token becomes unavailable once the user has registered a machine to it.

Closes #389270 (closed)

Screenshots or screen recordings

Screenshots are required for UI changes, and strongly recommended for all other merge requests.

glrt- prefix? is creator? created < 3 hours ago? screenshot
image
🚫 image
🚫 image
🚫 image

How to set up and validate locally

Numbered steps to set up and validate the change are strongly suggested.

NOTE: These instructions assume that you're logged in to your GDK at http://gdk.test:3000 using user root (id: 1).

  1. In the rails console, create 4 runners with different characteristics (similar to screenshot above):

    reload!; [Ci::Runner.new(legacy_registered: false, creator: User.find(1), **args), Ci::Runner.new(creator: User.find(1), **args), Ci::Runner.new(legacy_registered: false, creator: User.find(2), **args), Ci::Runner.new(legacy_registered: false,creator: User.find(1), created_at: 3.hours.ago, **args)].map { |r| r.tap(&:save!).id }
    => [10039, 10040, 10041, 10042]
  2. Plug in the IDs of the created runners in order into the following snippet inside http://gdk.test:3000/-/graphql-explorer:

    {
      currentUser { id }
      uiRecentlyCreatedRunner: runner(id: "gid://gitlab/Ci::Runner/10039") {
        id
        createdAt
        ephemeralAuthenticationToken
      }
      legacyRegisteredRunner: runner(id: "gid://gitlab/Ci::Runner/10040") {
        id
        createdAt
        ephemeralAuthenticationToken
      }
      nonOwnedUiCreatedRunner: runner(id: "gid://gitlab/Ci::Runner/10041") {
        id
        createdAt
        ephemeralAuthenticationToken
      }
      ownedUiCreatedRunnerLongAgo: runner(id: "gid://gitlab/Ci::Runner/10042") {
        id
        createdAt
        ephemeralAuthenticationToken
      }
    }
  3. Execute the query and confirm that only the first one returns the ephemeral token, since it complies with all the conditions:

    image

  4. In the Rails console, create a Ci::RunnerMachine to simulate the fact that a user has registered their first runner in the command line:

    Ci::RunnerMachine.new(runner: Ci::Runner.find(10039), machine_xid: 'r_some_random_id').save!
    => true
  5. Go back to the GraphiQL Explorer and rerun the query. This time the first runner (uiRecentlyCreatedRunner) should not return an ephemeral token since it was theoretically already used:

    image

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Pedro Pombeiro

Merge request reports