From d618bc46d10a751841fa5f3ee35abfa141c455a0 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Wed, 5 Jul 2023 11:16:56 +0200 Subject: [PATCH] Plugins: Add config option to exclude specific plugins from frontend sandbox (#70899) --- conf/defaults.ini | 3 ++ conf/sample.ini | 3 ++ .../setup-grafana/configure-grafana/_index.md | 5 +++ packages/grafana-runtime/src/config.ts | 1 + pkg/api/dtos/frontend_settings.go | 33 ++++++++++--------- pkg/api/frontendsettings.go | 1 + pkg/setting/setting.go | 11 +++++-- public/app/features/plugins/plugin_loader.ts | 6 ++-- 8 files changed, 43 insertions(+), 20 deletions(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index cfaf7b6ba71..8e365834b9f 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -378,6 +378,9 @@ angular_support_enabled = true # The CSRF check will be executed even if the request has no login cookie. csrf_always_check = false +# Comma-separated list of plugins ids that won't be loaded inside the frontend sandbox +disable_frontend_sandbox_for_plugins = + [security.encryption] # Defines the time-to-live (TTL) for decrypted data encryption keys stored in memory (cache). # Please note that small values may cause performance issues due to a high frequency decryption operations. diff --git a/conf/sample.ini b/conf/sample.ini index 151a0aa306f..ea22fdaa6b9 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -384,6 +384,9 @@ # The CSRF check will be executed even if the request has no login cookie. ;csrf_always_check = false +# Comma-separated list of plugins ids that won't be loaded inside the frontend sandbox +;disable_frontend_sandbox_for_plugins = + [security.encryption] # Defines the time-to-live (TTL) for decrypted data encryption keys stored in memory (cache). # Please note that small values may cause performance issues due to a high frequency decryption operations. diff --git a/docs/sources/setup-grafana/configure-grafana/_index.md b/docs/sources/setup-grafana/configure-grafana/_index.md index c41a53c1ce4..38661540e1d 100644 --- a/docs/sources/setup-grafana/configure-grafana/_index.md +++ b/docs/sources/setup-grafana/configure-grafana/_index.md @@ -699,6 +699,11 @@ List of allowed headers to be set by the user. Suggested to use for if authentic Set to `true` to execute the CSRF check even if the login cookie is not in a request (default `false`). +### disable_frontend_sandbox_for_plugins + +Comma-separated list of plugins ids that won't be loaded inside the frontend sandbox. It is recommended to only use this +option for plugins that are known to have problems running inside the frontend sandbox. + ## [snapshots] ### enabled diff --git a/packages/grafana-runtime/src/config.ts b/packages/grafana-runtime/src/config.ts index 94da6d52272..346fe61a779 100644 --- a/packages/grafana-runtime/src/config.ts +++ b/packages/grafana-runtime/src/config.ts @@ -162,6 +162,7 @@ export class GrafanaBootConfig implements GrafanaConfig { }; tokenExpirationDayLimit: undefined; + disableFrontendSandboxForPlugins: string[] = []; constructor(options: GrafanaBootConfig) { this.bootData = options.bootData; diff --git a/pkg/api/dtos/frontend_settings.go b/pkg/api/dtos/frontend_settings.go index 02bd8136c65..f551121de8f 100644 --- a/pkg/api/dtos/frontend_settings.go +++ b/pkg/api/dtos/frontend_settings.go @@ -159,22 +159,23 @@ type FrontendSettingsDTO struct { RudderstackSdkUrl string `json:"rudderstackSdkUrl"` RudderstackConfigUrl string `json:"rudderstackConfigUrl"` - FeedbackLinksEnabled bool `json:"feedbackLinksEnabled"` - ApplicationInsightsConnectionString string `json:"applicationInsightsConnectionString"` - ApplicationInsightsEndpointUrl string `json:"applicationInsightsEndpointUrl"` - DisableLoginForm bool `json:"disableLoginForm"` - DisableUserSignUp bool `json:"disableUserSignUp"` - LoginHint string `json:"loginHint"` - PasswordHint string `json:"passwordHint"` - ExternalUserMngInfo string `json:"externalUserMngInfo"` - ExternalUserMngLinkUrl string `json:"externalUserMngLinkUrl"` - ExternalUserMngLinkName string `json:"externalUserMngLinkName"` - ViewersCanEdit bool `json:"viewersCanEdit"` - AngularSupportEnabled bool `json:"angularSupportEnabled"` - EditorsCanAdmin bool `json:"editorsCanAdmin"` - DisableSanitizeHtml bool `json:"disableSanitizeHtml"` - TrustedTypesDefaultPolicyEnabled bool `json:"trustedTypesDefaultPolicyEnabled"` - CSPReportOnlyEnabled bool `json:"cspReportOnlyEnabled"` + FeedbackLinksEnabled bool `json:"feedbackLinksEnabled"` + ApplicationInsightsConnectionString string `json:"applicationInsightsConnectionString"` + ApplicationInsightsEndpointUrl string `json:"applicationInsightsEndpointUrl"` + DisableLoginForm bool `json:"disableLoginForm"` + DisableUserSignUp bool `json:"disableUserSignUp"` + LoginHint string `json:"loginHint"` + PasswordHint string `json:"passwordHint"` + ExternalUserMngInfo string `json:"externalUserMngInfo"` + ExternalUserMngLinkUrl string `json:"externalUserMngLinkUrl"` + ExternalUserMngLinkName string `json:"externalUserMngLinkName"` + ViewersCanEdit bool `json:"viewersCanEdit"` + AngularSupportEnabled bool `json:"angularSupportEnabled"` + EditorsCanAdmin bool `json:"editorsCanAdmin"` + DisableSanitizeHtml bool `json:"disableSanitizeHtml"` + TrustedTypesDefaultPolicyEnabled bool `json:"trustedTypesDefaultPolicyEnabled"` + CSPReportOnlyEnabled bool `json:"cspReportOnlyEnabled"` + DisableFrontendSandboxForPlugins []string `json:"disableFrontendSandboxForPlugins"` Auth FrontendSettingsAuthDTO `json:"auth"` diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index b98893cb628..0d62d559679 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -151,6 +151,7 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro CSPReportOnlyEnabled: hs.Cfg.CSPReportOnlyEnabled, DateFormats: hs.Cfg.DateFormats, SecureSocksDSProxyEnabled: hs.Cfg.SecureSocksDSProxy.Enabled && hs.Cfg.SecureSocksDSProxy.ShowUI, + DisableFrontendSandboxForPlugins: hs.Cfg.DisableFrontendSandboxForPlugins, Auth: dtos.FrontendSettingsAuthDTO{ OAuthSkipOrgRoleUpdateSync: hs.Cfg.OAuthSkipOrgRoleUpdateSync, diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index bc9e051dc03..61e93513328 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -226,8 +226,9 @@ type Cfg struct { // CSPReportEnabled toggles Content Security Policy Report Only support. CSPReportOnlyEnabled bool // CSPReportOnlyTemplate contains the Content Security Policy Report Only template. - CSPReportOnlyTemplate string - AngularSupportEnabled bool + CSPReportOnlyTemplate string + AngularSupportEnabled bool + DisableFrontendSandboxForPlugins []string TempDataLifetime time.Duration @@ -1408,6 +1409,12 @@ func readSecuritySettings(iniFile *ini.File, cfg *Cfg) error { cfg.CSPReportOnlyEnabled = security.Key("content_security_policy_report_only").MustBool(false) cfg.CSPReportOnlyTemplate = security.Key("content_security_policy_report_only_template").MustString("") + disableFrontendSandboxForPlugins := security.Key("frontend_sandbox_disable_for_plugins").MustString("") + for _, plug := range strings.Split(disableFrontendSandboxForPlugins, ",") { + plug = strings.TrimSpace(plug) + cfg.DisableFrontendSandboxForPlugins = append(cfg.DisableFrontendSandboxForPlugins, plug) + } + if cfg.CSPEnabled && cfg.CSPTemplate == "" { return fmt.Errorf("enabling content_security_policy requires a content_security_policy_template configuration") } diff --git a/public/app/features/plugins/plugin_loader.ts b/public/app/features/plugins/plugin_loader.ts index 471263a85cd..29d0e662eb1 100644 --- a/public/app/features/plugins/plugin_loader.ts +++ b/public/app/features/plugins/plugin_loader.ts @@ -220,20 +220,22 @@ export async function importPluginModule({ } // the sandboxing environment code cannot work in nodejs and requires a real browser - if (isFrontendSandboxSupported(isAngular)) { + if (isFrontendSandboxSupported({ isAngular, pluginId })) { return importPluginModuleInSandbox({ pluginId }); } return grafanaRuntime.SystemJS.import(path); } -function isFrontendSandboxSupported(isAngular?: boolean): boolean { +function isFrontendSandboxSupported({ isAngular, pluginId }: { isAngular?: boolean; pluginId: string }): boolean { // To fast test and debug the sandbox in the browser. const sandboxQueryParam = location.search.includes('nosandbox') && config.buildInfo.env === 'development'; + const isPluginExcepted = config.disableFrontendSandboxForPlugins.includes(pluginId); return ( !isAngular && Boolean(config.featureToggles.pluginsFrontendSandbox) && process.env.NODE_ENV !== 'test' && + !isPluginExcepted && !sandboxQueryParam ); }