diff --git a/README.md b/README.md index e31ad0e..20b32fc 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Notable features: - Fix enforcement of permissions - Fix MISP modules loading of faup library - Fix MISP modules loading of gl library -- Authentication using LDAP or OIDC +- Authentication using LDAP, OIDC or CustomAuth - Add support for new background job [system](https://github.com/MISP/MISP/blob/2.4/docs/background-jobs-migration-guide.md) - Add support for building specific MISP and MISP-modules commits - Add automatic configuration of syncservers (see `configure_misp.sh`) @@ -122,7 +122,7 @@ If it is a setting controlled by an environment variable which is meant to overr ### MISP-Guard (optional) -[MISP-Guard](https://github.com/MISP/misp-guard) is a mitmproxy add-on designed to apply configurable filters that prevent the unintentional leakage of sensitive threat intelligence data while facilitating controlled information sharing. +[MISP-Guard](https://github.com/MISP/misp-guard) is a mitmproxy add-on designed to apply configurable filters that prevent the unintentional leakage of sensitive threat intelligence data while facilitating controlled information sharing. It is disabled by default, but can be enabled using compose profiles. @@ -152,11 +152,11 @@ The following format is required to target the misp-core, the IP is replaced wit ```json { - "instances": { - "misp_container": { - "ip": "placeholder" - } + "instances": { + "misp_container": { + "ip": "placeholder" } + } } ``` @@ -195,36 +195,67 @@ OIDC Auth is implemented through the MISP OidcAuth plugin. For example configuration using KeyCloak, see [MISP Keycloak 26.1.x Basic Integration Guide](docs/keycloak-integration-guide.md) For Okta, create a new application integration: - - Applications -> Applications -> Create App Integration - - Select Sign-in method "OIDC - OpenID Connect" and Application type "Web Application" - - In Client Authentication, select "Client secret" - - Set the Sign-in redirect URI to: "https:///users/login" - - Under the Sign-in tab, add a group claim called "roles" and an appropriate filter - - In MISP docker `.env` file, set the following variables: - ``` - OIDC_ENABLE=true - OIDC_PROVIDER_URL=https:///.well-known/openid-configuration - OIDC_ISSUER=https:// - OIDC_CLIENT_ID=[client_id] - OIDC_CLIENT_SECRET=[client_secret] - OIDC_ROLES_PROPERTY="roles" - OIDC_ROLES_MAPPING="{\"Okta group - MISP Admin\": 1}" # - OIDC_DEFAULT_ORG="[Your default org in MISP]" - #OIDC_LOGOUT_URL= - OIDC_SCOPES="[\"profile\", \"email\", \"groups\"]" - OIDC_MIXEDAUTH=true # (Set this to false if you want to disable password login, make sure OIDC is working first) - OIDC_CODE_CHALLENGE_METHOD=S256 - OIDC_AUTH_METHOD="client_secret_post" - OIDC_REDIRECT_URI="https:///users/login" # (same value set in Okta) - OIDC_DISABLE_REQUEST_OBJECT=false - OIDC_SKIP_PROXY=true - ``` - Valid options for OIDC_AUTH_METHOD are: - - client_secret_post: tested - - client_secret_basic: the default if variable is not set, but seems broken with Okta. It will return the following error: _"Error 'invalid_request' received from IdP: Cannot supply multiple client credentials"_. - - client_secret_jwt: *not tested* - - private_key_jwt: *not tested* +- Applications -> Applications -> Create App Integration +- Select Sign-in method "OIDC - OpenID Connect" and Application type "Web Application" +- In Client Authentication, select "Client secret" +- Set the Sign-in redirect URI to: "https:///users/login" +- Under the Sign-in tab, add a group claim called "roles" and an appropriate filter +- In MISP docker `.env` file, set the following variables: + +``` +OIDC_ENABLE=true +OIDC_PROVIDER_URL=https:///.well-known/openid-configuration +OIDC_ISSUER=https:// +OIDC_CLIENT_ID=[client_id] +OIDC_CLIENT_SECRET=[client_secret] +OIDC_ROLES_PROPERTY="roles" +OIDC_ROLES_MAPPING="{\"Okta group - MISP Admin\": 1}" # +OIDC_DEFAULT_ORG="[Your default org in MISP]" +#OIDC_LOGOUT_URL= +OIDC_SCOPES="[\"profile\", \"email\", \"groups\"]" +OIDC_MIXEDAUTH=true # (Set this to false if you want to disable password login, make sure OIDC is working first) +OIDC_CODE_CHALLENGE_METHOD=S256 +OIDC_AUTH_METHOD="client_secret_post" +OIDC_REDIRECT_URI="https:///users/login" # (same value set in Okta) +OIDC_DISABLE_REQUEST_OBJECT=false +OIDC_SKIP_PROXY=true +``` + +Valid options for `OIDC_AUTH_METHOD` are: + +- `client_secret_post`: tested +- `client_secret_basic`: the default if variable is not set, but seems broken with Okta. It will return the following error: `"Error 'invalid_request' received from IdP: Cannot supply multiple client credentials"`. +- `client_secret_jwt`: _not tested_ +- `private_key_jwt`: _not tested_ + +#### CustomAuth + +You can add authentication using the `Plugin.CustomAuth` plugin as described here https://www.circl.lu/doc/misp/appendices/#appendix-a-external-authentication. It will use a user provided http header to authenticate the user. This is useful where MISP runs behind an authenticating reverse proxy server. + +``` +# Enable this functionality if you would like to handle the authentication via an external tool and authenticate with MISP using a custom header. +CUSTOM_AUTH_ENABLE=true +# Set the header that MISP should look for here. If left empty it will default to the Authorization header. +# This needs to be in all uppercase and all `-` replaced with `_` +CUSTOM_AUTH_HEADER="X_CUSTOM_AUTH" +# Use a header namespace for the auth header - default setting is enabled +CUSTOM_AUTH_USE_HEADER_NAMESPACE=true +# The default header namespace for the auth header - default setting is HTTP_ +CUSTOM_AUTH_HEADER_NAMESPACE="HTTP_" +# If this setting is enabled then the only way to authenticate will be using the custom header. Alternatively, you can run in mixed mode that will log users in via the header if found, otherwise users will be redirected to the normal login page. +CUSTOM_AUTH_REQUIRED=false +# If you are using an external tool to authenticate with MISP and would like to only allow the tool's url as a valid point of entry then set this field. +CUSTOM_AUTH_ONLY_ALLOW_SOURCE= +# The name of the authentication method, this is cosmetic only and will be shown on the user creation page and logs. +CUSTOM_AUTH_NAME="External Authentication" +# Disable the logout button for users authenticated with the external auth mechanism. +CUSTOM_AUTH_DISABLE_LOGOUT=false +# Provide your custom authentication users with an external URL to the authentication system to reset their passwords. +CUSTOM_AUTH_CUSTOM_PASSWORD_RESET= +# Provide a custom logout URL for your users that will log them out using the authentication system you use. +CUSTOM_AUTH_CUSTOM_LOGOUT= +``` ### Production @@ -248,6 +279,7 @@ This project supports multiple build methods to suit different needs. #### Using Docker Compose (Standard Method) For most users, the standard Docker Compose build is recommended: + ```bash docker compose build ``` @@ -257,10 +289,12 @@ docker compose build Docker Buildx bake provides advanced build capabilities including multi-platform builds and parallel building of multiple targets. This method uses the `docker-bake.hcl` configuration file. **Prerequisites:** + - Docker Buildx plugin installed and enabled - `template.env` file in the project root **Build full-featured images:** + ```bash export NAMESPACE=local export COMMIT_HASH=`git rev-parse --short HEAD` @@ -271,6 +305,7 @@ docker buildx bake -f docker-bake.hcl -f env.hcl --provenance false debian This builds `misp-core`, `misp-modules`, and `misp-guard` with all features included. **Build slim images:** + ```bash export NAMESPACE=local export COMMIT_HASH=`git rev-parse --short HEAD` @@ -281,6 +316,7 @@ docker buildx bake -f docker-bake.hcl -f env.hcl --provenance false debian-slim This builds lightweight versions of `misp-core-slim`, `misp-modules-slim`, and `misp-guard` with reduced dependencies. **Available bake targets:** + - `standard` - Full-featured images (misp-core, misp-modules, misp-guard) - `slim` - Lightweight images (misp-core-slim, misp-modules-slim, misp-guard) - `default` - Builds all variants (both standard and slim) @@ -290,9 +326,11 @@ This builds lightweight versions of `misp-core-slim`, `misp-modules-slim`, and ` **After building with buildx bake:** You can still use Docker Compose to run the services: + ```bash docker compose up ``` + #### Using slow disks as volume mounts Using a slow disk as the mounted volume or a volume with high latency like NFS, EFS or S3 might significantly increase the startup time and downgrade the performance of the service. To address this we will mount the bare minimum that needs to be persisted. @@ -318,24 +356,24 @@ Custom root CA certificates can be mounted under `/usr/local/share/ca-certificat **Note:** It is important to have the .crt extension on the file, otherwise it will not be processed. ```yaml - misp-core: - # ... - volumes: - - "./configs/:/var/www/MISP/app/Config/" - - "./logs/:/var/www/MISP/app/tmp/logs/" - - "./files/:/var/www/MISP/app/files/" - - "./ssl/:/etc/nginx/certs/" - - "./gnupg/:/var/www/MISP/.gnupg/" - # customize by replacing ${CUSTOM_PATH} with a path containing 'files/customize_misp.sh' - # - "${CUSTOM_PATH}/:/custom/" - # mount custom ca root certificates - - "./rootca.pem:/usr/local/share/ca-certificates/rootca.crt" +misp-core: + # ... + volumes: + - "./configs/:/var/www/MISP/app/Config/" + - "./logs/:/var/www/MISP/app/tmp/logs/" + - "./files/:/var/www/MISP/app/files/" + - "./ssl/:/etc/nginx/certs/" + - "./gnupg/:/var/www/MISP/.gnupg/" + # customize by replacing ${CUSTOM_PATH} with a path containing 'files/customize_misp.sh' + # - "${CUSTOM_PATH}/:/custom/" + # mount custom ca root certificates + - "./rootca.pem:/usr/local/share/ca-certificates/rootca.crt" ``` ## Database Management It is possible to backup and restore the underlying database using volume archiving. -The process is *NOT* battle-tested, so it is *NOT* to be followed uncritically. +The process is _NOT_ battle-tested, so it is _NOT_ to be followed uncritically. ### Backup diff --git a/core/files/configure_misp.sh b/core/files/configure_misp.sh index 7302d34..62b180a 100755 --- a/core/files/configure_misp.sh +++ b/core/files/configure_misp.sh @@ -298,6 +298,102 @@ set_up_aad() { sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Security.require_password_confirmation" false } +set_up_custom_auth() { + if [[ "$CUSTOM_AUTH_ENABLE" == "true" ]]; then + # OPTIONAL: + # - CUSTOM_AUTH_HEADER + # - CUSTOM_AUTH_USE_HEADER_NAMESPACE + # - CUSTOM_AUTH_REQUIRED + # - CUSTOM_AUTH_HEADER_NAMESPACE + # - CUSTOM_AUTH_NAME + # - CUSTOM_AUTH_DISABLE_LOGOUT + # - CUSTOM_AUTH_ONLY_ALLOW_SOURCE + # - CUSTOM_AUTH_CUSTOM_PASSWORD_RESET + # - CUSTOM_AUTH_CUSTOM_LOGOUT + + # Configure CustomAuth in MISP + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_enable" true + + if [[ -n "$CUSTOM_AUTH_HEADER" ]]; then + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_header" "${CUSTOM_AUTH_HEADER}" + else + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q -n "Plugin.CustomAuth_header" + fi + + if [[ -n "$CUSTOM_AUTH_USE_HEADER_NAMESPACE" ]]; then + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_use_header_namespace" "${CUSTOM_AUTH_USE_HEADER_NAMESPACE}" + else + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_use_header_namespace" true + fi + + if [[ -n "$CUSTOM_AUTH_REQUIRED" ]]; then + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_required" "${CUSTOM_AUTH_REQUIRED}" + else + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_required" false + fi + + if [[ -n "$CUSTOM_AUTH_HEADER_NAMESPACE" ]]; then + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_header_namespace" "${CUSTOM_AUTH_HEADER_NAMESPACE}" + else + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_header_namespace" "HTTP_" + fi + + if [[ -n "$CUSTOM_AUTH_NAME" ]]; then + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_name" "${CUSTOM_AUTH_NAME}" + else + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_name" "External Authentication" + fi + + if [[ -n "$CUSTOM_AUTH_DISABLE_LOGOUT" ]]; then + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_disable_logout" "${CUSTOM_AUTH_DISABLE_LOGOUT}" + else + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_disable_logout" false + fi + + if [[ -n "$CUSTOM_AUTH_ONLY_ALLOW_SOURCE" ]]; then + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_only_allow_source" "${CUSTOM_AUTH_ONLY_ALLOW_SOURCE}" + else + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q -n "Plugin.CustomAuth_only_allow_source" + fi + + if [[ -n "$CUSTOM_AUTH_CUSTOM_PASSWORD_RESET" ]]; then + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_custom_password_reset" "${CUSTOM_AUTH_CUSTOM_PASSWORD_RESET}" + else + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q -n "Plugin.CustomAuth_custom_password_reset" + fi + + if [[ -n "$CUSTOM_AUTH_CUSTOM_LOGOUT" ]]; then + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_custom_logout" "${CUSTOM_AUTH_CUSTOM_LOGOUT}" + else + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q -n "Plugin.CustomAuth_custom_logout" + fi + + # normally users need to enter their password on updating their profile even if they are using external authentication, which can be problematic if the password is not known due to external management. Disable this confirmation as recommended. + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Security.require_password_confirmation" false + # Disable auth logging as it doesn't add much value when using external authentication. Otherwise each single request triggers a authentication log entry. + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "MISP.log_auth" false + + echo "... CUSTOM_AUTH authentication enabled" + + else + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_enable" false + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q -n "Plugin.CustomAuth_header" + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_use_header_namespace" true + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_required" false + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_header_namespace" "HTTP_" + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q -n "Plugin.CustomAuth_only_allow_source" + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_name" "External Authentication" + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Plugin.CustomAuth_disable_logout" false + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q -n "Plugin.CustomAuth_custom_password_reset" + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q -n "Plugin.CustomAuth_custom_logout" + # Re-enable settings + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "Security.require_password_confirmation" true + sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting -q "MISP.log_auth" true + + echo "... CUSTOM_AUTH authentication disabled" + fi +} + set_up_session() { # Command to modify MISP session configuration sudo -u www-data php /var/www/MISP/tests/modify_config.php modify "{ @@ -634,6 +730,8 @@ echo "MISP | Set Up LDAP ..." && set_up_ldap echo "MISP | Set Up AAD ..." && set_up_aad +echo "MISP | Set Up CustomAuth ..." && set_up_custom_auth + echo "MISP | Set Up Session ..." && set_up_session echo "MISP | Set Up Proxy ..." && set_up_proxy diff --git a/core/files/entrypoint_nginx.sh b/core/files/entrypoint_nginx.sh index 460abdd..19101f6 100755 --- a/core/files/entrypoint_nginx.sh +++ b/core/files/entrypoint_nginx.sh @@ -271,7 +271,7 @@ enforce_misp_data_permissions(){ echo "... chmod -R 0770 directories /var/www/MISP/app/tmp" && find /var/www/MISP/app/tmp -not -perm 770 -type d -exec chmod 0770 {} + # We make 'files' and 'tmp' (logs) directories and files user and group writable (we removed the SGID bit) echo "... chmod -R u+w,g+w /var/www/MISP/app/tmp" && chmod -R u+w,g+w /var/www/MISP/app/tmp - + echo "... chown -R www-data:www-data /var/www/MISP/app/files" && find /var/www/MISP/app/files \( ! -user www-data -or ! -group www-data \) -exec chown www-data:www-data {} + # Files are also executable and read only, because we have some rogue scripts like 'cake' and we can not do a full inventory echo "... chmod -R 0550 files /var/www/MISP/app/files" && find /var/www/MISP/app/files -not -perm 550 -type f -exec chmod 0550 {} + @@ -280,7 +280,7 @@ enforce_misp_data_permissions(){ # We make 'files' and 'tmp' (logs) directories and files user and group writable (we removed the SGID bit) echo "... chmod -R u+w,g+w /var/www/MISP/app/files" && chmod -R u+w,g+w /var/www/MISP/app/files fi - + echo "... chown -R www-data:www-data /var/www/MISP/app/Config" && find /var/www/MISP/app/Config \( ! -user www-data -or ! -group www-data \) -exec chown www-data:www-data {} + # Files are also executable and read only, because we have some rogue scripts like 'cake' and we can not do a full inventory echo "... chmod -R 0550 files /var/www/MISP/app/Config ..." && find /var/www/MISP/app/Config -not -perm 550 -type f -exec chmod 0550 {} + @@ -424,7 +424,7 @@ init_nginx() { echo "... enabling IPv6 on port 443" sed -i "s/# listen \[/listen \[/" /etc/nginx/sites-enabled/misp443 fi - + if [[ ! -f /etc/nginx/certs/cert.pem || ! -f /etc/nginx/certs/key.pem ]]; then echo "... generating new self-signed TLS certificate" openssl req -x509 -subj '/CN=localhost' -nodes -newkey rsa:4096 -keyout /etc/nginx/certs/key.pem -out /etc/nginx/certs/cert.pem -days 365 \ @@ -432,7 +432,7 @@ init_nginx() { else echo "... TLS certificates found" fi - + if [[ "$FASTCGI_STATUS_LISTEN" != "" ]]; then echo "... enabling php-fpm status page" ln -s /etc/nginx/sites-available/php-fpm-status /etc/nginx/sites-enabled/php-fpm-status diff --git a/docker-compose.yml b/docker-compose.yml index 01d02c5..2def8e9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -222,6 +222,17 @@ services: - "AAD_MISP_ORGADMIN=${AAD_MISP_ORGADMIN}" - "AAD_MISP_SITEADMIN=${AAD_MISP_SITEADMIN}" - "AAD_CHECK_GROUPS=${AAD_CHECK_GROUPS}" + # Custom Auth Plugin settings + - "CUSTOM_AUTH_ENABLE=${CUSTOM_AUTH_ENABLE}" + - "CUSTOM_AUTH_HEADER=${CUSTOM_AUTH_HEADER}" + - "CUSTOM_AUTH_USE_HEADER_NAMESPACE=${CUSTOM_AUTH_USE_HEADER_NAMESPACE}" + - "CUSTOM_AUTH_REQUIRED=${CUSTOM_AUTH_REQUIRED}" + - "CUSTOM_AUTH_HEADER_NAMESPACE=${CUSTOM_AUTH_HEADER_NAMESPACE}" + - "CUSTOM_AUTH_ONLY_ALLOW_SOURCE=${CUSTOM_AUTH_ONLY_ALLOW_SOURCE}" + - "CUSTOM_AUTH_NAME=${CUSTOM_AUTH_NAME}" + - "CUSTOM_AUTH_DISABLE_LOGOUT=${CUSTOM_AUTH_DISABLE_LOGOUT}" + - "CUSTOM_AUTH_CUSTOM_PASSWORD_RESET=${CUSTOM_AUTH_CUSTOM_PASSWORD_RESET}" + - "CUSTOM_AUTH_CUSTOM_LOGOUT=${CUSTOM_AUTH_CUSTOM_LOGOUT}" # nginx settings - "NGINX_X_FORWARDED_FOR=${NGINX_X_FORWARDED_FOR}" - "NGINX_SET_REAL_IP_FROM=${NGINX_SET_REAL_IP_FROM}" diff --git a/template.env b/template.env index 17d09d4..a866637 100644 --- a/template.env +++ b/template.env @@ -243,6 +243,18 @@ SYNCSERVERS_1_PULL_RULES= # AAD_MISP_SITEADMIN="Misp Site Admins" # AAD_CHECK_GROUPS=false +# Enable Custom Auth Plugin +# CUSTOM_AUTH_ENABLE=true +# CUSTOM_AUTH_HEADER="X_CUSTOM_AUTH" +# CUSTOM_AUTH_USE_HEADER_NAMESPACE=true +# CUSTOM_AUTH_REQUIRED=false +# CUSTOM_AUTH_HEADER_NAMESPACE="HTTP_" +# CUSTOM_AUTH_ONLY_ALLOW_SOURCE= +# CUSTOM_AUTH_NAME="External Authentication" +# CUSTOM_AUTH_DISABLE_LOGOUT=false +# CUSTOM_AUTH_CUSTOM_PASSWORD_RESET= +# CUSTOM_AUTH_CUSTOM_LOGOUT= + # Enable the use of a Proxy server (MISP-Guard or external) # PROXY_ENABLE=true # PROXY_HOST=