Bearer Tokens

Bearer tokens are a topic which has gained a lot of traction within WLCG. Eventually, the goal is for bearer tokens to replace X509 authentication in the (hopefully not-so-far) future.

This page describes what bearer tokens are in Gfal2 and how they are used.

Why bearer tokens?

In the simplest words, a bearer token is a series of bytes which grants the holder of the token certain permissions on a server. The client presents the token to the server as means of authorization, when performing a given operation. It doesn't matter what is in the token or whether the client can read it. What matters is that the storage performs authorization based on the token.

This brings a level of simplicity and mobility on the client's part. No complex cryptography or requirements of agreed-upon authorities is involved, as is the case for X509 proxy certificates. More so, delegation becomes very easy. If you have write access to a storage, passing your token to another entity allows them to perform the write operation. If that token also contains some identity information, combined with the proper instructions, the entrusted entity can write the file and announce it is doing so on your behalf. Which, in fact, is what happens during HTTP-TPC.

Bearer tokens can be issued either directly by the Storage Element (colloquially called macaroons, albeit sometimes incorrectly, as there are other types available) or by a dedicated Identity and Authorization entity (as is the case for OIDC tokens).

Gfal2 and bearer tokens

Gfal2 offers bearer tokens support for the HTTP protocol. This is done with the help of a credentials map. Gfal2 performs HTTP operations by using the Davix library, preparing the request parameters and passing them to the library for the actual HTTP request. There are many request parameters (many of them configurable), including some related to authentication. Gfal2 uses the following algorithm to set up the authentication parameters:

  • Load the X509 credentials (proxy or user/key pair)
    • Will always be used as fallback
  • Identify if Cloud endpoint by URI protocol
    • Load the cloud credentials from the Gfal2 environment
  • Search for bearer tokens in the credentials map for the given path
    • If not found, search for bearer tokens in the credentials map for the given host
    • If still not found, attempt to retrieve bearer token from Storage Element (requires gfal2 >= v2.20.0)

The Gfal2 credentials map

The Gfal2 credentials map is a mechanism that allows Gfal2 users to associate a type of credentials to a particular path prefix.

Notice the type of credential.
This means that a path may have multiple types of credentials associated to it. The available types are: X509_CERT, X509_KEY, BEARER, USER, PASSWORD.

Notice the path prefix.
Retrieving from the credentials map takes as input a type of credential and a desired path. As the paths stored in the credentials maps are prefixes, they will attempt to match your path, starting from the longest match towards the smallest.

More so, there are 3 important authentication variables that may be loaded in the Gfal2 environment, namely [X509] CERT=<cert>, [X509] KEY=<key> and [BEARER] TOKEN=<token>. If no specific credential object is retrieved, then the credential is loaded from the Gfal2 environment, if available.

Some things are better explained with a (Python) example:

# Set general [BEARER] TOKEN option
context.set_opt_string("BEARER", "TOKEN", "<token>")

# Create Gfal2 credential objects
token_cred = gfal2.cred_new("BEARER", "<bearer-token>")
macaroon_cred = gfal2.cred_new("BEARER", "<macaroon>")

# Set credential objects in the credentials map
gfal2.cred_set(context, "https://grid-storage/path/dir/file", token_cred)
gfal2.cred_set(context, "https://grid-storage/", macaroon_cred)

# Retrieves the <token_cred> object
gfal2.cred_get(context, "BEARER", "https://grid-storage/path/dir/file")

# Retrieves the <macaroon_cred> object
gfal2.cred_get(context, "BEARER", "https://grid-storage/path/dir/")

# Retrieves the general "[BEARER] TOKEN=<token>" value
gfal2.cred_get(context, "BEARER", "https://other-grid-stroage/path/")

In the example, we have the [BEARER] TOKEN=<token> loaded as a Gfal2 environment option and 2 user-set credential objects:

  • The first request, for the full path, we get the longest match, which is the token_cred object
  • Second request, for the containing directory, we get the macaroon_cred, which was set for the full storage, but is in fact the longest user-set match for us
  • The third time, we request credentials for a different storage, which has no user-set credentials associated to it. Therefore, we receive the token from the Gfal2 environment

Important to note, there is a correlation between the Gfal2 environment and the shell environment. As soon as one is loaded, the others are not processed anymore.

Order Shell environment Gfal2 environment
1 BEARER_TOKEN [BEARER] TOKEN
2 X509_USER_PROXY [X509] CERT
[X509] KEY
3 X509_USER_CERT
X509_USER_KEY
[X509] CERT
[X509] KEY

Automatically requesting Storage Element issued bearer tokens

This feature is available starting from version 2.20.0. It allows Gfal2 to request a bearer token from the storage element, when no such token could be retrieved from the credentials map. This operation is transparent to the user and the lifecycle management of these tokens is handled by Gfal2.

To enable this feature, the following configuration must be set in the Gfal2 HTTP plugin config file (generally /etc/gfal2.d/http_plugin.conf):

RETRIEVE_BEARER_TOKEN=true

