diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..521e55f --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Build artifacts +buildroot/ +rpmbuild/ +*.tar.gz +*.rpm +*.src.rpm + +# Editor/OS files +*~ +.DS_Store diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..59a6222 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016-2025 CB-601 - the open tec Elevator + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cb15331 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +NAME = edh-keygen +VERSION = 1.0 +RELEASE = 1 +PREFIX = /opt/edh-keygen +BUILDROOT = $(CURDIR)/buildroot +RPMBUILD = $(CURDIR)/rpmbuild + +all: rpm + +buildroot: + rm -rf $(BUILDROOT) + mkdir -p $(BUILDROOT)$(PREFIX) + chmod 750 $(BUILDROOT)$(PREFIX) + install -m 750 edh-keygen.sh $(BUILDROOT)$(PREFIX)/edh-keygen.sh + install -m 640 edh-keygen.conf $(BUILDROOT)$(PREFIX)/edh-keygen.conf + +rpm: buildroot + rm -rf $(RPMBUILD) + mkdir -p $(RPMBUILD)/SOURCES $(RPMBUILD)/SPECS + + mkdir -p $(RPMBUILD)/TMP/$(NAME)-$(VERSION) + cp -a $(BUILDROOT)/* $(RPMBUILD)/TMP/$(NAME)-$(VERSION)/ + tar czf $(RPMBUILD)/SOURCES/$(NAME)-$(VERSION).tar.gz -C $(RPMBUILD)/TMP $(NAME)-$(VERSION) + + cp rpm/$(NAME).spec $(RPMBUILD)/SPECS/ + rpmbuild --define "_topdir $(RPMBUILD)" \ + --define "_buildrootdir $(RPMBUILD)" \ + -ba $(RPMBUILD)/SPECS/$(NAME).spec + +clean: + rm -rf $(BUILDROOT) $(RPMBUILD) diff --git a/README.md b/README.md index 6a1c736..00fb017 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,147 @@ # edh-keygen -Automated Diffie-Hellman key generation and service management script with flexible configuration, systemd integration and RPM packaging. \ No newline at end of file +Automated Diffie-Hellman key generation and service management script with flexible configuration and systemd integration and RPM packaging. + +--- + +## Outline + +1. [Features](#features) +2. [Installation](#installation) +3. [Configuration](#configuration) +4. [Directory Layout](#directory-layout) +5. [CRON Job Example](#cron-job-example) +6. [License](#license) +7. [Authors](#authors) +8. [Project Home](#project-home) + +--- + +## Features + +- Generates DH parameters for secure services +- Supports service restarts for root and non-root systemd users +- Configurable per-service and global settings via config file +- Customizable sync paths, ownership, and permissions for DH keys +- Weekly cron job integration for automated key regeneration +- RPM packaging for easy deployment + +## Installation + +1. Install required packages + +```bash +sudo dnf install git rpm-build rpmdevtools yum-utils -y +``` + +2. Clone the Repository + +```bash +git clone https://dev.town-square.de/cb601/edh-keygen.git + +cd edh-keygen +``` + +3. Build the RPM package + +You can use the provided Makefile: + +```bash +make clean +make rpm +``` + +4. Install the RPM package + +```bash +sudo yum localinstall rpmbuild/RPMS/noarch/edh-keygen-1.0-1.noarch.rpm +``` + +5. Verify the Installation + +```bash +ls -l /opt/edh-keygen +``` + +You should see: + +```bash +-rwxr-x--- 1 root root ... edh-keygen.sh +-rw-r----- 1 root root ... edh-keygen.conf +``` + +Check RPM info: + +```bash +rpm -qil edh-keygen +``` + + +## Configuration + +The configuration file (`edh-keygen.conf` or `edh-keygen.local`) supports both global path settings and per-service lines. +See the file itself for detailed documentation and examples. + +## Directory Layout + +| Path | Purpose | +|------------------------------------ |---------------------------------| +| /opt/edh-keygen/edh-keygen.sh | Main script | +| /opt/edh-keygen/edh-keygen.conf | Overwritten config (always) | +| /opt/edh-keygen/edh-keygen.local | User config (never overwritten) | +| /etc/cron.weekly/edh-keygen | Cron job script (optional) | + +## CRON Job Example + +To run the key generator weekly, you have two options: + +### 1. Crontab + +You can add a weekly cron job directly to the root user's crontab: + +Open the root crontab for editing: + +```bash +sudo crontab -e +``` + +Add the following line to run the script every Sunday at 3:30 AM: + +```bash +30 3 * * 0 /opt/edh-keygen/edh-keygen.sh +``` + +*(Adjust the schedule as needed. This example runs the script weekly on Sunday.)* + +### 2. System Cron Weekly Directory + +Create a script as `/etc/cron.weekly/edh-keygen`: + +```bash +#!/bin/sh + +/opt/edh-keygen/edh-keygen.sh + +exit 0 +``` + +Ensure the script is executable: + +```bash +chmod 750 /etc/cron.weekly/edh-keygen +``` + +## License + +[MIT](https://dev.town-square.de/cb601/edh-keygen/LICENSE) + +## Authors + +CB-601 - the open tec Elevator + +- [Stephan Düsterhaupt](xmpp:me@jabber.stephanduesterhaupt.de) +- [Ivo Noack](xmpp:me@jabber.ivonoack.de) aka Insonic + +## Project Home + +Project Home: [https://dev.town-square.de/cb601/edh-keygen](https://dev.town-square.de/cb601/edh-keygen) diff --git a/edh-keygen.conf b/edh-keygen.conf new file mode 100644 index 0000000..4fc61a3 --- /dev/null +++ b/edh-keygen.conf @@ -0,0 +1,63 @@ +# ----------------------------------------------------------------------------- +# edh-keygen Configuration File +# +# 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 +# +# If omitted, the following defaults are used: +# tls_tmp_path=/etc/pki/tls/tmp +# tls_private_path=/etc/pki/tls/private/ +# +# Example: +# tls_tmp_path=/etc/pki/tls/tmp +# tls_private_path=/etc/pki/tls/private/ +# +# ----------------------------------------------------------------------------- +# +# SERVICE LINES +# +# Supported Formats (per line): +# +# 1. Simple format: +# service_name:owner +# - Only the service and owner are specified. +# - The DH keys will be managed in the default/generic folder. +# +# 2. Extended format: +# service_name:owner:key_size:sync_path:user.group:file_permissions +# - All fields are specified for advanced key syncing and permission control. +# +# Fields (for extended format): +# service_name - The systemd service name (without .service) +# owner - The user who owns the service (e.g. root, 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 +# file_permissions - Permissions to set on the DH key file (e.g. 640, 600) +# +# 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. +# +# Examples: +# # Simple usage (uses default key folder): +# dovecot:root +# +# # 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 +# +# This file can be overridden by 'edh-keygen.local' in the same directory, +# which is preserved during package upgrades. +# ----------------------------------------------------------------------------- + +# Global settings +#tls_tmp_path=/etc/pki/tls/tmp +#tls_private_path=/etc/pki/tls/private/ + +# Service lines +#dovecot:root +#postfix:postfix:4096:/etc/postfix/ssl:postfix.postfix:600 diff --git a/edh-keygen.sh b/edh-keygen.sh new file mode 100644 index 0000000..331c399 --- /dev/null +++ b/edh-keygen.sh @@ -0,0 +1,181 @@ +#!/bin/sh +# +############################################################################### +# +# edh-keygen.sh +# +# Diffie-Hellman Key Generation and Service Management Script +# +# This script generates Diffie-Hellman parameter files for various key sizes, +# manages their permissions, and can synchronize keys to custom locations +# with specified ownership and permissions. It supports service restarts +# for both root and non-root systemd users, and is designed for integration +# with automated cron jobs. +# +# Configuration is read from a .conf or .local file, supporting per-service +# customization including: +# - Service name and owner +# - DH key size +# - Sync path for DH key +# - User.group for destination +# - File permissions for the key +# +# Authors: Ivo Noack aka Insonic +# Stephan Düsterhaupt +# +# Copyright (c) 2016-2025 CB-601 - the open tec Elevator +# License: MIT +# +# Project Home: https://dev.town-square.de/cb601/edh-keygen +# +############################################################################### + +# MIT License +# +# Copyright (c) 2025 CB-601 - the open tec Elevator +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +# Default values (in case not set in config) +tls_tmp_path='/etc/pki/tls/tmp' +tls_private_path='/etc/pki/tls/private/' + +# Determine config file: prefer edh-keygen.local, else use edh-keygen.conf +script_dir=$(dirname "$0") +if [ -f "$script_dir/edh-keygen.local" ]; then + my_service_conf="$script_dir/edh-keygen.local" +else + my_service_conf="$script_dir/edh-keygen.conf" +fi + +# Check config file +if [ ! -f "$my_service_conf" ]; then + echo "Service config file $my_service_conf not found!" 1>&2 + exit 1 +fi + +# Read global settings from config file +while IFS= read -r line || [ -n "$line" ]; do + case "$line" in + ''|\#*) continue ;; + tls_tmp_path=*) tls_tmp_path="${line#tls_tmp_path=}" ;; + tls_private_path=*) tls_private_path="${line#tls_private_path=}" ;; + *) break ;; # Stop at first non-global line + esac +done < "$my_service_conf" + +# Create path for 'tmp' in '/etc/pki/tls' +if [ ! -d "$tls_tmp_path" ]; then + mkdir -p "$tls_tmp_path" +fi + +umask 022 + +# Generate DH params +for bits in 512 1024 2048 4096; do + openssl dhparam -out "$tls_tmp_path/dh_${bits}.pem" "$bits" +done + +# Set permissions +find "$tls_tmp_path" -type f -name "*.pem" -exec chmod 644 {} \; + +# Sync certs from temporary to private folder +rsync -a "$tls_tmp_path/"*.pem "$tls_private_path" + +# Delete the temporary files +rm -rf "$tls_tmp_path" + +# Read and process service list +while IFS= read -r line || [ -n "$line" ]; do + # Skip empty lines and lines starting with # + case "$line" in + ''|\#*) continue ;; + esac + + # Extract service, owner, and sync parameters + service=$(printf "%s" "$line" | awk -F: '{print $1}') + owner=$(printf "%s" "$line" | awk -F: '{print $2}') + key_size=$(printf "%s" "$line" | awk -F: '{print $3}') + sync_path=$(printf "%s" "$line" | awk -F: '{print $4}') + user_group=$(printf "%s" "$line" | awk -F: '{print $5}') + permissions=$(printf "%s" "$line" | awk -F: '{print $6}') + + echo "$service.service (owner: $owner)..." + + # Check service status (must run as root) + if [ "$owner" = "root" ]; then + mySubState=$(systemctl show -p SubState --value "$service.service" 2>/dev/null) + else + uid=$(id -u "$owner" 2>/dev/null) + if [ -n "$uid" ]; then + mySubState=$(sudo -u "$owner" XDG_RUNTIME_DIR="/run/user/$uid" /usr/bin/systemctl --user show -p SubState --value "$service.service" 2>/dev/null) + else + echo "User $owner not found! Skipping $service." 1>&2 + continue + fi + fi + + if [ "$mySubState" = "running" ]; then + echo "$service.service is running, restarting as $owner..." + if [ "$owner" = "root" ]; then + /usr/bin/systemctl restart "$service.service" + else + sudo -u "$owner" XDG_RUNTIME_DIR="/run/user/$uid" /usr/bin/systemctl --user restart "$service" + fi + echo "$service.service restarted." + fi + + # Handle DH key sync if parameters exist + if [ -n "$key_size" ] && [ -n "$sync_path" ] && [ -n "$user_group" ] && [ -n "$permissions" ]; then + if ! echo "$user_group" | grep -q "."; then + echo "Error: user_group must be 'user.group' for $service. Skipping sync." 1>&2 + continue + fi + + dh_file="$tls_private_path/dh_${key_size}.pem" + if [ ! -f "$dh_file" ]; then + echo "DH key $dh_file not found. Skipping sync for $service." 1>&2 + continue + fi + + # Create directory if missing + if [ ! -d "$sync_path" ]; then + mkdir -p "$sync_path" || { + echo "Failed to create $sync_path for $service." 1>&2 + continue + } + chown "$user_group" "$sync_path" + chmod 750 "$sync_path" + echo "Created directory $sync_path for $service." + fi + + # Copy DH key and set permissions + cp "$dh_file" "$sync_path/" || { + echo "Failed to copy DH key to $sync_path for $service." 1>&2 + continue + } + chown "$user_group" "$sync_path/dh_${key_size}.pem" + chmod "$permissions" "$sync_path/dh_${key_size}.pem" + echo "Synced DH key (${key_size}-bit) to $sync_path for $service." + fi +done < "$my_service_conf" + + +exit 0 diff --git a/rpm/edh-keygen.spec b/rpm/edh-keygen.spec new file mode 100644 index 0000000..eaccc92 --- /dev/null +++ b/rpm/edh-keygen.spec @@ -0,0 +1,43 @@ +Name: edh-keygen +Version: 1.0 +Release: 1%{?dist} +Summary: Automated Diffie-Hellman key generation and service management + +License: MIT +Source0: %{name}-%{version}.tar.gz + +BuildArch: noarch + +%description +Script for automated Diffie-Hellman key generation, service management and flexible key syncing with custom permissions. + +%prep +%setup -q + +%install +mkdir -p %{buildroot}/opt/edh-keygen +install -m 750 opt/edh-keygen/edh-keygen.sh %{buildroot}/opt/edh-keygen/ +install -m 640 opt/edh-keygen/edh-keygen.conf %{buildroot}/opt/edh-keygen/ + +# Set permissions explicitly +chmod 750 %{buildroot}/opt/edh-keygen + +%preun +# If uninstalling (not upgrading) +if [ "$1" = 0 ] && ls /opt/edh-keygen/*.local >/dev/null 2>&1; then + rm -f /opt/edh-keygen/edh-keygen.sh /opt/edh-keygen/edh-keygen.conf + exit 0 +fi + +%postun +rmdir --ignore-fail-on-non-empty /opt/edh-keygen 2>/dev/null || : + +%files +%dir %attr(750,root,root) /opt/edh-keygen +%attr(750,root,root) /opt/edh-keygen/edh-keygen.sh +%attr(640,root,root) /opt/edh-keygen/edh-keygen.conf +%ghost /opt/edh-keygen/edh-keygen.local + +%changelog +* Sun May 18 2025 Ivo Noack, Stephan Düsterhaupt - 1.0-1 +- Initial RPM release with preservation of .local files on uninstall