Certificates
X509 certificates for TLS are managed by the Traefik instance running in the local node. For more details see Traefik in the core documentation.
Web applications
Web applications should not care about the TLS certificate, as the Traefik HTTP proxy listens on TCP port 443 for HTTPS requests. HTTP backends must be configured only for clear text HTTP connections.
If the module wants to set up an host-name-based HTTP route, it is possible to instruct Traefik to obtain a TLS certificate for it in a unique action.
agent.tasks.run(
agent_id=agent.resolve_agent_id('traefik@node'), # e.g. module/traefik1
action='set-route',
data={
'instance': os.environ['MODULE_ID'],
'url': f'http://127.0.0.1:{os.environ["TCP_PORT"]}',
'host': host_fqdn,
'lets_encrypt': True, # request cetificate for host_fqdn
'http2https': True, # redirect http:// URL scheme to https://
},
)
Note that instance
must be a unique route identifier. If the module uses
multiple HTTP routes, add a prefix to MODULE_ID
to distinguish them.
Other applications
Applications that need .pem
, .key
, .crt
and similar files for their
configuration can obtain the certificate ansynchronously:
-
issue the certificate request
-
handle the
certificate-updated
event
For instance, to issue an asynchronous Let’s Encrypt certificate request
for SERVICE_FQDN
run:
agent.tasks.run_nowait( # _nowait runs in background
agent_id=agent.resolve_agent_id('traefik@node'), # e.g. module/traefik1
action='set-certificate',
data={
"fqdn": os.environ["SERVICE_FQDN"],
"sync": True, # For the UI task progress
},
parent='', # Run as a root task
extra={
'title': 'set-certificate',
'isNotificationHidden': False, # Show the task progress in the UI
},
)
Then to handle the event, create an executable script under
$AGENT_INSTALL_DIR/events/certificate-updated
event = json.load(sys.stdin)
if str(event['node']) != os.environ['NODE_ID']:
sys.exit(0) # ignore events from other cluster nodes
if event["domain"] != os.environ["SERVICE_FQDN"]:
sys.exit(0) # nothing to do for certificates of other services
agent.run_helper('systemctl', '--user', 'reload', 'myservice', check=True)
The handler script reloads myservice
when the certificate of the service
is obtained, renewed, or changed by other means.
While the Let’s Encrypt certificate request is pending the service could
be temporarily started with a self-signed certificate, for instance by
using the openssl
command. Generating such certificate is out of the
scope of this tutorial.
In any case, before starting the service, the module can retrieve the
certificate from Redis. Certificates are saved in a Redis HASH key like
module/traefik1/certificates/www.example.org
. See Redis DB
reference for details.
For example
mtraefik=$(redis-exec GET "node/${NODE_ID}/default_instance/traefik")
redis-exec HGET "module/${mtraefik}/certificate/${SERVICE_FQDN}" key | base64 -d > server.key
redis-exec HGET "module/${mtraefik}/certificate/${SERVICE_FQDN}" cert | base64 -d > server.crt