Use smallstep Certificate Authoritiy for truenas scale

nestor_78

Dabbler
Joined
Oct 14, 2023
Messages
12
Hi all,

I buildt a tiny Certificate Authority for my homelab (RasperberryPi with smallstep) following this tutorial:

It is an internal ACME server on my local network (ACME is the same protocol used by Let's Encrypt).

Truenas describes how to use Lets Encrypt here:

There is a discussion how to use a smallstep ca with truenas core here:

Has someone experience how to use smallstep ca with truenas scale?

Best regards,
Nestor
 
Last edited:

danb35

Hall of Famer
Joined
Aug 16, 2011
Messages
15,504
I'm no longer using the Smallstep CA for TrueNAS. But if I were, I think I'd abandon the ACME authenticator and instead do this:
  • Get a cert at the CLI using the normal step certificate command, validate with the standard provisioner password.
  • Deploy it to TrueNAS using my deploy-freenas script.
  • Set a cron job every 8-12 hours to call a script in which you'd:
    • Renew the cert using step certificate renew
    • Call deploy-freenas to deploy it to TrueNAS
 

nestor_78

Dabbler
Joined
Oct 14, 2023
Messages
12
I'm no longer using the Smallstep CA for TrueNAS. But if I were, I think I'd abandon the ACME authenticator and instead do this:
  • Get a cert at the CLI using the normal step certificate command, validate with the standard provisioner password.
  • Deploy it to TrueNAS using my deploy-freenas script.
  • Set a cron job every 8-12 hours to call a script in which you'd:
    • Renew the cert using step certificate renew
    • Call deploy-freenas to deploy it to TrueNAS
Thank you, I will study your tutorial at github.

If you dont use smallstep anymore, does that mean that you use Lets encrypt/nginx instead or another local ca?

Best regards,
Nestor
 

danb35

Hall of Famer
Joined
Aug 16, 2011
Messages
15,504
I'm using Let's Encrypt certs for TrueNAS SCALE using its built-in support for Cloudflare DNS authentication.
 

nestor_78

Dabbler
Joined
Oct 14, 2023
Messages
12
I'm no longer using the Smallstep CA for TrueNAS. But if I were, I think I'd abandon the ACME authenticator and instead do this:
  • Get a cert at the CLI using the normal step certificate command, validate with the standard provisioner password.
  • Deploy it to TrueNAS using my deploy-freenas script.
  • Set a cron job every 8-12 hours to call a script in which you'd:
    • Renew the cert using step certificate renew
    • Call deploy-freenas to deploy it to TrueNAS

Thank you!

However I did not manage to get the script running. Can you please help me. I guess I did not understand the config-file correctly
I made the following steps:

1. installed tinyca on a pi
according to

2. installed pi-hole as app under truenas scale
and added the follwoing dns entries for:
tinyca -> tinyca.lan.internal
truenas -truenas.lan internal

3. Installed acme.sh on my truenas server in /home/admin/.acme.sh according to:
with
curl https://get.acme.sh | sh -s email=nestor@na.na

1711125151881.png


I made no further configuration.

4. installed deploy-freenas in truenas asscoding to
with
git clone https://github.com/danb35/deploy-freenas

1711125417974.png


6. copied the content of
root_ca.cert
and
intermediate_ca.crt
which were generated with smallstep on m pi in /mnt/ca/certs
(including lines "--- BEGIN..." and " ---END ...") into a file with filename
fullchain.cer

7. moved fullchain.cer to /home/admin/.acme.sh/tinyca.lan.internal/fullchain.cer in truenas

8. configured deploy_config

# Configuration file for deploy_freenas.py
as follows:

[deploy]
# Choose one of the following authentication methods, "api_key" or "password" (comment out the other one).
# Auth via API keys is highly recommended, but is only available from TrueNAS (Core) 12.0 up.
# You can generate a new API key in the web interface under "Settings" (upper right) > "API Keys".
api_key = xxxxxxxxx api key generated in truenas xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# If you are on FreeNAS 11 or lower, set this to your FreeNAS root password
# password = YourSuperSecurePassword#@#$*

# Everything below here is optional

# cert_fqdn specifies the FQDN used for your certificate. Default is your system hostname
cert_fqdn = truenas.lan.internal

# 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 = tinyca.lan.internal

# verify sets whether the script will attempt to verify the server's certificate with a HTTPS
# connection. Set to true if you're using a HTTPS connection to a remote host. If connect_host
# is set to localhost (or is unset), set to false. Default is false.
# verify = false

# privkey_path is the path to the certificate private key on your system. Default
# assumes you're using acme.sh:
# /root/.acme.sh/cert_fqdn/cert_fqdn.key or /root/.acme.sh/cert_fqdn_ecc/cert_fqdn.key
privkey_path = /home/admin/.acme.sh/truenas.lan.internal_ecc/truenas.lan.internal.key

# fullchain_path is the path to the full chain (leaf cert + intermediate certs)
# on your system. Default assumes you're using acme.sh:
# /root/.acme.sh/cert_fqdn/fullchain.cer or /root/.acme.sh/cert_fqdn_ecc/fullchain.cer
fullchain_path = /home/admin/.acme.sh/tinyca.lan.internal/fullchain.cer

# protocol sets the connection protocol, http or https. Include '://' at the end.
# Default is http
# protocol = https://

# port sets the port to use to connect. Default is 80. If protocol is https,
# this MUST be set to your https port.
# port = 443

# 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 s3_enabled to true if you have the S3 service enabled on your FreeNAS. Default is false.
# s3_enabled = true

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

# set webdav_enabled to true if you have the WEBDAV service enabled on your FreeNAS. Default is false.
# webdav_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.
# apps_enabled = true

# only update TrueNAS SCALE chart applications where the san of the current and the new cert matches. Default is false.
#apps_only_matching_san = 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

9.
Where do I find the truenas.lan.internal.key? Is this identical with the file localhost.key generated with smallstep???

As I have no such file I generated and empty file with touch /home/admin/.acme.sh/truenas.lan.internal_ecc/truenas.lan.internal.key

10. Starting deploy_freenas.py
I get the following error message:

admin@truenas[/opt/deploy-freenas]$ ./deploy_freenas.py
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 169, in _new_conn
conn = connection.create_connection(
File "/usr/lib/python3/dist-packages/urllib3/util/connection.py", line 96, in create_connection
raise err
File "/usr/lib/python3/dist-packages/urllib3/util/connection.py", line 86, in create_connection
sock.connect(sa)
ConnectionRefusedError: [Errno 111] Connection refused

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 699, in urlopen
httplib_response = self._make_request(
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 394, in _make_request
conn.request(method, url, **httplib_request_kw)
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 234, in request
super(HTTPConnection, self).request(method, url, body=body, headers=headers)
File "/usr/lib/python3.9/http/client.py", line 1255, in request
self._send_request(method, url, body, headers, encode_chunked)
File "/usr/lib/python3.9/http/client.py", line 1301, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "/usr/lib/python3.9/http/client.py", line 1250, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "/usr/lib/python3.9/http/client.py", line 1010, in _send_output
self.send(msg)
File "/usr/lib/python3.9/http/client.py", line 950, in send
self.connect()
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 200, in connect
conn = self._new_conn()
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 181, in _new_conn
raise NewConnectionError(
urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPConnection object at 0x7f9006f5daf0>: Failed to establish a new connection: [Errno 111] Connection refused

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/requests/adapters.py", line 439, in send
resp = conn.urlopen(
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 755, in urlopen
retries = retries.increment(
File "/usr/lib/python3/dist-packages/urllib3/util/retry.py", line 574, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='tinyca.lan.internal', port=80): Max retries exceeded with url: /api/v2.0/certificate/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f9006f5daf0>: Failed to establish a new connection: [Errno 111] Connection refused'))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/opt/deploy-freenas/./deploy_freenas.py", line 97, in <module>
r = session.post(
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 590, in post
return self.request('POST', url, data=data, json=json, **kwargs)
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 542, in request
resp = self.send(prep, **send_kwargs)
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 655, in send
r = adapter.send(request, **kwargs)
File "/usr/lib/python3/dist-packages/requests/adapters.py", line 516, in send
raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='tinyca.lan.internal', port=80): Max retries exceeded with url: /api/v2.0/certificate/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f9006f5daf0>: Failed to establish a new connection: [Errno 111] Connection refused'))
admin@truenas[/opt/deploy-freenas]$



Best regards,
Nestor
 

Attachments

  • 1711129607433.png
    1711129607433.png
    27.9 KB · Views: 18

danb35

Hall of Famer
Joined
Aug 16, 2011
Messages
15,504
copied the content of
root_ca.cert
and
intermediate_ca.crt
which were generated with smallstep on m pi in /mnt/ca/certs
(including lines "--- BEGIN..." and " ---END ...") into a file with filename
fullchain.cer
This is incorrect. If you're using acme.sh to obtain the cert from your local CA, it will create fullchain.cer for you, and that file will contain the cert for your NAS as well as the intermediate signing certificate.
connect_host = tinyca.lan.internal
No, this should point to your NAS--if you're running the script on your NAS, the default of localhost is appropriate. If you're running it on some other host, it should be truenas.lan.internal.
Where do I find the truenas.lan.internal.key? Is this identical with the file localhost.key generated with smallstep???
acme.sh will generate that private key when you use it to get the cert from your local CA.
 

danb35

Hall of Famer
Joined
Aug 16, 2011
Messages
15,504
But I'd like to emphasize what I suggested above:
But if I were, I think I'd abandon the ACME authenticator
The step CLI utility is a standalone binary that doesn't have any system dependencies, so you can safely download it and put it somewhere on your NAS. Then:
  • /path/to/step ca bootstrap --ca-url tinyca.lan.internal --fingerprint (your fingerprint)
  • /path/to/step certificate create truenas.lan.internal truenas.crt truenas.key
  • Choose the default authenticator and enter the provisioner password
  • Edit the deploy-config file to point to the newly-created truenas.crt and truenas.key
  • Run deploy_freenas.py, which should successfully deploy the cert
  • Now you'll need to set up renewal. Create a script that would look like this:
  • Code:
    #!/bin/bash
    /path/to/step ca renew --force /path/to/truenas.crt /path/to/truenas.key
    /path/to/deploy_freenas.py
    
  • The step ca renew command will renew the cert as long as it's still valid (i.e., not expired), so no further authentication is required
  • Then set up a cron task to run that script every 8-12 hours

The ACME authenticator, and acme.sh to interface with it, are unnecessary complications in this environment.
 

Constantin

Vampire Pig
Joined
May 19, 2017
Messages
1,829
I gave up on the small step CA. It’s more trouble than it is worth now that cloud flare offers free 90 day CAs as long as you own a domain. I have no idea what kept breaking, but between piOS, small step, whatever, the thing was more down than up and the guide I looked at the last time was hopelessly out of date WRT the current version of small step. Bottom line, I don’t enjoy trouble-shooting balky piOS installs, wonky small step issues, etc. so I use cloud flare instead.
 

danb35

Hall of Famer
Joined
Aug 16, 2011
Messages
15,504
cloud flare offers free 90 day CAs as long as you own a domain.
I think you're confused here; it's Let's Encrypt (and now a few others) who offer free 90-day certificates, and have been doing so for the past eight years or more. Cloudflare can be helpful in getting those certs (particularly if you're wanting to use DNS validation), but they don't issue the certs.

But I'm surprised you had a bad experience with the Smallstep CA; I've found mine to be very reliable. Occasionally (a few times a year, maybe) it needs a reboot, but it's just been sitting there issuing certs like nobody's business. And you still can't get a cert for an IP address from Let's Encrypt.
 

Constantin

Vampire Pig
Joined
May 19, 2017
Messages
1,829
Apologies, you are correct re: cloudflare. I found assigning a web site to cloudflare for issuing certificates ultimately a lot easier than maintaining my small step CA. Part of the issue was likely that I had raspberry pi OS auto-update, which likely breaks stuff.

Another weird issue I have run into repeatedly with Pis is that their password file somehow gets corrupted. Known-good passwords cease working, a delp, etc from the command line fixes the issue. But it’s super annoying and a repeated issue here.

For me, your script combined with a FQDN works great and I’m super grateful. I have yet to secure everything here (namely my new printer will pose a significant challenge) but I’m getting there. Some assets I will also eschew protecting since I consider them compromised from the get-go (ie IP cameras which simply cannot communicate with the internet).

I wish core could update its certificate with cloudflare. I presume your script could work in Scale if I ever made the jump?
 

danb35

Hall of Famer
Joined
Aug 16, 2011
Messages
15,504
I wish core could update its certificate with cloudflare.
I think that will be possible in 13.3. Not 100%, but it's sounding like it.
I presume your script could work in Scale if I ever made the jump?
AFAIK it works with both. Though SCALE does already support Cloudflare DNS authentication. And Cert Manager/Cluster Issuer support many more DNS hosts.
 

polaolla

Cadet
Joined
Mar 27, 2024
Messages
4
Great idea!
Hi all,

I buildt a tiny Certificate Authority for my homelab (RasperberryPi with smallstep) following this tutorial:
Got smallstep running. However, how do you get the root certificate of the ca into the trust center of truenas?

Can I use the gui of truenas? Is smallstep an internal or external ca? Or do I have to copy the root certificate to a directory of truenas manually?
 

danb35

Hall of Famer
Joined
Aug 16, 2011
Messages
15,504
Is smallstep an internal or external ca?
Internal and External are relative to the NAS, so if the CA is anything other than the NAS itself, it's an external CA. But why do you want to? Why do you care if your NAS trusts that cert?
 

polaolla

Cadet
Joined
Mar 27, 2024
Messages
4
I thought i have to in order to get certificates from the smallstep ca. But reading your post above twice it seems that the step cli utility does the job with out a root certificate. I will try it.
 

polaolla

Cadet
Joined
Mar 27, 2024
Messages
4
I thought i have to in order to get certificates from the smallstep ca. But reading your post above twice it seems that the step cli utility does the job with out a root certificate. I will try it.
There is no version for truenas. So i use the version for freebsd right?
 

polaolla

Cadet
Joined
Mar 27, 2024
Messages
4
Ok got it truenas core is freebsd and truenas scale is debian. Got the right step.

First command
  • /path/to/step ca bootstrap --ca-url …
Was a sucess: root.crt was copied to .step/certs/root_ca.crt

But next command
  • /path/to/step certificate create ….
Gave error:
—profile leaf requires the —ca flag
 
Top