... Go back to home

How to use JWT Auth for Grafana Iframe + Python REST API

#grafana #jwt #python #rest-api
2024-08-16

This guide requires you to have a permission to mount/modify the Grafana configuration files (grafana.ini)

  1. Generate RS256 key pair using openssl

    a. Run the following commands in terminal, make sure openssl is installed

    1openssl genpkey -algorithm RSA -out private.key
    2openssl rsa -pubout -in private.key -out public.key
    

    b. These commands will generate 2 files, private.key and public.key

    1├── private.key
    2└── public.key
    
  2. Convert the contents of public.key file to JSON format using https://russelldavies.github.io/jwk-creator/

    a. Copy the contents of public.key into the PEM encoded key field

    b. Fill in the Key ID with grafana

    c. Leave the Public Key Use and Algorithm fields empty

    d. Click the Convert button

  3. Create a jwks.json file

    a. Create a new file named jwks.json and fill it with the following JSON

    1{
    2    "keys": []
    3}
    

    b. Copy the JWK result from https://russelldavies.github.io/jwk-creator/ into the keys array in the jwks.json file. For example:

     1{
     2    "keys": [
     3        {
     4            "kty": "RSA",
     5            "n": "mCE7VaNgkjT0EyiMhyybdOfMaMWbdGyFhmWr-2e4cHY3oVxsLpdT9rcqPUtpGUI9KpRB-V8fcJj8W8YxpTLEFdca-wDP3Vgdyq76-tNYLicMCuvqQD-2PIHDgzPvGBdbj7SZLKs9v8XUfyJ5MhdeSsQVHczgun34h7BfMPhW_qZwd7mXmXB0NHNRVUSYEpBJFmnp6i6CAF5hIRCCxaFZLdzArWg1WXADDJqTC_nVlKMZkpOLTFP5JqtOrWKJGn-uYINyJ0HreXMSehknCZNh1-S7-J8LG--YL2E4JtwkdbbSA-iyuQYRJUT9WezrS-kQSXypntrC-aAH0YOFj9lw8Q",
     6            "e": "AQAB",
     7            "kid": "grafana"
     8        }
     9    ]
    10}
    

    c. Save the jwks.json file

  4. Mount jwks.json to /etc/grafana/jwks.json in the Grafana container

  5. Configure Grafana in the grafana.ini file in the Grafana container

     1[security]
     2allow_embedding = true
     3...
     4
     5[auth.jwt]
     6enabled = true
     7url_login = true
     8header_name = X-JWT-Assertion
     9email_claim = sub
    10username_claim = user
    11jwk_set_file = /etc/grafana/jwks.json
    
  6. Restart the Grafana container

  7. To access Grafana using JWT, an auth_token needs to be generated first.

     1import jwt
     2import datetime
     3
     4# Replace with your actual `private.key` content
     5SECRET_KEY = f"""-----BEGIN PRIVATE KEY-----
     6MIIEvQIBADANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQ...
     7-----END PRIVATE KEY-----
     8"""
     9
    10payload = {
    11    "exp": int((datetime.datetime.now() + datetime.timedelta(hours=50)).timestamp()), # token expiration time (unix timestamp)
    12    'sub': 'admin@gmail.com', # grafana user email
    13    'user': 'admin', # grafana username
    14}
    15
    16token = jwt.encode(payload, SECRET_KEY, algorithm='RS256', headers={
    17    'kid': 'grafana' # use the same key_id (kid) as in jwks.json
    18})
    19
    20token = token.decode('utf-8')
    21
    22print(f'auth_token: {token}')
    
     1from flask_restx import Resource
     2from flask import render_template_string
     3
     4class ApiClass(Resource):
     5    def get(self):
     6        iframe = 'http://localhost:3000/d-solo/a5919b27-0868-44a0-9f4e-28fad226288f/new-dashboard?orgId=1&panelId=1&auth_token=' + token
     7
     8        template = f"""
     9        <iframe
    10            frameborder="0"
    11            noresize="noresize"
    12            style="position: absolute; background: transparent; width: 100%; height: 100%"
    13            src="{ iframe }"
    14            frameborder="0"
    15        ></iframe>
    16        """
    17
    18        return Response(render_template_string(template), mimetype='text/html')