soyMAIL 2.1.0 requires JavaScript
soyMAIL @ wasd.vsm.com.au
       info-WASD Mailing List 2023 

Mon 03:49:57 Message "2023 / 0035" opened.  MIME.  UTF-8.  12 kbytes.    JavaScript

Subject:[Info-WASD] wuCME versatility0035 / 0000
From:Mark.Daniel@wasd.vsm.com.au
Reply-to:info-wasd@vsm.com.au
Date:Thu, 23 Feb 2023 16:02:34 +1030  [23-FEB-2023 16:02]
To:info-wasd@vsm.com.au

TL;DR wuCME is WASD's Let's Encrypt certificate management environment.
      It manages server certificates for a single system or cluster,
      automatically renewing and reloading certificates -- AND MORE.

The Let's Encrypt (LE) project

  https://letsencrypt.org
  https://en.wikipedia.org/wiki/Let%27s_Encrypt
  https://wasd.vsm.com.au/wasd_root/src/wucme/readmore.html

has simplified browser-trusted server certification for the SOHO cohort.

Browsers, increasing the number of hoops to be leapt through before accepting
anything self-signed -- if at all -- were proving an increasing PITA.

Of course it's not just about Internet-facing hosts.  "Internal" systems
experience the same untrusted certificate issues.  It is also possible to
have an internal system generating its own LE certs -- provided the host name
is externally resolvable.

My X86 VM is for local use only.  However, the host name is visible to the
wider Internet (via DynDNS, or Dyn as they prefer to be known these days) but
resolves to a single (not even fixed) address provided by my ISP.  The setup
is pretty standard.

                                           :
                                           |    +--------+
                                           +~~~>|  WASD  |  proxy
  +--------+           +--------+          |    +--------+  192.168.1.3
  |   LE   |<~~~WAN~~~>| router |<~~~LAN~~~+
  +--------+           +--------+          |    +--------+
                                           +~~~>|  WASD  |  wuCME
                                           |    +--------+  192.168.1.86
                                           :

In addition to other (more general purpose) services, the 192.168.1.3 server
has the following proxy capable service configured.

