Plugins: Add config option to exclude specific plugins from frontend sandbox (#70899)

pull/71065/head
Esteban Beltran 2 years ago committed by GitHub
parent d153fd434a
commit d618bc46d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      conf/defaults.ini
  2. 3
      conf/sample.ini
  3. 5
      docs/sources/setup-grafana/configure-grafana/_index.md
  4. 1
      packages/grafana-runtime/src/config.ts
  5. 33
      pkg/api/dtos/frontend_settings.go
  6. 1
      pkg/api/frontendsettings.go
  7. 11
      pkg/setting/setting.go
  8. 6
      public/app/features/plugins/plugin_loader.ts

@ -378,6 +378,9 @@ angular_support_enabled = true
# The CSRF check will be executed even if the request has no login cookie. # The CSRF check will be executed even if the request has no login cookie.
csrf_always_check = false 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] [security.encryption]
# Defines the time-to-live (TTL) for decrypted data encryption keys stored in memory (cache). # 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. # Please note that small values may cause performance issues due to a high frequency decryption operations.

@ -384,6 +384,9 @@
# The CSRF check will be executed even if the request has no login cookie. # The CSRF check will be executed even if the request has no login cookie.
;csrf_always_check = false ;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] [security.encryption]
# Defines the time-to-live (TTL) for decrypted data encryption keys stored in memory (cache). # 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. # Please note that small values may cause performance issues due to a high frequency decryption operations.

