Skip to content

Commit a2817b8

Browse files
Merge pull request #2042 from jhadvig/CONSOLE-4265
CONSOLE-4265: Add new API field to ConsolePlugin CRD for allowing additional CSP sources
2 parents e22f17d + 424692f commit a2817b8

21 files changed

+2358
-8
lines changed
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this
2+
name: "ConsolePlugin"
3+
crdName: consoleplugins.console.openshift.io
4+
featureGate: ConsolePluginContentSecurityPolicy
5+
version: v1
6+
tests:
7+
onCreate:
8+
- name: Should be able to create a ConsolePlugin with valid CSP configuration
9+
initial: |
10+
apiVersion: console.openshift.io/v1
11+
kind: ConsolePlugin
12+
spec:
13+
displayName: foo
14+
backend:
15+
type: Service
16+
contentSecurityPolicy:
17+
- directive: ScriptSrc
18+
values:
19+
- https://script1.com/
20+
- directive: ImgSrc
21+
values:
22+
- https://img1.com/
23+
expected: |
24+
apiVersion: console.openshift.io/v1
25+
kind: ConsolePlugin
26+
spec:
27+
displayName: foo
28+
backend:
29+
type: Service
30+
contentSecurityPolicy:
31+
- directive: ScriptSrc
32+
values:
33+
- https://script1.com/
34+
- directive: ImgSrc
35+
values:
36+
- https://img1.com/
37+
- name: Should throw an error for duplicate CSP directive entries
38+
initial: |
39+
apiVersion: console.openshift.io/v1
40+
kind: ConsolePlugin
41+
spec:
42+
displayName: foo
43+
backend:
44+
type: Service
45+
contentSecurityPolicy:
46+
- directive: ScriptSrc
47+
values:
48+
- https://script1.com/
49+
- directive: ScriptSrc
50+
values:
51+
- https://script1.com/
52+
expectedError: "spec.contentSecurityPolicy[1]: Duplicate value: map[string]interface {}{\"directive\":\"ScriptSrc\"}"
53+
- name: Should throw an error for duplicate CSP directive values
54+
initial: |
55+
apiVersion: console.openshift.io/v1
56+
kind: ConsolePlugin
57+
spec:
58+
displayName: foo
59+
backend:
60+
type: Service
61+
contentSecurityPolicy:
62+
- directive: ScriptSrc
63+
values:
64+
- https://script1.com/
65+
- https://script1.com/
66+
expectedError: "spec.contentSecurityPolicy[0].values: Invalid value: \"array\": each CSP directive value must be unique"
67+
- name: Should throw an error for incorrect directive type
68+
initial: |
69+
apiVersion: console.openshift.io/v1
70+
kind: ConsolePlugin
71+
spec:
72+
displayName: foo
73+
backend:
74+
type: Service
75+
contentSecurityPolicy:
76+
- directive: TestSrc
77+
values:
78+
- https://script1.com/
79+
expectedError: "spec.contentSecurityPolicy[0].directive: Unsupported value: \"TestSrc\": supported values: \"DefaultSrc\", \"ScriptSrc\", \"StyleSrc\", \"ImgSrc\", \"FontSrc\""
80+
- name: Should throw an error for invalid CSP directive values, using wildcard
81+
initial: |
82+
apiVersion: console.openshift.io/v1
83+
kind: ConsolePlugin
84+
spec:
85+
displayName: foo
86+
backend:
87+
type: Service
88+
contentSecurityPolicy:
89+
- directive: ScriptSrc
90+
values:
91+
- "*"
92+
expectedError: "spec.contentSecurityPolicy[0].values[0]: Invalid value: \"string\": CSP directive value cannot be a wildcard"
93+
- name: Should be able to create a ConsolePlugin with valid CSP value, using domain with wildcard prefix
94+
initial: |
95+
apiVersion: console.openshift.io/v1
96+
kind: ConsolePlugin
97+
spec:
98+
displayName: foo
99+
backend:
100+
type: Service
101+
contentSecurityPolicy:
102+
- directive: ScriptSrc
103+
values:
104+
- "*.example.com"
105+
expected: |
106+
apiVersion: console.openshift.io/v1
107+
kind: ConsolePlugin
108+
spec:
109+
displayName: foo
110+
backend:
111+
type: Service
112+
contentSecurityPolicy:
113+
- directive: ScriptSrc
114+
values:
115+
- "*.example.com"
116+
- name: Should throw an error for invalid CSP directive values, starting and ending with quotes
117+
initial: |
118+
apiVersion: console.openshift.io/v1
119+
kind: ConsolePlugin
120+
spec:
121+
displayName: foo
122+
backend:
123+
type: Service
124+
contentSecurityPolicy:
125+
- directive: ScriptSrc
126+
values:
127+
- "'none'"
128+
expectedError: "\"string\": CSP directive value cannot contain a quote"
129+
- name: Should throw an error for invalid CSP directive values with quote
130+
initial: |
131+
apiVersion: console.openshift.io/v1
132+
kind: ConsolePlugin
133+
spec:
134+
displayName: foo
135+
backend:
136+
type: Service
137+
contentSecurityPolicy:
138+
- directive: ScriptSrc
139+
values:
140+
- "foo'bar"
141+
expectedError: "\"string\": CSP directive value cannot contain a quote"
142+
- name: Should throw an error for invalid CSP directive values with comma
143+
initial: |
144+
apiVersion: console.openshift.io/v1
145+
kind: ConsolePlugin
146+
spec:
147+
displayName: foo
148+
backend:
149+
type: Service
150+
contentSecurityPolicy:
151+
- directive: ScriptSrc
152+
values:
153+
- "foo,bar"
154+
expectedError: "spec.contentSecurityPolicy[0].values[0]: Invalid value: \"string\": CSP directive value cannot contain a comma"
155+
- name: Should throw an error for invalid CSP directive values with semi-colon
156+
initial: |
157+
apiVersion: console.openshift.io/v1
158+
kind: ConsolePlugin
159+
spec:
160+
displayName: foo
161+
backend:
162+
type: Service
163+
contentSecurityPolicy:
164+
- directive: ScriptSrc
165+
values:
166+
- "foo;bar"
167+
expectedError: "spec.contentSecurityPolicy[0].values[0]: Invalid value: \"string\": CSP directive value cannot contain a semi-colon"
168+
- name: Should throw an error for invalid CSP directive values with whitespace, using space
169+
initial: |
170+
apiVersion: console.openshift.io/v1
171+
kind: ConsolePlugin
172+
spec:
173+
displayName: foo
174+
backend:
175+
type: Service
176+
contentSecurityPolicy:
177+
- directive: ScriptSrc
178+
values:
179+
- https://scr ipt1.com/
180+
expectedError: "spec.contentSecurityPolicy[0].values[0]: Invalid value: \"string\": CSP directive value cannot contain a whitespace"
181+
- name: Should throw an error for invalid CSP directive values with whitespace, using tab
182+
initial: |
183+
apiVersion: console.openshift.io/v1
184+
kind: ConsolePlugin
185+
spec:
186+
displayName: foo
187+
backend:
188+
type: Service
189+
contentSecurityPolicy:
190+
- directive: ScriptSrc
191+
values:
192+
- https://scri pt1.com/
193+
expectedError: "spec.contentSecurityPolicy[0].values[0]: Invalid value: \"string\": CSP directive value cannot contain a whitespace"

