Skip to content

Add user tracking for deploy tokens from registry events

Adie (she/her) requested to merge 390874-add-tracking-to-deploy-token into master

🚁 Overview

#390874 (closed)

This MR utilizes the existing webhook notifications and existing tracking to also track events from deploy tokens (previously we only had tracking for users).

New events:

  • i_container_registry_delete_tag_deploy_token
  • i_container_registry_push_tag_deploy_token
  • i_container_registry_create_repository_deploy_token
  • i_container_registry_delete_repository_deploy_token
  • i_container_registry_push_repository_deploy_token

For groupcontainer registry, we want to have weekly and monthly aggregations of these events thus the monthly and weekly metric definitions (same as what we already have for User). For this MR, we consider events from a Deploy Token.

See below for the event structure (reference) that Gitlab Rails receives.

Important Note: Compared to before, we have a new key user, under actor, which was added in !127622 (merged). The value for this new user key is a JWT containing user information. To get the correct actor for the event, we will decode this token and use that information.

{
   "events": [
      {
         "id": "a582a0f3-e620-43e6-8e98-ff850fc9d984",
         "timestamp": "2023-01-25T14:45:54.17327+11:00",
         "action": "push",
         "target": {
            "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
            "size": 528,
            "digest": "sha256:xxxx",
            "length": 528,
            "repository": "root/test",
            "url": "http://registry.test:5000/v2/root/test/manifests/sha256:xxxxx",
            "tag": "more-auth"
         },
         "request": {
            "id": "8ef8d69b-f957-45ab-ba2c-9153291f47b6",
            "addr": "172.16.123.1:56969",
            "host": "registry.test:5000",
            "method": "PUT",
            "useragent": "docker/20.10.18 go/go1.18.6 git-commit/e42327a6d3c55ceda3bd5475be7aae6036d02db3 kernel/5.15.68-0-virt os/linux arch/arm64 UpstreamClient(Docker-Client/20.10.22 \\(darwin\\))"
         },
         "actor": {
            "name": "root",
            "user_type": "deploy_token",
            "user": "tokentokentoken"
         },
         "source": {
            "addr": "127.0.0.1:5000",
            "instanceID": "45681f21-a006-42f2-ab7c-4cc37d8906b4"
         }
      }
   ]

The value under user, once decoded, will have a structure similar to the following if the actor is a Deploy Token:


Token claims
------------
{
  "exp": 1704947819,
  "iat": 1704947759,
  "jti": "ee559f2b",
  "nbf": 1704947754,
  "user_info": {
    "deploy_token_id": 1,
    "token_type": "deploy_token",
    "username": "january2024"
  }
}

if the actor is a user, we will find user_id instead of deploy_token_id.

🙌 Validating Locally

To validate locally, we first need to setup the Service Ping locally with this guide. And after that, we verify that the counts are incremented when an event is received.

The counters are incremented whenever the above events are emitted. They are emitted whenever:

  • a tag gets pushed
  • a tag gets deleted
  • a repository gets deleted
  • a repository gets created
  • a repository gets pushed

To be able to do this, we will have to setup the Container Registry standalone on a fresh master (outside the GDK) and enable notifications with the help of the instructions here.

An alternative is to call the endpoint with the ContainerRegistry event payload format as documented in container-registry!1205 (merged) and simulate what the container registry would send to Gitlab Rails.

Sending Events to the /events endpoint

In this section, we will simulate Gitlab Rails receiving an event from the container registry.

Before we do that, let's check if we have any usage data from a deploy token. We do this now and compare it with the counts later and see that it has been increased 🙌

[27] pry(main)> Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: 'i_container_registry_push_tag_deploy_token',
start_date: Date.current.beginning_of_week, end_date: Date.current.next_week)

=> 0

A. Authentication

Now, let's start! Sending events to Gitlab Rails require some token and authentication. For simplicity, we can skip the token checks and curl without any tokens:

  • Open api/container_registry_event.rb and
  • Comment out the line before { authenticate_registry_notification! }

