From 84ea13bf6c584cb4aebfb76e162e5cba7b004cec Mon Sep 17 00:00:00 2001 From: Tania B Date: Wed, 2 Feb 2022 15:02:57 +0200 Subject: [PATCH 01/17] Docs: Refactor encryption docs (#44718) * Docs: Refactor encryption docs * Rename enterprise encr * Remove envelope encr page * combine database encryption sections * fix reference * Fix link Co-authored-by: Mitchel Seaman --- .../database-encryption-enterprise.md | 22 ------------ .../administration/database-encryption.md | 24 +++++++++++-- .../administration/envelope-encryption.md | 21 ----------- .../enterprise-encryption/_index.md | 35 +++++++++++++++++++ ...ing-aws-kms-to-encrypt-database-secrets.md | 0 ...e-key-vault-to-encrypt-database-secrets.md | 0 ...e-cloud-kms-to-encrypt-database-secrets.md | 0 ...p-key-vault-to-encrypt-database-secrets.md | 0 .../enterprise/kms-integration/_index.md | 19 ---------- 9 files changed, 56 insertions(+), 65 deletions(-) delete mode 100644 docs/sources/administration/database-encryption-enterprise.md delete mode 100644 docs/sources/administration/envelope-encryption.md create mode 100644 docs/sources/enterprise/enterprise-encryption/_index.md rename docs/sources/enterprise/{kms-integration => enterprise-encryption}/using-aws-kms-to-encrypt-database-secrets.md (100%) rename docs/sources/enterprise/{kms-integration => enterprise-encryption}/using-azure-key-vault-to-encrypt-database-secrets.md (100%) rename docs/sources/enterprise/{kms-integration => enterprise-encryption}/using-google-cloud-kms-to-encrypt-database-secrets.md (100%) rename docs/sources/enterprise/{kms-integration => enterprise-encryption}/using-hashicorp-key-vault-to-encrypt-database-secrets.md (100%) delete mode 100644 docs/sources/enterprise/kms-integration/_index.md diff --git a/docs/sources/administration/database-encryption-enterprise.md b/docs/sources/administration/database-encryption-enterprise.md deleted file mode 100644 index d0974ab581c..00000000000 --- a/docs/sources/administration/database-encryption-enterprise.md +++ /dev/null @@ -1,22 +0,0 @@ -+++ -title = "Database encryption (Enterprise)" -description = "Grafana Enterprise database encryption" -keywords = ["grafana", "enterprise", "database", "encryption", "documentation"] -aliases = [""] -weight = 440 -+++ - -# Grafana Enterprise database encryption - -If you are using Grafana Enterprise, you can change Grafana’s cryptographic mode of operation from AES-CFB to AES-GCM, and integrate with a key management system (KMS) provider. - -## Changing your encryption mode to AES-GCM - -Grafana encrypts secrets using Advanced Encryption Standard in Cipher -FeedBack mode (AES-CFB). You might prefer to use AES in Galois/Counter -Mode (AES-GCM) instead, to meet your company’s security requirements or -in order to maintain consistency with other services. - -To change your encryption mode, update the `algorithm` value in the -`[security.encryption]` section of your Grafana configuration file. -For details, refer to Enterprise configuration. diff --git a/docs/sources/administration/database-encryption.md b/docs/sources/administration/database-encryption.md index e441aa1bb63..ceb343d512f 100644 --- a/docs/sources/administration/database-encryption.md +++ b/docs/sources/administration/database-encryption.md @@ -1,7 +1,7 @@ +++ title = "Database encryption" description = "Grafana database encryption" -keywords = ["grafana", "database", "encryption", "documentation"] +keywords = ["grafana", "database", "encryption", "envelope encryption", "documentation"] aliases = [""] weight = 450 +++ @@ -12,6 +12,24 @@ Grafana’s database contains secrets, which are used to query data sources, sen Grafana encrypts these secrets before they are written to the database, by using a symmetric-key encryption algorithm called Advanced Encryption Standard (AES), and using a [secret key]({{< relref "../administration/configuration/#secret_key" >}}) that you can change when you configure a new Grafana instance. -You can choose to use [envelope encryption]({{< relref "./envelope-encryption.md" >}}), which complements a [KMS integration]({{< relref "../enterprise/kms-integration/_index.md" >}}) in Grafana Enterprise by adding a layer of indirection to the encryption process. +You can choose to use [envelope encryption](#envelope-encryption), which adds a layer of indirection to the encryption process. -In Grafana Enterprise, you can also choose to [encrypt secrets in AES-GCM mode]({{< relref "../administration/database-encryption-enterprise.md" >}}) instead of AES-CFB. +> **Note:** In Grafana Enterprise, you can also choose to [encrypt secrets in AES-GCM mode]({{< relref "../enterprise/enterprise-encryption/#changing-your-encryption-mode-to-aes-gcm" >}}) instead of AES-CFB. + +# Envelope encryption + +In Grafana, you can choose to use envelope encryption. Instead of +encrypting all secrets with a single key, Grafana uses a set of keys +called data encryption keys (DEKs) to encrypt them. These data +encryption keys are themselves encrypted with a single key encryption +key (KEK). + +To turn on envelope encryption, add the term `envelopeEncryption` to the list of feature toggles in your [Grafana configuration]({{< relref "../administration/configuration/#feature_toggles" >}}). + +> **Note:** Avoid turning off envelope encryption once you have turned it on, and back up your database before turning it on for the first time. If you turn envelope encryption on, create new secrets or update your existing secrets (for example, by creating a new data source or alert notification channel), and then turn envelope encryption off, then those data sources, alert notification channels, and other resources using envelope encryption will stop working and you will experience errors. This is because the secrets encrypted with envelope encryption cannot be decrypted or used by Grafana when envelope encryption is turned off. + +# KMS integration + +With KMS integrations, you can choose to encrypt secrets stored in the Grafana database using a key from a KMS, which is a secure central storage location that is designed to help you to create and manage cryptographic keys and control their use across many services. + +> **Note:** KMS integration is available in Grafana Enterprise. For more information, refer to [Enterprise Encryption]({{< relref "../enterprise/enterprise-encryption/_index.md" >}}) in Grafana Enterprise. diff --git a/docs/sources/administration/envelope-encryption.md b/docs/sources/administration/envelope-encryption.md deleted file mode 100644 index db8887b51bb..00000000000 --- a/docs/sources/administration/envelope-encryption.md +++ /dev/null @@ -1,21 +0,0 @@ -+++ -title = "Envelope encryption" -description = "Envelope encryption" -keywords = ["grafana", "envelope encryption", "documentation"] -aliases = [""] -weight = 430 -+++ - -# Envelope encryption - -In Grafana, you can choose to use envelope encryption. Instead of -encrypting all secrets with a single key, Grafana uses a set of keys -called data encryption keys (DEKs) to encrypt them. These data -encryption keys are themselves encrypted with a single key encryption -key (KEK). - -To turn on envelope encryption, add the term `envelopeEncryption` to the list of feature toggles in your [Grafana configuration]({{< relref "../administration/configuration/#feature_toggles" >}}). - -> **Note:** Avoid turning off envelope encryption once you have turned it on, and back up your database before turning it on for the first time. If you turn envelope encryption on, create new secrets or update your existing secrets (for example, by creating a new data source or alert notification channel), and then turn envelope encryption off, then those data sources, alert notification channels, and other resources using envelope encryption will stop working and you will experience errors. This is because the secrets encrypted with envelope encryption cannot be decrypted or used by Grafana when envelope encryption is turned off. - -Refer to [Database encryption]({{< relref "../administration/database-encryption.md" >}}) to learn more about how Grafana encrypts secrets in the database. diff --git a/docs/sources/enterprise/enterprise-encryption/_index.md b/docs/sources/enterprise/enterprise-encryption/_index.md new file mode 100644 index 00000000000..ca4a52640a3 --- /dev/null +++ b/docs/sources/enterprise/enterprise-encryption/_index.md @@ -0,0 +1,35 @@ ++++ +title = "Enterprise database encryption" +description = "Grafana Enterprise database encryption" +keywords = ["grafana", "enterprise", "database", "encryption", "documentation"] +aliases = [""] +weight = 130 ++++ + +# Grafana Enterprise database encryption + +If you are using Grafana Enterprise, you can integrate with a key management system (KMS) provider, and change Grafana’s cryptographic mode of operation from AES-CFB to AES-GCM. + +## Encrypting your database with a key from a Key Management System (KMS) + +You can choose to encrypt secrets stored in the Grafana database using a key from a KMS, which is a secure central storage location that is designed to help you to create and manage cryptographic keys and control their use across many services. When you integrate with a KMS, Grafana does not directly store your encryption key. Instead, Grafana stores KMS credentials and the identifier of the key, which Grafana uses to encrypt the database. + +Grafana integrates with the following key management systems: + +- [AWS KMS]({{< relref "/using-aws-kms-to-encrypt-database-secrets.md" >}}) +- [Azure Key Vault]({{< relref "/using-azure-key-vault-to-encrypt-database-secrets.md" >}}) +- [Google Cloud KMS]({{< relref "/using-google-cloud-kms-to-encrypt-database-secrets.md" >}}) +- [Hashicorp Key Vault]({{< relref "/using-hashicorp-key-vault-to-encrypt-database-secrets.md" >}}) + +Refer to [Database encryption]({{< relref "../../administration/database-encryption.md" >}}) to learn more about how Grafana encrypts secrets in the database. + +## Changing your encryption mode to AES-GCM + +Grafana encrypts secrets using Advanced Encryption Standard in Cipher +FeedBack mode (AES-CFB). You might prefer to use AES in Galois/Counter +Mode (AES-GCM) instead, to meet your company’s security requirements or +in order to maintain consistency with other services. + +To change your encryption mode, update the `algorithm` value in the +`[security.encryption]` section of your Grafana configuration file. +For details, refer to [Enterprise configuration]({{< relref "../enterprise-configuration.md#securityencryption" >}}). diff --git a/docs/sources/enterprise/kms-integration/using-aws-kms-to-encrypt-database-secrets.md b/docs/sources/enterprise/enterprise-encryption/using-aws-kms-to-encrypt-database-secrets.md similarity index 100% rename from docs/sources/enterprise/kms-integration/using-aws-kms-to-encrypt-database-secrets.md rename to docs/sources/enterprise/enterprise-encryption/using-aws-kms-to-encrypt-database-secrets.md diff --git a/docs/sources/enterprise/kms-integration/using-azure-key-vault-to-encrypt-database-secrets.md b/docs/sources/enterprise/enterprise-encryption/using-azure-key-vault-to-encrypt-database-secrets.md similarity index 100% rename from docs/sources/enterprise/kms-integration/using-azure-key-vault-to-encrypt-database-secrets.md rename to docs/sources/enterprise/enterprise-encryption/using-azure-key-vault-to-encrypt-database-secrets.md diff --git a/docs/sources/enterprise/kms-integration/using-google-cloud-kms-to-encrypt-database-secrets.md b/docs/sources/enterprise/enterprise-encryption/using-google-cloud-kms-to-encrypt-database-secrets.md similarity index 100% rename from docs/sources/enterprise/kms-integration/using-google-cloud-kms-to-encrypt-database-secrets.md rename to docs/sources/enterprise/enterprise-encryption/using-google-cloud-kms-to-encrypt-database-secrets.md diff --git a/docs/sources/enterprise/kms-integration/using-hashicorp-key-vault-to-encrypt-database-secrets.md b/docs/sources/enterprise/enterprise-encryption/using-hashicorp-key-vault-to-encrypt-database-secrets.md similarity index 100% rename from docs/sources/enterprise/kms-integration/using-hashicorp-key-vault-to-encrypt-database-secrets.md rename to docs/sources/enterprise/enterprise-encryption/using-hashicorp-key-vault-to-encrypt-database-secrets.md diff --git a/docs/sources/enterprise/kms-integration/_index.md b/docs/sources/enterprise/kms-integration/_index.md deleted file mode 100644 index 3ee28fa22a8..00000000000 --- a/docs/sources/enterprise/kms-integration/_index.md +++ /dev/null @@ -1,19 +0,0 @@ -+++ -title = "KMS integration" -description = "" -keywords = ["grafana", "kms", "key management system integration"] -weight = 1200 -+++ - -# Key management systems (KMSs) - -You can choose to encrypt secrets stored in the Grafana database using a key from a KMS, which is a secure central storage location that is designed to help you to create and manage cryptographic keys and control their use across many services. When you integrate with a KMS, Grafana does not directly store your encryption key. Instead, Grafana stores KMS credentials and the identifier of the key, which Grafana uses to encrypt the database. - -Grafana integrates with the following key management systems: - -- [AWS KMS]({{< relref "/using-aws-kms-to-encrypt-database-secrets.md" >}}) -- [Azure Key Vault]({{< relref "/using-azure-key-vault-to-encrypt-database-secrets.md" >}}) -- [Google Cloud KMS]({{< relref "/using-google-cloud-kms-to-encrypt-database-secrets.md" >}}) -- [Hashicorp Key Vault]({{< relref "/using-hashicorp-key-vault-to-encrypt-database-secrets.md" >}}) - -Refer to [Database encryption]({{< relref "../../administration/database-encryption.md" >}}) to learn more about how Grafana encrypts secrets in the database. From b78082f4265fa12149e65af8bf1826f38840567e Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Wed, 2 Feb 2022 14:03:14 +0100 Subject: [PATCH 02/17] doc: snapshots: fix JSON response (#44758) --- docs/sources/http_api/snapshot.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/http_api/snapshot.md b/docs/sources/http_api/snapshot.md index 5b88002f713..3db642fc013 100644 --- a/docs/sources/http_api/snapshot.md +++ b/docs/sources/http_api/snapshot.md @@ -71,7 +71,7 @@ JSON Body schema: "deleteUrl":"myurl/api/snapshots-delete/XXXXXXX", "key":"YYYYYYY", "url":"myurl/dashboard/snapshot/YYYYYYY", - "id": 1, + "id": 1 } ``` From 924deda589d7150cdb668a25b255ee4168dc2763 Mon Sep 17 00:00:00 2001 From: George Robinson Date: Wed, 2 Feb 2022 13:28:41 +0000 Subject: [PATCH 03/17] Fix Discord Webhook URL for invalid template (#44763) This commit fixes an issue where an invalid template for Discord would change the Webhook URL to "" and cause "unsupported protocol scheme" errors. --- pkg/services/ngalert/notifier/channels/discord.go | 1 + pkg/services/ngalert/notifier/channels/discord_test.go | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/pkg/services/ngalert/notifier/channels/discord.go b/pkg/services/ngalert/notifier/channels/discord.go index 22cb9bd23b3..3937a1cfe4e 100644 --- a/pkg/services/ngalert/notifier/channels/discord.go +++ b/pkg/services/ngalert/notifier/channels/discord.go @@ -103,6 +103,7 @@ func (d DiscordNotifier) Notify(ctx context.Context, as ...*types.Alert) (bool, u := tmpl(d.WebhookURL) if tmplErr != nil { d.log.Warn("failed to template Discord message", "err", tmplErr.Error()) + return false, tmplErr } body, err := json.Marshal(bodyJSON) diff --git a/pkg/services/ngalert/notifier/channels/discord_test.go b/pkg/services/ngalert/notifier/channels/discord_test.go index 3a7efd27c22..51a89589e64 100644 --- a/pkg/services/ngalert/notifier/channels/discord_test.go +++ b/pkg/services/ngalert/notifier/channels/discord_test.go @@ -3,6 +3,7 @@ package channels import ( "context" "encoding/json" + "errors" "net/url" "testing" @@ -99,6 +100,14 @@ func TestDiscordNotifier(t *testing.T) { settings: `{}`, expInitError: `failed to validate receiver "discord_testing" of type "discord": could not find webhook url property in settings`, }, + { + name: "Invalid template returns error", + settings: `{ + "url": "http://localhost", + "message": "{{ template \"invalid.template\" }}" + }`, + expMsgError: errors.New("template: :1:12: executing \"\" at <{{template \"invalid.template\"}}>: template \"invalid.template\" not defined"), + }, { name: "Default config with one alert, use default discord username", settings: `{ From 0cb3037b55f63280f60f0163d56894636124d390 Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Wed, 2 Feb 2022 13:38:23 +0000 Subject: [PATCH 04/17] Panel: Embed URL is now correctly generated for a panel in the home dashboard (#44706) * user essentials mob! :trident: * user essentials mob! :trident: * user essentials mob! :trident: * user essentials mob! :trident: * user essentials mob! :trident: * user essentials mob! :trident: * user essentials mob! :trident: * user essentials mob! :trident: * user essentials mob! :trident: * user essentials mob! :trident: * user essentials mob! :trident: * user essentials mob! :trident: * user essentials mob! :trident: * user essentials mob! :trident: * user essentials mob! :trident: * test tidyup * Add comment for route Co-authored-by: kay delaney Co-authored-by: Alexandra Vargas Co-authored-by: joshhunt Co-authored-by: Muaaz Saleem --- .../components/ShareModal/ShareEmbed.test.tsx | 132 ++++++++++++++++++ .../components/ShareModal/ShareEmbed.tsx | 5 +- .../components/ShareModal/ShareLink.test.tsx | 39 +++++- .../components/ShareModal/ShareLink.tsx | 4 +- .../dashboard/components/ShareModal/utils.ts | 34 ++++- public/app/routes/routes.tsx | 9 ++ public/app/routes/utils.test.ts | 8 ++ public/app/routes/utils.ts | 2 +- 8 files changed, 220 insertions(+), 13 deletions(-) create mode 100644 public/app/features/dashboard/components/ShareModal/ShareEmbed.test.tsx diff --git a/public/app/features/dashboard/components/ShareModal/ShareEmbed.test.tsx b/public/app/features/dashboard/components/ShareModal/ShareEmbed.test.tsx new file mode 100644 index 00000000000..c54132fc6a8 --- /dev/null +++ b/public/app/features/dashboard/components/ShareModal/ShareEmbed.test.tsx @@ -0,0 +1,132 @@ +import React from 'react'; +import { ShareEmbed } from './ShareEmbed'; +import { render, screen } from '@testing-library/react'; +import config from 'app/core/config'; +import { DashboardModel, PanelModel } from '../../state'; + +jest.mock('app/features/dashboard/services/TimeSrv', () => ({ + getTimeSrv: () => ({ + timeRange: () => { + return { from: new Date(1000), to: new Date(2000) }; + }, + }), +})); + +jest.mock('app/core/services/context_srv', () => ({ + contextSrv: { + sidemenu: true, + user: {}, + isSignedIn: false, + isGrafanaAdmin: false, + isEditor: false, + hasEditPermissionFolders: false, + }, +})); + +function mockLocationHref(href: string) { + const location = window.location; + + let search = ''; + const searchPos = href.indexOf('?'); + if (searchPos >= 0) { + search = href.substring(searchPos); + } + + // @ts-ignore + delete window.location; + (window as any).location = { + ...location, + href, + origin: new URL(href).origin, + search, + }; +} + +describe('ShareEmbed', () => { + let originalBootData: any; + + beforeAll(() => { + originalBootData = config.bootData; + config.appUrl = 'http://dashboards.grafana.com/'; + + config.bootData = { + user: { + orgId: 1, + }, + }; + }); + + afterAll(() => { + config.bootData = originalBootData; + }); + + it('generates the correct embed url for a dashboard', () => { + const mockDashboard = new DashboardModel({ + uid: 'mockDashboardUid', + }); + const mockPanel = new PanelModel({ + id: 'mockPanelId', + }); + mockLocationHref(`http://dashboards.grafana.com/d/${mockDashboard.uid}?orgId=1`); + render(); + + const embedUrl = screen.getByTestId('share-embed-html'); + expect(embedUrl).toBeInTheDocument(); + expect(embedUrl).toHaveTextContent( + `http://dashboards.grafana.com/d-solo/${mockDashboard.uid}?orgId=1&from=1000&to=2000&panelId=${mockPanel.id}` + ); + }); + + it('generates the correct embed url for a dashboard set to the homepage in the grafana config', () => { + mockLocationHref('http://dashboards.grafana.com/?orgId=1'); + const mockDashboard = new DashboardModel({ + uid: 'mockDashboardUid', + }); + const mockPanel = new PanelModel({ + id: 'mockPanelId', + }); + render(); + + const embedUrl = screen.getByTestId('share-embed-html'); + expect(embedUrl).toBeInTheDocument(); + expect(embedUrl).toHaveTextContent( + `http://dashboards.grafana.com/d-solo/${mockDashboard.uid}?orgId=1&from=1000&to=2000&panelId=${mockPanel.id}` + ); + }); + + it('generates the correct embed url for a snapshot', () => { + const mockSlug = 'mockSlug'; + mockLocationHref(`http://dashboards.grafana.com/dashboard/snapshot/${mockSlug}?orgId=1`); + const mockDashboard = new DashboardModel({ + uid: 'mockDashboardUid', + }); + const mockPanel = new PanelModel({ + id: 'mockPanelId', + }); + render(); + + const embedUrl = screen.getByTestId('share-embed-html'); + expect(embedUrl).toBeInTheDocument(); + expect(embedUrl).toHaveTextContent( + `http://dashboards.grafana.com/dashboard-solo/snapshot/${mockSlug}?orgId=1&from=1000&to=2000&panelId=${mockPanel.id}` + ); + }); + + it('generates the correct embed url for a scripted dashboard', () => { + const mockSlug = 'scripted.js'; + mockLocationHref(`http://dashboards.grafana.com/dashboard/script/${mockSlug}?orgId=1`); + const mockDashboard = new DashboardModel({ + uid: 'mockDashboardUid', + }); + const mockPanel = new PanelModel({ + id: 'mockPanelId', + }); + render(); + + const embedUrl = screen.getByTestId('share-embed-html'); + expect(embedUrl).toBeInTheDocument(); + expect(embedUrl).toHaveTextContent( + `http://dashboards.grafana.com/dashboard-solo/script/${mockSlug}?orgId=1&from=1000&to=2000&panelId=${mockPanel.id}` + ); + }); +}); diff --git a/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx b/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx index 92100d76a56..f1c97a727a8 100644 --- a/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx +++ b/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx @@ -34,10 +34,10 @@ export class ShareEmbed extends PureComponent { } buildIframeHtml = () => { - const { panel } = this.props; + const { panel, dashboard } = this.props; const { useCurrentTimeRange, selectedTheme } = this.state; - const iframeHtml = buildIframeHtml(useCurrentTimeRange, selectedTheme, panel); + const iframeHtml = buildIframeHtml(useCurrentTimeRange, dashboard.uid, selectedTheme, panel); this.setState({ iframeHtml }); }; @@ -92,6 +92,7 @@ export class ShareEmbed extends PureComponent { the user viewing that page need to be signed into Grafana for the graph to load." >