Important to note, when Gfal2 is contacting the Storage Element to request a bearer token, X509 certificate is used for the authentication.

Implementation details

When requesting SE-issued bearer tokens, sooner or later, you'll run into the scenario where Gfal2 performs a read operation on <path>, no token is available, thus a<read-bearer-token> is obtained, but later Gfal2 has to do a write operation on the same <path>, where it will find the <read-bearer-token> in the credentials map.

To work around this problem, Gfal2 keeps an additional token access map, in the form of <token, access>. Once a token is retrieved from the credentials map, the read/write permissions are checked against the token access map. If the permissions are not sufficient (namely, read token for write operation), the token is discarded and a new token with the needed permissions is obtained for the path.

In case a token is retrieved from the credentials map but this token cannot be found in the token access map, then the token is assumed to be user-set and will be used without any additional checks.

Note: A previous version of Gfal2 relied on the x509-scitokens-issuer-client package for the token retrieval. Now, the functionality is fully implemented in the Gfal2 HTTP-plugin.

Examples for Gfal2 and SE-issued tokens

Make sure gfal2 v2.20.0, python2/3-gfal2 v1.11.0 and python2/3-gfal2-util v1.7.0 are installed. The packages are available via the DMC RC or DMC production repositories.

Prerequisites:

  • Set RETRIEVE_BEARER_TOKEN=true in the Gfal2 HTTP-plugin config file (default /etc/gfal2.d/http_plugin.conf)
  • Make sure you have a valid proxy certificate

Submit a transfer

$ gfal-copy <http_src> <http_dst> [-vvv --logfile=gfal2.log]
# (Optional) Check the log file for mentions of `SEToken` (requires debug logging)

Obtain SE-issued token via Python bindings

import gfal2

ctx = gfal2.creat_context()

# retrieve_token(<path>, <issuer> (default=""), validity (default=60), [list of capabilities])
ctx.retrieve_token("<http_storage_endpoint>", "", 60, ["LIST", "DOWNLOAD"])

# Out of convenience, we offer a second method signature with write_access=<True/False>
# write_access=False <==> ["LIST", "DOWNLOAD"]
# write_access=True  <==> ["LIST", "UPLOAD", "MANAGE", "DELETE"]
# retrieve_token(<path>, <issuer> (default=""), validity (default=60), write_access (default=False))

Obtain SE-issued token from the command line

$ gfal-token --validity 60 <http_storage_endpoint> READ,LIST,MANAGE

What about FTS?

Until now, FTS was the service requesting the tokens from the Storage Elements and passing them to Gfal2. It can still do this, as v2.20.0 is backwards compatible with FTS versions. However, starting with FTS v3.11.0, a new server configuration RetrieveSEToken=<true|false> is introduced to enable or disable FTS requesting SE-issued tokens.

A log message is printed at INFO level:

INFO    Mon, 20 Sep 2021 17:20:00 +0200; Configured to skip retrieval of SE-issued tokens

If DEBUG level is enabled, search for SEToken mentions:

DEBUG   Mon, 20 Sep 2021 17:20:00 +0200; (SEToken) Set bearer token in credential_map[https://eospps.cern.ch/eos/opstest/dteam/file.test] (access=read) (validity=180)
DEBUG   Mon, 20 Sep 2021 17:20:00 +0200; (SEToken) Set bearer token in credential_map[https://prometheus.desy.de:2443/VOs/dteam/file.test] (access=read) (validity=180)
DEBUG   Mon, 20 Sep 2021 17:20:01 +0200; (SEToken) Found token in credential_map[https://prometheus.desy.de:2443/VOs/dteam/file.test] (access=read) (needed=read)
DEBUG   Mon, 20 Sep 2021 17:20:01 +0200; (SEToken) Set bearer token in credential_map[https://prometheus.desy.de:2443/VOs/dteam] (access=read) (validity=180)
DEBUG   Mon, 20 Sep 2021 17:20:01 +0200; (SEToken) Found token in credential_map[https://eospps.cern.ch/eos/opstest/dteam/file.test] (access=read) (needed=read)
DEBUG   Mon, 20 Sep 2021 17:20:01 +0200; (SEToken) Found token in credential_map[https://prometheus.desy.de:2443/VOs/dteam/file.test] (access=read) (needed=write)
DEBUG   Mon, 20 Sep 2021 17:20:01 +0200; (SEToken) Invalidating token for path=https://prometheus.desy.de:2443/VOs/dteam/file.test because write access is missing
DEBUG   Mon, 20 Sep 2021 17:20:02 +0200; (SEToken) Set bearer token in credential_map[https://prometheus.desy.de:2443/VOs/dteam/file.test] (access=write) (validity=36)
DEBUG   Mon, 20 Sep 2021 17:20:05 +0200; (SEToken) Found token in credential_map[https://prometheus.desy.de:2443/VOs/dteam/file.test] (access=write) (needed=read)

Please report any bugs, inconsistencies, unexpected behavior or documentation improvements at:

results matching ""

    No results matching ""