RAZL is a really handy addition to a Sitecore developers toolbox. It allows for content comparison and sync between environments. Great for pre-production environments where you need to “refresh” some content or get a brand new environment up to date with the latest stuff your content producers have been working on. Razl v5+ also offers powershell scripting, so you can easily sync the same items across many environments ….it’s handy. But it can be challenging to deploy in a repeatable way when not using containers, due to it’s installation method and security model.
There is some doco available (http://hedgehogdevelopment.github.io/razl/index.html) on how to use it, but it’s all pretty intuitive. Razl is installed in 2 parts:
- A client windows application for a GUI (or powershell scripts)
- A web service installed on the Sitecore CM
You can download the application from https://www.teamdevelopmentforsitecore.com/Download/Razl. It is a licensed product, but also sold in a bundle with TDS if that’s your jam.
After installation the application will guide you through the process of setting up a connection. Part of this process is “installing” the webservice and associated configuration. The webservice can be installed “Directly” (ie. copies the necessary files direct to your CM) for local instances or via a Sitecore Package, which the connection manager will create for you as you go through the process.
Also note that Razl v5+ is available for containers as an asset image in the Sitecore container registry (scr.sitecore.com/tools/sitecore-razl-assets:[Razl Version]-1809 ), this asset is pretty much just the contents of the package the connection manager would create that you can pre-bake into your CM image….with a couple of subtle, key differences.
So what’s the problem?
For security purposes the Razl web service is configured with an “Access Guid“, a shared key the Razl client connection (app or powershell) needs to authenticate with. This is set via config in the /_CMP folder, which is created at install time to house the web service endpoint. Unfortunately this makes it a bit messy to deploy via “traditional” (ie. not in containers) means for a couple of reasons:
- Each environment should have a unique, secret access key….but it’s baked into a package
- The access key is a secret, it really shouldn’t be in any file. Most modern deployment flows would use secret stores and/or environment variables to handle this. It makes rotation easier and secrets on the filesystem always feels…..icky.
Luckily, thanks to the docker support, we can leverage that implementation to set the access guid as in env var. It just takes some tweaks to the connection packages created by Razl connection manager.
Let’s just fix that
Firstly, lets take a look at the contents of the folder in the package that houses the Webservice and it’s config:
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <section name="HedgehogDevelopment.Razl.Service.Configuration" type="HedgehogDevelopment.Razl.Service.ServiceConfiguration, HedgehogDevelopment.Razl.Service" /> </configSections> <HedgehogDevelopment.Razl.Service.Configuration accessGuid="233be2de-f12e-4760-8904-5b2a9f4c4ce8" /> <system.web> <httpHandlers> <add verb="*" path="RazlStream.axd" validate="false" type="HedgehogDevelopment.Razl.Service.StreamingHandler, HedgehogDevelopment.Razl.Service"/> </httpHandlers> </system.web> <system.webServer> <handlers> <add name="RazlStream" verb="*" path="RazlStream.axd" type="HedgehogDevelopment.Razl.Service.StreamingHandler, HedgehogDevelopment.Razl.Service"/> </handlers> </system.webServer> </configuration>
Given I was keen to have the Access Guid configuration similar to how the container handled it with an environment variable, I had a dig into how it was handled there.
The suggested docker-compose sets the RAZL_AccessGuid on the CM, but just setting that env var, didnt just work. So I dug into the the asset image, which omitted just a couple of elements in the configuration. NB: the missing configSections and HedgehogDevelopment.Razl.Service.Configuration elements that include the accessGuid.
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <httpHandlers> <add verb="*" path="RazlStream.axd" validate="false" type="HedgehogDevelopment.Razl.Service.StreamingHandler, HedgehogDevelopment.Razl.Service"/> </httpHandlers> </system.web> <system.webServer> <handlers> <add name="RazlStream" verb="*" path="RazlStream.axd" type="HedgehogDevelopment.Razl.Service.StreamingHandler, HedgehogDevelopment.Razl.Service"/> </handlers> </system.webServer> </configuration>
After a quick test locally using this config, the Access Guid is successfully picked up by the webservice from the RAZL_AccessGuid environment, so this is exactly what I was after.
From here I was able to unzip the package, modify the web.config to the above then rezip it. At that point we have a generic Sitecore package (with no Access Guid set) that can be deployed to any environment (via your favourite means….I converted it to a WebDeploy package and pushed with MSDeploy in our pipelines) and the Access Guid can be set by the RAZL_AccessGuid environment variable. NB: Not setting the environment variable effectively disables RAZL, as all connection attempts would be rejected.