Sitecore provide a number of examples (https://github.com/Sitecore/container-deployment) of implementations using containers via Kubernetes and docker compose. All examples utilise a reverse proxy for ingress (be it via traefik or nginx in the k8s examples) to access the cd, cm and id services. All of the examples terminate TLS at the reverse proxy. By default each service is running on port 80, with no TLS encryption between the reverse proxy and the service container . This is a common approach for container based deployments that remain in a secure LAN (ie. in cloud native deployments). However, does raise eyebrows with security teams that may not have extensive in these sorts of environments or with rusted on control requirements.
With a bit of effort, there are strategies to inject certificates and bind to port 443 to provide end to end HTTPS/TLS. Ideally, from a managed certificate instance (e.g. Keyvault or ACM) at deploy time.
The current state of XP is split into 2 when it comes to the HTTP services.
a) IIS based (e.g. .NET framework services like CM,CD, XConnect) and
b) Sitecore Host based (e.g. .NET core based like Sitecore Identity).
Below I’ll focus on the Sitecore Host based services, but the approach is similar for IIS services however the “bindings” would need to be reconfigured by powershell in a custom entrypoint or baked into a custom image.
You will need a “real” SSL certificate signed by a CA that is trusted by the host container. Self signed or generated certs can be used, but require some additional work to add it to the trust store. This can be challenging in particular on Sitecore Host based services as by default the container images are Nanoserver based and do not include many of the certificate tools available on the full strength windows server images. I’ve managed to do this, but may be a post for another day as it will require additional steps in the entrypoint and has some implementation specific hurdles.
As Sitecore Host is .NET core based, it creates applications by default running on the Kestrel web server. Kestrel allows for configuration via config files or at runtime by following naming conventions in environment variables. To support extensibility in the same manner, Sitecore Host exposes environment variables to both the IHostingEnvironment.Configuration and the ISitecoreConfiguration objects, which allows for overriding configuration of both the hosting environment (eg. ASPNetCore and Kestrel) and the Sitecore configuration (Sitecore settings etc). Although documented here (https://doc.sitecore.com/xp/en/developers/102/sitecore-experience-manager/configuration.html#override-configuration-values-at-runtime_body), it’s not immediately clear if or how this applies to the Hosting Environment as the Sitecore Identity image abstracts away the basics in environment variables and the embedded entrypoint. It’s also worth noting that this is not the same as the certificate dumped into base64 and exposed as the Sitecore_Sitecore__IdentityServer__CertificateRawData environment variable for use internally in Identity Server. The solution below specifically discusses using a separate certificate for the web server (ie. Kestrel)
After a bit of digging in the Kestrel/ASPNetCore documentation (see refs below) and some trial and error, the following environment variables will force Sitecore Host services to start on port 443 with the referenced certificate/key as a pfx, which can be mounted as a volume (or retrieved in a custom entrypoint if that suits your devops process better).
ASPNETCORE_URLS: https://+:443;
SITECORE_Kestrel__Certificates__Default__Path: "c:\path\to\certkey.pfx"
SITECORE_Kestrel__Certificates__Default__Password: "my_strong_password"
Of course, you will also need to expose port 443 on the container, as previously only port 80 is exposed in the Sitecore provided identity server image.
Here’s an example of a standalone docker-compose file running Identity server running with a trusted cert, that has been adapted from the docker examples getting-started repo. You would need to adapt into your docker-compose or k8s setup, but should give you the gist of the necessary changes.
services:
id:
isolation: ${ISOLATION}
image: ${SITECORE_DOCKER_REGISTRY}sitecore-id6:${SITECORE_VERSION}
environment:
Sitecore_Sitecore__IdentityServer__SitecoreMemberShipOptions__ConnectionString: Data Source=${SQL_SERVER};Initial Catalog=Sitecore.Core;User ID=${SQL_SA_LOGIN};Password=${SQL_SA_PASSWORD}
Sitecore_Sitecore__IdentityServer__AccountOptions__PasswordRecoveryUrl: https://${CM_HOST}/sitecore/login?rc=1
Sitecore_Sitecore__IdentityServer__Clients__PasswordClient__ClientSecrets__ClientSecret1: ${SITECORE_IDSECRET}
Sitecore_Sitecore__IdentityServer__Clients__DefaultClient__AllowedCorsOrigins__AllowedCorsOriginsGroup1: https://${CM_HOST}
Sitecore_Sitecore__IdentityServer__CertificateRawData: ${SITECORE_ID_CERTIFICATE}
Sitecore_Sitecore__IdentityServer__PublicOrigin: https://${ID_HOST}
Sitecore_Sitecore__IdentityServer__CertificateRawDataPassword: ${SITECORE_ID_CERTIFICATE_PASSWORD}
Sitecore_License: ${SITECORE_LICENSE}
ASPNETCORE_URLS: https://+:443;
SITECORE_Kestrel__Certificates__Default__Password: "my_strong_password_from_a_secure_store"
SITECORE_Kestrel__Certificates__Default__Path: "c:\\certs\\myidcert.pfx"
ports:
- "443:443"
volumes:
- C:\certs:C:\certs
healthcheck:
test: ["CMD", "pwsh", "-command", "C:/Healthchecks/Healthcheck.ps1"]
timeout: 300s
Points of note:
- The additional environment variables listed above
- Changing ports to map 443 to 443
- Mounting a certs folder containing an appropriately CA signed certificate into the location specified in
SITECORE_Kestrel__Certificates__Default__Path
Hope that helps someone, as I found little documented on the exact process and no doubt something others may run into in future.
Refs:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints?view=aspnetcore-6.0
https://learn.microsoft.com/en-us/aspnet/core/security/docker-compose-https?view=aspnetcore-6.0
https://doc.sitecore.com/xp/en/developers/102/sitecore-experience-manager/configuration.html#override-configuration-values-at-runtime_body