diff --git a/readme-vars.yml b/readme-vars.yml index 06129e2..8fa536c 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -15,6 +15,9 @@ available_architectures: # container parameters param_usage_include_ports: true param_container_name: "{{ project_name }}" +opt_param_usage_include_vols: true +opt_param_volumes: + - { vol_path: "/config", vol_host_path: "", desc: "Persistent cache for the fernet key" } param_ports: - { external_port: "8888", internal_port: "8888", port_desc: "the port for ldap auth daemon" } - { external_port: "9000", internal_port: "9000", port_desc: "the port for ldap login page" } @@ -22,7 +25,7 @@ param_ports: # optional container parameters opt_param_usage_include_env: true opt_param_env_vars: - - { env_var: "FERNETKEY", env_value: "", desc: "Optionally define a custom valid fernet key (only needed if container is frequently recreated, or if using multi-node setups, invalidating previous authentications)" } + - { env_var: "FERNETKEY", env_value: "", desc: "Optionally define a custom valid fernet key (only needed if the /config volume is not mounted, or if using multi-node setups, invalidating previous authentications)" } - { env_var: "CERTFILE", env_value: "", desc: "Optionally point this to a certificate file to enable HTTP over SSL (HTTPS) for the ldap auth daemon" } - { env_var: "KEYFILE", env_value: "", desc: "Optionally point this to the private key file, matching the certificate file referred to in CERTFILE" } @@ -33,9 +36,11 @@ app_setup_block: | - Here's a sample config: [nginx-ldap-auth.conf](https://github.com/nginxinc/nginx-ldap-auth/blob/master/nginx-ldap-auth.conf). - Unlike the upstream project, this image encodes the cookie information with fernet, using a randomly generated key during container creation (or optionally user defined). - Also unlike the upstream project, this image serves the login page at `/ldaplogin` (as well as `/login`) to prevent clashes with reverse proxied apps that may also use `/login` for their internal auth. + - If the `config` volume is specified, it will be used the cache the generated fernet key across restarts. # changelog changelogs: + - { date: "12.11.24:", desc: "Cache the generated fernet key in /config"} - { date: "30.06.24:", desc: "Rebase to Alpine 3.20."} - { date: "23.12.23:", desc: "Rebase to Alpine 3.19."} - { date: "20.06.23:", desc: "Sync upstream changes, including the ability to disable referrals with `X-Ldap-DisableReferrals`." } diff --git a/root/etc/s6-overlay/s6-rc.d/init-ldap-config/run b/root/etc/s6-overlay/s6-rc.d/init-ldap-config/run index 25cf1b7..64fabca 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-ldap-config/run +++ b/root/etc/s6-overlay/s6-rc.d/init-ldap-config/run @@ -1,20 +1,53 @@ #!/usr/bin/with-contenv bash # shellcheck shell=bash +KEY_FILE=/config/fernet.key + +normalize_key () { + if [[ -z ${1} || ${1} =~ ^b\'.*\'$ ]]; then + echo "${1}" + else + echo "b'${1}'" + fi +} + +test_key () { + if [[ -z ${1} ]]; then + return 1 + fi + python3 -c "from cryptography.fernet import Fernet; Fernet(${1}).encrypt(b'my deep dark secret')" 2>/dev/null +} + # generate fernet key for ldap if it doesn't exist if grep -q 'REPLACEWITHFERNETKEY' /app/ldap-backend-app.py; then - if [[ -z "${FERNETKEY}" ]]; then - KEY=$(python3 /app/fernet-key.py) - echo "generated fernet key" - elif ! python3 -c "from cryptography.fernet import Fernet; Fernet(b'${FERNETKEY}').encrypt(b'my deep dark secret')" 2>/dev/null; then - echo "FERNETKEY env var is not set to a base64 encoded 32-byte key" - KEY=$(python3 /app/fernet-key.py) - echo "generated fernet key" - else - KEY="b'${FERNETKEY}'" - echo "using FERNETKEY from env variable" + key= + # First check environment variable + if [[ -n ${FERNETKEY} ]]; then + _key=$(normalize_key "${FERNETKEY}") + if test_key "${_key}"; then + key="${_key}" + echo "using FERNETKEY from env variable" + else + echo "FERNETKEY env var is not set to a base64 encoded 32-byte key" + fi + fi + # Second, check for a cached key + if [[ -z ${key} && -f ${KEY_FILE} ]]; then + _key=$(normalize_key $(cat "${KEY_FILE}")) + if test_key "${_key}"; then + echo "using key from ${KEY_FILE}" + key="${_key}" + else + echo "${KEY_FILE} does not contain a base64 encoded 32-byte key" + fi + fi + # Finally generate (and save) a new one + if [[ -z ${key} ]]; then + key=$(python3 /app/fernet-key.py) + echo "${key}" > ${KEY_FILE} + echo "generated and saved new key" fi - sed -i "s/REPLACEWITHFERNETKEY/${KEY}/" /app/ldap-backend-app.py - sed -i "s/REPLACEWITHFERNETKEY/${KEY}/" /app/nginx-ldap-auth-daemon.py + sed -i "s/REPLACEWITHFERNETKEY/${key}/" /app/ldap-backend-app.py + sed -i "s/REPLACEWITHFERNETKEY/${key}/" /app/nginx-ldap-auth-daemon.py fi