From 35ed22af75716b92ce8c9f8a7454b2d30d621ad6 Mon Sep 17 00:00:00 2001 From: Cliff Casey Date: Fri, 25 Aug 2023 14:15:54 -0400 Subject: [PATCH 1/5] basic sec header interceptors and vars --- src/main/lrsql/admin/routes.clj | 11 ++++-- src/main/lrsql/spec/config.clj | 17 ++++++++- src/main/lrsql/system/webserver.clj | 17 ++++++++- src/main/lrsql/util/headers.clj | 59 +++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 src/main/lrsql/util/headers.clj diff --git a/src/main/lrsql/admin/routes.clj b/src/main/lrsql/admin/routes.clj index f2f25dbb0..c6bc3a0c6 100644 --- a/src/main/lrsql/admin/routes.clj +++ b/src/main/lrsql/admin/routes.clj @@ -8,13 +8,15 @@ [lrsql.admin.interceptors.ui :as ui] [lrsql.admin.interceptors.jwt :as ji] [lrsql.admin.interceptors.status :as si] - [lrsql.util.interceptor :as util-i])) + [lrsql.util.interceptor :as util-i] + [lrsql.util.headers :as h])) (defn- make-common-interceptors - [lrs] + [lrs sec-head-opts] [i/error-interceptor (util-i/handle-json-parse-exn true) i/x-forwarded-for-interceptor + (h/secure-headers sec-head-opts) json-body (body-params) (i/lrs-interceptor lrs)]) @@ -124,12 +126,13 @@ enable-admin-status enable-account-routes oidc-interceptors - oidc-ui-interceptors] + oidc-ui-interceptors + head-opts] :or {oidc-interceptors [] oidc-ui-interceptors [] enable-account-routes true}} routes] - (let [common-interceptors (make-common-interceptors lrs) + (let [common-interceptors (make-common-interceptors lrs head-opts) common-interceptors-oidc (into common-interceptors oidc-interceptors)] (cset/union routes (when enable-account-routes diff --git a/src/main/lrsql/spec/config.clj b/src/main/lrsql/spec/config.clj index 6352285f6..6939f2419 100644 --- a/src/main/lrsql/spec/config.clj +++ b/src/main/lrsql/spec/config.clj @@ -168,6 +168,14 @@ (s/def ::oidc-verify-remote-issuer boolean?) (s/def ::oidc-enable-local-admin boolean?) +(s/def ::sec-head-hsts (s/nilable string?)) +(s/def ::sec-head-frame (s/nilable string?)) +(s/def ::sec-head-content-type (s/nilable string?)) +(s/def ::sec-head-xss (s/nilable string?)) +(s/def ::sec-head-download (s/nilable string?)) +(s/def ::sec-head-cross-domain (s/nilable string?)) +(s/def ::sec-head-content (s/nilable string?)) + (s/def ::webserver (s/keys :req-un [::http-host ::http-port @@ -193,7 +201,14 @@ ::key-cert-chain ::oidc-issuer ::oidc-audience - ::oidc-client-id])) + ::oidc-client-id + ::sec-head-hsts + ::sec-head-frame + ::sec-head-content-type + ::sec-head-xss + ::sec-head-download + ::sec-head-cross-domain + ::sec-head-content])) (s/def ::tuning (s/keys :opt-un [::enable-jsonb])) diff --git a/src/main/lrsql/system/webserver.clj b/src/main/lrsql/system/webserver.clj index 9b7b78b8b..167d3d3d8 100644 --- a/src/main/lrsql/system/webserver.clj +++ b/src/main/lrsql/system/webserver.clj @@ -27,6 +27,13 @@ enable-admin-ui enable-admin-status enable-stmt-html + sec-head-hsts + sec-head-frame + sec-head-content-type + sec-head-xss + sec-head-download + sec-head-cross-domain + sec-head-content allow-all-origins allowed-origins] jwt-exp :jwt-exp-time @@ -62,7 +69,15 @@ :enable-admin-status enable-admin-status :enable-account-routes enable-local-admin :oidc-interceptors oidc-admin-interceptors - :oidc-ui-interceptors oidc-admin-ui-interceptors})) + :oidc-ui-interceptors oidc-admin-ui-interceptors + :head-opts + {:sec-head-hsts sec-head-hsts + :sec-head-frame sec-head-frame + :sec-head-content-type sec-head-content-type + :sec-head-xss sec-head-xss + :sec-head-download sec-head-download + :sec-head-cross-domain sec-head-cross-domain + :sec-head-content sec-head-content}})) ;; Build allowed-origins list. Add without ports as well for ;; default ports allowed-list diff --git a/src/main/lrsql/util/headers.clj b/src/main/lrsql/util/headers.clj new file mode 100644 index 000000000..e429362ef --- /dev/null +++ b/src/main/lrsql/util/headers.clj @@ -0,0 +1,59 @@ +(ns lrsql.util.headers + (:require [io.pedestal.http.csrf :as csrf] + [io.pedestal.http.secure-headers :as hsh] + [io.pedestal.interceptor :refer [interceptor]])) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; General +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn headers-interceptor + "Takes a map of header names to values and creates an interceptor to inject + them in response." + [headers] + (interceptor + {:leave (fn [{response :response :as context}] + (assoc-in context [:response :headers] + (merge headers (:headers response))))})) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Security Headers +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(def default-value "[default]") + +(def sec-head-defaults + {:sec-head-hsts (hsh/hsts-header) + :sec-head-frame (hsh/frame-options-header) + :sec-head-content-type (hsh/content-type-header) + :sec-head-xss (hsh/xss-protection-header) + :sec-head-download (hsh/download-options-header) + :sec-head-cross-domain (hsh/cross-domain-policies-header) + :sec-head-content (hsh/content-security-policy-header)}) + +(def sec-head-names + {:sec-head-hsts "Strict-Transport-Security" + :sec-head-frame "X-Frame-Options" + :sec-head-content-type "X-Content-Type-Options" + :sec-head-xss "X-XSS-Protection" + :sec-head-download "X-Download-Options" + :sec-head-cross-domain "X-Permitted-Cross-Domain-Policies" + :sec-head-content "Content-Security-Policy"}) + +(defn build-sec-headers + [sec-header-opts] + (reduce-kv + (fn [agg h-key h-val] + (if (string? h-val) + (assoc agg (get sec-head-names h-key) + (if (= default-value h-val) + (get sec-head-defaults h-key) + h-val)) + agg)) {} sec-header-opts)) + +(defn secure-headers + "Iterate header-opts, generating values for each header and returning an + interceptor" + [sec-header-opts] + (let [sec-headers (build-sec-headers sec-header-opts)] + (headers-interceptor sec-headers))) From 6f266b26d716aeb5af6ec5ec9d01ece1627b38fe Mon Sep 17 00:00:00 2001 From: Cliff Casey Date: Tue, 29 Aug 2023 09:44:13 -0400 Subject: [PATCH 2/5] docs + prd vars --- doc/env_vars.md | 7 +++++++ resources/lrsql/config/prod/default/webserver.edn | 7 +++++++ src/main/lrsql/util/headers.clj | 7 +++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/doc/env_vars.md b/doc/env_vars.md index 8b1ae4f77..9af507a58 100644 --- a/doc/env_vars.md +++ b/doc/env_vars.md @@ -141,5 +141,12 @@ _NOTE:_ `LRSQL_STMT_RETRY_LIMIT` and `LRSQL_STMT_RETRY_BUDGET` are used to mitig | `LRSQL_OIDC_CLIENT_TEMPLATE` | `oidcClientTemplate` | An optional template to modify LRS Admin UI client OIDC configuration. No effect if `LRSQL_OIDC_ISSUER` is not set. | Not Set | | `LRSQL_OIDC_VERIFY_REMOTE_ISSUER` | `oidcVerifyRemoteIssuer` | Verify on startup that the issuer in remote configuration matches `LRSQL_OIDC_ISSUER`. No effect if `LRSQL_OIDC_ISSUER` is not set. | `true` | | `LRSQL_OIDC_ENABLE_LOCAL_ADMIN` | `oidcEnableLocalAdmin` | Whether or not to enable local administrative account authentication, login and management when `LRSQL_OIDC_ISSUER` is set. No effect if `LRSQL_OIDC_ISSUER` is not set. | `false` | +| `LRSQL_SEC_HEAD_HSTS` | `secHeadHsts` | Sets HTTP security response header `Strict-Transport-Security`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `max-age=31536000; includeSubdomains`) | Not Set | +| `LRSQL_SEC_HEAD_FRAME` | `secHeadFrame` | Sets HTTP security response header `X-Frame-Options`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `DENY`) | Not Set | +| `LRSQL_SEC_HEAD_CONTENT_TYPE` | `secHeadContentType` | Sets HTTP security response header `X-Content-Type-Options`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `nosniff`) | Not Set | +| `LRSQL_SEC_HEAD_XSS` | `secHeadXss` | Sets HTTP security response header `X-Xss-Protection`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `1; mode=block`) | Not Set | +| `LRSQL_SEC_HEAD_DOWNLOAD` | `secHeadDownload` | Sets HTTP security response header `X-Download-Options`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `noopen`) | Not Set | +| `LRSQL_SEC_HEAD_CROSS_DOMAIN` | `secHeadCrossDomain` | Sets HTTP security response header `X-Permitted-Cross-Domain-Policies`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `none`) | Not Set | +| `LRSQL_SEC_HEAD_CONTENT` | `secHeadContent` | Sets HTTP security response header `Content-Security-Policy`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `object-src 'none'; script-src 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:;`) | Not Set | [<- Back to Index](index.md) diff --git a/resources/lrsql/config/prod/default/webserver.edn b/resources/lrsql/config/prod/default/webserver.edn index 242e0778d..6077ec936 100644 --- a/resources/lrsql/config/prod/default/webserver.edn +++ b/resources/lrsql/config/prod/default/webserver.edn @@ -11,6 +11,13 @@ :jwt-no-val-issuer #or [#env LRSQL_JWT_NO_VAL_ISSUER nil] :jwt-no-val-role-key #or [#env LRSQL_JWT_NO_VAL_ROLE_KEY nil] :jwt-no-val-role #or [#env LRSQL_JWT_NO_VAL_ROLE nil] + :sec-head-hsts #or [#env LRSQL_SEC_HEAD_HSTS nil] + :sec-head-frame #or [#env LRSQL_SEC_HEAD_FRAME nil] + :sec-head-content-type #or [#env LRSQL_SEC_HEAD_CONTENT_TYPE nil] + :sec-head-xss #or [#env LRSQL_SEC_HEAD_XSS nil] + :sec-head-download #or [#env LRSQL_SEC_HEAD_DOWNLOAD nil] + :sec-head-cross-domain #or [#env LRSQL_SEC_HEAD_CROSS_DOMAIN nil] + :sec-head-content #or [#env LRSQL_SEC_HEAD_CONTENT nil] :enable-http #boolean #or [#env LRSQL_ENABLE_HTTP true] :enable-http2 #boolean #or [#env LRSQL_ENABLE_HTTP2 true] :http-host #or [#env LRSQL_HTTP_HOST "0.0.0.0"] diff --git a/src/main/lrsql/util/headers.clj b/src/main/lrsql/util/headers.clj index e429362ef..15fb70bb2 100644 --- a/src/main/lrsql/util/headers.clj +++ b/src/main/lrsql/util/headers.clj @@ -1,6 +1,5 @@ (ns lrsql.util.headers - (:require [io.pedestal.http.csrf :as csrf] - [io.pedestal.http.secure-headers :as hsh] + (:require [io.pedestal.http.secure-headers :as hsh] [io.pedestal.interceptor :refer [interceptor]])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -8,7 +7,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn headers-interceptor - "Takes a map of header names to values and creates an interceptor to inject + "Takes a map of header names to values and creates an interceptor to inject them in response." [headers] (interceptor @@ -52,7 +51,7 @@ agg)) {} sec-header-opts)) (defn secure-headers - "Iterate header-opts, generating values for each header and returning an + "Iterate header-opts, generating values for each header and returning an interceptor" [sec-header-opts] (let [sec-headers (build-sec-headers sec-header-opts)] From 47caa084e1ac6b434f92d16a965642a70785be8f Mon Sep 17 00:00:00 2001 From: Cliff Casey Date: Tue, 29 Aug 2023 11:33:15 -0400 Subject: [PATCH 3/5] tested nil, custom and [default] headers --- src/test/lrsql/admin/route_test.clj | 50 ++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/src/test/lrsql/admin/route_test.clj b/src/test/lrsql/admin/route_test.clj index fd54f0ba8..042c8b496 100644 --- a/src/test/lrsql/admin/route_test.clj +++ b/src/test/lrsql/admin/route_test.clj @@ -2,10 +2,12 @@ "Test for admin-related interceptors + routes (as opposed to just the protocol)." (:require [clojure.test :refer [deftest testing is use-fixtures]] + [clojure.string :refer [lower-case]] [babashka.curl :as curl] [com.stuartsierra.component :as component] [xapi-schema.spec.regex :refer [Base64RegEx]] [lrsql.test-support :as support] + [lrsql.util.headers :as h] [lrsql.util :as u])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -80,15 +82,18 @@ (catch clojure.lang.ExceptionInfo e# (is (= ~code (-> e# ex-data :status)))))) +(def sec-header-names (mapv #(lower-case (% h/sec-head-names)) + (keys h/sec-head-names))) + (deftest admin-routes-test (let [sys (support/test-system) sys' (component/start sys) ;; Seed information - {:keys [api-key-default - api-secret-default]} (get-in sys' [:lrs :config]) + {:keys [admin-user-default + admin-pass-default]} (get-in sys' [:lrs :config]) seed-body (u/write-json-str - {"username" api-key-default - "password" api-secret-default}) + {"username" admin-user-default + "password" admin-pass-default}) seed-jwt (-> (login-account content-type seed-body) :body u/parse-json @@ -134,7 +139,7 @@ ;; success (is (= 200 status)) ;; is the created user - (is (= (get edn-body "username") api-key-default)))) + (is (= (get edn-body "username") admin-user-default)))) (testing "log into the `myname` account" (let [{:keys [status body]} (login-account content-type req-body) @@ -283,6 +288,41 @@ :throw false})] ;; failure (is (= 400 status)))))) + (testing "omitted sec headers because not configured" + (let [{:keys [headers]} (get-env content-type)] + (is (empty? (select-keys headers sec-header-names))))) + (component/stop sys'))) + +(def custom-sec-header-config + {:sec-head-hsts h/default-value + :sec-head-frame "Chocolate" + :sec-head-content-type h/default-value + :sec-head-xss "Banana" + :sec-head-download h/default-value + :sec-head-cross-domain "Pancakes" + :sec-head-content h/default-value}) + +(def custom-sec-header-expected + (reduce-kv + (fn [hdrs k v] + (assoc hdrs (lower-case (k h/sec-head-names)) + (if (= v h/default-value) + (k h/sec-head-defaults) + v))) + {} custom-sec-header-config)) + +(deftest custom-header-admin-routes + (let [hdr-conf (reduce-kv (fn [m k v] (assoc m [:webserver k] v)) + {} custom-sec-header-config) + sys (support/test-system + :conf-overrides hdr-conf) + sys' (component/start sys)] + (testing "Custom Sec Headers" + ;; Run a basic admin routes call and verify success + (let [{:keys [headers]} (get-env content-type)] + ;; equals the same combination of custom and default hdr values + (is (= custom-sec-header-expected + (select-keys headers sec-header-names))))) (component/stop sys'))) (def proxy-jwt-body From c8694404bf2e87c137966271dd748a54d9da23ac Mon Sep 17 00:00:00 2001 From: Cliff Casey Date: Tue, 29 Aug 2023 16:35:45 -0400 Subject: [PATCH 4/5] redid webserver sections --- doc/env_vars.md | 73 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/doc/env_vars.md b/doc/env_vars.md index 9af507a58..173741a84 100644 --- a/doc/env_vars.md +++ b/doc/env_vars.md @@ -109,6 +109,19 @@ _NOTE:_ `LRSQL_STMT_RETRY_LIMIT` and `LRSQL_STMT_RETRY_BUDGET` are used to mitig ### Webserver +#### Host & Ports + +| Env Var | Config | Description | Default | +| --------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | +| `LRSQL_ENABLE_HTTP` | `enableHttp` | Whether HTTP is enabled or not (as opposed to HTTPS, which is always enabled). | `true` | +| `LRSQL_ENABLE_HTTP2` | `enableHttp2` | Whether HTTP/2 is supported or not. | `true` | +| `LRSQL_HTTP_HOST` | `httpHost` | The host that the webserver will run on. | `0.0.0.0` | +| `LRSQL_HTTP_PORT` | `httpPort` | The HTTP port that the webserver will be open on. | `8080` | +| `LRSQL_SSL_PORT` | `sslPort` | The HTTPS port that the webserver will be open on. | `8443` | +| `LRSQL_URL_PREFIX` | `urlPrefix` | The prefix of the webserver URL path, e.g. the prefix in `http://0.0.0.0:8080/xapi` is `/xapi`. Used when constructing the `more` value for multi-statement queries. | `/xapi` | + +#### TLS/SSL Certificate + | Env Var | Config | Description | Default | | --------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | | `LRSQL_KEY_FILE` | `keyFile` | The path to the Java Keystore file that contains the key pair and credentials, which are used for HTTPS as well as JWT signing and verification. | `config/keystore.jks` | @@ -117,36 +130,56 @@ _NOTE:_ `LRSQL_STMT_RETRY_LIMIT` and `LRSQL_STMT_RETRY_BUDGET` are used to mitig | `LRSQL_KEY_PKEY_FILE` | `keyPkeyFile` | Private key in PEM format | `config/server.key.pem` | | `LRSQL_KEY_CERT_CHAIN` | `keyCertChain` | Comma separated PEM files for cert. See the TLS/HTTPS section below. |
`config/server.crt.pem,config/cacert.pem`(Filepaths)
| | `LRSQL_KEY_ENABLE_SELFIE` | `keyEnableSelfie` | Boolean, whether or not to enable self-signed cert generation. | `true` | -| `LRSQL_JWT_EXP_TIME` | `jwtExpTime` | The amount of time, in seconds, after a JWT is created when it expires. Since JWTs are not revocable, **this this time should be short** (i.e. one hour or less). | `3600` (one hour) | -| `LRSQL_JWT_EXP_LEEWAY` | `jwtExpLeeway` | The amount of time, in seconds, before or after the expiration instant when a JWT should still count as un-expired. Used to compensate for clock desync. Applied to both LRS and OIDC tokens. | `1` (one second) | + +#### JWT Config + +| Env Var | Config | Description | Default | +| --------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | +| `LRSQL_JWT_EXP_TIME` | `jwtExpTime` | The amount of time, in seconds, after a JWT is created when it expires. Since JWTs are not revocable, **this this time should be short** (i.e. one hour or less). | `3600` (one hour | +| `LRSQL_JWT_EXP_LEEWAY` | `jwtExpLeeway` | The amount of time, in seconds, before or after the expiration instant when a JWT should still count as un-expired. Used to compensate for clock desync. Applied to both LRS and OIDC tokens. | `1` (one second | | `LRSQL_JWT_NO_VAL` | `jwtNoVal` | (**DANGEROUS!**) This flag removes JWT Token Validation and simply accepts token claims as configured by the associated variables below. It is extemely unlikely that you need this as it is for very specific proxy-overwrite authentication scenarios, and it poses a serious threat to system security if enabled. | `false` | | `LRSQL_JWT_NO_VAL_UNAME` | `jwtNoValUname` | (**DANGEROUS!** See `LRSQL_JWT_NO_VAL`) This variable configures which claim key to use for the username when token validation is turned off. | Not Set | | `LRSQL_JWT_NO_VAL_ISSUER` | `jwtNoValIssuer` | (**DANGEROUS!** See `LRSQL_JWT_NO_VAL`) This variable configures which claim key to use for the issuer when token validation is turned off. | Not Set | | `LRSQL_JWT_NO_VAL_ROLE_KEY` | `jwtNoValRoleKey` | (**DANGEROUS!** See `LRSQL_JWT_NO_VAL`) This variable configures which claim key to look in for the role when token validation is turned off. | Not Set | | `LRSQL_JWT_NO_VAL_ROLE` | `jwtNoValRole` | (**DANGEROUS!** See `LRSQL_JWT_NO_VAL`) This variable configures what role must be present in the key above when token validation is turned off. | Not Set | -| `LRSQL_ENABLE_HTTP` | `enableHttp` | Whether HTTP is enabled or not (as opposed to HTTPS, which is always enabled). | `true` | -| `LRSQL_ENABLE_HTTP2` | `enableHttp2` | Whether HTTP/2 is supported or not. | `true` | -| `LRSQL_HTTP_HOST` | `httpHost` | The host that the webserver will run on. | `0.0.0.0` | -| `LRSQL_HTTP_PORT` | `httpPort` | The HTTP port that the webserver will be open on. | `8080` | -| `LRSQL_SSL_PORT` | `sslPort` | The HTTPS port that the webserver will be open on. | `8443` | -| `LRSQL_ALLOW_ALL_ORIGINS` | `allowAllOrigins` | Determines whether to enable CORS. When false, it will not allow all origins, it will only allow either `LRSQL_HTTP_HOST` (for both HTTPS and HTTP ports) or if `LRSQL_ALLOWED_ORIGINS` is set that will override. | `false` | -| `LRSQL_ALLOWED_ORIGINS` | `allowedOrigins` | This is a list of allowed origins which overrides the defaults. As an ENV it should be written as a comma separated list with no spaces. In JSON config it can be written directly as an array, e.g. `["http://myhost:myport", "https://anotherhost"]` | Not Set | -| `LRSQL_URL_PREFIX` | `urlPrefix` | The prefix of the webserver URL path, e.g. the prefix in `http://0.0.0.0:8080/xapi` is `/xapi`. Used when constructing the `more` value for multi-statement queries. | `/xapi` | -| `LRSQL_ENABLE_ADMIN_UI` | `enableAdminUi` | Whether or not to serve the administrative UI at `/admin` | `true` | -| `LRSQL_ENABLE_ADMIN_STATUS` | `enableAdminStatus` | Whether or not to serve admin system status data that queries the database. | `true` | -| `LRSQL_ENABLE_STMT_HTML` | `enableStmtHtml` | Whether or not HTML data is returned in the LRS HTTP response. If `false` disables HTML rendering even if `LRSQL_ENABLE_ADMIN_UI` is `true`. In that case the UI will not display the Statement Browser feature. | `true` | + +#### OIDC + +| Env Var | Config | Description | Default | +| --------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | | `LRSQL_OIDC_ISSUER` | `oidcIssuer` | OIDC Issuer address used for [discovery](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig). Will enable OIDC if present. | Not set | | `LRSQL_OIDC_AUDIENCE` | `oidcAudience` | Optional OIDC audience for token claim verification. No effect if `LRSQL_OIDC_ISSUER` is not set. | Not set | | `LRSQL_OIDC_CLIENT_ID` | `oidcClientId` | An optional OIDC client ID for the SQL LRS Admin SPA. If provided, along with the `LRSQL_OIDC_ISSUER` and `LRSQL_OIDC_AUDIENCE` variables, will enable OIDC access to the Admin UI. No effect if `LRSQL_OIDC_ISSUER` is not set. | Not Set | | `LRSQL_OIDC_CLIENT_TEMPLATE` | `oidcClientTemplate` | An optional template to modify LRS Admin UI client OIDC configuration. No effect if `LRSQL_OIDC_ISSUER` is not set. | Not Set | | `LRSQL_OIDC_VERIFY_REMOTE_ISSUER` | `oidcVerifyRemoteIssuer` | Verify on startup that the issuer in remote configuration matches `LRSQL_OIDC_ISSUER`. No effect if `LRSQL_OIDC_ISSUER` is not set. | `true` | | `LRSQL_OIDC_ENABLE_LOCAL_ADMIN` | `oidcEnableLocalAdmin` | Whether or not to enable local administrative account authentication, login and management when `LRSQL_OIDC_ISSUER` is set. No effect if `LRSQL_OIDC_ISSUER` is not set. | `false` | -| `LRSQL_SEC_HEAD_HSTS` | `secHeadHsts` | Sets HTTP security response header `Strict-Transport-Security`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `max-age=31536000; includeSubdomains`) | Not Set | -| `LRSQL_SEC_HEAD_FRAME` | `secHeadFrame` | Sets HTTP security response header `X-Frame-Options`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `DENY`) | Not Set | -| `LRSQL_SEC_HEAD_CONTENT_TYPE` | `secHeadContentType` | Sets HTTP security response header `X-Content-Type-Options`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `nosniff`) | Not Set | -| `LRSQL_SEC_HEAD_XSS` | `secHeadXss` | Sets HTTP security response header `X-Xss-Protection`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `1; mode=block`) | Not Set | -| `LRSQL_SEC_HEAD_DOWNLOAD` | `secHeadDownload` | Sets HTTP security response header `X-Download-Options`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `noopen`) | Not Set | -| `LRSQL_SEC_HEAD_CROSS_DOMAIN` | `secHeadCrossDomain` | Sets HTTP security response header `X-Permitted-Cross-Domain-Policies`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `none`) | Not Set | -| `LRSQL_SEC_HEAD_CONTENT` | `secHeadContent` | Sets HTTP security response header `Content-Security-Policy`. When not set, the header is omitted. When set to any string other than `"[default]"` it will use that value as the header. When set to `"[default]"` it will have the framework default (which is at time of writing this: `object-src 'none'; script-src 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:;`) | Not Set | + +#### CORS + +| Env Var | Config | Description | Default | +| --------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | +| `LRSQL_ALLOW_ALL_ORIGINS` | `allowAllOrigins` | Determines whether to enable CORS. When false, it will not allow all origins, it will only allow either `LRSQL_HTTP_HOST` (for both HTTPS and HTTP ports) or if `LRSQL_ALLOWED_ORIGINS` is set that will override. | `false` | +| `LRSQL_ALLOWED_ORIGINS` | `allowedOrigins` | This is a list of allowed origins which overrides the defaults. As an ENV it should be written as a comma separated list with no spaces. In JSON config it can be written directly as an array, e.g. `["http://myhost:myport", "https://anotherhost"]` | Not Set | + +#### Browser Security Headers +These config vars enable and configure browser security response headers from the server. In all cases, not setting them results in no corresponding header, setting them to `"[default]"` results in a generic server default (specified below), and any other string manually overrides the header value. + +| Env Var | Config | Header Name | `[default]` value | +| --------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | +| `LRSQL_SEC_HEAD_HSTS` | `secHeadHsts` | `Strict-Transport-Security` |`max-age=31536000; includeSubdomains` +| `LRSQL_SEC_HEAD_FRAME` | `secHeadFrame` | `X-Frame-Options` |`DENY` | +| `LRSQL_SEC_HEAD_CONTENT_TYPE` | `secHeadContentType` | `X-Content-Type-Options` | `nosniff` | +| `LRSQL_SEC_HEAD_XSS` | `secHeadXss` | `X-Xss-Protection` | `1; mode=block` | +| `LRSQL_SEC_HEAD_DOWNLOAD` | `secHeadDownload` | `X-Download-Options` | `noopen` | +| `LRSQL_SEC_HEAD_CROSS_DOMAIN` | `secHeadCrossDomain` | `X-Permitted-Cross-Domain-Policies` | `none` | +| `LRSQL_SEC_HEAD_CONTENT` | `secHeadContent` | `Content-Security-Policy` | `object-src 'none'; script-src 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:;` | + +#### Admin Features + +| Env Var | Config | Description | Default | +| --------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | +| `LRSQL_ENABLE_ADMIN_UI` | `enableAdminUi` | Whether or not to serve the administrative UI at `/admin` | `true` | +| `LRSQL_ENABLE_ADMIN_STATUS` | `enableAdminStatus` | Whether or not to serve admin system status data that queries the database. | `true` | +| `LRSQL_ENABLE_STMT_HTML` | `enableStmtHtml` | Whether or not HTML data is returned in the LRS HTTP response. If `false` disables HTML rendering even if `LRSQL_ENABLE_ADMIN_UI` is `true`. In that case the UI will not display the Statement Browser feature. | `true` | [<- Back to Index](index.md) From 175011173fc3f314ddadcc1b8c0844cd8cab4cea Mon Sep 17 00:00:00 2001 From: Cliff Casey Date: Wed, 30 Aug 2023 09:01:34 -0400 Subject: [PATCH 5/5] OIDC summary --- doc/env_vars.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/env_vars.md b/doc/env_vars.md index 173741a84..741fac717 100644 --- a/doc/env_vars.md +++ b/doc/env_vars.md @@ -145,14 +145,16 @@ _NOTE:_ `LRSQL_STMT_RETRY_LIMIT` and `LRSQL_STMT_RETRY_BUDGET` are used to mitig #### OIDC +This section is for optionally configuring OIDC Authentication/Authorization through a compatible third party access / identity management provider such as Keycloak. These variables have no effect if the first one, `LRSQL_OIDC_ISSUER`, is not set. + | Env Var | Config | Description | Default | | --------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | | `LRSQL_OIDC_ISSUER` | `oidcIssuer` | OIDC Issuer address used for [discovery](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig). Will enable OIDC if present. | Not set | -| `LRSQL_OIDC_AUDIENCE` | `oidcAudience` | Optional OIDC audience for token claim verification. No effect if `LRSQL_OIDC_ISSUER` is not set. | Not set | -| `LRSQL_OIDC_CLIENT_ID` | `oidcClientId` | An optional OIDC client ID for the SQL LRS Admin SPA. If provided, along with the `LRSQL_OIDC_ISSUER` and `LRSQL_OIDC_AUDIENCE` variables, will enable OIDC access to the Admin UI. No effect if `LRSQL_OIDC_ISSUER` is not set. | Not Set | -| `LRSQL_OIDC_CLIENT_TEMPLATE` | `oidcClientTemplate` | An optional template to modify LRS Admin UI client OIDC configuration. No effect if `LRSQL_OIDC_ISSUER` is not set. | Not Set | -| `LRSQL_OIDC_VERIFY_REMOTE_ISSUER` | `oidcVerifyRemoteIssuer` | Verify on startup that the issuer in remote configuration matches `LRSQL_OIDC_ISSUER`. No effect if `LRSQL_OIDC_ISSUER` is not set. | `true` | -| `LRSQL_OIDC_ENABLE_LOCAL_ADMIN` | `oidcEnableLocalAdmin` | Whether or not to enable local administrative account authentication, login and management when `LRSQL_OIDC_ISSUER` is set. No effect if `LRSQL_OIDC_ISSUER` is not set. | `false` | +| `LRSQL_OIDC_AUDIENCE` | `oidcAudience` | Optional OIDC audience for token claim verification. | Not set | +| `LRSQL_OIDC_CLIENT_ID` | `oidcClientId` | An optional OIDC client ID for the SQL LRS Admin SPA. If provided, along with the `LRSQL_OIDC_ISSUER` and `LRSQL_OIDC_AUDIENCE` variables, will enable OIDC access to the Admin UI. | Not Set | +| `LRSQL_OIDC_CLIENT_TEMPLATE` | `oidcClientTemplate` | An optional template to modify LRS Admin UI client OIDC configuration. | Not Set | +| `LRSQL_OIDC_VERIFY_REMOTE_ISSUER` | `oidcVerifyRemoteIssuer` | Verify on startup that the issuer in remote configuration matches `LRSQL_OIDC_ISSUER`. | `true` | +| `LRSQL_OIDC_ENABLE_LOCAL_ADMIN` | `oidcEnableLocalAdmin` | Whether or not to enable local administrative account authentication, login and management when `LRSQL_OIDC_ISSUER` is set. | `false` | #### CORS