system Requirements - RIT-ITS/CertifiCat-PS GitHub Wiki
The following requirements relate to the use of the CertifiCat-PS module. For more information on the main Posh-ACME module, its capabilities and requirements, please see https://poshac.me/docs/v4/.
Many of the functions that can be performed with both the main Posh-ACME module, as well as CertifiCat-PS, require local administrative rights.
As such, the CertifiCat-PS module will perform a check for local administrative rights at the start of each function, and return an error if the shell in which the function is running does not have access.
An important point of note is that the main Posh-ACME module discusses the use of a netsh
command (see Invoke-HttpChallengeListener and WebSelfHost Windows Prerequisites) as a means of allowing the module to start an internal web server to respond to ACME challenges.
It is worth noting that this command is typically only necessary in cases where the web server (i.e. PowerShell terminal) is running from a non-administrative session. Because the CertifiCat-PS module checks for administrative access (which would be required to run the netsh
command anyway), the netsh command does not need to be run.
Beyond the internal web server to respond to challenges, local administrator access would be required to perform various additional functions, including:
- Importing certificates into the LocalMachine store
- Interacting with IIS (e.g. to get and update site binding configuration)
In general, CertifiCat-PS is not dependent upon a particular version of PowerShell.
The notable exception is in cases where the module interacts with IIS. In these cases, modern versions of PowerShell (those being version 7 or newer) are not supported. Instead, a version of 6 or older must be used (version 5.1 is included in all modern versions of Windows Server).
At a high level, the limitation is due to the API calls that are needed in order to interact with IIS. While these calls are available in the .NET Framework, they have not yet been migrated to .NET. Versions of PowerShell 6 and prior are based upon the .NET Framework, while PowerShell 7 is based on .NET.
For more information, see this issue on GitHub.
All of the functions that are documented in this wiki will explicitly call out the when PowerShell 6 (or older) is required, either entirely or in part (e.g. a specific switch or parameter value).
In cases where CertifiCat-PS will not update IIS Bindings, or use an IIS binding to check the certificate expiration date, this will not present an issue.
If CertifiCat-PS interacts with an IIS component, and it detects that the session is running in a PowerShell 7 console, an exception will be thrown. All of the functions in this module return an object, which includes a property called PS5Command
. The contents of this property can be used (either manually or as part of an upstream automation script) to run the function again, with the same arguments, in a PowerShell 5 console.
For example:
C:\ITS\Scripts> $newCertificate = Initialize-NewACMECertificate -UpdateBindings -DomainList myserver.example.com
=========================================
[Initialize-NewACMECertificate]
Attempting to renew TLS Certificate
=========================================
-> Confirming that we are in an admin session...ok
-> Validating incoming parameters...fail!
Detected this function running from a modern PowerShell console. This combination of parameters REQUIRES the use of PowerShell 6 or later. Check the 'PS5Command' property of the return object for a complete command to run instead.
=========================================
[Initialize-NewACMECertificate]
Completed unsuccessfully!
=========================================
C:\ITS\Scripts> $newCertificate
FunctionName : Initialize-NewACMECertificate
RunningPSVersion : 7.3.1
PS5Command : powershell.exe {import-module CertifiCat-PS -Force;
Initialize-NewACMECertificate -UpdateBindings -DomainList "myserver.example.com" }
FunctionArguments : -UpdateBindings -DomainList "myserver.example.com"
FunctionSuccess : False
Errors : {Function/parameters require PowerShell 6 or earlier, but running from a modern console. See
the PS5Command property for a PowerShell 5 equivalent to run.}
Certificate : {}
Bindings : {}
CertificateImported : False
BindingsUpdated : False
StoreLocation : LocalMachine
StoreName : WebHosting
PFXPath :
ReadyForRenewal : True
CertificateCentralized : False
CentralDirectory : c:\programdata\certificat-ps\posh-acme\myserver.example.com\05-27-2024-01-41-54
In order to validate the domains included on the certificate request, CertifiCat uses the HTTP-01 challenge method. This involves the CertifiCat server querying each of the domains in the certificate for a custom "token file" which is then verified to confirm ownership of the domain. For more information on the challenge verification process, see Let's Encrypt.
While CertifiCat allows for a limited number of HTTP redirects as part of the challenge process, the initial request is made on port 80. Therefore, a server's firewall must be opened to an organization's CertifiCat server in order to allow the verification process to complete.
When renewing certificates for a pool of servers, a single certificate is requested from a primary server, containing SANs for each of the remaining servers in the pool / cluster. This request is made from a single "primary" server, and, using the Initialize-ExistingACMECertificate
function, the secondary servers can be updated. For more information, see [../Getting-Started/Usage-Examples].
The following considerations need to be made both when making the initial request for a SAN certificate, and in making the updates on the remaining servers:
In order to remotely copy the new certificate to the secondary nodes, and execute the Initialize-ExistingACMECertificate
function, the primary node will need to be able to access the other servers via WinRM.
In addition to having firewall access, the biggest consideration to make is which user will be executing the functions. When run interactively, this is the user logged into the main server. However, when a script is scheduled to run via the Task Scheduler, you must consider the run-as user.
While SYSTEM could be used to run an automation script on a standalone server (providing the necessary administrative rights), it cannot be used in cases where you are remotely updating multiple nodes in a pool. Therefore, a service account, or ideally, a Group Managed Service Account (gMSA), which has administrative access on all of the servers, will need to be used.
When a certificate is requested, the Posh-ACME module will start up a temporary web server to respond to the HTTP challenge (as described above). While this works for standalone servers, there are additional considerations for certificates being used with multiple servers.
Notably, after the CertifiCat server validates the primary domain, it will move on to each secondary domain in the SAN list. In cases where the domain is not a CNAME to the primary server, these subsequent servers will not be running the Posh-ACME server, and will not respond with the necessary challenge files. This will cause the domain validation process to fail, and the certificate order will fail.
There are multiple methods that could be used to address this:
- Use the official Posh-ACME module to generate the necessary challenge validation files, and copy them to the secondary servers, hosting them on the server as appropriate. This requires additional work to generate the files, configure IIS, copy the files, and then send a separate request to the ACME server that the environment is "ready" for validation. For more information on this technique, see the Posh-ACME Custom Challenge Validation instructions.
- Proxy or forward the requests from the secondary nodes to the primary node, which will respond with the correct challenge file
While either option can be used, the CertifiCat-PS module provides a function, Initialize-ACMEProxyRedirect
, which can be used in cases where the secondary servers are running IIS, to proxy these requests.
Consider the following example for an overview of the challenge authorization process in an environment with multiple servers:
flowchart
A(Start: Primary Server
Submits Order);
B[ACME Server Queries
Main Domain for
Challenge Token];
C[Primary Server Responds
With Challenge Token];
D{ACME Server
Validates Response};
E([Authorization and
Order Fail]);
G[ACME Server Queries
Next Domain in List
for Challenge Token];
H[Secondary Server Forwards
Request to Primary Server];
I[Primary Server Responds
With Challenge Token];
J{ACME Server
Validates Response};
K{More Domains
To Validate?};
L([Authorization Succeeds -
Order Continues]);
A --> B;
B --> C;
C --> D;
D --> |Invalid Response| E;
D --> |Valid Response| G;
G --> H;
H --> I;
I --> J;
J --> |Invalid Response| E;
J --> |Valid Response| K;
K --> |Yes| G;
K --> |No| L
style E stroke:#fb380f,stroke-width:4px
style L stroke:#2f8d35,stroke-width:4px
The ACME server will follow a limited number of redirects, which will allow the secondary servers to forward validation requests to the primary server.
Note that in cases where a proxy or redirect is configured manually, the following should be kept in mind:
- The initial query from the ACME server will always be on port 80
- The ACME challenge URLs take the form
http://server/.well-known/acme-challenge/<randomly generated filename here>
- The redirects from a secondary server to the primary server should be scoped specifically to the
acme-challenge
sub-directory, as this will ensure that there aren't conflicts with other .well-known URIs where the secondary server should be the responding node. For example:- A request to
http://secondaryServer/.well-known/acme-challenge/1234
should redirect tohttp://primaryServer/.well-known/acme-challenge/1234
, but - A request to
http://secondaryServer/.well-known/caldav/abcd
should not redirect to the primary server, instead be served from the secondary server
- A request to