Docker configuration

Docker configuration [v1.0] #

Please make sure you are familiar with Aggregator design as explained in Design.

Prerequisites #

Azure DevOps PAT #

You must have an Azure DevOps Personal Access Token as described here to authenticate against Azure DevOps. This is the identity that authenticates and acts on Azure DevOps.

DNS name #

Azure DevOps Server does not allow web hooks to localhost. The container must be accessible through a proper DNS name.

SSL Certificate #

Azure DevOps requires TLS encrypted connections to third party. The docker image assumes to find a certificate in the secrets folder to use for HTTPS.

Create / get a certificate in PFX format, name it aggregator.pfx. If you have a PEM (.pem, .crt, .cer) or PKCS#7/P7B (.p7b, .p7c) file, you can use OpenSSL to produce an equivalent PFX format (e.g. follow this guide).

You can generate a test certificate with a similar PowerShell snippet.

$cert = New-SelfSignedCertificate -KeyLength 2048 -KeyAlgorithm RSA -Type SSLServerAuthentication -FriendlyName "Aggregator" -NotAfter 2025-12-31 -Subject "aggregator.example.com" -TextExtension @("2.5.29.17={text}DNS=aggregator.example.com&IPAddress=127.0.0.1&IPAddress=::1")
$certPass = Read-Host -Prompt "My password" -AsSecureString
Export-PfxCertificate -FilePath "aggregator.pfx" -Cert $cert -Password $certPass

Define the set of valid API Keys #

Add a file apikeys.json, similar to the following.

[
  { "key": "api-123457890abcdef1234567890abcdef" },
  { "key": "api-23457890abcdef1234567890abcdef1" }
]

A valid API Key is made of 32 hexadecimal characters prefixed by api- for a total 36 chars. In PowerShell

"api-$( (New-Guid) -replace '-','' )"

or on Linux/Mac

echo "api-$( uuidgen | tr -d '-' )"

or

echo "api-$( openssl rand -hex 16 )"

The API Key values will be used to authenticate the Web Hook call from Azure DevOps.

Shared secret with CLI (optional) #

Define the environment variable Aggregator_SharedSecret both at the container and where you launch the CLI. This is required to use CLI commands like map.local.rule to configure Azure DevOps.

Volume with Rule files #

Create a folder to contain the Rule files, e.g. C:\aggregator-cli\docker\rules\ and copy there the Rule files. Test the Rules before using the invoke.rule command.

Test the container #

Pull the latest image from Docker Hub using the version matching the operating system.

docker pull tfsaggregator/aggregator3:latest

Example of running the container.

docker run --rm -it -p 5320:5320 -e Aggregator_VstsToken=********  -e ASPNETCORE_Kestrel__Certificates__Default__Password="********"  --mount type=bind,source=c:/src/github.com/tfsaggregator/aggregator-cli/docker/secrets/,target=c:/secrets --mount type=bind,source=c:/src/github.com/tfsaggregator/aggregator-cli/docker/rules/,target=c:/rules   tfsaggregator/aggregator3:latest
docker run --rm -it -p 5320:5320 -e Aggregator_VstsToken=******** -e ASPNETCORE_Kestrel__Certificates__Default__Password="********"  -v /mnt/c/src/github.com/tfsaggregator/aggregator-cli/docker/rules:/rules  -v /mnt/c/src/github.com/tfsaggregator/aggregator-cli/docker/secrets:/secrets   tfsaggregator/aggregator3:latest

Clearly, replace the asterisks (********) with secret values.

The output should be similar to the following

Docker mode.
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://[::]:5320
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:\app
Azure DevOps refuses localhost connections for Web hooks. The container must be exposed using a DNS name.

Try access the /config/status endpoint to check connectivity, e.g.

curl -X GET https://aggregator.example.com:5320/config/status

Add the --insecure if you are using a self-signed certificate (not recommended for production). If your system hasn’t curl, you can test using PowerShell

