feat(edh-keygen): configure shared DH parameter permissions
Add configurable ownership and permission defaults for shared DH parameter directories and files. Set shared DH parameter defaults to root:root, directory mode 0755, and file mode 0644 so non-root TLS services can traverse the directory and read DH parameter files. Enforce configured ownership and modes after synchronization and document the security boundary between public DH parameters and TLS private keys.
This commit is contained in:
1 parent
27f665bbf7
commit
cc2ca834d2
3 files changed
+91
-23
No files matched your search
@@ -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/),
|
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).
|
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
|
## 1.0.0 - 2026-09-06
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
+51
-17
@@ -3,32 +3,57 @@
|
|||||||
#
|
#
|
||||||
# GLOBAL SETTINGS (must appear before any service lines):
|
# GLOBAL SETTINGS (must appear before any service lines):
|
||||||
#
|
#
|
||||||
# tls_tmp_path - Temporary folder for DH key generation
|
# tls_tmp_path - Temporary directory for DH parameter generation
|
||||||
# tls_private_path - Folder where DH keys are stored permanently
|
# tls_private_path - Shared directory where generated DH parameters are
|
||||||
# key_sizes - (Optional) Space-separated list of DH key sizes to generate.
|
# 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:
|
# If omitted, the following defaults are used:
|
||||||
|
#
|
||||||
# tls_tmp_path=/etc/pki/tls/tmp
|
# tls_tmp_path=/etc/pki/tls/tmp
|
||||||
# tls_private_path=/etc/pki/tls/private/
|
# 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:
|
# 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
|
# Set key_sizes to explicitly control which DH parameter files are generated,
|
||||||
# to explicitly control which DH parameter sizes are created, regardless of
|
# independent of the sizes referenced in individual service definitions.
|
||||||
# the sizes specified in individual service lines.
|
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
# key_sizes=2048 4096
|
# key_sizes=2048 4096
|
||||||
#
|
#
|
||||||
# - This will instruct the script to generate DH parameters for 2048
|
# If key_sizes is not set, the script extracts numeric key sizes from
|
||||||
# and 4096 bits.
|
# extended service definitions. If no sizes are configured, it generates
|
||||||
# - If 'key_sizes' is not set, the script will automatically extract all key
|
# 2048-bit and 4096-bit DH parameters.
|
||||||
# sizes used in the service definitions and generate those.
|
|
||||||
# - Use a space-separated list for multiple sizes.
|
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
|
#
|
||||||
# tls_tmp_path=/etc/pki/tls/tmp
|
# tls_tmp_path=/etc/pki/tls/tmp
|
||||||
# tls_private_path=/etc/pki/tls/private/
|
# 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
|
# key_sizes=2048 4096
|
||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@@ -48,7 +73,8 @@
|
|||||||
#
|
#
|
||||||
# Fields (for extended format):
|
# Fields (for extended format):
|
||||||
# service_name - The systemd service name (without .service)
|
# 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)
|
# 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
|
# 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
|
# user.group - Ownership (user and group) to set on the sync_path and DH key
|
||||||
@@ -56,8 +82,13 @@
|
|||||||
#
|
#
|
||||||
# Notes:
|
# Notes:
|
||||||
# - Lines starting with '#' or empty lines are ignored.
|
# - Lines starting with '#' or empty lines are ignored.
|
||||||
# - If only service_name and owner are given, the script uses the default key folder.
|
# - If only service_name and owner are given, the unit is managed after the
|
||||||
# - If sync_path, user.group, or file_permissions are omitted, syncing is skipped.
|
# 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:
|
# Examples:
|
||||||
# # Simple usage (uses default key folder):
|
# # Simple usage (uses default key folder):
|
||||||
@@ -65,7 +96,7 @@
|
|||||||
#
|
#
|
||||||
# # Extended usage (custom sync, owner and permissions):
|
# # Extended usage (custom sync, owner and permissions):
|
||||||
# dovecot:root:2048:/etc/dovecot/ssl:root.dovecot:640
|
# 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,
|
# This file can be overridden by 'edh-keygen.local' in the same directory,
|
||||||
# which is preserved during package upgrades.
|
# which is preserved during package upgrades.
|
||||||
@@ -74,8 +105,11 @@
|
|||||||
# Global settings
|
# Global settings
|
||||||
#tls_tmp_path=/etc/pki/tls/tmp
|
#tls_tmp_path=/etc/pki/tls/tmp
|
||||||
#tls_private_path=/etc/pki/tls/private/
|
#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
|
#key_sizes=2048 4096
|
||||||
|
|
||||||
# Service lines
|
# Service lines
|
||||||
#dovecot:root
|
#dovecot:root
|
||||||
#postfix:postfix:4096:/etc/postfix/ssl:postfix.postfix:600
|
#postfix:root:4096:/etc/postfix/ssl:postfix.postfix:640
|
||||||
+25
-6
@@ -57,6 +57,14 @@
|
|||||||
tls_tmp_path='/etc/pki/tls/tmp'
|
tls_tmp_path='/etc/pki/tls/tmp'
|
||||||
tls_private_path='/etc/pki/tls/private/'
|
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
|
# Determine config file: prefer edh-keygen.local, else use edh-keygen.conf
|
||||||
script_dir=$(dirname "$0")
|
script_dir=$(dirname "$0")
|
||||||
if [ -f "$script_dir/edh-keygen.local" ]; then
|
if [ -f "$script_dir/edh-keygen.local" ]; then
|
||||||
@@ -74,11 +82,14 @@ fi
|
|||||||
# Read global settings from config file
|
# Read global settings from config file
|
||||||
while IFS= read -r line || [ -n "$line" ]; do
|
while IFS= read -r line || [ -n "$line" ]; do
|
||||||
case "$line" in
|
case "$line" in
|
||||||
''|\#*) continue ;; # Skip empty lines and comments
|
''|\#*) continue ;;
|
||||||
tls_tmp_path=*) tls_tmp_path="${line#tls_tmp_path=}" ;;
|
tls_tmp_path=*) tls_tmp_path="${line#tls_tmp_path=}" ;;
|
||||||
tls_private_path=*) tls_private_path="${line#tls_private_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=}" ;;
|
key_sizes=*) key_sizes="${line#key_sizes=}" ;;
|
||||||
*) break ;; # Stop at first non-global line (service lines start here)
|
*) break ;;
|
||||||
esac
|
esac
|
||||||
done < "$my_service_conf"
|
done < "$my_service_conf"
|
||||||
|
|
||||||
@@ -110,29 +121,29 @@ for bits in $key_sizes; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# Set permissions
|
# 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
|
echo "Failed to set permissions on generated DH parameters." >&2
|
||||||
rm -rf "$tls_tmp_path"
|
rm -rf "$tls_tmp_path"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Synchronize DH parameters from the temporary to the private directory.
|
# 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 [ ! -d "$tls_private_path" ]; then
|
||||||
if ! mkdir -p "$tls_private_path"; then
|
if ! mkdir -p "$tls_private_path"; then
|
||||||
echo "Failed to create private key directory $tls_private_path." >&2
|
echo "Failed to create private key directory $tls_private_path." >&2
|
||||||
rm -rf "$tls_tmp_path"
|
rm -rf "$tls_tmp_path"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
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
|
echo "Failed to set ownership on private key directory $tls_private_path." >&2
|
||||||
rm -rf "$tls_tmp_path"
|
rm -rf "$tls_tmp_path"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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
|
echo "Failed to set permissions on private key directory $tls_private_path." >&2
|
||||||
rm -rf "$tls_tmp_path"
|
rm -rf "$tls_tmp_path"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -152,6 +163,14 @@ for dh_file in "$tls_tmp_path"/dh_*.pem; do
|
|||||||
fi
|
fi
|
||||||
done
|
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
|
# Delete the temporary files
|
||||||
if ! rm -rf "$tls_tmp_path"; then
|
if ! rm -rf "$tls_tmp_path"; then
|
||||||
echo "Failed to remove temporary directory $tls_tmp_path." >&2
|
echo "Failed to remove temporary directory $tls_tmp_path." >&2
|
||||||
|
|||||||
Reference in new issue
Block a user