# SSL Management Project Guidelines This document provides guidelines for developing and maintaining the SSL Management project, which is a Python-based tool for managing SSL certificates for UniFi devices such as UDM-SE. The tool helps automate the process of obtaining, validating, and deploying SSL certificates to UniFi devices. ## Build/Configuration Instructions ### Prerequisites 1. **Python 3.6+**: The project is written in Python and requires Python 3.6 or higher. 2. **OpenSSL**: Required for certificate operations. Must be installed and available in your PATH. 3. **Virtual Environment**: The project uses a virtual environment for dependency isolation. 4. **Linux Environment**: The script is designed to run on Linux systems such as Ubuntu 24.04. While development can occur on any platform, deployment is expected on a Linux server. ### Setup 1. Clone the repository: ```bash git clone cd ssl-managment ``` 2. Create and activate a virtual environment: ```bash python -m venv .venv source .venv/bin/activate # On Windows: .venv\Scripts\activate ``` 3. No external Python packages are required as the project uses standard library modules. ### Configuration The SSL Manager uses a configuration file (`config.json`) to store default settings. The configuration file should be placed in the project root directory. Here's an example of the configuration file: ```json { "cert_dir": "~/.ssl-certs", "default_port": 443, "connection_timeout": 3.0, "default_validity_days": 365, "key_size": 2048, "unifi": { "host": "unifi.example.com", "username": "admin", "password": "password", "site": "default", "ssh_port": 22, "ssh_username": "root", "ssh_password": "", "ssh_key_path": "~/.ssh/id_rsa" } } ``` Configuration options: - `cert_dir`: Directory where certificates and keys will be stored - `default_port`: Default port to use when checking certificate expiration - `connection_timeout`: Timeout in seconds for SSL connections - `default_validity_days`: Default validity period in days for generated certificates - `key_size`: Key size in bits for generated certificates - `unifi`: UniFi device connection parameters - `host`: Hostname or IP address of the UniFi device - `username`: Username for authenticating with the UniFi device - `password`: Password for authenticating with the UniFi device - `site`: Site name for the UniFi device (default: 'default') - `ssh_port`: SSH port for the UniFi device (default: 22) - `ssh_username`: Username for SSH authentication with the UniFi device - `ssh_password`: Password for SSH authentication (leave empty to use SSH key) - `ssh_key_path`: Path to the SSH private key file for authentication ### Usage The SSL Manager provides three main commands. All commands support the following global options: - `--config`: Path to the config file (default: config.json) - `--cert-dir`: Directory to store certificates (overrides config) 1. **Check Certificate Expiration**: ```bash python src/ssl_manager.py check example.com [--port PORT] ``` The `--port` option overrides the `default_port` from the config file. 2. **Generate Self-Signed Certificate**: ```bash python src/ssl_manager.py generate example.com [--days DAYS] ``` The `--days` option overrides the `default_validity_days` from the config file. 3. **Validate Certificate Chain**: ```bash python src/ssl_manager.py validate path/to/certificate.crt [--ca-path path/to/ca.crt] ``` ## Testing Information ### Running Tests Tests are written using the Python `unittest` framework. To run all tests: ```bash cd ssl-managment # Ensure you're in the project root python -m unittest discover tests ``` To run a specific test file: ```bash python -m tests.test_ssl_manager ``` ### Adding New Tests 1. Create a new test file in the `tests` directory, following the naming convention `test_*.py`. 2. Import the necessary modules and the `SSLManager` class: ```python import os import sys import unittest from unittest.mock import patch # Add the src directory to the Python path sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) from ssl_manager import SSLManager ``` 3. Create a test class that inherits from `unittest.TestCase`: ```python class TestYourFeature(unittest.TestCase): def setUp(self): # Set up test fixtures self.ssl_manager = SSLManager() def test_your_feature(self): # Test your feature result = self.ssl_manager.your_method() self.assertEqual(result, expected_value) ``` 4. Use mocking to avoid actual network or system calls: ```python @patch('ssl_manager.subprocess.run') def test_with_mock(self, mock_run): mock_run.return_value = MagicMock(returncode=0) # Test with mock ``` ### Test Example Here's a simple test that verifies the SSLManager initializes correctly: ```python def test_init_creates_cert_dir(self): """Test that the constructor creates the certificate directory.""" test_path = os.path.expanduser("~/test-ssl-certs") # Remove the directory if it exists if os.path.exists(test_path): os.rmdir(test_path) # Create a new SSLManager with the test path ssl_manager = SSLManager(cert_dir=test_path) # Verify the directory was created self.assertTrue(os.path.exists(test_path)) self.assertTrue(os.path.isdir(test_path)) # Clean up os.rmdir(test_path) ``` ## Development Guidelines ### Code Style 1. **PEP 8**: Follow the [PEP 8](https://www.python.org/dev/peps/pep-0008/) style guide for Python code. 2. **Docstrings**: Use docstrings for all modules, classes, and functions. Follow the [Google style](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings) for docstrings. 3. **Type Hints**: Use type hints for function parameters and return values. ### Project Structure - `src/`: Contains the source code - `ssl_manager.py`: Main module with the SSLManager class - `tests/`: Contains test files - `test_ssl_manager.py`: Tests for the SSLManager class ### Best Practices 1. **Error Handling**: Use try-except blocks to handle exceptions gracefully. 2. **Logging**: Use the Python logging module for logging instead of print statements. 3. **Testing**: Write tests for all new features and bug fixes. 4. **Documentation**: Update documentation when making changes to the code. ## Deployment and Automation ### Cross-Machine Deployment The SSL Management tool can be developed on one machine and deployed to another server for production use. When deploying across machines: 1. Ensure the target server meets all the prerequisites (Python 3.6+, OpenSSL, etc.) 2. Transfer the entire project directory to the target server 3. Set up the virtual environment on the target server 4. Configure the `config.json` file with the appropriate settings for the target environment 5. Test the deployment by running a simple command like `python src/ssl_manager.py check ` ### Automated Certificate Updates To automate certificate updates using cron: 1. Create a shell script wrapper for the SSL Manager: ```bash #!/bin/bash # File: update_certificates.sh # Change to the project directory cd /path/to/ssl-managment # Activate the virtual environment source .venv/bin/activate # Run the SSL Manager to update certificates python src/ssl_manager.py generate your-unifi-device.example.com --days 90 # Additional commands to deploy the certificate to the UniFi device can be added here ``` 2. Make the script executable: ```bash chmod +x update_certificates.sh ``` 3. Add a cron job to run the script periodically (e.g., every 60 days): ```bash # Edit the crontab crontab -e # Add a line like this to run at 2:30 AM on the 1st of every other month 30 2 1 */2 * /path/to/update_certificates.sh >> /var/log/certificate-updates.log 2>&1 ``` 4. Verify the cron job is set up correctly: ```bash crontab -l ``` ## Troubleshooting ### Common Issues 1. **OpenSSL Command Not Found** Ensure OpenSSL is installed and in your PATH. 2. **Permission Denied When Creating Certificates** Check that you have write permissions to the certificate directory. 3. **Import Errors in Tests** Make sure you're running tests from the project root directory. ### Debugging - Set the `SSL_DEBUG=1` environment variable for verbose output - Check the OpenSSL version with `openssl version` - Verify certificate paths are correct and accessible