@ -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`). 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] ## [snapshots]
### enabled ### enabled

@ -162,6 +162,7 @@ export class GrafanaBootConfig implements GrafanaConfig {
}; };
tokenExpirationDayLimit: undefined; tokenExpirationDayLimit: undefined;
disableFrontendSandboxForPlugins: string[] = [];
constructor(options: GrafanaBootConfig) { constructor(options: GrafanaBootConfig) {
this.bootData = options.bootData; this.bootData = options.bootData;

@ -159,22 +159,23 @@ type FrontendSettingsDTO struct {
RudderstackSdkUrl string `json:"rudderstackSdkUrl"` RudderstackSdkUrl string `json:"rudderstackSdkUrl"`
RudderstackConfigUrl string `json:"rudderstackConfigUrl"` RudderstackConfigUrl string `json:"rudderstackConfigUrl"`
FeedbackLinksEnabled bool `json:"feedbackLinksEnabled"` FeedbackLinksEnabled bool `json:"feedbackLinksEnabled"`
ApplicationInsightsConnectionString string `json:"applicationInsightsConnectionString"` ApplicationInsightsConnectionString string `json:"applicationInsightsConnectionString"`
ApplicationInsightsEndpointUrl string `json:"applicationInsightsEndpointUrl"` ApplicationInsightsEndpointUrl string `json:"applicationInsightsEndpointUrl"`
DisableLoginForm bool `json:"disableLoginForm"` DisableLoginForm bool `json:"disableLoginForm"`
DisableUserSignUp bool `json:"disableUserSignUp"` DisableUserSignUp bool `json:"disableUserSignUp"`
LoginHint string `json:"loginHint"` LoginHint string `json:"loginHint"`
PasswordHint string `json:"passwordHint"` PasswordHint string `json:"passwordHint"`
ExternalUserMngInfo string `json:"externalUserMngInfo"` ExternalUserMngInfo string `json:"externalUserMngInfo"`
ExternalUserMngLinkUrl string `json:"externalUserMngLinkUrl"` ExternalUserMngLinkUrl string `json:"externalUserMngLinkUrl"`
ExternalUserMngLinkName string `json:"externalUserMngLinkName"` ExternalUserMngLinkName string `json:"externalUserMngLinkName"`
ViewersCanEdit bool `json:"viewersCanEdit"` ViewersCanEdit bool `json:"viewersCanEdit"`
AngularSupportEnabled bool `json:"angularSupportEnabled"` AngularSupportEnabled bool `json:"angularSupportEnabled"`
EditorsCanAdmin bool `json:"editorsCanAdmin"` EditorsCanAdmin bool `json:"editorsCanAdmin"`
DisableSanitizeHtml bool `json:"disableSanitizeHtml"` DisableSanitizeHtml bool `json:"disableSanitizeHtml"`
TrustedTypesDefaultPolicyEnabled bool `json:"trustedTypesDefaultPolicyEnabled"` TrustedTypesDefaultPolicyEnabled bool `json:"trustedTypesDefaultPolicyEnabled"`
CSPReportOnlyEnabled bool `json:"cspReportOnlyEnabled"` CSPReportOnlyEnabled bool `json:"cspReportOnlyEnabled"`
DisableFrontendSandboxForPlugins []string `json:"disableFrontendSandboxForPlugins"`
Auth FrontendSettingsAuthDTO `json:"auth"` Auth FrontendSettingsAuthDTO `json:"auth"`

@ -151,6 +151,7 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
CSPReportOnlyEnabled: hs.Cfg.CSPReportOnlyEnabled, CSPReportOnlyEnabled: hs.Cfg.CSPReportOnlyEnabled,
DateFormats: hs.Cfg.DateFormats, DateFormats: hs.Cfg.DateFormats,
SecureSocksDSProxyEnabled: hs.Cfg.SecureSocksDSProxy.Enabled && hs.Cfg.SecureSocksDSProxy.ShowUI, SecureSocksDSProxyEnabled: hs.Cfg.SecureSocksDSProxy.Enabled && hs.Cfg.SecureSocksDSProxy.ShowUI,
DisableFrontendSandboxForPlugins: hs.Cfg.DisableFrontendSandboxForPlugins,
Auth: dtos.FrontendSettingsAuthDTO{ Auth: dtos.FrontendSettingsAuthDTO{
OAuthSkipOrgRoleUpdateSync: hs.Cfg.OAuthSkipOrgRoleUpdateSync, OAuthSkipOrgRoleUpdateSync: hs.Cfg.OAuthSkipOrgRoleUpdateSync,

@ -226,8 +226,9 @@ type Cfg struct {
// CSPReportEnabled toggles Content Security Policy Report Only support. // CSPReportEnabled toggles Content Security Policy Report Only support.
CSPReportOnlyEnabled bool CSPReportOnlyEnabled bool
// CSPReportOnlyTemplate contains the Content Security Policy Report Only template. // CSPReportOnlyTemplate contains the Content Security Policy Report Only template.
CSPReportOnlyTemplate string CSPReportOnlyTemplate string
AngularSupportEnabled bool AngularSupportEnabled bool
DisableFrontendSandboxForPlugins []string
TempDataLifetime time.Duration 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.CSPReportOnlyEnabled = security.Key("content_security_policy_report_only").MustBool(false)
cfg.CSPReportOnlyTemplate = security.Key("content_security_policy_report_only_template").MustString("") 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 == "" { if cfg.CSPEnabled && cfg.CSPTemplate == "" {
return fmt.Errorf("enabling content_security_policy requires a content_security_policy_template configuration") return fmt.Errorf("enabling content_security_policy requires a content_security_policy_template configuration")
} }

@ -220,20 +220,22 @@ export async function importPluginModule({
} }
// the sandboxing environment code cannot work in nodejs and requires a real browser // the sandboxing environment code cannot work in nodejs and requires a real browser
if (isFrontendSandboxSupported(isAngular)) { if (isFrontendSandboxSupported({ isAngular, pluginId })) {
return importPluginModuleInSandbox({ pluginId }); return importPluginModuleInSandbox({ pluginId });
} }
return grafanaRuntime.SystemJS.import(path); 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. // To fast test and debug the sandbox in the browser.
const sandboxQueryParam = location.search.includes('nosandbox') && config.buildInfo.env === 'development'; const sandboxQueryParam = location.search.includes('nosandbox') && config.buildInfo.env === 'development';
const isPluginExcepted = config.disableFrontendSandboxForPlugins.includes(pluginId);
return ( return (
!isAngular && !isAngular &&
Boolean(config.featureToggles.pluginsFrontendSandbox) && Boolean(config.featureToggles.pluginsFrontendSandbox) &&
process.env.NODE_ENV !== 'test' && process.env.NODE_ENV !== 'test' &&
!isPluginExcepted &&
!sandboxQueryParam !sandboxQueryParam
); );
} }

Loading…
Cancel
Save