Skip to content
Merged
52 changes: 5 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,7 @@
# deploy-freenas
# Deploy TLS Certificates to FreeNAS/TrueNAS
This repository contains scripts to automate deployment of a TLS certificate to your FreeNAS (11.1 or newer) or TrueNAS server. Due to a complete overhaul of the API in more recent versions of TrueNAS, this repo contains two different scripts, each with its own README.

deploy-freenas.py is a Python script to deploy TLS certificates to a FreeNAS/TrueNAS (Core) server using the FreeNAS/TrueNAS API. This should ensure that the certificate data is properly stored in the configuration database, and that all appropriate services use this certificate. Its original intent was to be called from a Let's Encrypt client like [acme.sh](https://github.com/Neilpang/acme.sh) after the certificate is issued, so that the entire process of issuance (or renewal) and deployment can be automated. However, it can be used with certificates from any source, whether a different ACME-based certificate authority or otherwise.
* If you're using FreeNAS, or TrueNAS CORE, use `deploy_freenas.py`. [README](README_freenas.md). This will also work with TrueNAS SCALE through 24.10, but as SCALE introduced a websocket API, the other script is recommended.
* If you're using TrueNAS SCALE or Community Edition (as of 25.04), use `deploy_truenas.py`. [README](README_truenas.md)
* I've had no reports of compatibility, pro or con, with any version of TrueNAS Enterprise. I expect the `_freenas` version will work with FreeBSD-based TrueNAS Enterprise installations, while the `_truenas` version will work with Linux-based installations, but I'm afraid you're largely on your own.

