From b129b4ceaaab3e93b0cef21379cd2bef597c67b1 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Fri, 14 Jul 2023 17:03:20 -0400 Subject: [PATCH 1/9] prepare for alt login --- salt/kratos/enabled.sls | 3 +-- salt/nginx/etc/nginx.conf | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/salt/kratos/enabled.sls b/salt/kratos/enabled.sls index 52d53a4db..31097ccf4 100644 --- a/salt/kratos/enabled.sls +++ b/salt/kratos/enabled.sls @@ -21,8 +21,7 @@ so-kratos: - sobridge: - ipv4_address: {{ DOCKER.containers['so-kratos'].ip }} - binds: - - /opt/so/conf/kratos/schema.json:/kratos-conf/schema.json:ro - - /opt/so/conf/kratos/kratos.yaml:/kratos-conf/kratos.yaml:ro + - /opt/so/conf/kratos/:/kratos-conf:ro - /opt/so/log/kratos/:/kratos-log:rw - /nsm/kratos/db:/kratos-data:rw {% if DOCKER.containers['so-kratos'].custom_bind_mounts %} diff --git a/salt/nginx/etc/nginx.conf b/salt/nginx/etc/nginx.conf index 52e3d6d3d..925583ff3 100644 --- a/salt/nginx/etc/nginx.conf +++ b/salt/nginx/etc/nginx.conf @@ -146,7 +146,7 @@ http { proxy_set_header X-Forwarded-Proto $scheme; } - location ~ ^/auth/.*?(login) { + location ~ ^/auth/.*?(login|oidc/callback/) { rewrite /auth/(.*) /$1 break; limit_req zone=auth_throttle burst={{ NGINXMERGED.config.throttle_login_burst }} nodelay; limit_req_status 429; From b24afac0f4776e72a23320da05c7013508d48795 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Tue, 18 Jul 2023 10:48:42 -0400 Subject: [PATCH 2/9] upgrade registry version --- salt/registry/enabled.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/registry/enabled.sls b/salt/registry/enabled.sls index 4d9867676..9ea3ad1df 100644 --- a/salt/registry/enabled.sls +++ b/salt/registry/enabled.sls @@ -14,7 +14,7 @@ include: # Install the registry container so-dockerregistry: docker_container.running: - - image: ghcr.io/security-onion-solutions/registry:latest + - image: ghcr.io/security-onion-solutions/registry:2.8.2 - hostname: so-registry - networks: - sobridge: From 101e2e8ba19cdfd875419bed0661584758a40ae9 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Mon, 24 Jul 2023 17:05:52 -0400 Subject: [PATCH 3/9] do not redirect to API URLs when not logged in --- salt/nginx/etc/nginx.conf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/salt/nginx/etc/nginx.conf b/salt/nginx/etc/nginx.conf index 925583ff3..bdcbdeacc 100644 --- a/salt/nginx/etc/nginx.conf +++ b/salt/nginx/etc/nginx.conf @@ -296,7 +296,9 @@ http { error_page 429 = @error429; location @error401 { - add_header Set-Cookie "AUTH_REDIRECT=$request_uri;Path=/;Max-Age=14400"; + if ($request_uri ~* ^/(?!(^/api/.*))) { + add_header Set-Cookie "AUTH_REDIRECT=$request_uri;Path=/;Max-Age=14400"; + } return 302 /auth/self-service/login/browser; } From 6d56deb2e46730df2fdeda35af096c6548cf1036 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Tue, 25 Jul 2023 08:12:45 -0400 Subject: [PATCH 4/9] oidc 1 --- salt/kratos/config.sls | 8 +++ salt/kratos/defaults.yaml | 13 +++++ salt/kratos/files/oidc.jsonnet | 8 +++ salt/kratos/map.jinja | 4 ++ salt/kratos/soc_kratos.yaml | 86 +++++++++++++++++++++++++++++++++ salt/manager/tools/sbin/so-user | 13 +++-- 6 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 salt/kratos/files/oidc.jsonnet diff --git a/salt/kratos/config.sls b/salt/kratos/config.sls index 55949ea3c..0be43b460 100644 --- a/salt/kratos/config.sls +++ b/salt/kratos/config.sls @@ -51,6 +51,14 @@ kratosschema: - group: 928 - mode: 600 +kratosoidc: + file.managed: + - name: /opt/so/conf/kratos/oidc.jsonnet + - source: salt://kratos/files/oidc.jsonnet + - user: 928 + - group: 928 + - mode: 600 + kratosconfig: file.managed: - name: /opt/so/conf/kratos/kratos.yaml diff --git a/salt/kratos/defaults.yaml b/salt/kratos/defaults.yaml index 3f5370dde..202670e3d 100644 --- a/salt/kratos/defaults.yaml +++ b/salt/kratos/defaults.yaml @@ -1,5 +1,18 @@ kratos: enabled: False + oidc: + enabled: false + config: + id: SSO + mapper_url: file:///kratos-conf/oidc.jsonnet + subject_source: userinfo + scopes: + - email + - profile + requested_claims: + id_token: + email: + essential: true config: session: lifespan: 24h diff --git a/salt/kratos/files/oidc.jsonnet b/salt/kratos/files/oidc.jsonnet new file mode 100644 index 000000000..c155b275d --- /dev/null +++ b/salt/kratos/files/oidc.jsonnet @@ -0,0 +1,8 @@ +local claims = std.extVar('claims'); +{ + identity: { + traits: { + email: if 'email' in claims then claims.email else claims.preferred_username + }, + }, +} \ No newline at end of file diff --git a/salt/kratos/map.jinja b/salt/kratos/map.jinja index 6a2b1e0c9..6d1e2917c 100644 --- a/salt/kratos/map.jinja +++ b/salt/kratos/map.jinja @@ -20,3 +20,7 @@ {% do KRATOSDEFAULTS.kratos.config.courier.smtp.update({'connection_uri': KRATOSDEFAULTS.kratos.config.courier.smtp.connection_uri | replace("URL_BASE", GLOBALS.url_base)}) %} {% set KRATOSMERGED = salt['pillar.get']('kratos', default=KRATOSDEFAULTS.kratos, merge=true) %} + +{% if KRATOSMERGED.oidc.enabled and 'oidc' in salt['pillar.get']('licensed_features') %} +{% do KRATOSMERGED.config.selfservice.methods.update({'oidc': {'enabled': true, 'config': {'providers': [KRATOSMERGED.oidc.config]}}}) %} +{% endif %} \ No newline at end of file diff --git a/salt/kratos/soc_kratos.yaml b/salt/kratos/soc_kratos.yaml index b580e9611..3d63f825e 100644 --- a/salt/kratos/soc_kratos.yaml +++ b/salt/kratos/soc_kratos.yaml @@ -3,6 +3,91 @@ kratos: description: You can enable or disable Kratos. advanced: True helpLink: kratos.html + + oidc: + enabled: + description: Set to True to enable OIDC / Single Sign-On (SSO) into SOC. Requires a valid Security Onion license key. + global: True + helpLink: oidc.html + config: + id: + description: Customize the OIDC provider name. This name appears on the login page. Required. + global: True + forcedType: string + helpLink: oidc.html + provider: + description: "Specify the provider type. Required. Valid values are: auth0, generic, github, google, microsoft" + global: True + forcedType: string + regex: "auth0|generic|github|google|microsoft" + regexFailureMessage: "Valid values are: auth0, generic, github, google, microsoft" + helpLink: oidc.html + client_id: + description: Specify the client ID, also referenced as the application ID. Required. + global: True + forcedType: string + helpLink: oidc.html + client_secret: + description: Specify the client secret. Required. + global: True + forcedType: string + helpLink: oidc.html + microsoft_tenant: + description: Specify the Microsoft Active Directory Tenant ID. Required when provider is 'microsoft'. + global: True + forcedType: string + helpLink: oidc.html + subject_source: + description: The source of the subject identifier. Typically 'userinfo'. Only used when provider is 'microsoft'. + global: True + forcedType: string + regex: me|userinfo + regexFailureMessage: "Valid values are: me, userinfo" + helpLink: oidc.html + auth_url: + description: Provider's auth URL. Required when provider is 'generic'. + global: True + forcedType: string + helpLink: oidc.html + issuer_url: + description: Provider's issuer URL. Required when provider is 'generic'. + global: True + forcedType: string + helpLink: oidc.html + mapper_url: + description: A file path or URL in Jsonnet format, used to map OIDC claims to the Kratos schema. Defaults to an included file that maps the email claim. Note that the contents of the included file can be customized via the "OIDC Claims Mapping" setting. + advanced: True + global: True + forcedType: string + helpLink: oidc.html + token_url: + description: Provider's token URL. Required when provider is 'generic'. + global: True + forcedType: string + helpLink: oidc.html + scope: + description: List of scoped data categories to request in the authentication response. Typically 'email' and 'profile' are the minimum required scopes. Some providers use an alternate scope name, such as 'user:email'. + advanced: True + global: True + forcedType: "[]string" + helpLink: oidc.html + requested_claims: + id_token: + email: + essential: + description: Specifies whether the email claim is necessary. Typically leave this value set to true. + advanced: True + global: True + helpLink: oidc.html + files: + oidc__jsonnet: + title: OIDC Claims Mapping + description: Customize the OIDC claim mappings to the Kratos schema. The default mappings include the minimum required for login functionality, so this typically does not need to be customized. Visit https://jsonnet.org for more information about this file format. + advanced: True + file: True + global: True + helpLink: oidc.html + config: session: lifespan: @@ -65,6 +150,7 @@ kratos: global: True advanced: True helpLink: kratos.html + flows: settings: privileged_session_max_age: diff --git a/salt/manager/tools/sbin/so-user b/salt/manager/tools/sbin/so-user index 50836e94c..98850143e 100755 --- a/salt/manager/tools/sbin/so-user +++ b/salt/manager/tools/sbin/so-user @@ -341,14 +341,19 @@ function syncElastic() { " and ic.identity_id=i.id " \ " and ict.id=ic.identity_credential_type_id " \ " and ict.name='password' " \ - " and instr(ic.config, 'hashed_password') " \ " and i.state == 'active' " \ "order by ici.identifier;" | \ sqlite3 -cmd ".timeout ${databaseTimeout}" "$databasePath") [[ $? != 0 ]] && fail "Unable to read credential hashes from database" - echo "${userData}" | \ - jq -r '.user + ":" + .data.hashed_password' \ - >> "$usersTmpFile" + + user_data_formatted=$(echo "${userData}" | jq -r '.user + ":" + .data.hashed_password') + if lookup_salt_value "licensed_features" "" "pillar" | grep -x oidc; then + # generate random placeholder salt/hash for users without passwords + random_crypt=$(get_random_value 53) + user_data_formatted=$(echo "${user_data_formatted}" | sed -r "s/^(.+:)\$/\\1\$2a\$12${random_crypt}/") + fi + + echo "${user_data_formatted}" >> "$usersTmpFile" # Append the user roles while IFS="" read -r rolePair || [ -n "$rolePair" ]; do From b712d505f2fc63278376bf212fc674c38c6613c1 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Wed, 26 Jul 2023 09:21:23 -0400 Subject: [PATCH 5/9] update version to use kilo images --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 79a614418..7f2e97617 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.4 +2.4.0-kilo From aa36e9a785b01c67052c7008775235f94a4fad41 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 27 Jul 2023 08:40:27 -0400 Subject: [PATCH 6/9] oidc --- salt/kratos/defaults.yaml | 2 +- salt/kratos/soc_kratos.yaml | 8 ++++---- salt/manager/tools/sbin/so-user | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/salt/kratos/defaults.yaml b/salt/kratos/defaults.yaml index 202670e3d..1e2eef5ed 100644 --- a/salt/kratos/defaults.yaml +++ b/salt/kratos/defaults.yaml @@ -6,7 +6,7 @@ kratos: id: SSO mapper_url: file:///kratos-conf/oidc.jsonnet subject_source: userinfo - scopes: + scope: - email - profile requested_claims: diff --git a/salt/kratos/soc_kratos.yaml b/salt/kratos/soc_kratos.yaml index 3d63f825e..6269fda60 100644 --- a/salt/kratos/soc_kratos.yaml +++ b/salt/kratos/soc_kratos.yaml @@ -6,7 +6,7 @@ kratos: oidc: enabled: - description: Set to True to enable OIDC / Single Sign-On (SSO) into SOC. Requires a valid Security Onion license key. + description: Set to True to enable OIDC / Single Sign-On (SSO) to SOC. Requires a valid Security Onion license key. global: True helpLink: oidc.html config: @@ -104,7 +104,7 @@ kratos: methods: password: enabled: - description: Set to True to enable traditional password authentication. Leave as default to ensure proper security protections remain in place. + description: Set to True to enable traditional password authentication to SOC. Typically set to true, except when exclusively using OIDC authentication. global: True advanced: True helpLink: kratos.html @@ -115,7 +115,7 @@ kratos: helpLink: kratos.html totp: enabled: - description: Set to True to enable Time-based One-Time Password (TOTP) multi-factor authentication (MFA). Enable to ensure proper security protections remain in place. Be aware that disabling this setting, after users have already setup TOTP, may prevent users from logging in. + description: Set to True to enable Time-based One-Time Password (TOTP) multi-factor authentication (MFA) to SOC. Enable to ensure proper security protections remain in place. Be aware that disabling this setting, after users have already setup TOTP, may prevent users from logging in. global: True helpLink: kratos.html config: @@ -126,7 +126,7 @@ kratos: helpLink: kratos.html webauthn: enabled: - description: Set to True to enable Security Keys (WebAuthn / PassKeys) for passwordless or multi-factor authentication (MFA) logins. Security Keys are a Public-Key Infrastructure (PKI) based authentication method, typically involving biometric hardware devices, such as laptop fingerprint scanners and USB hardware keys. Be aware that disabling this setting, after users have already setup their accounts with Security Keys, may prevent users from logging in. + description: Set to True to enable Security Keys (WebAuthn / PassKeys) for passwordless or multi-factor authentication (MFA) SOC logins. Security Keys are a Public-Key Infrastructure (PKI) based authentication method, typically involving biometric hardware devices, such as laptop fingerprint scanners and USB hardware keys. Be aware that disabling this setting, after users have already setup their accounts with Security Keys, may prevent users from logging in. global: True helpLink: kratos.html config: diff --git a/salt/manager/tools/sbin/so-user b/salt/manager/tools/sbin/so-user index 98850143e..d597cdacb 100755 --- a/salt/manager/tools/sbin/so-user +++ b/salt/manager/tools/sbin/so-user @@ -235,8 +235,8 @@ function updatePassword() { # Update DB with new hash echo "update identity_credentials set config=CAST('{\"hashed_password\":\"$passwordHash\"}' as BLOB), created_at=datetime('now'), updated_at=datetime('now') where identity_id='${identityId}' and identity_credential_type_id=(select id from identity_credential_types where name='password');" | sqlite3 -cmd ".timeout ${databaseTimeout}" "$databasePath" # Deactivate MFA - echo "delete from identity_credential_identifiers where identity_credential_id=(select id from identity_credentials where identity_id='${identityId}' and identity_credential_type_id=(select id from identity_credential_types where name in ('totp', 'webauthn')));" | sqlite3 -cmd ".timeout ${databaseTimeout}" "$databasePath" - echo "delete from identity_credentials where identity_id='${identityId}' and identity_credential_type_id=(select id from identity_credential_types where name in ('totp', 'webauthn'));" | sqlite3 -cmd ".timeout ${databaseTimeout}" "$databasePath" + echo "delete from identity_credential_identifiers where identity_credential_id=(select id from identity_credentials where identity_id='${identityId}' and identity_credential_type_id=(select id from identity_credential_types where name in ('totp', 'webauthn', 'oidc')));" | sqlite3 -cmd ".timeout ${databaseTimeout}" "$databasePath" + echo "delete from identity_credentials where identity_id='${identityId}' and identity_credential_type_id=(select id from identity_credential_types where name in ('totp', 'webauthn', 'oidc'));" | sqlite3 -cmd ".timeout ${databaseTimeout}" "$databasePath" [[ $? != 0 ]] && fail "Unable to update password" fi } From a5c47835641a728591704d1fc4c8cbe430bd957e Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 27 Jul 2023 18:36:50 -0400 Subject: [PATCH 7/9] oidc --- salt/kratos/soc_kratos.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/salt/kratos/soc_kratos.yaml b/salt/kratos/soc_kratos.yaml index 6269fda60..0ac2fcd44 100644 --- a/salt/kratos/soc_kratos.yaml +++ b/salt/kratos/soc_kratos.yaml @@ -50,7 +50,7 @@ kratos: forcedType: string helpLink: oidc.html issuer_url: - description: Provider's issuer URL. Required when provider is 'generic'. + description: Provider's issuer URL. Required when provider is 'auth0' or 'generic'. global: True forcedType: string helpLink: oidc.html @@ -66,8 +66,7 @@ kratos: forcedType: string helpLink: oidc.html scope: - description: List of scoped data categories to request in the authentication response. Typically 'email' and 'profile' are the minimum required scopes. Some providers use an alternate scope name, such as 'user:email'. - advanced: True + description: List of scoped data categories to request in the authentication response. Typically 'email' and 'profile' are the minimum required scopes. However, GitHub requires `user:email', instead and Auth0 requires 'profile', 'email', and 'openid'. global: True forcedType: "[]string" helpLink: oidc.html From a66006c8a639491ecd13aca6f0357c7cd69d5978 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Wed, 25 Oct 2023 09:04:23 -0400 Subject: [PATCH 8/9] minor updates --- salt/kratos/map.jinja | 2 +- salt/kratos/soc_kratos.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/salt/kratos/map.jinja b/salt/kratos/map.jinja index 6d1e2917c..a2477098d 100644 --- a/salt/kratos/map.jinja +++ b/salt/kratos/map.jinja @@ -21,6 +21,6 @@ {% set KRATOSMERGED = salt['pillar.get']('kratos', default=KRATOSDEFAULTS.kratos, merge=true) %} -{% if KRATOSMERGED.oidc.enabled and 'oidc' in salt['pillar.get']('licensed_features') %} +{% if KRATOSMERGED.oidc.enabled and 'oidc' in salt['pillar.get']('features') %} {% do KRATOSMERGED.config.selfservice.methods.update({'oidc': {'enabled': true, 'config': {'providers': [KRATOSMERGED.oidc.config]}}}) %} {% endif %} \ No newline at end of file diff --git a/salt/kratos/soc_kratos.yaml b/salt/kratos/soc_kratos.yaml index 0ac2fcd44..6285bf1ad 100644 --- a/salt/kratos/soc_kratos.yaml +++ b/salt/kratos/soc_kratos.yaml @@ -103,10 +103,10 @@ kratos: methods: password: enabled: - description: Set to True to enable traditional password authentication to SOC. Typically set to true, except when exclusively using OIDC authentication. + description: Set to True to enable traditional password authentication to SOC. Typically set to true, except when exclusively using OIDC authentication. Some external tool interfaces may not be accessible if local password authentication is disabled. global: True advanced: True - helpLink: kratos.html + helpLink: oidc.html config: haveibeenpwned_enabled: description: Set to True to check if a newly chosen password has ever been found in a published list of previously-compromised passwords. Requires outbound Internet connectivity when enabled. From 4942f83d4f001328679b77849fce19b7adc2da7d Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 26 Oct 2023 11:45:39 -0400 Subject: [PATCH 9/9] adjust version to match target branch --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 247af78a9..8ea99f559 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.0-kilo \ No newline at end of file +2.4.30