This topic describes how to use an API key to generate a sharable Grafana dashboard link that can be accessed without logon to Grafana.
Background information
To access Grafana native dashboards, you can use the snapshot feature or enable the anonymous mode. The snapshot feature captures a static view of the accessed data, but snapshots do not reflect data updates over time. If you enable the anonymous mode, you must configure an IP address whitelist to ensure data security.
Managed Service for Grafana allows you to use an API key to generate a sharable dashboard link that can be accessed without logon to Grafana.
You can share the dashboard link with other users.
Users can access the specified dashboard by using the link without the need to log on to Grafana because the authentication is implemented based on an API key.
Step 1: Configure Grafana parameters
Log on to the ARMS console. In the left-side navigation pane, choose .
On the Workspace Management page, click the ID of the workspace that you want to manage.
In the left-side navigation pane, click Parameter Settings.
In the left-side parameter list, select aliyun, and then click Modify Parameters.
Set the api_key_share parameter to true and click Save and Apply.
Optional. If you want to embed a dashboard link into a web page by using an <iframe> tag, modify the relevant parameters based on your scenario.
Cross-domain embedding when the link and the web page are on different domain names:
Configure the link as an HTTPS URL and modify the following three parameters in security:
allow_embedding=true cookie_samesite=none cookie_secure=true
Same-domain embedding when the link and the web page share the same domain name:
Change the value of the allow_embedding parameter in security to true to enable embedding with an <iframe> tag.
To use the <iframe> tag for embedding into another Grafana instance, change the value of the
panels
parameter for the instance:enable_alpha = true disable_sanitize_html = true
Step 2: Create an API key
The procedure to create an API key varies in Grafana 9.0.x and Grafana 10.0.x. Check your Grafana version and follow the corresponding procedure.
If you upgrade Grafana from 9.0.x to 10.0.x, you can still view the API keys created in Grafana 9.0.x on the API Keys page. You can click Migrate to service account to migrate the API keys created in Grafana 9.0.x to your service account. After the migration is complete, the API Keys page is forever hidden. You can still use the API keys created in Grafana 9.0.x after upgrading Grafana from 9.0.x to 10.0.x.
Grafana 9.0.x
Log on to the ARMS console. In the left-side navigation pane, choose .
On the Workspace Management page, find the workspace that you want to manage and click the URL in the URL column to go to Grafana.
NoteYou can log on to Grafana with the administrator account of Grafana and the password that you configured when you created the workspace. You can also click Sign in with Alibaba Cloud to log on to Grafana with the current Alibaba Cloud account.
Click the
icon in the upper-left corner of the Grafana homepage.
In the left-side navigation pane of the Grafana interface, choose
.NoteAdmin permissions are required to access the API Keys page.
Click New API key or Add API key, and then configure the following parameters.
Parameter
Description
Key name
The name of the API key. The name cannot be the same as that of an existing API key.
Role
Select Viewer.
Time to live
The validity period of the API key. Examples: 60s (60 seconds), 10m (10 minutes), and 1d (one day).
Click Add. In the dialog box that appears, obtain and save the value of the API key.
ImportantAfter the dialog box is closed, you cannot view the value of the API key again.
Grafana 10.0.x
Log on to the ARMS console. In the left-side navigation pane, choose .
On the Workspace Management page, find the workspace that you want to manage and click the URL in the URL column to go to Grafana.
NoteYou can log on to Grafana with the administrator account of Grafana and the password that you configured when you created the workspace. You can also click Sign in with Alibaba Cloud to log on to Grafana with the current Alibaba Cloud account.
Click the
icon in the upper-left corner of the Grafana homepage.
In the left-side navigation pane, choose
.ImportantAdmin permissions are required to access the Service Accounts page.
Creating a service account uses one of the available user account slots.
Click Add service account token, configure the following parameters, and then click Create.
Parameter
Description
Display name
The name of the service account. The name cannot be the same as that of an existing service account.
Role
Select Viewer.
Click Add service account token and configure the following parameters.
Parameter
Description
Display name
The name of the API key. The name cannot be the same as that of an existing API key.
Expiration
The validity period of the API key. Valid values:
No Expiration
Set Expiration date
Expiration date
If you set Expiration to Set Expiration date, you need to set the expiration date of the validity period.
Click Generate token. In the dialog box that appears, click Copy to clipboard and close.
After the dialog box is closed, you cannot view the value of the API key again.
Step 3: Generate a sharable dashboard link
Grafana 9.0.x
On the Grafana interface, go to the page of the dashboard that you want to share.
Click the
icon. In the dialog box that appears, click the Link tab. On the Link tab, obtain the sharable link of the dashboard.
Append
&aliyun_api_key=<API key value>
to the end of the link. <API key value> indicates the value of the API key that you obtained in Step 2.https://grafana-example.grafana.aliyuncs.com/d/TZWea****/test?orgId=1&from=167081684****&to=167083844****&aliyun_api_key=eyJr****WkIwNnN2c0RTSD******
You can use the sharable link that contains the API key to access the dashboard without logon to Grafana.
Grafana 10.0.x
On the Grafana interface, go to the page of the dashboard that you want to share.
Click the
icon. In the dialog box that appears, click the Link tab. On the Link tab, obtain the sharable link of the dashboard.
Append
&aliyun_api_key=<API key value>
to the end of the link. <API key value> indicates the value of the API key that you obtained in Step 2.https://grafana-example.grafana.aliyuncs.com/d/TZWea****/test?orgId=1&from=167081684****&to=167083844****&aliyun_api_key=eyJrIjoiWkIwNnN2c0RTSD******
You can use the sharable link that contains the API key to access the dashboard without logon to Grafana.
(Optional) Step 4: Generate a high-security sharable link
To avoid data security risks caused by API key leaks, you must periodically change the API key of the shared link that is generated in Step 3: Generate a sharable dashboard link. This step describes how to generate high-security sharable links in the API key and service account token scenarios. In Grafana versions later than 10.0.x, API keys are called service account tokens.
First, you need to change the runtime parameters of api_key_share_version to v2.
Log on to the ARMS console. In the left-side navigation pane, choose .
On the Workspace Management page, click the workspace ID. In the left-side navigation pane of the page that appears, click Parameter Settings.
Set the api_key_share_version parameter to v2 and click Save and Apply.
API keys (Grafana 9.0.x)
Decrypt the API key obtained in Step 2: Create an API key in Base64.
Base64 is a common encoding method used on the web for transmitting 8-bit byte codes. It is a technique that represents binary data using 64 printable characters.
Use common online tools for decryption, such as base64.
Decrypt the API key in Java.
package main import java.util.Base64; public class Base64Example{ public static void main(String[] args) { String apiKey = "eyJr****REpzZGYzd2JIa0N3ekgyWjlWWmhrSTM5bWdGT2hGSmwiLCJuIjoidGVzdDEiLCJpZCI6MX0="; String decodeKey = new String(Base64.getDecoder().decode(apiKey)); System.out.println(decodeKey); } }
Output:
{"k":"DJsd****HkCwzH2Z9VZhkI39mgFOhFJl","n":"test1","id":1}
Decrypt the API key in Go.
package main import "fmt" import "encoding/base64" func main() { apiKey := "eyJr****REpzZGYzd2JIa0N3ekgyWjlWWmhrSTM5bWdGT2hGSmwiLCJuIjoidGVzdDEiLCJpZCI6MX0=" decodeKey, err := base64.StdEncoding.DecodeString(apiKey) if err != nil { fmt.Println(err.Error()) return } fmt.Println(string(decodeKey)) }
Output:
{"k":"DJsd****HkCwzH2Z9VZhkI39mgFOhFJl","n":"test1","id":1}
Encrypt the decrypted API key value obtained above using PBKDF2.
Password-Based Key Derivation Function 2 (PBKDF2) is a password-based key derivation function used to securely derive an encryption key from a user-provided password along with some additional parameters such as a salt and iteration count. It is primarily used in scenarios where user passwords need to be stored, aiming to ensure that even if the database is compromised, attackers will find it difficult to directly obtain the user plaintext password or easily crack the derived key.
Multiple encryption methods are available. The following table describes the encryption parameters.
Parameter
Description
salt
Enter the name of the API key (that is, the value of n decrypted above). In this example, set the value to test1.
iteration
Set the value to 10000.
output length
Set the value to 50.
key size
Set the value to 256.
output type
Set the value to Hex.
Use common online tools for encryption, such as df2.
Derive the key in Java.
package main import javax.crypto.SecretKeyFactory; import java.security.GeneralSecurityException; import javax.crypto.spec.PBEKeySpec; import java.security.spec.KeySpec; public class PBKDFExapmle { public static void main(String[] args) { String password = "DJsd****HkCwzH2Z9VZhkI39mgFOhFJl"; String salt = "test1"; int iterationCount = 10000; int outputLength = 50 * 8; try { KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), iterationCount, outputLength); SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); byte[] keyBytes = skf.generateSecret(spec).getEncoded(); System.out.println(bytesToHex(keyBytes)); } catch (GeneralSecurityException e) { e.printStackTrace(); } } private static String bytesToHex(byte[] bytes) { StringBuilder hexString = new StringBuilder(); for (byte b : bytes) { String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) { hexString.append('0'); } hexString.append(hex); } return hexString.toString(); } }
Output: PBKDF2 Password
1e5b****80184e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****
Derive the key in Go.
package main import "fmt" import "encoding/hex" import "crypto/sha256" import "golang.org/x/crypto/pbkdf2" func main() { password:="DJsd****HkCwzH2Z9VZhkI39mgFOhFJl" salt="test1" newPasswd := pbkdf2.Key([]byte(password), []byte(salt), 10000, 50, sha256.New) encodePassword:= hex.EncodeToString(newPasswd) fmt.Println(encodePassword) }
Output: PBKDF2 Password
1e5b****80184e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****
Construct an MD5 digest signature parameter based on information encrypted using PBKDF2.
The MD5 Message-Digest Algorithm is a widely used cryptographic hash function that produces a 128-bit (16-byte) hash value, designed to ensure the integrity and consistency of transmitted information.
The content to be encrypted is composed of: <PBKDF2 Password> + "_" + <current system time as an integer in seconds>.
Example:
If the PBKDF2 Password is: 1e5b****80184e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****
And the current system time is: 2024-09-20 17:12:13, then the precise time in seconds since epoch would be: 1726823533
Therefore, the complete information for generating the MD5 signature would be: 1e5b****80184 e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****_1726823533.
Methods for generating the MD5 signature:
Use common online tools for encryption, such as MD5.
Implement MD5 hashing in Java.
package main; import java.security.MessageDigest; public class MD5 { public static void main(String[] args) { String pbkdfPassword = "1e5b****80184e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****"; long timeSeconds=System.currentTimeMillis()/1000; String key=pbkdfPassword+"_"+timeSeconds; System.out.println(MD5.getMD5String(key,"UTF-8")); } public static String getMD5String(String str, String charset) { try { MessageDigest messageDigest = MessageDigest.getInstance("MD5"); messageDigest.reset(); messageDigest.update(str.getBytes(charset)); byte[] byteArray = messageDigest.digest(); StringBuffer md5StrBuff = new StringBuffer(); for (int i = 0; i < byteArray.length; i++) { if (Integer.toHexString(0xFF & byteArray[i]).length() == 1) { md5StrBuff.append("0").append( Integer.toHexString(0xFF & byteArray[i])); } else { md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i])); } } return md5StrBuff.toString().toLowerCase(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("MD5 error:"+e.getMessage()); } } }
Implement MD5 hashing in Go.
package main import ( "crypto/md5" "encoding/hex" "fmt" "io" "time" "strconv" ) func main() { // The string that needs to be hashed with MD5. pbkdfPassword := "1e5b****80184e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****" timeSeconds:= time.Now().Unix() key:=pbkdfPassword+"_"+strconv.FormatInt(timeSeconds, 10) // Calculate the MD5 hash of the string using the md5 package. hash := md5.New() io.WriteString(hash, key) md5Str := hash.Sum(nil) // Convert the binary MD5 value to a hexadecimal string. md5StrHex := hex.EncodeToString(md5Str) fmt.Println("MD5 of", key, "is", md5StrHex) }
Construct URL parameters based on the generated MD5 signature.
The following table describes the parameters.
Parameter
Description
Example
aliyun_api_key_sign
The MD5 signature, which changes over time.
c3bf89b867cc88df72d507edc4d1****
aliyun_api_key_timestamp
The signature time. The signature expires and becomes invalid if the difference between the signature time and the system time exceeds 1 minute.
1726823533
aliyun_api_key_name
The name of the API key.
test1
aliyun_api_key_org_id
The organization ID of the API key.
1
aliyun_api_key_expire_seconds
The time when the MD5 signature expires after logon. Unit: seconds.
3600 (default)
Example:
https://grafana-example.grafana.aliyuncs.com/d/TZWea****/test?orgId=1&from=167081684****&to=167083844****&aliyun_api_key_sign=c3bf89b867cc88df72d507edc4d1****&aliyun_api_key_timestamp=1726823533&aliyun_api_key_name=test1&aliyun_api_key_org_id=1
This way, you can dynamically generate a more secure password-free logon link to Grafana each time based on the program code and avoid API key leaks.
Service account tokens (Grafana 10.0.x)
Split and encrypt the API key (referred to as service account token in Grafana 10.0.x and later) from Step 2: Create an API key using PBKDF2.
Password-Based Key Derivation Function 2 (PBKDF2) is a password-based key derivation function used to securely derive an encryption key from a user-provided password along with some additional parameters such as a salt and iteration count. It is primarily used in scenarios where user passwords need to be stored, aiming to ensure that even if the database is compromised, attackers will find it difficult to directly obtain the user plaintext password or easily crack the derived key.
Split the service account token with an underscore (_).
# Use the following service account token as an example: Token:glsa_yV9HAOVCjNKkvKoLMiypOc5T0Oov****_4f5ff3ce # After splitting, it becomes: Prefix: glsa Secret:yV9HAOVCjNKkvKoLMiypOc5T0Oov**** Salt:4f5ff3ce
Multiple encryption methods are available. The following table describes the encryption parameters.
Parameter
Description
salt
Enter the token suffix. In this example, set the value to 4f5ff3ce.
iteration
Set the value to 10000.
output length
Set the value to 50.
key size
Set the value to 256.
output type
Set the value to Hex.
Use common online tools for decryption, such as charsetpbkdf2.
Decrypt the API key in Java.
package main import javax.crypto.SecretKeyFactory; import java.security.GeneralSecurityException; import javax.crypto.spec.PBEKeySpec; import java.security.spec.KeySpec; public class PBKDFExapmle { public static void main(String[] args) { String password = "yV9H****jNKkvKoLMiypOc5T0OovHXPV"; String salt = "4f5ff3ce"; int iterationCount = 10000; int outputLength = 50 * 8; try { KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), iterationCount, outputLength); SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); byte[] keyBytes = skf.generateSecret(spec).getEncoded(); System.out.println(bytesToHex(keyBytes)); } catch (GeneralSecurityException e) { e.printStackTrace(); } } private static String bytesToHex(byte[] bytes) { StringBuilder hexString = new StringBuilder(); for (byte b : bytes) { String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) { hexString.append('0'); } hexString.append(hex); } return hexString.toString(); } }
Output: PBKDF2 Password
c3cd****971bab928e4ecd6e7a00c74657696ea07d38c43f3bb5dc3190f2285cb80695cf7bf2f25c9b1f34fe1e0f9549****
Derive the key in Go.
package main import "fmt" import "encoding/hex" import "crypto/sha256" import "golang.org/x/crypto/pbkdf2" func main() { password:="yV9H****jNKkvKoLMiypOc5T0OovHXPV" salt="4f5ff3ce" newPasswd := pbkdf2.Key([]byte(password), []byte(salt), 10000, 50, sha256.New) encodePassword:= hex.EncodeToString(newPasswd) fmt.Println(encodePassword) }
Output: PBKDF2 Password
c3cd****971bab928e4ecd6e7a00c74657696ea07d38c43f3bb5dc3190f2285cb80695cf7bf2f25c9b1f34fe1e0f9549****
Construct an MD5 digest signature parameter based on information encrypted using PBKDF2.
The MD5 Message-Digest Algorithm is a widely used cryptographic hash function that produces a 128-bit (16-byte) hash value, designed to ensure the integrity and consistency of transmitted information.
The content to be encrypted is composed of: <PBKDF2 Password> + "_" + <current system time as an integer in seconds>.
Example:
If the PBKDF2 Password is: 1e5b****80184e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****
And the current system time is: 2024-09-20 17:12:13, then the precise time in seconds since epoch would be: 1726823533
Therefore, the complete information for generating the MD5 signature would be: 1e5b****80184 e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****_1726823533.
Methods for generating the MD5 signature:
Use common online tools for encryption, such as MD5.
Implement MD5 hashing in Java.
package main; import java.security.MessageDigest; public class MD5 { public static void main(String[] args) { String pbkdfPassword = "1e5b****80184e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****"; long timeSeconds=System.currentTimeMillis()/1000; String key=pbkdfPassword+"_"+timeSeconds; System.out.println(MD5.getMD5String(key,"UTF-8")); } public static String getMD5String(String str, String charset) { try { MessageDigest messageDigest = MessageDigest.getInstance("MD5"); messageDigest.reset(); messageDigest.update(str.getBytes(charset)); byte[] byteArray = messageDigest.digest(); StringBuffer md5StrBuff = new StringBuffer(); for (int i = 0; i < byteArray.length; i++) { if (Integer.toHexString(0xFF & byteArray[i]).length() == 1) { md5StrBuff.append("0").append( Integer.toHexString(0xFF & byteArray[i])); } else { md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i])); } } return md5StrBuff.toString().toLowerCase(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("MD5 error:"+e.getMessage()); } } }
Implement MD5 hashing in Go.
package main import ( "crypto/md5" "encoding/hex" "fmt" "io" "time" "strconv" ) func main() { // The string that needs to be hashed with MD5. pbkdfPassword := "1e5b****80184e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****" timeSeconds:= time.Now().Unix() key:=pbkdfPassword+"_"+strconv.FormatInt(timeSeconds, 10) // Calculate the MD5 hash of the string using the md5 package. hash := md5.New() io.WriteString(hash, key) md5Str := hash.Sum(nil) // Convert the binary MD5 value to a hexadecimal string. md5StrHex := hex.EncodeToString(md5Str) fmt.Println("MD5 of", key, "is", md5StrHex) }
Construct URL parameters based on the generated MD5 signature.
The following table describes the parameters.
Parameter
Description
Example
aliyun_api_key_sign
The MD5 signature, which changes over time.
c3bf89b867cc88df72d507edc4d1****
aliyun_api_key_timestamp
The signature time. The signature expires and becomes invalid if the difference between the signature time and the system time exceeds 1 minute.
1726823533
aliyun_api_key_name
The name of the service account token.
test1
aliyun_api_key_org_id
The organization ID of the service account token.
1
aliyun_api_key_expire_seconds
The time when the MD5 signature expires after logon. Unit: seconds.
3600 (default)
Example:
https://grafana-example.grafana.aliyuncs.com/d/TZWea****/test?orgId=1&from=167081684****&to=167083844****&aliyun_api_key_sign=c3bf89b867cc88df72d507edc4d1****&aliyun_api_key_timestamp=1726823533&aliyun_api_key_name=test1&aliyun_api_key_org_id=1
This way, you can dynamically generate a more secure password-free logon link to Grafana each time based on the program code and avoid service account token leaks.
FAQ
What do I do if the following error was reported when I accessed a dashboard by using a sharable link?
Possible cause: You did not configure the allow_embedding parameter when you embedded the dashboard link into a web page by using an <iframe> tag. For information about how to configure the allow_embedding parameter, see Step 1 of this topic.
Why did a dashboard fail to display data?
If you have embedded the dashboard link into a web page by using an <iframe> tag, cookies cannot be written due to the following possible causes:
The link and the web page are on different domain names. In this case, cookies cannot be written by default.
The cookie_samesite parameter is set to none, but the cookie_secure parameter is set to false.
The link was configured as an HTTP URL. However, an HTTP URL is not supported because the cookie_secure parameter cannot take effect for HTTP.
You can reconfigure the Grafana parameters to troubleshoot the issue. For more information, see Step 1 of this topic.
What do I do if the following error was reported when accessing a dashboard by using a sharable link?
Possible causes:
Your browser version is outdated.
The browser configuration is invalid if you have embedded the dashboard link into a web page by using an <iframe> tag.
Solutions:
View the configuration of cookies and enable cookies.
If you use Chrome, you need to enable all cookies in incognito mode.
When I embed a dashboard link into a web page by using an API key, do I need to specify a short validity period for one-time use of the API key, or a long validity period for the API key for a logon-free experience?
You can specify a validity period for the API key based on your security requirements. We recommend that you change the API key every three months to ensure security. If the API key is leaked, you can delete the key to prevent unauthorized access.
Am I able to create API keys without limits?
The number of API keys that can be created is not limited in the official source code. However, only up to 100 API keys are displayed on the Grafana interface at a time. We recommend that you keep the number of API keys to 100 or fewer.
Does the system automatically delete an API key after the API key expires?
No, the system retains the data of expired API keys. To make room for new API keys, you can manually delete the expired API keys. By default, expired API keys are hidden on the Grafana interface. To view expired API keys, you can turn on Include expired keys. Then, you can delete the expired API keys.