Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
126 changes: 126 additions & 0 deletions console/v1/types_console_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Copy link
Contributor

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)

}

// 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"
// 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

Choose a reason for hiding this comment

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

'self', 'unsafe-eval' etc. are all tokens with special meaning when interpreted by the browser and I think that only Console web application itself should be allowed to use these when generating the security policy.

For example, it makes no sense for a plugin to use 'self' value since that's already included by default. Also, it makes no sense for a plugin to e.g. use 'unsafe-hashes' or 'unsafe-inline' to lower the security constraint for specific asset fetch directives.

The above validation list should include a rule that disallows a string that begins and ends with ' character.

Copy link
Member Author

Choose a reason for hiding this comment

The 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"`
// 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
Expand Down
Loading