Example server providing JWT tokens for ChartMuseum auth.
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.
System requirements to run example:
- docker-compose (version 3)
- jq
- curl
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
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.
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"
]
}
]
}
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: {}
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>
.
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.