This Python script manages certificates issued by HashiCorp Vault. It requests, renews, deploys, and manages certificates based on a configuration file.
- Requests certificates from HashiCorp Vault.
- Stores certificates in a defined directory.
- Deploys certificates to defined destinations with proper permissions.
- Restarts/reloads services after certificates are updated.
- Renews managed certificates.
- Python 3.x
- Python 3.x Virtual Environments module (venv)
- HashiCorp Vault
- Vault's API
- Required (additional) Python libraries:
requestspyyamlpyopenssl
We'll assume you already have python3 installed on your system, however you need to enusre you have python3 venv installed
- RHEL:
sudo yum install python3-venv - Debian:
sudo apt install python3-venv
As this is a raw python script it requires a little setup in order to get going.
- Prerequisites
Ensure Vault is accessible from the system. - Ensure you can access the WebUI of your Vault server, and ensure suitable permissions on the Vault server. More information on this coming soon!
- Create application directory and set permissions
I suggest placing the application in your opt directory, however this could just as easily run from your root home directory. For the sake of simplicity we'll use the first option for the examples. If you do change the installation path you'll need to modify the hashbang (#!) statement at line #1 in main.py so the script is executable.
sudo mkdir /opt/vcm- Get Files
Option1: Clone Respository with GIT
sudo git clone https://github.com/tfindley/vault_certificate_manager.git /opt/vcmOption2: Download .zip and extract
wget https://github.com/tfindley/vault_certificate_manager/archive/refs/heads/main.zip
sudo unzip main.zip
mv vault_certificate_manager-main * /opt/vcm
rmdir vault_certificate_manager-main- Install dependencies:
Now you've got all of the files down from git. we need to create our Python Virtual Environment and install dependencies.
Start with generating your venv inside of the vcm directory
cd /opt/vcm
python3 -m venv .venv
. .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
deactivateNow you should have a fully build Python Virtual Environment which is ready to run the main.py script.
- Edit the configuration file
See below for details on the config.yml and its sections
- Set permissions
The application should ideally run as root (or an equally privilaged user) as it needs to be able to manage service restarts. You could theoretically run this as another user however this is beyond the scope of this README.
sudo chown -R root:root /opt/vcm
sudo chmod 0700 /opt/vcm
sudo chmod 0700 /opt/vcm/main.py
sudo chmod 0600 /opt/config.yaml- Execute the application
/opt/vcm/main.py- Configure Crontab to run
See 'Automating with Cron' section below.
Modify the config.yaml file:
- Set the Vault server, PKI role, renewal threshold and access credentials.
- Define what certificates you want to generate
- Define where certificates should be stored and deployed.
- Specify services to restart upon renewal.
| Key | Required | Overridable | Type | Example Value | ENV Option | Description |
|---|---|---|---|---|---|---|
vault |
True | False | string | https://vault.example.com:8200 |
VAULT_ADDR |
|
vault_ssl_verify |
False | False | string | /etc/ssl/cert.pem |
||
pki |
True | True | string | pki |
||
role |
True | True | string | pki_role |
||
renew |
True | True | string | 14d |
||
cert_store |
True | False | string | /opt/vcm/certs |
||
log_file |
False | False | string | /var/log/vert_manager.log |
||
token_file |
False | False | string | /etc/vault-token |
VAULT_TOKEN |
|
vault_role_id |
False | False | string | your-role-id |
VAULT_ROLE_ID |
|
vault_secret_id |
False | False | string | your-role-secret-id |
VAULT_SECRET_ID |
| Key | Required | Overridable | Type | Example Value | Description |
|---|---|---|---|---|---|
name |
True | False | string | test.example.tld |
|
renew |
True | False | string | 7d |
|
ttl |
True | False | string | 90d |
|
pki |
True | False | string | anotherpki |
|
role |
True | False | string | anotherpki_role |
|
dns_sans |
True | False | list | ["name1.domain.tld", "name2.domain.tld"] |
|
ip_sans |
True | False | list | ["192.168.69.11", "192.168.69.101"] |
| Key | Required | Overridable | Type | Example Value | Description |
|---|---|---|---|---|---|
source |
True | False | string | cert |
cert, chain, fullchain, privkey |
dest |
True | False | string | /opt/path/to/directory/cert.pem |
|
owner |
True | False | string | username |
|
group |
True | False | string | groupname |
|
mode |
True | False | string | 0640 |
| Key | Required | Overridable | Type | Example Value | Description |
|---|---|---|---|---|---|
name |
True | False | string | nginx.service |
|
control |
True | False | string | reload |
Choose from reload or restart depending on the service. |
order |
True | False | int | 1 |
To set the Vault Address, you can use the Environmental Variable, or you can specify this in the config.yaml file
The order of presedence for the Vault Address is:
- Vault Address Env
VAULT_ADDR - Vault Address value in config.yaml
vault
This script can use a Vault Token, or it can request a token when provided with a Role ID and Secret ID.
The order of presendence for Authentication is:
- Vault Token Env
VAULT_TOKEN - Vault Token File
token_file - Vault Role Env
VAULT_ROLE_ID/VAULT_SECRET_ID - Vault Role values in config.yaml
vault_role_id+vault_secret_id
| ENV | Overrides | Description |
|---|---|---|
VAULT_ADDR |
vault in config.yaml |
Vault url: i.e: https://vault.domain.tld:8200 |
VAULT_TOKEN |
token_file in config.yaml |
Vault token |
VAULT_ROLE_ID |
vault_role_id in config.yaml |
Vault role ID |
VAULT_SECRET_ID |
vault_secret_id in config.yaml |
Vault secret ID |
To manually execute the script:
python3 main.pyTo run the script periodically, add a cron job:
crontab -eExample cron job (runs every 6 hours):
0 */6 * * * /opt/vcm/main.py >/dev/null 2>&1Example crontab (runs once a day at 04:05)
5 4 * * * /opt/vcm/main.py >/dev/null 2>&1You can construct your own crontab easily using the Crontab Generator
- Environment Variable First: The script prioritizes the
VAULT_TOKENenvironment variable. - Token File Fallback: If
VAULT_TOKENis not set, it reads fromtoken_file(default:/etc/vault-token). - Restrict File Permissions:
sudo chmod 600 /etc/vault-token
sudo chown root:root /etc/vault-tokenThe python script will request certificates in the default format of the Vault PKI Role. If the role key type is set to 'any' there is no way to specify the certificate key type in the script. It will likely default to the defaults for the Python OpenSSL module (probably RSA2048), but I haven't tested this yet!
You are able to request a certificate for the same domain name more than once on the same host. In this instance, the python script would check for the existance of the CN directory and not request a new certificate. That cert would then be copied to any new destinations that you had specified.
If log_file is set in config.yaml, logs are written there.
MIT License