diff --git a/CHANGELOG.md b/CHANGELOG.md index cab5c75..68f0f78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Added configurable ownership and permission defaults for the shared DH parameter directory and generated DH parameter files through `tls_private_owner`, `tls_private_dir_mode`, and `tls_private_file_mode`. +- Added configuration documentation for shared DH parameter access and for the distinction between DH parameters and TLS private keys. +- Added deterministic ownership and permission enforcement for the shared DH parameter directory and `dh_*.pem` files. + +### Changed + +- Changed the default shared DH parameter directory ownership and mode to `root:root` and `0755`. +- Changed the default shared DH parameter file ownership and mode to `root:root` and `0644`. +- Changed the shared DH parameter defaults to allow non-root TLS services to traverse the directory and read DH parameter files. +- Changed global DH parameter synchronization to apply the configured ownership and file mode after transfer. + ## 1.0.0 - 2026-09-06 ### Added diff --git a/edh-keygen.conf b/edh-keygen.conf index 612088d..7fbfdfc 100644 --- a/edh-keygen.conf +++ b/edh-keygen.conf @@ -3,32 +3,57 @@ # # GLOBAL SETTINGS (must appear before any service lines): # -# tls_tmp_path - Temporary folder for DH key generation -# tls_private_path - Folder where DH keys are stored permanently -# key_sizes - (Optional) Space-separated list of DH key sizes to generate. +# tls_tmp_path - Temporary directory for DH parameter generation +# tls_private_path - Shared directory where generated DH parameters are +# stored permanently +# tls_private_owner - Owner and group for the shared DH parameter +# directory and generated DH parameter files, +# e.g. root:root +# tls_private_dir_mode - Octal mode for the shared DH parameter directory, +# e.g. 0755 or 0750 +# tls_private_file_mode - Octal mode for generated DH parameter files, +# e.g. 0644 or 0640 +# key_sizes - Optional space-separated list of DH parameter +# sizes to generate # # If omitted, the following defaults are used: +# # tls_tmp_path=/etc/pki/tls/tmp # tls_private_path=/etc/pki/tls/private/ +# tls_private_owner=root:root +# tls_private_dir_mode=0755 +# tls_private_file_mode=0644 +# +# DH parameter access: +# +# DH parameters contain shared cryptographic group parameters and are not +# private TLS keys. The default directory and file modes allow non-root TLS +# services to traverse the shared directory and read DH parameter files. +# +# Do not use a directory containing private keys such as *.key, privkey.pem, +# or server.key with tls_private_dir_mode=0755 and +# tls_private_file_mode=0644. Use a dedicated DH parameter directory or a +# restrictive group-based access model in that case. # # key_sizes usage: -# You can define a global list of Diffie-Hellman key sizes to generate by -# setting the 'key_sizes' parameter at the top of this file. This allows you -# to explicitly control which DH parameter sizes are created, regardless of -# the sizes specified in individual service lines. +# +# Set key_sizes to explicitly control which DH parameter files are generated, +# independent of the sizes referenced in individual service definitions. # # Example: # key_sizes=2048 4096 # -# - This will instruct the script to generate DH parameters for 2048 -# and 4096 bits. -# - If 'key_sizes' is not set, the script will automatically extract all key -# sizes used in the service definitions and generate those. -# - Use a space-separated list for multiple sizes. +# If key_sizes is not set, the script extracts numeric key sizes from +# extended service definitions. If no sizes are configured, it generates +# 2048-bit and 4096-bit DH parameters. # # Example: +# # tls_tmp_path=/etc/pki/tls/tmp # tls_private_path=/etc/pki/tls/private/ +# tls_private_owner=root:root +# tls_private_dir_mode=0755 +# tls_private_file_mode=0644 # key_sizes=2048 4096 # # ----------------------------------------------------------------------------- @@ -48,7 +73,8 @@ # # Fields (for extended format): # service_name - The systemd service name (without .service) -# owner - The user who owns the service (e.g. root, containeradmin) +# owner - root for a system-wide unit, or the account owning a +# systemd --user unit, e.g. containeradmin # key_size - Size of the DH key to generate and sync (e.g. 2048, 4096) # sync_path - Absolute path where the DH key should be copied/synced # user.group - Ownership (user and group) to set on the sync_path and DH key @@ -56,8 +82,13 @@ # # Notes: # - Lines starting with '#' or empty lines are ignored. -# - If only service_name and owner are given, the script uses the default key folder. -# - If sync_path, user.group, or file_permissions are omitted, syncing is skipped. +# - If only service_name and owner are given, the unit is managed after the +# shared DH parameters have been updated in tls_private_path. +# - A simple service definition does not perform a service-specific DH sync. +# - A complete extended definition requires key_size, sync_path, user.group, +# and file_permissions. +# - An incomplete extended definition is treated as an error; the script skips +# both the service-specific DH sync and the service action. # # Examples: # # Simple usage (uses default key folder): @@ -65,7 +96,7 @@ # # # Extended usage (custom sync, owner and permissions): # dovecot:root:2048:/etc/dovecot/ssl:root.dovecot:640 -# postfix:postfix:4096:/etc/postfix/ssl:postfix.postfix:600 +# postfix:root:4096:/etc/postfix/ssl:postfix.postfix:640 # # This file can be overridden by 'edh-keygen.local' in the same directory, # which is preserved during package upgrades. @@ -74,8 +105,11 @@ # Global settings #tls_tmp_path=/etc/pki/tls/tmp #tls_private_path=/etc/pki/tls/private/ +#tls_private_owner=root:root +#tls_private_dir_mode=0755 +#tls_private_file_mode=0644 #key_sizes=2048 4096 # Service lines #dovecot:root -#postfix:postfix:4096:/etc/postfix/ssl:postfix.postfix:600 +#postfix:root:4096:/etc/postfix/ssl:postfix.postfix:640 diff --git a/edh-keygen.sh b/edh-keygen.sh index fef528f..61a8856 100644 --- a/edh-keygen.sh +++ b/edh-keygen.sh @@ -57,6 +57,14 @@ tls_tmp_path='/etc/pki/tls/tmp' tls_private_path='/etc/pki/tls/private/' +# Shared DH parameter directory ownership and permissions. +# DH parameters are public cryptographic parameters, not private keys. +# The default allows non-root TLS services to traverse the directory and read +# generated DH parameter files. +tls_private_owner='root:root' +tls_private_dir_mode='0755' +tls_private_file_mode='0644' + # Determine config file: prefer edh-keygen.local, else use edh-keygen.conf script_dir=$(dirname "$0") if [ -f "$script_dir/edh-keygen.local" ]; then @@ -74,11 +82,14 @@ fi # Read global settings from config file while IFS= read -r line || [ -n "$line" ]; do case "$line" in - ''|\#*) continue ;; # Skip empty lines and comments + ''|\#*) continue ;; tls_tmp_path=*) tls_tmp_path="${line#tls_tmp_path=}" ;; tls_private_path=*) tls_private_path="${line#tls_private_path=}" ;; + tls_private_owner=*) tls_private_owner="${line#tls_private_owner=}" ;; + tls_private_dir_mode=*) tls_private_dir_mode="${line#tls_private_dir_mode=}" ;; + tls_private_file_mode=*) tls_private_file_mode="${line#tls_private_file_mode=}" ;; key_sizes=*) key_sizes="${line#key_sizes=}" ;; - *) break ;; # Stop at first non-global line (service lines start here) + *) break ;; esac done < "$my_service_conf" @@ -110,29 +121,29 @@ for bits in $key_sizes; do done # Set permissions -if ! find "$tls_tmp_path" -type f -name '*.pem' -exec chmod 644 {} \;; then +if ! find "$tls_tmp_path" -type f -name '*.pem' -exec chmod "$tls_private_file_mode" {} \;; then echo "Failed to set permissions on generated DH parameters." >&2 rm -rf "$tls_tmp_path" exit 1 fi # Synchronize DH parameters from the temporary to the private directory. +# Ensure the shared DH parameter directory exists and has the configured metadata. if [ ! -d "$tls_private_path" ]; then if ! mkdir -p "$tls_private_path"; then echo "Failed to create private key directory $tls_private_path." >&2 rm -rf "$tls_tmp_path" exit 1 fi - fi -if ! chown root:root "$tls_private_path"; then +if ! chown "$tls_private_owner" "$tls_private_path"; then echo "Failed to set ownership on private key directory $tls_private_path." >&2 rm -rf "$tls_tmp_path" exit 1 fi -if ! chmod 750 "$tls_private_path"; then +if ! chmod "$tls_private_dir_mode" "$tls_private_path"; then echo "Failed to set permissions on private key directory $tls_private_path." >&2 rm -rf "$tls_tmp_path" exit 1 @@ -152,6 +163,14 @@ for dh_file in "$tls_tmp_path"/dh_*.pem; do fi done +# Enforce ownership and mode on the shared DH parameter files. +if ! find "$tls_private_path" -maxdepth 1 -type f -name 'dh_*.pem' \ + -exec chown "$tls_private_owner" {} \; \ + -exec chmod "$tls_private_file_mode" {} \;; then + echo "Failed to set ownership or permissions on shared DH parameters." >&2 + exit 1 +fi + # Delete the temporary files if ! rm -rf "$tls_tmp_path"; then echo "Failed to remove temporary directory $tls_tmp_path." >&2