From 59f78ac1f84b6d8966703dbc7c416eba009c4fbc Mon Sep 17 00:00:00 2001 From: Johan Brandhorst-Satzkorn Date: Mon, 29 May 2023 13:30:16 -0700 Subject: [PATCH] config: allow wasm execution under UI CSP The wasm-unsafe-eval option is necessary for the asciinema player on the Admin UI --- go.mod | 4 ++-- go.sum | 4 ++++ internal/cmd/config/config.go | 11 ++++++++++- internal/cmd/config/config_load_test.go | 2 +- internal/cmd/config/config_test.go | 6 +++--- website/content/docs/configuration/listener/tcp.mdx | 4 +++- 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index eb23d2c5db..beb42aabc0 100644 --- a/go.mod +++ b/go.mod @@ -34,10 +34,10 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.2 github.com/hashicorp/go-rootcerts v1.0.2 github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 - github.com/hashicorp/go-secure-stdlib/configutil/v2 v2.0.9 + github.com/hashicorp/go-secure-stdlib/configutil/v2 v2.0.10-0.20230529201716-91e78a9970b4 github.com/hashicorp/go-secure-stdlib/gatedwriter v0.1.1 github.com/hashicorp/go-secure-stdlib/kv-builder v0.1.2 - github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.6 + github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.7-0.20230529201716-91e78a9970b4 github.com/hashicorp/go-secure-stdlib/mlock v0.1.3 github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 github.com/hashicorp/go-secure-stdlib/password v0.1.2 diff --git a/go.sum b/go.sum index ff8ffae062..d29f6324f3 100644 --- a/go.sum +++ b/go.sum @@ -715,12 +715,16 @@ github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 h1:ET4pqyjiGmY09R5y+rSd70J2w github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= github.com/hashicorp/go-secure-stdlib/configutil/v2 v2.0.9 h1:YZ01/aiARPneDUryzjiPGvr3pmjCSC+1WBZKI1P7I7k= github.com/hashicorp/go-secure-stdlib/configutil/v2 v2.0.9/go.mod h1:G8x+Vlrimz5ut7wC6tI/Lr/kcryPN0BskeWmI3gpr1k= +github.com/hashicorp/go-secure-stdlib/configutil/v2 v2.0.10-0.20230529201716-91e78a9970b4 h1:RCxroYl2qNXhvfmeQ4uPqyc1UCSLvmpKAPyyeF9H/P0= +github.com/hashicorp/go-secure-stdlib/configutil/v2 v2.0.10-0.20230529201716-91e78a9970b4/go.mod h1:HMhbgSmrkmnKA2fh50EJUmOjVboh9ug+1evG1ek9MiY= github.com/hashicorp/go-secure-stdlib/gatedwriter v0.1.1 h1:9um9R8i0+HbRHS9d64kdvWR0/LJvo12sIonvR9zr1+U= github.com/hashicorp/go-secure-stdlib/gatedwriter v0.1.1/go.mod h1:6RoRTSMDK2H/rKh3P/JIsk1tK8aatKTt3JyvIopi3GQ= github.com/hashicorp/go-secure-stdlib/kv-builder v0.1.2 h1:NS6BHieb/pDfx3M9jDdaPpGyyVp+aD4A3DjX3dgRmzs= github.com/hashicorp/go-secure-stdlib/kv-builder v0.1.2/go.mod h1:rf5JPE13wi+NwjgsmGkbg4b2CgHq8v7Htn/F0nDe/hg= github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.6 h1:rOmnqOSUBn5opme1Kh9OXO8qWd0KztO+f02vvCwCc/w= github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.6/go.mod h1:Gbwv+gqdNaKMKQq+1c1Yl4OtX1khZ9qe3eYMhJqtGtI= +github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.7-0.20230529201716-91e78a9970b4 h1:GZkfxX/imqOzQmeKmEAfbzGXN4Tt27WRjtEraopcHIQ= +github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.7-0.20230529201716-91e78a9970b4/go.mod h1:Gbwv+gqdNaKMKQq+1c1Yl4OtX1khZ9qe3eYMhJqtGtI= github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= github.com/hashicorp/go-secure-stdlib/mlock v0.1.3 h1:kH3Rhiht36xhAfhuHyWJDgdXXEx9IIZhDGRk24CDhzg= github.com/hashicorp/go-secure-stdlib/mlock v0.1.3/go.mod h1:ov1Q0oEDjC3+A4BwsG2YdKltrmEw8sf9Pau4V9JQ4Vo= diff --git a/internal/cmd/config/config.go b/internal/cmd/config/config.go index b17cbeb8ba..6d099dbf46 100644 --- a/internal/cmd/config/config.go +++ b/internal/cmd/config/config.go @@ -123,6 +123,11 @@ kms "aead" { key_id = "worker-auth-storage" } ` + + // We use a custom Content-Security-Policy because we need to add wasm-unsafe-eval + // as a script-src to support asciinema playback on the Admin UI. Users can still + // override this value via the configuration. + defaultCsp = "default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; frame-src 'self'; font-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self'; media-src 'self'; manifest-src 'self'; style-src-attr 'self'; frame-ancestors 'self'" ) // Config is the configuration for the boundary controller @@ -856,7 +861,11 @@ func Parse(d string) (*Config, error) { // Now that we can have multiple KMSes for downstream workers, allow an // unlimited number of KMS blocks as we don't know how many might be defined - sharedConfig, err := configutil.ParseConfig(d, configutil.WithMaxKmsBlocks(-1)) + sharedConfig, err := configutil.ParseConfig( + d, + configutil.WithMaxKmsBlocks(-1), + configutil.WithListenerOptions(listenerutil.WithDefaultUiContentSecurityPolicyHeader(defaultCsp)), + ) if err != nil { return nil, err } diff --git a/internal/cmd/config/config_load_test.go b/internal/cmd/config/config_load_test.go index d0c24a7698..1a8e8001f0 100644 --- a/internal/cmd/config/config_load_test.go +++ b/internal/cmd/config/config_load_test.go @@ -28,7 +28,7 @@ func TestLoad(t *testing.T) { } uiHeaders := map[int]http.Header{ 0: { - "Content-Security-Policy": {"default-src 'none'; script-src 'self'; frame-src 'self'; font-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self'; media-src 'self'; manifest-src 'self'; style-src-attr 'self'; frame-ancestors 'self'"}, + "Content-Security-Policy": {"default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; frame-src 'self'; font-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self'; media-src 'self'; manifest-src 'self'; style-src-attr 'self'; frame-ancestors 'self'"}, "X-Content-Type-Options": {"nosniff"}, "Strict-Transport-Security": {"max-age=31536000; includeSubDomains"}, "Cache-Control": {"no-store"}, diff --git a/internal/cmd/config/config_test.go b/internal/cmd/config/config_test.go index a570b2b128..e35dd0683a 100644 --- a/internal/cmd/config/config_test.go +++ b/internal/cmd/config/config_test.go @@ -37,7 +37,7 @@ func TestDevController(t *testing.T) { } uiHeaders := map[int]http.Header{ 0: { - "Content-Security-Policy": {"default-src 'none'; script-src 'self'; frame-src 'self'; font-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self'; media-src 'self'; manifest-src 'self'; style-src-attr 'self'; frame-ancestors 'self'"}, + "Content-Security-Policy": {defaultCsp}, "X-Content-Type-Options": {"nosniff"}, "Strict-Transport-Security": {"max-age=31536000; includeSubDomains"}, "Cache-Control": {"no-store"}, @@ -226,7 +226,7 @@ func TestDevWorker(t *testing.T) { }, CustomUiResponseHeaders: map[int]http.Header{ 0: { - "Content-Security-Policy": {"default-src 'none'; script-src 'self'; frame-src 'self'; font-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self'; media-src 'self'; manifest-src 'self'; style-src-attr 'self'; frame-ancestors 'self'"}, + "Content-Security-Policy": {defaultCsp}, "X-Content-Type-Options": {"nosniff"}, "Strict-Transport-Security": {"max-age=31536000; includeSubDomains"}, "Cache-Control": {"no-store"}, @@ -396,7 +396,7 @@ func TestDevCombined(t *testing.T) { } uiHeaders := map[int]http.Header{ 0: { - "Content-Security-Policy": {"default-src 'none'; script-src 'self'; frame-src 'self'; font-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self'; media-src 'self'; manifest-src 'self'; style-src-attr 'self'; frame-ancestors 'self'"}, + "Content-Security-Policy": {defaultCsp}, "X-Content-Type-Options": {"nosniff"}, "Strict-Transport-Security": {"max-age=31536000; includeSubDomains"}, "Cache-Control": {"no-store"}, diff --git a/website/content/docs/configuration/listener/tcp.mdx b/website/content/docs/configuration/listener/tcp.mdx index 7c71c07834..d77352f6b2 100644 --- a/website/content/docs/configuration/listener/tcp.mdx +++ b/website/content/docs/configuration/listener/tcp.mdx @@ -263,7 +263,7 @@ listener "tcp" { custom_ui_response_headers { "default" = { "Strict-Transport-Security" = ["max-age=31536000; includeSubDomains"], - "Content-Security-Policy" = ["default-src 'none'; script-src 'self'; frame-src 'self'; font-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self'; media-src 'self'; manifest-src 'self'; style-src-attr 'self'; frame-ancestors 'self'"], + "Content-Security-Policy" = ["default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; frame-src 'self'; font-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self'; media-src 'self'; manifest-src 'self'; style-src-attr 'self'; frame-ancestors 'self'"], "X-Custom-Header" = ["Custom Header Default Value"], }, "2xx" = { @@ -277,6 +277,8 @@ listener "tcp" { } ``` +Note that Boundary requires `script-src 'wasm-unsafe-eval'` for playback of session recordings. + In situations where a header is defined under several status code subsections, Boundary returns the header matching the most specific response code. For example, with the config example below, a `307` response would return `307 Custom header value`,