Since this script was developed, acme.sh has added a [deployment script](https://github.com/acmesh-official/acme.sh/wiki/deployhooks#25-deploy-the-cert-on-truenas-core-server) which can deploy newly-issued certs to your TrueNAS system, so you may not need this script. However, it isn't clear whether the acme.sh deployment script handles the services covered by this script (S3, FTP, WebDAV, Apps for SCALE).

# Installation
This script can run on any machine running Python 3 that has network access to your FreeNAS/TrueNAS server, but in most cases it's best to run it directly on the FreeNAS/TrueNAS box. Change to a convenient directory and run `git clone https://github.com/danb35/deploy-freenas`.

If you're not running this script on your Free/TrueNAS server itself, you'll need to make sure that the Python `requests` module is available (it's there by default in Free/TrueNAS). How you'll do that will depend on the OS you're using wherever you're running the script.

# Usage

The relevant configuration takes place in the `deploy_config` file. You can create this file either by copying `deploy_config.example` from this repository, or directly using your preferred text editor. Its format is as follows:

```
[deploy]
password = YourReallySecureRootPassword
cert_fqdn = foo.bar.baz
connect_host = baz.bar.foo
verify = false
privkey_path = /some/other/path
fullchain_path = /some/other/other/path
protocol = https://
port = 443
ui_certificate_enabled = false
s3_enabled = false
ftp_enabled = false
webdav_enabled = false
apps_enabled = false
apps_only_matching_san = false
cert_base_name = letsencrypt
```

Everything but `password` (or `api_key`) is optional, and the defaults are documented in `deploy_config.example`.

On TrueNAS (Core) 12.0 and up you should use API key authentication instead of password authentication.
[Generate a new API token in the UI](https://www.truenas.com/docs/hub/additional-topics/api/#creating-api-keys) first, then add it as `api_key` to the config, which replaces the `password` field:
```
api_key = 1-DXcZ19sZoZFdGATIidJ8vMP6dxk3nHWz3XX876oxS7FospAGMQjkOft0h4itJDSP
```

Once you've prepared `deploy_config`, you can run `deploy_freenas.py`. The intended use is that it would be called by your ACME client after issuing a certificate. With acme.sh, for example, you'd add `--reloadcmd "/path/to/deploy_freenas.py"` to your command.

There is an optional paramter, `-c` or `--config`, that lets you specify the path to your configuration file. By default the script will try to use `deploy_config` in the script working directoy:

```
/path/to/deploy_freenas.py --config /somewhere/else/deploy_config
```
49 changes: 49 additions & 0 deletions README_freenas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# deploy-freenas

deploy_freenas.py is a Python script to deploy TLS certificates to a FreeNAS/TrueNAS (Core) server using the FreeNAS/TrueNAS API. This should ensure that the certificate data is properly stored in the configuration database, and that all appropriate services use this certificate. Its original intent was to be called from a Let's Encrypt client like [acme.sh](https://github.com/Neilpang/acme.sh) after the certificate is issued, so that the entire process of issuance (or renewal) and deployment can be automated. However, it can be used with certificates from any source, whether a different ACME-based certificate authority or otherwise.

Since this script was developed, acme.sh has added a [deployment script](https://github.com/acmesh-official/acme.sh/wiki/deployhooks#25-deploy-the-cert-on-truenas-core-server) which can deploy newly-issued certs to your TrueNAS system, so you may not need this script. However, it isn't clear whether the acme.sh deployment script handles the services covered by this script (S3, FTP, WebDAV, Apps for SCALE).

# Installation
This script can run on any machine running Python 3 that has network access to your FreeNAS/TrueNAS server, but in most cases it's best to run it directly on the FreeNAS/TrueNAS box. Change to a convenient directory and run `git clone https://github.com/danb35/deploy-freenas`.

If you're not running this script on your Free/TrueNAS server itself, you'll need to make sure that the Python `requests` module is available (it's there by default in Free/TrueNAS). How you'll do that will depend on the OS you're using wherever you're running the script.

# Usage

The relevant configuration takes place in the `deploy_config` file. You can create this file either by copying `deploy_config_freenas.example` from this repository, or directly using your preferred text editor. Its format is as follows:

```
[deploy]
password = YourReallySecureRootPassword
cert_fqdn = foo.bar.baz
connect_host = baz.bar.foo
verify = false
privkey_path = /some/other/path
fullchain_path = /some/other/other/path
protocol = https://
port = 443
ui_certificate_enabled = false
s3_enabled = false
ftp_enabled = false
webdav_enabled = false
apps_enabled = false
apps_only_matching_san = false
cert_base_name = letsencrypt
```

Everything but `password` (or `api_key`) is optional, and the defaults are documented in `deploy_config.example`.

On TrueNAS (Core) 12.0 and up you should use API key authentication instead of password authentication.
[Generate a new API token in the UI](https://www.truenas.com/docs/hub/additional-topics/api/#creating-api-keys) first, then add it as `api_key` to the config, which replaces the `password` field:
```
api_key = 1-DXcZ19sZoZFdGATIidJ8vMP6dxk3nHWz3XX876oxS7FospAGMQjkOft0h4itJDSP
```

Once you've prepared `deploy_config`, you can run `deploy_freenas.py`. The intended use is that it would be called by your ACME client after issuing a certificate. With acme.sh, for example, you'd add `--reloadcmd "/path/to/deploy_freenas.py"` to your command.

There is an optional paramter, `-c` or `--config`, that lets you specify the path to your configuration file. By default the script will try to use `deploy_config` in the script working directoy:

```
/path/to/deploy_freenas.py --config /somewhere/else/deploy_config
```
69 changes: 69 additions & 0 deletions README_truenas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# deploy-freenas

deploy_truenas.py is a Python script to deploy TLS certificates to a TrueNAS SCALE/Community Edition server using the TrueNAS Websocket API. This should ensure that the certificate data is properly stored in the configuration database, and that all appropriate services use this certificate. Its original intent was to be called from an ACME client like [acme.sh](https://github.com/acmesh-official/acme.sh) after the certificate is issued, so that the entire process of issuance (or renewal) and deployment can be automated. However, it can be used with certificates from any source, whether a different ACME-based certificate authority or otherwise.

Since this script was developed, acme.sh has added a [deployment script](https://github.com/acmesh-official/acme.sh/wiki/deployhooks#25-deploy-the-cert-on-truenas-core-server) which can deploy newly-issued certs to your TrueNAS system, so you may not need this script. However, it isn't clear whether the acme.sh deployment script handles the services covered by this script (S3, FTP, WebDAV, Apps for SCALE). `acme.sh` also has a separate deployment script for the websocket API, but again, its capabilities compared to this one are unknown.

# WORK IN PROGRESS
This version of this script is a work in progress, and has had minimal testing.

# Known issues
Connections to the Websocket API will fail if you have a HTTP -> HTTPS redirect enabled, either in TrueNAS itself or in some other system (e.g., Traefik) in front of TrueNAS. This results from an [issue](https://github.com/truenas/api_client/issues/13) in the upstream API client. If your NAS has a trusted and valid certificate, or you've set `verify_ssl = false` in `deploy_config`, you may be able to avoid this issue by setting `protocol = wss` in `deploy_config`.

# Status
* TrueNAS 25.04-RC1 - Works locally (running on the TrueNAS host) and remotely (so long as all dependencies are installed), but see notes below.
* TrueNAS SCALE 24.10 - Works locally and remotely.
* TrueNAS SCALE 24.04 - Works remotely only--the TrueNAS API client isn't installed in this version of TrueNAS. Will not update certificates for apps on this or earlier versions of TrueNAS SCALE.
* TrueNAS SCALE 23.10 - Same as 24.04.

## Notes for 25.04
Security measures in TrueNAS SCALE 25.04 require that the API keys be passed over a secure channel. In order to use this script with 25.04, you must set `protocol = wss` in `deploy_config`. And then, either:
* You must have already deployed a trusted cert to your NAS
* That cert must not be expired
* You must have configured the UI to use that cert
* The address you're using to connect to the NAS (`connect_host` in `deploy_config`) must be named in that cert

Or set `verify_ssl = false` in `deploy_config`. This will disable validation of the TLS certificate, and should not be used on a routine basis.

# Installation
This script can run on any machine running Python 3 that has network access to your TrueNAS server, but in most cases it's best to run it directly on the TrueNAS box. Change to a convenient directory and run `git clone https://github.com/danb35/deploy-freenas`. If you're installing this on your TrueNAS server, it cannot be in your home directory; place it in a convenient place on a storage pool instead.

## Running the script somewhere else
As noted above, this script doesn't need to run on your NAS; it can run on any system running Python 3 that can reach your NAS over the network, but it does have a couple of dependencies. Assuming a bare-bones Debian 12 system, start with `apt install curl wget nano git python3 python3-setuptools python3-openssl`.

You'll next need to install the [TrueNAS API client](https://github.com/truenas/api_client). To do this, change to a convenient directory and run `git clone https://github.com/truenas/api_client`. Change into the `api_client` directory and run `python3 setup.py install`.

Then clone this repository as described above. Your system should be prepared to run the script.

# Usage

The relevant configuration takes place in the `deploy_config` file. You can create this file either by copying `deploy_config_truenas.example` from this repository, or directly using your preferred text editor. Its format is as follows:

```
[deploy]
api_key = YourReallySecureAPIKey
privkey_path = /some/other/path
fullchain_path = /some/other/other/path
connect_host = baz.bar.foo
verify_ssl = false
ui_certificate_enabled = true
ftp_enabled = false
apps_enabled = false
cert_base_name = letsencrypt
protocol = ws
```

Everything but `api_key` and paths to the cert and key are optional, and the defaults are documented in `deploy_config.example`.

An API key is required for authentication. [Generate a new API token in the UI](https://www.truenas.com/docs/hub/additional-topics/api/#creating-api-keys) first, then add it as `api_key` to the config:
```
api_key = 1-DXcZ19sZoZFdGATIidJ8vMP6dxk3nHWz3XX876oxS7FospAGMQjkOft0h4itJDSP
```

Once you've prepared `deploy_config`, you can run `deploy_truenas.py`. The intended use is that it would be called by your ACME client after issuing a certificate. With acme.sh, for example, you'd add `--reloadcmd "/path/to/deploy_truenas.py"` to your command.

There is an optional paramter, `-c` or `--config`, that lets you specify the path to your configuration file. By default the script will try to use `deploy_config` in the script working directoy:

```
/path/to/deploy_truenas.py --config /somewhere/else/deploy_config
```
2 changes: 1 addition & 1 deletion deploy_config.example → deploy_config_freenas.example
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,4 @@ password = YourSuperSecurePassword#@#$*

# Certificates will be given a name with a timestamp, by default it will be
# letsencrypt-yyyy-mm-dd-hhmmss. You can change the first part if you like.
# cert_base_name = something_else
# cert_base_name = something_else
50 changes: 50 additions & 0 deletions deploy_config_truenas.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Configuration file for deploy_freenas.py

[deploy]
# API key for your TrueNAS installation, with necessary permissions
api_key = YourNewlyGeneratedAPIKey#@#$*

# privkey_path is the path to the certificate private key on your system.
# privkey_path = /some/other/path

# fullchain_path is the path to the full chain (leaf cert + intermediate certs)
# on your system.
# fullchain_path = /some/other/other/path

# Everything below here is optional

# connect_host specifies the hostname the script should attempt to connect to, to deploy the cert.
# Default is localhost (assuming the script is running on your FreeNAS box)
# connect_host = baz.bar.foo

# protocol specifies the protocol used to connect to the API. Default is ws.
# Set to wss for TrueNAS 25.04 and later
# protocol = wss

# set ui_certificate_enabled to false if you want to skip using the new cerificate for the UI. Default is true.
# ui_certificate_enabled = false

# set ftp_enabled to true if you have the FTP service enabled on your FreeNAS. Default is false.
# ftp_enabled = true

# set apps_enabled to true if you want to update your TrueNAS SCALE chart applications to use the new certificate. Default is false.
# If this is enabled, any catalog app that's already set to use a certificate will be updated to use the new one. Custom apps,
# or apps without a certificate configured, will not be adjusted.
# apps_enabled = true

# Certificates will be given a name with a timestamp, by default it will be
# letsencrypt-yyyy-mm-dd-hhmmss. You can change the first part if you like.
# cert_base_name = something_else

# Set delete_old_certs to true to delete certs from the NAS whose name begins with cert_base_name
# other than the cert just imported by the script. Default is false.
# delete_old_certs = true

# log_level defines how verbose the script will be. Valid values are debug, info,
# warning, error, and critical. Default is info.
# log_level = debug

# If verify_ssl is false and protocol is set to wss, connections to the API will not validate the certificate.
# This means that connections will be permitted using expired and/or untrusted certificates.
# Default is true.
# verify_ssl = false
2 changes: 1 addition & 1 deletion deploy_freenas.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -357,4 +357,4 @@
sys.exit(1)
except requests.exceptions.ConnectionError:
print ("Reloading WebUI successful")
print ("deploy_freenas.py executed successfully")
print ("deploy_freenas.py executed successfully")
Loading