/auth-server-example

Example server providing JWT tokens for ChartMuseum auth

Primary LanguageGo

ChartMuseum Auth Server Example

Example server providing JWT tokens for ChartMuseum auth.

Running the example

Source Code

Check out the source code for the auth server here.

This makes use of the chartmuseum/auth Go library in order to generate valid JWT tokens.

Getting started

System requirements to run example:

In the root of this repo, run the following commands to start both the auth server and ChartMuseum:

docker-compose pull  # get the latest images
docker-compose up

Steps

Step 1: Making an unauthenticated request to ChartMuseum

ChartMuseum server is configured to use bearer auth.

In order to access protected resources, a JWT token must be supplied in the Authorization header that indicates access to perform a specific action against a specific resource.

However, in order to obtain the scope required to obtain a token, we first make an unautheticated request.

For example:

curl -v http://localhost:8080/org1/repo1/index.yaml

The output should contain the following:

< HTTP/1.1 401 Unauthorized
< Content-Type: application/json; charset=utf-8
< Www-Authenticate: Bearer realm="http://localhost:5001/oauth/token",service="localhost:5001",scope="artifact-repository:org1/repo1:pull"

The result is an expected 401 Unauthorized.

Look at the contents of the Www-Authenticate response header. You will see that realm and scope fields are defined.

realm -> http://localhost:5001/oauth/token

scope -> artifact-repository:org1/repo1:pull

These values will be used in the next step.

Step 2: Requesting a token from the auth server

After obtaining the realm and scope, we make a request to the auth server (realm) to obtain a token.

Run the following:

REALM="http://localhost:5001/oauth/token"
SCOPE="artifact-repository:org1/repo1:pull"

curl -s -X POST -H "Authorization: Bearer MASTERKEY" \
  "$REALM?grant_type=client_credentials&scope=$SCOPE" | jq .

Note: "MASTERKEY" is a hardcoded token in the auth server which is required to authenticate.

This should output something like the following:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDM5OTU3NzAsImlhdCI6MTU0Mzk5NTQ3MCwiYWNjZXNzIjpbeyJ0eXBlIjoiYXJ0aWZhY3QtcmVwb3NpdG9yeSIsIm5hbWUiOiJvcmcxL3JlcG8xIiwiYWN0aW9ucyI6WyJwdWxsIl19XX0.0Ajgwy5Yhl_HwF3yKoggicpxCiFTffiGcWVxhttR_SU3czn2WogkRazXAAQE2CuIzganw5u5WDuZIBPC2RucP8KT5uKvKDiakDsVYHMACCDjpTotAWamZF2MFCTpXzhpCLkcv_dgGHnInGV_VYJj1xhD6B4ksuxMpDflLCNPqV4GyTxdrIplRxurePNLs5yLKngMXs42eAsD44FGDSLbW65RLM7QFZaUvwlbcst0g9KsVxN4NJ4uIPS-dC0HOvdf6bw2E_GTbpTcpzgn5gMXKzKGFxTi8Tch-NA9t6jghsEDUk3WYJGH1Ko0-xI8XpjYf6l4wQ6_Yg2dGrMBxFqfmQ"
}

access_token is a signed JWT token that indicates access to perform the action pull on the org1/repo1 namespace. It is set to expire in 5 minutes.

You can decode this token on https://jwt.io or with something like jwt-cli.

If you examine the token payload, it will resemble the following:

{
  "exp": 1543995770,
  "iat": 1543995470,
  "access": [
    {
      "type": "artifact-repository",
      "name": "org1/repo1",
      "actions": [
        "pull"
      ]
    }
  ]
}

Step 3. Making an authenticated request to ChartMuseum

Once you have obtained a token from the auth server, simply retry the original request, this time sending the token in the Authorization header:

TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDM5OTU3NzAsImlhdCI6MTU0Mzk5NTQ3MCwiYWNjZXNzIjpbeyJ0eXBlIjoiYXJ0aWZhY3QtcmVwb3NpdG9yeSIsIm5hbWUiOiJvcmcxL3JlcG8xIiwiYWN0aW9ucyI6WyJwdWxsIl19XX0.0Ajgwy5Yhl_HwF3yKoggicpxCiFTffiGcWVxhttR_SU3czn2WogkRazXAAQE2CuIzganw5u5WDuZIBPC2RucP8KT5uKvKDiakDsVYHMACCDjpTotAWamZF2MFCTpXzhpCLkcv_dgGHnInGV_VYJj1xhD6B4ksuxMpDflLCNPqV4GyTxdrIplRxurePNLs5yLKngMXs42eAsD44FGDSLbW65RLM7QFZaUvwlbcst0g9KsVxN4NJ4uIPS-dC0HOvdf6bw2E_GTbpTcpzgn5gMXKzKGFxTi8Tch-NA9t6jghsEDUk3WYJGH1Ko0-xI8XpjYf6l4wQ6_Yg2dGrMBxFqfmQ"

curl -v -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/org1/repo1/index.yaml

This should result in a 200 OK and return the repo index contents as expected:

apiVersion: v1
entries:
  mychart:
  - created: "2018-12-05T06:57:46Z"
    digest: 159ba395ef891a90339f5d8a6ff964fb38265ec24a2e1d09fe6c390cda75b17c
    name: mychart
    urls:
    - charts/mychart-0.1.0.tgz
    version: 0.1.0
generated: "2018-12-05T07:04:40Z"
serverInfo: {}

Using with helm-push

There is currently no way to pass this token via Helm CLI.

However, if you are using the helm-push plugin, you are able to add your repo with the cm:// protocol. This, in combination with the HELM_REPO_ACCESS_TOKEN environment variable, will allow you to use this token for all repo-related requests:

# export necessary vars
export HELM_REPO_USE_HTTP="true"        # needed if repo running over http vs https
export HELM_REPO_ACCESS_TOKEN="$TOKEN"  # token created above

# Add the repo with cm protocol
helm repo add chartmuseum cm://localhost:8080/org1/repo1

# Run repo-related helm commands
helm push mychart/ chartmuseum
helm repo update
helm fetch chartmuseum/mychart

The scope to use when requesting a token to perform pull and push actions (see step #2) will look like the following:

artifact-repository:org1/repo1:pull,push

The suported scope format looks like:

artifact-repository:<namespace>:<action[s]>

where "repo" is the default, single-tenant <namespace>.

Helm 3

The following diagram shows an example of how repo auth might work between Helm 3 and ChartMuseum 1.0:

The specifics behind the helm login command which will be introduced in Helm 3 is still to be determined.

"Auth flow" section in the image above stolen shamelessly from Docker docs.