Force a certificate for authentication
Introduction
Two certificates are used to sign or encrypt data related to authentication.
By default, these certificates are automatically generated in the profile of the user running the web server.
If the application is behind a load balancer, you must pre-generate the certificate to use.
Generate a certificate
Generate the certificate and the private key
openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout myapp.key -out myapp.crt -subj "/CN=myapp" -days 3653
Generate the exchange file
openssl pkcs12 -export -passout pass: -out myapp.pfx -inkey myapp.key -in myapp.crt
Do not set a password on the pfx file. The -passout pass: parameter is used to skip the password prompt.
Configure the certificate
Add the certificate to the root of the server project, for example MyApp\Server\MyApp.pfx.
Then add the pfx file to the server project file.
<ItemGroup>
<None Update="MyApp.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
Set the name of the file containing the certificate in the Lagoon:Authentication:OpendIdCertificate key of the appsettings.json file.
{
"Lagoon": {
"Authentication": {
"OpendIdCertificate": "MyApp.pfx"
}
}
}
- The
IdentityServer:Key:FilePathkey is used ifLagoon:Authentication:OpendIdCertificateis not set. - The Lagoon server also checks
Lagoon:Authentication:CertificateThumbprint,Lagoon:Authentication:CertificateBase64, thenLagoon:Authentication:CertificateFilePathbefore the legacyLagoon:Authentication:OpendIdCertificatekey.
Provide the certificate via an environment variable or a vault
When secrets can only be provided as strings (environment variables, secrets vault), put the certificate in the Lagoon:Authentication:CertificateBase64 key. No file is then necessary: the private key stays in memory. Two forms are accepted:
- compact form, the shortest: the base64 of the certificate (DER), a dot, then the base64 of the private key (PKCS#8), without PEM header or line breaks;
- the base64 of a
pfxfile, protected or not by the password of theLagoon:Authentication:OpendIdCertificatePasswordkey.
$rsa = [System.Security.Cryptography.RSA]::Create(2048)
$request = [System.Security.Cryptography.X509Certificates.CertificateRequest]::new('CN=myapp', $rsa,
[System.Security.Cryptography.HashAlgorithmName]::SHA256, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1)
$certificate = $request.CreateSelfSigned([DateTimeOffset]::UtcNow.AddDays(-1), [DateTimeOffset]::UtcNow.AddYears(3))
[Convert]::ToBase64String($certificate.RawData) + '.' + [Convert]::ToBase64String($rsa.ExportPkcs8PrivateKey())
Lagoon__Authentication__CertificateBase64=MIIC...Q==.MIIE...Aw==
The CertificateLoader.FromBase64 method (namespace Lagoon.Server.Helpers) reads both forms, and CertificateLoader.ToCompactBase64 produces the compact form of a certificate: an application can use it for its own certificates.
This key takes precedence before Lagoon:Authentication:CertificateFilePath and Lagoon:Authentication:OpendIdCertificate, but after Lagoon:Authentication:CertificateThumbprint. Local storage that simulates the cloud (CloudStorage:Local:RootPath) does not read it: it always uses Lagoon:Authentication:OpendIdCertificate.