console/v1/types_console_plugin.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,137 @@ type ConsolePluginSpec struct {
4343
Backend ConsolePluginBackend `json:"backend"`
4444
// proxy is a list of proxies that describe various service type
4545
// to which the plugin needs to connect to.
46+
// +listType=atomic
4647
// +optional
4748
Proxy []ConsolePluginProxy `json:"proxy,omitempty"`
4849
// i18n is the configuration of plugin's localization resources.
4950
// +optional
5051
I18n ConsolePluginI18n `json:"i18n"`
52+
// contentSecurityPolicy is a list of Content-Security-Policy (CSP) directives for the plugin.
53+
// Each directive specifies a list of values, appropriate for the given directive type,
54+
// for example a list of remote endpoints for fetch directives such as ScriptSrc.
55+
// Console web application uses CSP to detect and mitigate certain types of attacks,
56+
// such as cross-site scripting (XSS) and data injection attacks.
57+
// Dynamic plugins should specify this field if need to load assets from outside
58+
// the cluster or if violation reports are observed. Dynamic plugins should always prefer
59+
// loading their assets from within the cluster, either by vendoring them, or fetching
60+
// from a cluster service.
61+
// CSP violation reports can be viewed in the browser's console logs during development and
62+
// testing of the plugin in the OpenShift web console.
63+
// Available directive types are DefaultSrc, ScriptSrc, StyleSrc, ImgSrc and FontSrc.
64+
// Each of the available directives may be defined only once in the list.
65+
// The value 'self' is automatically included in all fetch directives by the OpenShift web
66+
// console's backend.
67+
// For more information about the CSP directives, see:
68+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
69+
//
70+
// The OpenShift web console server aggregates the CSP directives and values across
71+
// its own default values and all enabled ConsolePlugin CRs, merging them into a single
72+
// policy string that is sent to the browser via `Content-Security-Policy` HTTP response header.
73+
//
74+
// Example:
75+
// ConsolePlugin A directives:
76+
// script-src: https://script1.com/, https://script2.com/
77+
// font-src: https://font1.com/
78+
//
79+
// ConsolePlugin B directives:
80+
// script-src: https://script2.com/, https://script3.com/
81+
// font-src: https://font2.com/
82+
// img-src: https://img1.com/
83+
//
84+
// Unified set of CSP directives, passed to the OpenShift web console server:
85+
// script-src: https://script1.com/, https://script2.com/, https://script3.com/
86+
// font-src: https://font1.com/, https://font2.com/
87+
// img-src: https://img1.com/
88+
//
89+
// OpenShift web console server CSP response header:
90+
// 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'
91+
//
92+
// +openshift:enable:FeatureGate=ConsolePluginContentSecurityPolicy
93+
// +kubebuilder:validation:MaxItems=5
94+
// +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)"
95+
// +listType=map
96+
// +listMapKey=directive
97+
// +optional
98+
ContentSecurityPolicy []ConsolePluginCSP `json:"contentSecurityPolicy"`
99+
}
100+
101+
// DirectiveType is an enumeration of OpenShift web console supported CSP directives.
102+
// LoadType is an enumeration of i18n loading types.
103+
// +kubebuilder:validation:Enum:="DefaultSrc";"ScriptSrc";"StyleSrc";"ImgSrc";"FontSrc"
104+
// +enum
105+
type DirectiveType string
106+
107+
const (
108+
// DefaultSrc directive serves as a fallback for the other CSP fetch directives.
109+
// For more information about the DefaultSrc directive, see:
110+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/default-src
111+
DefaultSrc DirectiveType = "DefaultSrc"
112+
// ScriptSrc directive specifies valid sources for JavaScript.
113+
// For more information about the ScriptSrc directive, see:
114+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
115+
ScriptSrc DirectiveType = "ScriptSrc"
116+
// StyleSrc directive specifies valid sources for stylesheets.
117+
// For more information about the StyleSrc directive, see:
118+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src
119+
StyleSrc DirectiveType = "StyleSrc"
120+
// ImgSrc directive specifies a valid sources of images and favicons.
121+
// For more information about the ImgSrc directive, see:
122+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/img-src
123+
ImgSrc DirectiveType = "ImgSrc"
124+
// FontSrc directive specifies valid sources for fonts loaded using @font-face.
125+
// For more information about the FontSrcdirective, see:
126+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/font-src
127+
FontSrc DirectiveType = "FontSrc"
128+
)
129+
130+
// CSPDirectiveValue is single value for a Content-Security-Policy directive.
131+
// Each directive value must have a maximum length of 1024 characters and must not contain
132+
// whitespace, commas (,), semicolons (;) or single quotes ('). The value '*' is not permitted.
133+
// +kubebuilder:validation:MinLength=1
134+
// +kubebuilder:validation:MaxLength=1024
135+
// +kubebuilder:validation:XValidation:rule="!self.contains(\"'\")",message="CSP directive value cannot contain a quote"
136+
// +kubebuilder:validation:XValidation:rule="!self.matches('\\\\s')",message="CSP directive value cannot contain a whitespace"
137+
// +kubebuilder:validation:XValidation:rule="!self.contains(',')",message="CSP directive value cannot contain a comma"
138+
// +kubebuilder:validation:XValidation:rule="!self.contains(';')",message="CSP directive value cannot contain a semi-colon"
139+
// +kubebuilder:validation:XValidation:rule="self != '*'",message="CSP directive value cannot be a wildcard"
140+
type CSPDirectiveValue string
141+
142+
// ConsolePluginCSP holds configuration for a specific CSP directive
143+
type ConsolePluginCSP struct {
144+
// directive specifies which Content-Security-Policy directive to configure.
145+
// Available directive types are DefaultSrc, ScriptSrc, StyleSrc, ImgSrc and FontSrc.
146+
// DefaultSrc directive serves as a fallback for the other CSP fetch directives.
147+
// For more information about the DefaultSrc directive, see:
148+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/default-src
149+
// ScriptSrc directive specifies valid sources for JavaScript.
150+
// For more information about the ScriptSrc directive, see:
151+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
152+
// StyleSrc directive specifies valid sources for stylesheets.
153+
// For more information about the StyleSrc directive, see:
154+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src
155+
// ImgSrc directive specifies a valid sources of images and favicons.
156+
// For more information about the ImgSrc directive, see:
157+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/img-src
158+
// FontSrc directive specifies valid sources for fonts loaded using @font-face.
159+
// For more information about the FontSrc directive, see:
160+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/font-src
161+
// +kubebuilder:validation:Required
162+
Directive DirectiveType `json:"directive"`
163+
// values defines an array of values to append to the console defaults for this directive.
164+
// Each ConsolePlugin may define their own directives with their values. These will be set
165+
// by the OpenShift web console's backend, as part of its Content-Security-Policy header.
166+
// The array can contain at most 16 values. Each directive value must have a maximum length
167+
// of 1024 characters and must not contain whitespace, commas (,), semicolons (;) or single
168+
// quotes ('). The value '*' is not permitted.
169+
// Each value in the array must be unique.
170+
//
171+
// +kubebuilder:validation:Required
172+
// +kubebuilder:validation:MinItems=1
173+
// +kubebuilder:validation:MaxItems=16
174+
// +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x == y))",message="each CSP directive value must be unique"
175+
// +listType=atomic
176+
Values []CSPDirectiveValue `json:"values"`
51177
}
52178

53179
// LoadType is an enumeration of i18n loading types

0 commit comments

Comments
 (0)