-
Notifications
You must be signed in to change notification settings - Fork 578
CONSOLE-4265: Add new API field to ConsolePlugin CRD for allowing additional CSP sources #2042
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,193 @@ | ||
| apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this | ||
| name: "ConsolePlugin" | ||
| crdName: consoleplugins.console.openshift.io | ||
| featureGate: ConsolePluginContentSecurityPolicy | ||
| version: v1 | ||
| tests: | ||
| onCreate: | ||
| - name: Should be able to create a ConsolePlugin with valid CSP configuration | ||
| initial: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: ScriptSrc | ||
| values: | ||
| - https://script1.com/ | ||
| - directive: ImgSrc | ||
| values: | ||
| - https://img1.com/ | ||
| expected: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: ScriptSrc | ||
| values: | ||
| - https://script1.com/ | ||
| - directive: ImgSrc | ||
| values: | ||
| - https://img1.com/ | ||
| - name: Should throw an error for duplicate CSP directive entries | ||
| initial: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: ScriptSrc | ||
| values: | ||
| - https://script1.com/ | ||
| - directive: ScriptSrc | ||
| values: | ||
| - https://script1.com/ | ||
| expectedError: "spec.contentSecurityPolicy[1]: Duplicate value: map[string]interface {}{\"directive\":\"ScriptSrc\"}" | ||
| - name: Should throw an error for duplicate CSP directive values | ||
| initial: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: ScriptSrc | ||
| values: | ||
| - https://script1.com/ | ||
| - https://script1.com/ | ||
| expectedError: "spec.contentSecurityPolicy[0].values: Invalid value: \"array\": each CSP directive value must be unique" | ||
| - name: Should throw an error for incorrect directive type | ||
| initial: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: TestSrc | ||
| values: | ||
| - https://script1.com/ | ||
| expectedError: "spec.contentSecurityPolicy[0].directive: Unsupported value: \"TestSrc\": supported values: \"DefaultSrc\", \"ScriptSrc\", \"StyleSrc\", \"ImgSrc\", \"FontSrc\"" | ||
| - name: Should throw an error for invalid CSP directive values, using wildcard | ||
| initial: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: ScriptSrc | ||
| values: | ||
| - "*" | ||
| expectedError: "spec.contentSecurityPolicy[0].values[0]: Invalid value: \"string\": CSP directive value cannot be a wildcard" | ||
| - name: Should be able to create a ConsolePlugin with valid CSP value, using domain with wildcard prefix | ||
| initial: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: ScriptSrc | ||
| values: | ||
| - "*.example.com" | ||
| expected: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: ScriptSrc | ||
| values: | ||
| - "*.example.com" | ||
| - name: Should throw an error for invalid CSP directive values, starting and ending with quotes | ||
| initial: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: ScriptSrc | ||
| values: | ||
| - "'none'" | ||
| expectedError: "\"string\": CSP directive value cannot contain a quote" | ||
| - name: Should throw an error for invalid CSP directive values with quote | ||
| initial: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: ScriptSrc | ||
| values: | ||
| - "foo'bar" | ||
| expectedError: "\"string\": CSP directive value cannot contain a quote" | ||
| - name: Should throw an error for invalid CSP directive values with comma | ||
| initial: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: ScriptSrc | ||
| values: | ||
| - "foo,bar" | ||
| expectedError: "spec.contentSecurityPolicy[0].values[0]: Invalid value: \"string\": CSP directive value cannot contain a comma" | ||
| - name: Should throw an error for invalid CSP directive values with semi-colon | ||
| initial: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: ScriptSrc | ||
| values: | ||
| - "foo;bar" | ||
| expectedError: "spec.contentSecurityPolicy[0].values[0]: Invalid value: \"string\": CSP directive value cannot contain a semi-colon" | ||
| - name: Should throw an error for invalid CSP directive values with whitespace, using space | ||
| initial: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: ScriptSrc | ||
| values: | ||
| - https://scr ipt1.com/ | ||
| expectedError: "spec.contentSecurityPolicy[0].values[0]: Invalid value: \"string\": CSP directive value cannot contain a whitespace" | ||
| - name: Should throw an error for invalid CSP directive values with whitespace, using tab | ||
| initial: | | ||
| apiVersion: console.openshift.io/v1 | ||
| kind: ConsolePlugin | ||
| spec: | ||
| displayName: foo | ||
| backend: | ||
| type: Service | ||
| contentSecurityPolicy: | ||
| - directive: ScriptSrc | ||
| values: | ||
| - https://scri pt1.com/ | ||
| expectedError: "spec.contentSecurityPolicy[0].values[0]: Invalid value: \"string\": CSP directive value cannot contain a whitespace" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,11 +43,137 @@ type ConsolePluginSpec struct { | |
| Backend ConsolePluginBackend `json:"backend"` | ||
| // proxy is a list of proxies that describe various service type | ||
| // to which the plugin needs to connect to. | ||
| // +listType=atomic | ||
| // +optional | ||
| Proxy []ConsolePluginProxy `json:"proxy,omitempty"` | ||
| // i18n is the configuration of plugin's localization resources. | ||
| // +optional | ||
| I18n ConsolePluginI18n `json:"i18n"` | ||
| // contentSecurityPolicy is a list of Content-Security-Policy (CSP) directives for the plugin. | ||
| // Each directive specifies a list of values, appropriate for the given directive type, | ||
| // for example a list of remote endpoints for fetch directives such as ScriptSrc. | ||
| // Console web application uses CSP to detect and mitigate certain types of attacks, | ||
| // such as cross-site scripting (XSS) and data injection attacks. | ||
| // Dynamic plugins should specify this field if need to load assets from outside | ||
| // the cluster or if violation reports are observed. Dynamic plugins should always prefer | ||
| // loading their assets from within the cluster, either by vendoring them, or fetching | ||
| // from a cluster service. | ||
| // CSP violation reports can be viewed in the browser's console logs during development and | ||
| // testing of the plugin in the OpenShift web console. | ||
| // Available directive types are DefaultSrc, ScriptSrc, StyleSrc, ImgSrc and FontSrc. | ||
| // Each of the available directives may be defined only once in the list. | ||
| // The value 'self' is automatically included in all fetch directives by the OpenShift web | ||
| // console's backend. | ||
| // For more information about the CSP directives, see: | ||
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy | ||
| // | ||
| // The OpenShift web console server aggregates the CSP directives and values across | ||
| // its own default values and all enabled ConsolePlugin CRs, merging them into a single | ||
| // policy string that is sent to the browser via `Content-Security-Policy` HTTP response header. | ||
| // | ||
| // Example: | ||
| // ConsolePlugin A directives: | ||
| // script-src: https://script1.com/, https://script2.com/ | ||
| // font-src: https://font1.com/ | ||
| // | ||
| // ConsolePlugin B directives: | ||
| // script-src: https://script2.com/, https://script3.com/ | ||
| // font-src: https://font2.com/ | ||
| // img-src: https://img1.com/ | ||
| // | ||
| // Unified set of CSP directives, passed to the OpenShift web console server: | ||
| // script-src: https://script1.com/, https://script2.com/, https://script3.com/ | ||
| // font-src: https://font1.com/, https://font2.com/ | ||
| // img-src: https://img1.com/ | ||
| // | ||
| // OpenShift web console server CSP response header: | ||
| // Content-Security-Policy: default-src 'self'; base-uri 'self'; script-src 'self' https://script1.com/ https://script2.com/ https://script3.com/; font-src 'self' https://font1.com/ https://font2.com/; img-src 'self' https://img1.com/; style-src 'self'; frame-src 'none'; object-src 'none' | ||
| // | ||
| // +openshift:enable:FeatureGate=ConsolePluginContentSecurityPolicy | ||
| // +kubebuilder:validation:MaxItems=5 | ||
| // +kubebuilder:validation:XValidation:rule="self.map(x, x.values.map(y, y.size()).sum()).sum() < 8192",message="the total combined size of values of all directives must not exceed 8192 (8kb)" | ||
| // +listType=map | ||
| // +listMapKey=directive | ||
| // +optional | ||
| ContentSecurityPolicy []ConsolePluginCSP `json:"contentSecurityPolicy"` | ||
| } | ||
|
|
||
| // DirectiveType is an enumeration of OpenShift web console supported CSP directives. | ||
| // LoadType is an enumeration of i18n loading types. | ||
| // +kubebuilder:validation:Enum:="DefaultSrc";"ScriptSrc";"StyleSrc";"ImgSrc";"FontSrc" | ||
| // +enum | ||
| type DirectiveType string | ||
|
|
||
| const ( | ||
| // DefaultSrc directive serves as a fallback for the other CSP fetch directives. | ||
| // For more information about the DefaultSrc directive, see: | ||
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/default-src | ||
| DefaultSrc DirectiveType = "DefaultSrc" | ||
jhadvig marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // ScriptSrc directive specifies valid sources for JavaScript. | ||
| // For more information about the ScriptSrc directive, see: | ||
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src | ||
| ScriptSrc DirectiveType = "ScriptSrc" | ||
| // StyleSrc directive specifies valid sources for stylesheets. | ||
| // For more information about the StyleSrc directive, see: | ||
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src | ||
| StyleSrc DirectiveType = "StyleSrc" | ||
| // ImgSrc directive specifies a valid sources of images and favicons. | ||
| // For more information about the ImgSrc directive, see: | ||
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/img-src | ||
| ImgSrc DirectiveType = "ImgSrc" | ||
| // FontSrc directive specifies valid sources for fonts loaded using @font-face. | ||
| // For more information about the FontSrcdirective, see: | ||
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/font-src | ||
| FontSrc DirectiveType = "FontSrc" | ||
| ) | ||
|
|
||
| // CSPDirectiveValue is single value for a Content-Security-Policy directive. | ||
| // Each directive value must have a maximum length of 1024 characters and must not contain | ||
| // whitespace, commas (,), semicolons (;) or single quotes ('). The value '*' is not permitted. | ||
| // +kubebuilder:validation:MinLength=1 | ||
| // +kubebuilder:validation:MaxLength=1024 | ||
| // +kubebuilder:validation:XValidation:rule="!self.contains(\"'\")",message="CSP directive value cannot contain a quote" | ||
| // +kubebuilder:validation:XValidation:rule="!self.matches('\\\\s')",message="CSP directive value cannot contain a whitespace" | ||
| // +kubebuilder:validation:XValidation:rule="!self.contains(',')",message="CSP directive value cannot contain a comma" | ||
| // +kubebuilder:validation:XValidation:rule="!self.contains(';')",message="CSP directive value cannot contain a semi-colon" | ||
| // +kubebuilder:validation:XValidation:rule="self != '*'",message="CSP directive value cannot be a wildcard" | ||
| type CSPDirectiveValue string | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Important ❗ I think we should explicitly disallow any CSP directive values which are enclosed in single quotes.
For example, it makes no sense for a plugin to use The above validation list should include a rule that disallows a string that begins and ends with
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added following validation // +kubebuilder:validation:XValidation:rule="!(self.startsWith(\"'\") && self.endsWith(\"'\"))",message="CSP directive value cannot start or and with a quote" |
||
|
|
||
| // ConsolePluginCSP holds configuration for a specific CSP directive | ||
| type ConsolePluginCSP struct { | ||
| // directive specifies which Content-Security-Policy directive to configure. | ||
| // Available directive types are DefaultSrc, ScriptSrc, StyleSrc, ImgSrc and FontSrc. | ||
| // DefaultSrc directive serves as a fallback for the other CSP fetch directives. | ||
| // For more information about the DefaultSrc directive, see: | ||
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/default-src | ||
| // ScriptSrc directive specifies valid sources for JavaScript. | ||
| // For more information about the ScriptSrc directive, see: | ||
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src | ||
| // StyleSrc directive specifies valid sources for stylesheets. | ||
| // For more information about the StyleSrc directive, see: | ||
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src | ||
| // ImgSrc directive specifies a valid sources of images and favicons. | ||
| // For more information about the ImgSrc directive, see: | ||
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/img-src | ||
| // FontSrc directive specifies valid sources for fonts loaded using @font-face. | ||
| // For more information about the FontSrc directive, see: | ||
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/font-src | ||
| // +kubebuilder:validation:Required | ||
| Directive DirectiveType `json:"directive"` | ||
spadgett marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // values defines an array of values to append to the console defaults for this directive. | ||
| // Each ConsolePlugin may define their own directives with their values. These will be set | ||
| // by the OpenShift web console's backend, as part of its Content-Security-Policy header. | ||
| // The array can contain at most 16 values. Each directive value must have a maximum length | ||
| // of 1024 characters and must not contain whitespace, commas (,), semicolons (;) or single | ||
| // quotes ('). The value '*' is not permitted. | ||
| // Each value in the array must be unique. | ||
| // | ||
| // +kubebuilder:validation:Required | ||
| // +kubebuilder:validation:MinItems=1 | ||
| // +kubebuilder:validation:MaxItems=16 | ||
| // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x == y))",message="each CSP directive value must be unique" | ||
| // +listType=atomic | ||
| Values []CSPDirectiveValue `json:"values"` | ||
| } | ||
|
|
||
| // LoadType is an enumeration of i18n loading types | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reminder to add the validation suggested in #2042 (comment)