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

This commit is contained in:
Esteban Beltran 2023-07-05 11:16:56 +02:00 committed by GitHub
parent d153fd434a
commit d618bc46d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 43 additions and 20 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

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

View File

@ -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"`

View File

@ -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,

View File

@ -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")
}

View File

@ -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
);
}