# WASD_CONFIG_SERVICE
[[https://x86vms.domain.net:80]]
[ServiceBind]  192.168.1.3
[ServiceProxy]  enabled

Remember, the SOHO network has a single IP address with multiple host names.
So the wuCME app on the internal network reaches renewal time and makes a
direct request of LE for a renewed certificate.  LE authenticates the request
with a challenge which connects to the certificate host name, resolving to
the ISP IP address, and ends up on port 80 of the 192.168.1.3 WASD server
(via router port forwarding rules).

|00:20:08.67 NET      2198 000001 CONNECT    MULTIHOME match for 192.168.1.3,80 arrived at 192.168.1.3,80|

The LE challenge request header contains

|00:20:08.80 REQUEST  2776 000002 REQ-HEADER HEADER 199 bytes|
GET /.well-known/acme-challenge/yIIZJXXiCJ0aynim9rn7HGRE_uBY-CgE.QH3pRwq2ZSCeEYlrN-0MNKHxB8zeq-uB-mb5nTt7SLlHfoD5Ox_Qk HTTP/1.1
Host: x86vms.domain.net
8< snip 8<

and so while connected to 168.192.1.3, it processes the virtual service 

|00:20:08.67 SERVICE  1749 000002 CONNECT    VIRTUAL x86vms.domain.net:80|

The following mapping rules redirect the /.well-known/acme-challenge/ to the
server at 192.168.1.86, then mapping any host not on the LAN to 418 ("I'm a
teapot").

|# WASD_CONFIG_MAP
|[[x86vms.domain.net:80]]
|redirect /.well-known/acme-challenge/* \
|         /http://192.168.1.86/cgi-bin/wucme/.well-known/acme-challenge/*
|pass http://192.168.1.86/cgi-bin/wucme/.well-known/acme-challenge/*
|if (remote-addr:192.168.*)
|   redirect /* /http://192.168.1.86/*
|   pass http://192.168.1.86/*
|endif
|[[x86vms.domain.net:*]]
|pass * "418"

Really quite simple.  Here is the complete WATCH report from which the above
snippets were extracted.

|Time_______|Module__|Line|Item__|Category__|Event...|
|00:20:08.67 NET      2198 000001 CONNECT    MULTIHOME match for 192.168.1.3,80 arrived at 192.168.1.3,80|
|00:20:08.67 NET      2203 000001 CONNECT    ACCEPTED acme-v02.api.letsencrypt.org,47422 on http://klaatu.lan,80 (192.168.1.3) BG11250:|
|++++++++++++++++++++++++++++++++++++++++++++
|00:20:08.67 SERVICE  1749 000002 CONNECT    VIRTUAL x86vms.domain.net:80|
|00:20:08.67 REQUEST  4419 000002 REQUEST    GET /.well-known/acme-challenge/yiizjxxicj0aynim9rn7hgre_uby-cge.qh3prwq2zsceeylrn-0mnkhxb8zeq-ub-mb5ntt7sllhfod5ox_qk|
|00:20:08.67 REDIRECT 0184 000002 REQUEST    REDIRECT /http://192.168.1.86/cgi-bin/wucme/.well-known/acme-challenge/yiizjxxicj0aynim9rn7hgre_uby-cge.qh3prwq2zsceeylrn-0mnkhxb8zeq-ub-mb5ntt7sllhfod5ox_qk|
|00:20:08.67 REQUEST  4419 000002 REQUEST    GET http://192.168.1.86/cgi-bin/wucme/.well-known/acme-challenge/yiizjxxicj0aynim9rn7hgre_uby-cge.qh3prwq2zsceeylrn-0mnkhxb8zeq-ub-mb5ntt7sllhfod5ox_qk|
|00:20:08.67 PROXY    0750 000002 PROXY      GET 192.168.1.86:80/cgi-bin/wucme/.well-known/acme-challenge/yiizjxxicj0aynim9rn7hgre_uby-cge.qh3prwq2zsceeylrn-0mnkhxb8zeq-ub-mb5ntt7sllhfod5ox_qk|
|00:20:08.67 PROXYNET 0432 000002 PROXY      CONNECT 192.168.1.86,80 as 0|
|00:20:08.67 PROXYNET 0823 000002 PROXY      CONNECTED 192.168.1.86,80 as 0 BG11259:|
|00:20:08.94 REQUEST  1436 000002 REQUEST    STATUS 200 (OK) rx:195 tx:423 bytes 267ms 2,318 B/s|
|--------------------------------------------

And this is the wuCME log containing the complete transaction.

|2023-02-13 00:20:00.86: certificate management
|2023-02-13 00:20:00.93: WASD_LOCAL:WUCME_C_X86VMS_DOMAIN_NET.PEM
|2023-02-13 00:20:01.32: x86vms.domain.net !before: Dec 13 12:52:12 2022 GMT !after: Mar 13 12:52:11 2023 GMT expires: 28 renew: -1
|2023-02-13 00:20:01.37: (5) dka100:[wasd_root.axp-bin.][000000]wucme.exe --uacme --verbose issue x86vms.domain.net
|2023-02-13 00:20:01.38: version WUCME AXP-1.1.9 (1.1.2) (OpenSSL 1.1.1s  1 Nov 2022) starting
|2023-02-13 00:20:01.40: loading key from /wasd_local/wucme_k_account.pem
|2023-02-13 00:20:01.42: loading key from /wasd_local/wucme_k_X86VMS_DOMAIN_net.pem
|2023-02-13 00:20:01.45: checking existence and expiration of /wasd_local/wucme_c_X86VMS_DOMAIN_net.pem
|2023-02-13 00:20:01.47: /wasd_local/wucme_c_X86VMS_DOMAIN_net.pem expires in 28 days
|2023-02-13 00:20:01.49: /wasd_local/wucme_c_X86VMS_DOMAIN_net.pem is due for renewal
|2023-02-13 00:20:01.50: fetching directory at https://acme-v02.api.letsencrypt.org/directory
|2023-02-13 00:20:03.36: retrieving account at https://acme-v02.api.letsencrypt.org/acme/new-acct
|2023-02-13 00:20:05.11: account location: https://acme-v02.api.letsencrypt.org/acme/acct/40234161
|2023-02-13 00:20:05.13: creating new order for x86vms.domain.net at https://acme-v02.api.letsencrypt.org/acme/new-order
|2023-02-13 00:20:06.82: order URL: https://acme-v02.api.letsencrypt.org/acme/order/40234161/164373540256
|2023-02-13 00:20:06.84: retrieving authorization at https://acme-v02.api.letsencrypt.org/acme/authz-v3/202892153246
|2023-02-13 00:20:08.51: challenge=http-01 ident=x86vms.domain.net token=yIIZJXXiC7HGQH3pRwq2ZSRJ0aynim9rnE_uBY-CgE key_auth=yIIZJXXiCJ0aynim9rn7HGRE_uBY-CgE.QH3pRwq2ZSCeEYlrN-0MNKHxB8zeq-uB-mb5nTt7SLlHfoD5Ox_Qk
|2023-02-13 00:20:09.96: starting challenge at https://acme-v02.api.letsencrypt.org/acme/chall-v3/202892153246/gAI5TQ
|2023-02-13 00:20:11.62: polling challenge status at https://acme-v02.api.letsencrypt.org/acme/chall-v3/202892153246/gAI5TQ
|2023-02-13 00:20:18.32: polling challenge status at https://acme-v02.api.letsencrypt.org/acme/chall-v3/202892153246/gAI5TQ
|2023-02-13 00:20:20.01: polling order status at https://acme-v02.api.letsencrypt.org/acme/order/40234161/164373540256
|2023-02-13 00:20:21.69: generating certificate request
|2023-02-13 00:20:21.84: finalizing order at https://acme-v02.api.letsencrypt.org/acme/finalize/40234161/164373540256
|2023-02-13 00:20:23.70: polling order status at https://acme-v02.api.letsencrypt.org/acme/order/40234161/164373540256
|2023-02-13 00:20:25.32: retrieving certificate at https://acme-v02.api.letsencrypt.org/acme/cert/034aa719dc53af387fb2f535547cb20bdd31
|2023-02-13 00:20:27.00: saving certificate to /wasd_local/wucme_c_X86VMS_DOMAIN_net.pem_tmp
|2023-02-13 00:20:27.06: reading private key /wasd_local/wucme_k_X86VMS_DOMAIN_net.pem
|2023-02-13 00:20:27.15: backed up /wasd_local/wucme_c_X86VMS_DOMAIN_net.pem as /wasd_local/wucme_c_X86VMS_DOMAIN_net.pem_2023021300202700
|2023-02-13 00:20:27.16: renaming /wasd_local/wucme_c_X86VMS_DOMAIN_net.pem_tmp to /wasd_local/wucme_c_X86VMS_DOMAIN_net.pem
|2023-02-13 00:20:28.37: wuCME successful x86vms.domain.net renewal
|WASD_LOCAL:WUCME_C_X86VMS_DOMAIN_NET.PEM
|x86vms.domain.net
|2023-02-13 00:20:28.60: load succeeded using internal commands
|2023-02-13 00:20:28.62: 193 files, 1 certs, 1 renewed, 0 failed

VIA PROXY
~~~~~~~~~
And of course it would still be possible for a system blocked from making any
direct connection to the Internet and LE, to proxy out via WASD (or other)
and use WASD (or other) to redirect the challenge to the wuCME system.

  +--------+           +--------+            +--------+            +--------+
  |   LE   |<~~~WAN~~~>| router |<~~~LANx~~~>|  WASD  |<~~~LANy~~~>|  WASD  |
  +--------+           +--------+            +--------+            +--------|
                                               proxy                 wuCME

This configuration is left as an exercise for the reader :-)

AND MORE
~~~~~~~~
While wuCME is dexterous enough for single systems and clusters of systems,
it can actually perform more complex feats with some simple sleight-of-hand.
When a certificate is successfully updated it is automatically reloaded into
the running server(s).  The server process log shows this happening

|%HTTPD-I-CONTROL, 13-FEB-2023 00:20:28, 00000338 X86VMS HTTP$NOBODY "wuCME-load", 'ssl=cert=load'
|%HTTPD-I-SSL, klaatu.lan:443
|-SSL-I-CERT, wasd_root:[local]wucme_c_x86vms_domain_net.pem
|-SSL-W-STRICT, HSTS transport security disabled
8< snip 8<

A poorly documented (but working) capability extends this reload to other
activities, even privileged ones.  A multi-valued logical name provides for a
first LOAD activity, followed by another, and potentially another...  In this
example two.

|$ show log wucme_load /table=lnm$system
|
|(LNM$SYSTEM_TABLE)
|
|  "WUCME_LOAD" = "+"
|       = "@pmdf_root:[table]wasd_cert_to_pmdf.com"
|
|(LNM$SYSCLUSTER_TABLE)

The first value indicates to perform a standard cert load.

The second value, to execute the specified DCL procedure, which can be
reasonably capable. 

|$! WASD_CERT_TO_PMDF.COM
|$! see logical name WUCME_LOAD
|$ SET PROCESS /PRIV=(SYSPRV,CMKRNL)
|$ IF F$MODE() .EQS. "BATCH"
|$ THEN
|$    COPY WASD_ROOT:[LOCAL]WUCME_C_THE_HOST_NAME.PEM -
|          PMDF_ROOT:[TABLE]MAIL-PUB.PEM;0 /PROTECTION=W:R
|$    COPY WASD_ROOT:[LOCAL]WUCME_K_THE_HOST_NAME.PEM -
|          PMDF_ROOT:[TABLE]MAIL-PRIV.PEM;0 /PROTECTION=W
|$    PMDF RESTART DISPATCH
|$    SUBMIT/USER=SYSTEM SYS$STARTUP:PMAS_STARTUP.COM
|$ ELSE
|$    PROCEDURE = F$ENVIRONMENT("PROCEDURE")
|$    SUBMIT/USER=SYSTEM 'PROCEDURE'
|$ ENDIF

This paradigm could be extended to COPY (whatever that entails) the license
negotiated and processed by the (intermediate) system to the end-user system.
The applications are manifold.

* Further detail in [SRC.WUCME]WUCERTMAN.C CertManLoad().
  Can require INSTALL with extended privileges.  YMMV!

** NOTE: some of the actual data in these examples are redacted, some fudged,
   and some completely made up (for illustrative purposes).

This item is one of a collection at
https://wasd.vsm.com.au/other/#occasional

  ¤¤¤       
  ¤¤¤