Files
opnsense_cert_exporter/README.md

235 lines
6.7 KiB
Markdown

# OPNsense Certificate Exporter
A Python tool to export SSL/TLS certificates and private keys from OPNsense firewalls via the API.
## Features
- Search and export certificates from OPNsense Trust store
- Exports both certificate (`cert.pem`) and private key (`privkey.pem`)
- Change detection: only writes files if content has changed
- Environment-based configuration (supports `.env` files)
- Optional systemd journal logging
- Optional file permission settings (Linux only)
## Prerequisites
- Python 3.13+
- [uv](https://docs.astral.sh/uv/) (recommended) or pip
- OPNsense firewall with API access enabled
- API key and secret with access to Trust/Certificates
## Installation
### Using uv (recommended)
```bash
git clone https://git.project-insanity.de/gmarth/opnsense_cert_exporter.git
cd opnsense-cert-exporter
uv sync
```
### Using pip
```bash
git clone https://git.project-insanity.de/gmarth/opnsense_cert_exporter.git
cd opnsense-cert-exporter
pip install -r requirements.txt
```
### Optional: systemd journal logging
To enable native systemd journal logging (Linux only):
```bash
# Install system dependency first
sudo apt install libsystemd-dev pkg-config # Debian/Ubuntu
sudo dnf install systemd-devel pkg-config # Fedora/RHEL
# Then install the optional Python dependency
uv sync --extra systemd
```
## Configuration
1. Copy the example environment file:
```bash
cp .env.example .env
```
2. Edit `.env` with your settings:
```bash
# Required
OPNSENSE_API_KEY=your_api_key_here
OPNSENSE_API_SECRET=your_api_secret_here
OPNSENSE_HOST=https://your-opnsense.local
# Optional
OUTPUT_DIRECTORY=./certs
# Optional: disable SSL verification for self-signed certificates
# VERIFY_SSL=false
# Optional: file permissions (Linux only)
# FILE_OWNER=root
# FILE_GROUP=root
# FILE_MODE=0600
```
### Configuration Options
| Environment Variable | Required | Description |
|---------------------|----------|-------------|
| `OPNSENSE_API_KEY` | Yes | OPNsense API key |
| `OPNSENSE_API_SECRET` | Yes | OPNsense API secret |
| `OPNSENSE_HOST` | Yes | OPNsense URL (e.g., `https://192.168.1.1`) |
| `OUTPUT_DIRECTORY` | No | Directory to save exported certificates (default: `./certs`) |
| `VERIFY_SSL` | No | Set to `false` to disable SSL verification for self-signed certs (default: `true`) |
| `FILE_OWNER` | No | Set file owner (Linux only) |
| `FILE_GROUP` | No | Set file group (Linux only) |
| `FILE_MODE` | No | Set file permissions in octal (e.g., `0600`) |
### Setting up OPNsense API Access
For security, create a dedicated user with minimal privileges for certificate export.
#### 1. Create a Group with Certificate Manager Access
1. Log in to your OPNsense web interface
2. Go to **System > Access > Groups**
3. Click **+** to add a new group
4. Configure the group:
- **Group name:** `cert-exporter`
- **Description:** `Certificate export API access`
- **Restrict access to networks (optional):** Limit API access to specific networks (e.g., `192.168.1.0/24` or a single host `192.168.1.100/32`)
5. Click **Save**
6. Click the **Edit** (pencil icon) on the newly created group
7. Under **Assigned Privileges**, click **Edit**
8. Select only **System: Certificate Manager** from the list
9. Click **Save**
> **Security tip:** Restricting access to the network where your export script runs adds an extra layer of security. Even if the API credentials are compromised, they cannot be used from unauthorized networks.
#### 2. Create a Dedicated API User
1. Go to **System > Access > Users**
2. Click **+** to add a new user
3. Configure the user:
- **Username:** `cert-exporter`
- **Password:** Set a strong password (not used for API access, but required)
- **Group Memberships:** Select `cert-exporter`
4. Click **Save**
#### 3. Generate an API Key
1. Edit the `cert-exporter` user
2. Scroll down to **API keys** and click the **+** button
3. Download the generated key file containing the key and secret
4. Store the credentials securely - they cannot be retrieved later
## Usage
### Using uv
```bash
uv run python main.py <certificate_name>
```
### Using Python directly
```bash
python main.py <certificate_name>
```
### Examples
```bash
# Export a single certificate
uv run python main.py mail.example.com
# Export multiple certificates
uv run python main.py mail.example.com
uv run python main.py vpn.example.com
uv run python main.py wildcard.example.com
```
The tool will:
1. Search for the certificate matching the provided name
2. Check if the certificate has changed since last export
3. Export the certificate to `<output_directory>/<certificate_name>/cert.pem`
4. Export the private key to `<output_directory>/<certificate_name>/privkey.pem`
5. Log whether the certificate was updated or unchanged
### Viewing logs
With systemd journal logging enabled:
```bash
journalctl -t opnsense-cert-exporter
journalctl -t opnsense-cert-exporter --since "1 hour ago"
journalctl -t opnsense-cert-exporter -f # follow
```
## Setting up a Cronjob for Periodic Exports
To automatically export certificates on a schedule, set up a cron job:
### 1. Open the crontab editor
```bash
crontab -e
```
### 2. Add a cron entry
The `.env` file is automatically loaded from the script directory, so no need to `cd` first.
**Daily at midnight:**
```cron
0 0 * * * /usr/local/bin/uv run python /opt/opnsense-cert-exporter/main.py mail.example.com
```
**Export multiple certificates:**
```cron
0 0 * * * /usr/local/bin/uv run python /opt/opnsense-cert-exporter/main.py mail.example.com
0 0 * * * /usr/local/bin/uv run python /opt/opnsense-cert-exporter/main.py vpn.example.com
```
**Weekly on Sunday at 2 AM:**
```cron
0 2 * * 0 /usr/local/bin/uv run python /opt/opnsense-cert-exporter/main.py mail.example.com
```
### 3. Example with service reload
```cron
# Export certificate daily at midnight and reload nginx if changed
0 0 * * * /usr/local/bin/uv run python /opt/opnsense-cert-exporter/main.py mail.example.com && systemctl reload nginx
```
### Cron Format Reference
```
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sunday=0)
│ │ │ │ │
* * * * * command
```
### Tips
- Use absolute paths for the `uv` binary and `main.py` script
- The `.env` file is loaded from the script directory automatically
- With systemd journal logging, output automatically goes to the journal
- Test the command manually before adding to cron
- Consider adding a service reload command (e.g., `systemctl reload nginx`) after export
- Ensure the cron user has appropriate permissions to write to the output directory
## License
MIT