mirror of
https://github.com/grafana/grafana.git
synced 2025-07-28 11:32:36 +08:00
Docs: Plugin signing docs (#28671)
* WIP * Update plugin signing docs * Fix review comments
This commit is contained in:
@ -83,4 +83,4 @@ Learn more about Grafana options and packages.
|
||||
|
||||
- [Grafana Plugin SDK for Go]({{< relref "backend/grafana-plugin-sdk-for-go" >}})
|
||||
|
||||
<!-- BEGIN Optimal Workshop Intercept Snippet --><div id='owInviteSnippet' style='position:fixed;right:20px;bottom:20px;width:280px;padding:20px;margin:0;border-radius:6px;background:#1857B8;color:#F7F8FA;text-align:left;z-index:2200000000;opacity:0;transition:opacity 500ms;-webkit-transition:opacity 500ms;display:none;'><div id='owInviteMessage' style='padding:0;margin:0 0 20px 0;font-size:16px;'>Got a spare two and a half minutes to help us improve the docs?</div><a id='owInviteOk' href='https://Grafana.optimalworkshop.com/questions/grafana-docs?tag=docs&utm_medium=intercept' onclick='this.parentNode.style.display="none";' target='_blank' style='color:#F7FAFF;font-size:16px;font-weight:bold;text-decoration:underline;'>Yes, I'll help</a><a id='owInviteCancel' href='javascript:void(0)' onclick='this.parentNode.style.display="none";' style='color:#F7F8FA;font-size:14px;text-decoration:underline;float:right;'>Close</a></div><script>var owOnload=function(){if(-1==document.cookie.indexOf('ow-intercept-quiz-4ior230e')){var o=new XMLHttpRequest;o.onloadend=function(){try{var o=document.getElementById('owInviteSnippet');var date=new Date();date.setMonth(date.getMonth()+1);this.response&&JSON.parse(this.response).active===!0&&(document.cookie='ow-intercept-quiz-4ior230e=Done;path=/;expires='+date.toUTCString()+';',setTimeout(function(){o.style.display='block',o.style.opacity=1},2e3))}catch(e){}},o.open('POST','https://app.optimalworkshop.com/survey_status/questions/4ior230e/active'),o.send()}};if(window.addEventListener){window.addEventListener('load',function(){owOnload();});}else if(window.attachEvent){window.attachEvent('onload',function(){owOnload();});}</script><!-- END Optimal Workshop snippet -->
|
||||
<!-- BEGIN Optimal Workshop Intercept Snippet --><div id='owInviteSnippet' style='position:fixed;right:20px;bottom:20px;width:280px;padding:20px;margin:0;border-radius:6px;background:#1857B8;color:#F7F8FA;text-align:left;z-index:2200000000;opacity:0;transition:opacity 500ms;-webkit-transition:opacity 500ms;display:none;'><div id='owInviteMessage' style='padding:0;margin:0 0 20px 0;font-size:16px;'>Got a spare two and a half minutes to help us improve the docs?</div><a id='owInviteOk' href='https://Grafana.optimalworkshop.com/questions/grafana-docs?tag=docs&utm_medium=intercept' onclick='this.parentNode.style.display="none";' target='_blank' style='color:#F7FAFF;font-size:16px;font-weight:bold;text-decoration:underline;'>Yes, I'll help</a><a id='owInviteCancel' href='javascript:void(0)' onclick='this.parentNode.style.display="none";' style='color:#F7F8FA;font-size:14px;text-decoration:underline;float:right;'>Close</a></div><script>var owOnload=function(){if(-1==document.cookie.indexOf('ow-intercept-quiz-4ior230e')){var o=new XMLHttpRequest;o.onloadend=function(){try{var o=document.getElementById('owInviteSnippet');var date=new Date();date.setMonth(date.getMonth()+1);this.response&&JSON.parse(this.response).active===!0&&(document.cookie='ow-intercept-quiz-4ior230e=Done;path=/;expires='+date.toUTCString()+';',setTimeout(function(){o.style.display='block',o.style.opacity=1},2e3))}catch(e){}},o.open('POST','https://app.optimalworkshop.com/survey_status/questions/4ior230e/active'),o.send()}};if(window.addEventListener){window.addEventListener('load',function(){owOnload();});}else if(window.attachEvent){window.attachEvent('onload',function(){owOnload();});}</script><!-- END Optimal Workshop snippet -->
|
||||
|
@ -46,7 +46,7 @@ For plugins prior to Grafana 7.0, all options are considered _Display options_.
|
||||
|
||||
While backend plugins were available as an experimental feature in previous versions of Grafana, the support has been greatly improved for Grafana 7. Backend plugins for Grafana 7.0 are backwards-compatible and will continue to work. However, the old backend plugin system has been deprecated, and we recommend that you use the new SDK for backend plugins.
|
||||
|
||||
Since Grafana 7.0 introduced [signing of backend plugins]({{< relref "../../plugins/plugin-signature-verification.md" >}}), community plugins won’t load by default if they’re unsigned.
|
||||
Since Grafana 7.0 introduced [signing of backend plugins]({{< relref "../../plugins/plugin-signatures.md" >}}), community plugins won’t load by default if they’re unsigned.
|
||||
|
||||
To learn more, refer to [Backend plugins]({{< relref "backend" >}}).
|
||||
|
||||
@ -165,4 +165,4 @@ For more information, refer to [Data frames](https://grafana.com/docs/grafana/la
|
||||
|
||||
## Troubleshoot plugin migration
|
||||
|
||||
With Grafana 7.0, backend plugins can now be cryptographically signed to verify their origin. By default, Grafana will ignore unsigned plugins. For more information, refer to [Allow unsigned plugins]({{< relref "../../plugins/plugin-signature-verification.md#allow-unsigned-plugins" >}}).
|
||||
With Grafana 7.0, backend plugins can now be cryptographically signed to verify their origin. By default, Grafana will ignore unsigned plugins. For more information, refer to [Allow unsigned plugins]({{< relref "../../plugins/plugin-signatures.md#allow-unsigned-plugins" >}}).
|
||||
|
47
docs/sources/developers/plugins/package-a-plugin.md
Normal file
47
docs/sources/developers/plugins/package-a-plugin.md
Normal file
@ -0,0 +1,47 @@
|
||||
+++
|
||||
title = "Package a plugin"
|
||||
type = "docs"
|
||||
aliases = ["/docs/grafana/latest/developers/plugins/share-a-plugin/"]
|
||||
+++
|
||||
|
||||
# Package a plugin
|
||||
|
||||
You've just built your first plugin, and now you want to share it with the world. In this guide, you'll learn how to package and share your plugin with others.
|
||||
|
||||
For Grafana to be able to load a plugin, it first needs to be built. When you build a plugin from source, a `dist` directory is created that contains the production build, or _plugin assets_, for your plugin.
|
||||
|
||||
When the Grafana server starts, it recursively looks in the plugin directory for any directory that contains a `plugin.json` file and tries to load the plugin assets in the same directory.
|
||||
|
||||
There are three steps needed to package a plugin:
|
||||
|
||||
- Building the plugin
|
||||
- Signing the plugin
|
||||
- Archiving the plugin
|
||||
|
||||
1. Build the plugin
|
||||
|
||||
```
|
||||
yarn install --pure-lockfile
|
||||
yarn build
|
||||
```
|
||||
|
||||
1. (Optional) If your data source plugin has a backend plugin, build it as well.
|
||||
|
||||
```
|
||||
mage
|
||||
```
|
||||
|
||||
1. [Sign the plugin]({{< relref "sign-a-plugin.md" >}}).
|
||||
|
||||
1. Create a ZIP archive of the `dist` directory.
|
||||
|
||||
```
|
||||
mv dist/ myorg-simple-panel
|
||||
zip myorg-simple-panel-1.0.0.zip myorg-simple-panel -r
|
||||
```
|
||||
|
||||
## Publish your plugin on Grafana.com
|
||||
|
||||
The best way to share your plugin with the world is to publish it on [Grafana Plugins](https://grafana.com/plugins). By having your plugin published on Grafana.com, more users will be able to discover your plugin.
|
||||
|
||||
To publish a plugin to [Grafana Plugins](https://grafana.com/grafana/plugins), create a pull request to the [Grafana Plugin Repository](https://github.com/grafana/grafana-plugin-repository). Please note that both the source code and the packaged plugin archive need to be publicly available.
|
@ -1,120 +0,0 @@
|
||||
+++
|
||||
title = "Share a plugin"
|
||||
type = "docs"
|
||||
+++
|
||||
|
||||
# Share a plugin
|
||||
|
||||
You've just built your first plugin, and now you want to share it with the world. In this guide, you'll learn how to package and share your plugin with others.
|
||||
|
||||
When you build a plugin from source, a `dist` directory is created that contains the production build, or _plugin assets_, for your plugin.
|
||||
|
||||
When loading your plugin, Grafana only cares about the plugin assets. Specifically, when the Grafana server starts, it attempts to discover and load plugins like this:
|
||||
|
||||
1. Look for a `plugin.json` file in any of the subdirectories in the plugin directory.
|
||||
1. If a `plugin.json` was found, try to load the plugin assets from a `dist` directory in the same directory as the `plugin.json` file.
|
||||
1. If there's no `dist` directory, try to load the plugin assets from the same directory as the `plugin.json` file.
|
||||
|
||||
Now that you know what Grafana needs to load your plugin, let's see how you can share the plugin with other users.
|
||||
|
||||
The best way to share your plugin with the world is to publish it on [Grafana Plugins](https://grafana.com/plugins). However, if you're not ready to make your plugin public just yet, you can still share your plugin by hosting the plugin yourself.
|
||||
|
||||
## Publish your plugin on Grafana.com
|
||||
|
||||
To publish a plugin to [Grafana Plugins](https://grafana.com/grafana/plugins), your plugin first needs to be publicly available in a commit on [GitHub](https://github.com).
|
||||
|
||||
The commit you submit needs to either:
|
||||
|
||||
- Contain a `dist` directory with the plugin assets
|
||||
- Contain the plugin assets in the root directory
|
||||
|
||||
We strongly recommend that you don't check in the plugin assets to the main branch. Instead, use the following steps to create a release branch that contains the plugin assets.
|
||||
|
||||
1. Create a release branch.
|
||||
|
||||
```
|
||||
git checkout -b release-0.1.x
|
||||
```
|
||||
|
||||
1. Build the plugin assets.
|
||||
|
||||
```
|
||||
yarn build
|
||||
```
|
||||
|
||||
1. Add the `dist` directory. The `-f` flag adds the directory even if it's ignored by `.gitignore`.
|
||||
|
||||
```
|
||||
git add -f dist
|
||||
```
|
||||
|
||||
1. Create the release commit.
|
||||
|
||||
```
|
||||
git commit -m "Release v0.1.0"
|
||||
```
|
||||
|
||||
1. Create a release tag. You can also [create the release on GitHub](https://docs.github.com/en/github/administering-a-repository/managing-releases-in-a-repository). If you do, then you can skip this step and the next one.
|
||||
|
||||
```
|
||||
git tag -a v0.1.0 -m "Create release tag v0.1.0"
|
||||
```
|
||||
|
||||
1. Push to GitHub. `follow-tags` tells Git to push the release tag along with our release branch.
|
||||
|
||||
```
|
||||
git push --set-upstream origin release-0.1.x --follow-tags
|
||||
```
|
||||
|
||||
The next step is to submit the URL to your repository, and the release commit, to the [Grafana Plugin Repository](https://github.com/grafana/grafana-plugin-repository).
|
||||
|
||||
## Host the plugin yourself
|
||||
|
||||
If you want to share your plugin by hosting it yourself, then we recommend that you package it by adding the plugin assets to a .zip archive. You can then make the archive available by hosting it yourself.
|
||||
|
||||
How you package the plugin depends on whether you want to include the source code or not.
|
||||
|
||||
### Package the plugin with source code
|
||||
|
||||
If you want to distribute the source code along with your plugin assets, then you can archive the entire plugin directory.
|
||||
|
||||
To create a .zip archive that contains the plugin assets and source code, run the following commands in your terminal:
|
||||
|
||||
```
|
||||
cd my-plugin/
|
||||
yarn build
|
||||
zip my-plugin-0.2.0.src.zip . -r -x "node_modules/*" -x ".git/*"
|
||||
```
|
||||
|
||||
### Package the plugin without source code
|
||||
|
||||
If you don't want to distribute the plugin with the source code, then you can archive the `dist` directory.
|
||||
|
||||
To create a .zip archive that only contains the bare minimum to load the plugin, run the following commands in your terminal:
|
||||
|
||||
```
|
||||
cd my-plugin/
|
||||
yarn build
|
||||
cd dist/
|
||||
zip my-plugin-0.2.0.nosrc.zip . -r
|
||||
```
|
||||
|
||||
### Package and host your plugin using GitHub
|
||||
|
||||
If you host your plugin on GitHub, then you can share the plugin using the following URL:
|
||||
|
||||
```
|
||||
https://github.com/GITHUB_USERNAME/GITHUB_REPO_NAME/archive/<VERSION>.zip
|
||||
```
|
||||
|
||||
For example, you can download the [Worldmap Panel](https://github.com/grafana/worldmap-panel) using the following URL:
|
||||
|
||||
[https://github.com/grafana/worldmap-panel/archive/v0.3.2.zip](https://github.com/grafana/worldmap-panel/archive/v0.3.2.zip)
|
||||
|
||||
### Install a packaged plugin
|
||||
|
||||
After the user has downloaded the archive containing the plugin assets, they can install it by extracting the archive into their plugin directory.
|
||||
|
||||
```
|
||||
unzip my-plugin-0.2.0.zip -d YOUR_PLUGIN_DIR/my-plugin
|
||||
```
|
@ -5,6 +5,97 @@ type = "docs"
|
||||
|
||||
# Sign a plugin
|
||||
|
||||
Signing a plugin allows Grafana to verify the authenticity of the plugin with [signature verification]({{< relref "../../plugins/plugin-signature-verification.md" >}}). This gives users a way to make sure plugins haven't been tampered with. All Grafana Labs-authored backend plugins, including Enterprise plugins, are signed.
|
||||
Signing a plugin allows Grafana to verify the authenticity of the plugin with [signature verification]({{< relref "../../plugins/plugin-signatures.md" >}}). This gives users a way to make sure plugins haven't been tampered with. All Grafana Labs-authored backend plugins, including Enterprise plugins, are signed.
|
||||
|
||||
We're looking into providing a process for allowing community plugins to be signed in an upcoming version of Grafana.
|
||||
> **Important:** Future versions of Grafana will require all plugins to be signed.
|
||||
|
||||
## Sign your plugin using Grafana Toolkit
|
||||
|
||||
The easiest way to sign your plugin is by using the [Grafana Toolkit](https://www.npmjs.com/package/@grafana/toolkit).
|
||||
|
||||
You can sign your plugin as a _public_ or a _private_ plugin. In both cases, you need to [create an account on Grafana.com](https://grafana.com/signup) and generate an API key with the `PluginPublisher` role. By creating an account, you can verify that you own the plugin that you want to sign.
|
||||
|
||||
### Sign a public plugin
|
||||
|
||||
Plugins signed under the community or commercial signature level are considered _public plugins_. Public plugins are published on [Grafana Plugin](https://grafana.com/plugins). For more information about installing public plugins, refer to [Install Grafana plugins]({{< relref "../../plugins/installation.md" >}}).
|
||||
|
||||
1. Request a plugin signature level by sending an email to [plugins@grafana.com](mailto:plugins@grafana.com).
|
||||
|
||||
1. Sign the plugin with the API key you just created. Grafana Toolkit creates a [MANIFEST.txt](#plugin-manifest) file in the `dist` directory of your plugin.
|
||||
|
||||
```
|
||||
export GRAFANA_API_KEY=<YOUR_API_KEY>
|
||||
npx @grafana/toolkit plugin:sign
|
||||
```
|
||||
|
||||
### Sign a private plugin
|
||||
|
||||
If you're developing plugins for internal use only and don't want to make it public, you can sign it under a Private [signature level](#plugin-signature-levels).
|
||||
|
||||
1. Sign the plugin with the API key you just created. Grafana Toolkit creates a [MANIFEST.txt](#plugin-manifest) file in the `dist` directory of your plugin.
|
||||
|
||||
The `rootUrls` flag accepts a comma-separated list of URLs for which the plugin can be used. The URLs need to match the [root_url]({{< relref "../../administration/configuration.md#root_url" >}}) setting.
|
||||
|
||||
```
|
||||
export GRAFANA_API_KEY=<YOUR_API_KEY>
|
||||
npx @grafana/toolkit plugin:sign --rootUrls https://example.com/grafana
|
||||
```
|
||||
|
||||
## Plugin signature levels
|
||||
|
||||
To sign a plugin, you need to decide the _signature level_ you want to sign it under. The signature level of your plugin determines how you can distribute it.
|
||||
|
||||
You can sign your plugin under three different _signature levels_.
|
||||
|
||||
|**Plugin Level**|**Paid Subscription Required?**|**Description**|
|
||||
|---|---|---|
|
||||
|Private|No;<br>Free of charge|<p>You can create and sign a Private Plugin for any technology at no charge.</p><p>Private Plugins are for use on your own Grafana. They may not be distributed to the Grafana community, and are not published in the Grafana catalog.</p>|
|
||||
|Community|No;<br>Free of charge|<p>You can create, sign and distribute plugins at no charge, provided that all dependent technologies are open source and not for profit.</p><p>Community Plugins are published in the official Grafana catalog, and are available to the Grafana community.</p>|
|
||||
|Commercial|Yes;<br>Commercial Plugin Subscription required|<p>You can create, sign and distribute plugins with dependent technologies that are closed source or commercially backed, by entering into a Commercial Plugin Subscription with Grafana Labs.</p><p>Commercial Plugins are published on the official Grafana catalog, and are available to the Grafana community.</p>|
|
||||
|
||||
For instructions on how to sign a plugin under the Community and Commercial signature level, refer to [Sign a public plugin](#sign-a-public-plugin).
|
||||
|
||||
For instructions on how to sign a plugin under the Private signature level, refer to [Sign a private plugin](#sign-a-private-plugin).
|
||||
|
||||
## Plugin manifest
|
||||
|
||||
For Grafana to verify the digital signature of a plugin, the plugin must include a signed manifest file, _MANIFEST.txt_. The signed manifest file contains two sections:
|
||||
|
||||
- **Signed message -** The signed message contains plugin metadata and plugin files with their respective checksums (SHA256).
|
||||
- **Digital signature -** The digital signature is created by encrypting the signed message using a private key. Grafana has a public key built-in that can be used to verify that the digital signature have been encrypted using expected private key.
|
||||
|
||||
**Example manifest file:**
|
||||
|
||||
```txt
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
{
|
||||
"manifestVersion": "2.0.0",
|
||||
"signatureType": "community",
|
||||
"signedByOrg": "myorgid",
|
||||
"signedByOrgName": "My Org",
|
||||
"plugin": "myorgid-simple-panel",
|
||||
"version": "1.0.0",
|
||||
"time": 1602753404133,
|
||||
"keyId": "7e4d0c6a708866e7",
|
||||
"files": {
|
||||
"LICENSE": "12ab7a0961275f5ce7a428e662279cf49bab887d12b2ff7bfde738346178c28c",
|
||||
"module.js.LICENSE.txt": "0d8f66cd4afb566cb5b7e1540c68f43b939d3eba12ace290f18abc4f4cb53ed0",
|
||||
"module.js.map": "8a4ede5b5847dec1c6c30008d07bef8a049408d2b1e862841e30357f82e0fa19",
|
||||
"plugin.json": "13be5f2fd55bee787c5413b5ba6a1fae2dfe8d2df6c867dadc4657b98f821f90",
|
||||
"README.md": "2d90145b28f22348d4f50a81695e888c68ebd4f8baec731fdf2d79c8b187a27f",
|
||||
"module.js": "b4b6945bbf3332b08e5e1cb214a5b85c82557b292577eb58c8eb1703bc8e4577"
|
||||
}
|
||||
}
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: OpenPGP.js v4.10.1
|
||||
Comment: https://openpgpjs.org
|
||||
|
||||
wqEEARMKAAYFAl+IE3wACgkQfk0ManCIZudpdwIHTCqjVzfm7DechTa7BTbd
|
||||
+dNIQtwh8Tv2Q9HksgN6c6M9nbQTP0xNHwxSxHOI8EL3euz/OagzWoiIWulG
|
||||
7AQo7FYCCQGucaLPPK3tsWaeFqVKy+JtQhrJJui23DAZLSYQYZlKQ+nFqc9x
|
||||
T6scfmuhWC/TOcm83EVoCzIV3R5dOTKHqkjIUg==
|
||||
=GdNq
|
||||
-----END PGP SIGNATURE-----
|
||||
```
|
||||
|
Reference in New Issue
Block a user