#!/usr/bin/env sh # install a certificate on a Windows host over OpenSSH and bind it to the Remote # Desktop listener (RDP-Tcp). # # One ssh invocation does the whole job: # * the PFX is built locally, base64'd, and embedded as a string literal # inside a generated PowerShell script; # * the script is piped to `powershell.exe -Command -` over ssh. No scp, # no temp files on the Windows host. # # First run: # export DEPLOY_WIN_RDP_HOST=winserver.example.com # acme.sh --deploy -d winserver.example.com --deploy-hook windows_rdp # # Available variables: # DEPLOY_WIN_RDP_HOST required SSH host # DEPLOY_WIN_RDP_USER optional SSH user, must be a local administrator (can also by set via ssh_config) # DEPLOY_WIN_RDP_PORT optional SSH port, default 22 # DEPLOY_WIN_RDP_SSH_OPTS optional extra ssh options, e.g. # "-i /root/.ssh/win_id_ed25519 -o StrictHostKeyChecking=yes" # DEPLOY_WIN_RDP_LISTENER optional RDP listener name, default RDP-Tcp # DEPLOY_WIN_RDP_RESTART optional "1" to restart TermService after install. # Active RDP sessions will drop! windows_rdp_deploy() { _cdomain="$1" _ckey="$2" _ccert="$3" _cca="$4" _cfullchain="$5" _debug _cdomain "$_cdomain" _debug _ckey "$_ckey" _debug _ccert "$_ccert" _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" if ! _exists "ssh"; then _err "ssh is required but was not found in PATH." return 1 fi # ---- configuration ------------------------------------------------------ _getdeployconf DEPLOY_WIN_RDP_HOST _getdeployconf DEPLOY_WIN_RDP_USER _getdeployconf DEPLOY_WIN_RDP_PORT _getdeployconf DEPLOY_WIN_RDP_SSH_OPTS _getdeployconf DEPLOY_WIN_RDP_LISTENER _getdeployconf DEPLOY_WIN_RDP_RESTART if [ -z "$DEPLOY_WIN_RDP_HOST" ]; then _err "DEPLOY_WIN_RDP_HOST must be set." return 1 fi _savedeployconf DEPLOY_WIN_RDP_HOST "$DEPLOY_WIN_RDP_HOST" [ -n "$DEPLOY_WIN_RDP_USER" ] && _savedeployconf DEPLOY_WIN_RDP_USER "$DEPLOY_WIN_RDP_USER" [ -n "$DEPLOY_WIN_RDP_PORT" ] && _savedeployconf DEPLOY_WIN_RDP_PORT "$DEPLOY_WIN_RDP_PORT" [ -n "$DEPLOY_WIN_RDP_SSH_OPTS" ] && _savedeployconf DEPLOY_WIN_RDP_SSH_OPTS "$DEPLOY_WIN_RDP_SSH_OPTS" [ -n "$DEPLOY_WIN_RDP_LISTENER" ] && _savedeployconf DEPLOY_WIN_RDP_LISTENER "$DEPLOY_WIN_RDP_LISTENER" [ -n "$DEPLOY_WIN_RDP_RESTART" ] && _savedeployconf DEPLOY_WIN_RDP_RESTART "$DEPLOY_WIN_RDP_RESTART" _port="${DEPLOY_WIN_RDP_PORT:-22}" _listener="${DEPLOY_WIN_RDP_LISTENER:-RDP-Tcp}" if [ -n "$DEPLOY_WIN_RDP_USER" ]; then _target="$DEPLOY_WIN_RDP_USER@$DEPLOY_WIN_RDP_HOST" else _target="$DEPLOY_WIN_RDP_HOST" fi _pfx_pass="acme" # ---- build thumbprint + PFX locally ------------------------------------ _thumb="$(_fingerprint "$_ccert" 'sha1')" if [ -z "$_thumb" ]; then _err "Failed to compute certificate thumbprint." return 1 fi _debug "Thumbprint: $_thumb" _debug "Building PFX at $_pfx_file" _pfx_file="$(_mktemp)" if ! _toPkcs "$_pfx_file" "$_ckey" "$_ccert" "$_cca" "$_pfx_pass"; then _err "Failed to build PFX archive." rm -f "$_pfx_file" return 1 fi _pfx_b64=$(_base64 "multiline" <"$_pfx_file") rm -f "$_pfx_file" # ---- build installer script -------------------------------------------- if [ "$DEPLOY_WIN_RDP_RESTART" = "1" ]; then _restart_ps='Restart-Service -Name TermService -Force' else _restart_ps='# New RdP connections will pick up the new cert automatically.' fi # Escape every literal `$` with `\$` so the shell does not expand it. # Values substituted from shell: $_pfx_b64, $_pfx_pass, $_thumb, $_listener. _ps1=$( cat <