B. Generating the user token

As mentioned above, we have a new key user which we need a JWT for. To get that token:

NOTE: The token expires in a few seconds so please do the steps right after one another. 😊

  1. Create a deploy token (or use an existing one) and take note of the username and password. Guide to creating deploy tokens here.
  2. Request a JWT for the user:
http -a deploytokenusername:'deploytokenpassword' http://gdk.test:3000/jwt/auth  client_id=="docker"  service=="container_registry" scope=="repository:october-group/proj-lalalo/proj-lalalo:pull"
  1. You will get a return value with a token key. Copy that token and decode it:

Return value:

HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Length: 1885
Permissions-Policy: interest-cohort=()
Referrer-Policy: strict-origin-when-cross-origin
Set-Cookie: perf_bar_enabled=true; path=/
Vary: Accept

{
    "token": <token>
}

Get the token and decode:

jwt decode <token>
  1. The return value will contain a user key. Get that token and replace in the curl command below.
Token claims
------------
{
  "access": [
    {
      "actions": [
        "pull"
      ],
      "meta": {
        "project_path": "october-group/proj-lalalo"
      },
      "name": "october-group/proj-lalalo/proj-lalalo",
      "type": "repository"
    }
  ],
  "aud": "container_registry",
  "auth_type": "deploy_token",
  "user": "tokentokentoken-get-this-token-and-put-it-in-curl-command"
}

C. curl Command

Below is a curl command that we can use to send events to Rails.

curl -d '{
  "events": [
    {
      "id": "a582a0f3-e620-43e6-8e98-ff850fc9d984",
      "timestamp": "2023-01-25T14:45:54.17327+11:00",
      "action": "push",
      "target": {
        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
        "size": 528,
        "digest": "sha256:af06af3514c44a964d3b905b498cf6493db8f1cde7c10e078213a89c87308ba0",
        "length": 528,
        "repository": "root/test",
        "url": "http://registry.test:5000/v2/root/test/manifests/sha256:02399a844fe2a14d062382fd6b3e048b742e8d647bc1ce4ce421decfb31ca938",
        "tag": "latest"
      },
      "request": {
        "id": "8ef8d69b-f957-45ab-ba2c-9153291f47b6",
        "addr": "172.16.123.1:56969",
        "host": "registry.test:5000",
        "method": "PUT",
        "useragent": "docker/20.10.18 go/go1.18.6 git-commit/e42327a6d3c55ceda3bd5475be7aae6036d02db3 kernel/5.15.68-0-virt os/linux arch/arm64 UpstreamClient(Docker-Client/20.10.22 \\(darwin\\))"
      },
      "actor": {
        "deploy_token_id": "1",
        "user_type": "deploy_token",
        "user": <token-from-earlier>
      },
      "source": {
        "addr": "127.0.0.1:5000",
        "instanceID": "45681f21-a006-42f2-ab7c-4cc37d8906b4"
      }
    }
  ]
}' -H "Content-Type: application/vnd.docker.distribution.events.v1+json"  -X POST  'http://gdk.test:3000/api/v4/container_registry_event/events'

NOTE: The token expires within a few seconds so if you get an error at this point, try again as the token might have expired.

D. Check that the metric increased

And then to verify that the metric was counted, do a:

[28] pry(main)> Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: 'i_container_registry_push_tag_deploy_token',
start_date: Date.current.beginning_of_week, end_date: Date.current.next_week)

=> 1

Replace i_container_registry_delete_tag_deploy_token with the event that you tried.

Notes:

  1. Feel free to replace deploy_token_id: "1" to other deploy tokens in your local machine.
  2. Feel free to replace "action": "push" which is for a push event
  3. Removing the line "tag": "latest" and the preceding comma will make it a repository event.

MR acceptance checklist

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

MR acceptance checklist

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

Related to #390874 (closed)

Edited by Adie (she/her)

Merge request reports