Invoke-RestMethod -Method Get -Uri https://aggregator.example.com:5320/config/status

Add -SkipCertificateCheck if you are using a self-signed certificate (not recommended).

Environment Variables #

The container is configurable using these environment variables.

VariableUseDefault value
ASPNETCORE_URLSSet the listening porthttps://*:5320
ASPNETCORE_Kestrel__Certificates__Default__PathSSL Certificatec:\\secrets\\aggregator.pfx
ASPNETCORE_Kestrel__Certificates__Default__PasswordSSL Certificate password
Logging__LogLevel__AggregatorLevel of Application LoggingDebug
Aggregator_ApiKeysPathValid API Keysc:\\secrets\\apikeys.json
Aggregator_SharedSecretShared password to authenticate CLI
Aggregator_RulesPathDirectory with Rule filesc:\\rules
Aggregator_VstsTokenTypeType of Azure DevOps authenticationPAT
Aggregator_VstsTokenAzure DevOps Personal Authentication Token
Aggregator_AzureDevOpsCertificateAzure DevOps certificate to trust
AGGREGATOR_TELEMETRY_DISABLEDControl telemetryfalse
VariableUseDefault value
ASPNETCORE_URLSSet the listening porthttps://*:5320
ASPNETCORE_Kestrel__Certificates__Default__PathSSL Certificate/secrets/aggregator.pfx
ASPNETCORE_Kestrel__Certificates__Default__PasswordSSL Certificate password
Logging__LogLevel__AggregatorLevel of Application LoggingDebug
Aggregator_ApiKeysPathValid API Keys/secrets/apikeys.json
Aggregator_SharedSecretShared password to authenticate CLI
Aggregator_RulesPathDirectory with Rule files/rules
Aggregator_VstsTokenTypeType of Azure DevOps authenticationPAT
Aggregator_VstsTokenAzure DevOps Personal Authentication Token
Aggregator_AzureDevOpsCertificateAzure DevOps certificate to trustAGGREGATOR_TELEMETRY_DISABLED

We do not recommend using unsecured HTTP. The certificate should be trusted by the Azure DevOps instance.

Note that the backslash character (\) must be doubled for Windows paths.

Azure DevOps SSL certificate (optional) #

This option is useful if Azure DevOps is using a certificate issued by an internal Certificate Authority (CA). Aggregator running in the container trusts only certificate issued by public CAs.

To add a certificate to the trusted roots, copy the .cer in the secrets folder and set the Aggregator_AzureDevOpsCertificate environment variable to the container internal path, like for Aggregator SSL cert.

Sample run:

docker run --rm -it -p 5320:5320 -e Aggregator_AzureDevOpsCertificate=c:/secrets/myazuredevops.cer -e Aggregator_VstsToken=********  -e ASPNETCORE_Kestrel__Certificates__Default__Password="********"  --mount type=bind,source=c:/src/github.com/tfsaggregator/aggregator-cli/docker/secrets/,target=c:/secrets --mount type=bind,source=c:/src/github.com/tfsaggregator/aggregator-cli/docker/rules/,target=c:/rules   tfsaggregator/aggregator3:latest

This will work also for a self-signed certificate.

Checklist for Docker setup [v1.0] #

  • DNS entry for Aggregator
  • generate a valid certificate in .pfx format (matches the above)
  • pull the docker image
  • prepare apikeys.json
  • copy the pfx and json files above in a secrets directory on the docker host
  • write the rule files (you can test them using the CLI)
  • copy the rule files in a rules directory on the docker host
  • run the container, mounting both the secrets and rules directories, and defining the Aggregator_SharedSecret environment variable

Now the Aggregator instance running in the container is ready to serve.

  • create a PAT in Azure DevOps
  • download the CLI on any machine that can see both Azure DevOps and the Aggregator Container
  • set the Aggregator_SharedSecret environment variable in the shell running the CLI
  • use the map.local.rule to setup the WebHook Subscriptions in Azure DevOps