Skip to content

Upload your script as an integration and use it in an installation plan.

  • A login with the Owner role on the appliance.
  • agent.yml and a script for the service. See the Windows and Linux examples.
  • A server with a service agent and administrator access to allow your integration.
  1. Put agent.yml and the script (.sh, .ps1 or .py) in a ZIP file.
  2. Open Appliance › Integrations › Catalogue, enable uploads of your own integrations, select the ZIP file and click Upload and approve.
  3. Open the server’s page. Under Own scripts, click Allow own scripts and enter an administrator login for this run.
  4. Select the integration and action under Advanced in the installation plan’s Review step. See choosing the service.

The server’s Own scripts shows Allowed. In the catalogue, the integration version shows Verified. The script must return status: success when installation succeeds.

  • The ZIP file is rejected → compare it with the agent.yml requirements and file limits below.
  • The licence has no slots left → Free allows 1 integration of your own, Basic 3. Professional and Enterprise have no licence limit. Another version of an existing integration takes no extra slot.
  • The server rejects the signing key → check permission on the server. Integrations can run only where the server trusts the appliance’s key.
  • The script returns error → read message in the result, fix the script and upload a version with the fix.

Your own integration runs on the target server, never on the appliance. It cannot call an API from the appliance. On a server with a service agent, this permission requires Windows service agent 1.5.0 or Linux service agent 0.7.0 or later. The appliance changes permission over WinRM or SSH and restarts the service agent.

During installation, select Allow own scripts from this appliance under Servers › Add server › With service agent. On an enrolled server, use Own scripts. The page shows permission, when it changed and who changed it. Every change is logged. Updating the service agent leaves permission unchanged.

Use an administrator login for the individual run. A saved administrator login can be misused if the appliance or its administrator accounts are compromised.

If you disable uploads of your own integrations in the catalogue, approved ones keep running. If you disable permission on the server, trust in this appliance’s key is removed. Other trusted keys are kept.

A ScriptPolicy from Group Policy still decides what may run. A value of 0 blocks everything, including signed FairSSL integrations. See the values under Policy and audit.

Open Appliance › Integrations › Catalogue. Appliance signing key shows a fingerprint as sha256:<64 hex>. For Linux, download sslbrain-appliance-signing-key.pem through Download the public key for the Linux service agent (PEM).

Add the fingerprint to Custom as REG_MULTI_SZ, with one fingerprint per line, and set AllowCustomAgentsFrom to local. Keep other keys and sources if the values already exist. The example is for a server without these values. Run as an administrator and replace <fingerprint> with the 64 hex characters:

Terminal window
reg add "HKLM\SOFTWARE\sslbrain\TrustedKeys" /v Custom /t REG_MULTI_SZ /d "sha256:<fingerprint>" /f
reg add "HKLM\SOFTWARE\sslbrain" /v AllowCustomAgentsFrom /t REG_SZ /d "local" /f
Restart-Service sslbrainagent

At installation, you can use ALLOW_CUSTOM_AGENTS_FROM=LOCAL TRUSTEDKEYS_CUSTOM="sha256:<fingerprint>". TRUSTEDKEYS_CUSTOM fills Custom only when the value is absent or empty (MSI properties).

Copy the downloaded PEM file to the server. Place it at the fixed path:

Terminal window
sudo install -m 0644 sslbrain-appliance-signing-key.pem /var/lib/sslbrain/state/appliance-signing-key.pem

Set this line in /etc/sslbrain/agent.conf:

ALLOW_CUSTOM_AGENTS_FROM=APPLIANCE

Restart the service agent:

Terminal window
sudo systemctl restart sslbrain-agent.service

Without the key file or the setting, the service agent refuses the integration of your own because of an untrusted key without running it.

The value is the sum of what the service agent may run:

ValueMay run
1FairSSL integrations that read
2FairSSL integrations that write
4Integrations from others that read
8Integrations from others that write
16Own integrations

Values 4 and 8 cover integrations from others. The catalogue’s integrations are written, reviewed and signed by FairSSL.

The Appliance › Integrations › Approval page on the appliance does not decide what the service agents run (policy).

The appliance refuses the integration if any of these fields is missing or wrong:

FieldValue
agent.nameA name no integration from FairSSL and no built-in integration uses
agent.tiercustom
agent.channelpush-ssh when the appliance runs the script over SSH on a server without a service agent, or pull-service-agent. On a server with an enrolled service agent, the action always runs through the service agent, whatever the channel
actions.<name>The action, for example deploy
scriptA .sh, .ps1 or .py file in the zip file
shellOn every action: bash for Linux or powershell for Windows. The service agent runs only the shell for the server’s operating system
runtime.locationtarget
runtime.interpreterbash for Linux or powershell for Windows
runtime.delivery.modestdin or scp-tmp for push-ssh, none for pull-service-agent
categorywrite for an action that changes something, read for one that only reads
timeoutSeconds the action may run
cert_formatpem or pfx_base64 (variables)
parametersThe inputs the script gets. On a service agent, these are the only inputs

The zip file may be at most 1 MB, with 64 files, 512 KB per file and 4 MB unpacked. The allowed file types are yml, yaml, sh, ps1, py, json, md and txt. Hidden files, symbolic links, binary files, absolute paths and .. are refused.

The zip file must not contain agent-manifest or agent-manifest.sig. The appliance signs it when uploaded.

On Windows servers, sslbrain installs certificates through the service agent. Prefer the signed catalogue integrations for IIS, Exchange, SQL Server and the Windows certificate store (Integrations). To install the service agent, see Windows servers.

For your own service, you can use this example. It imports the certificate into Cert:\LocalMachine\My. Adapt the script if the service also needs the certificate bound or needs a restart. Trust the appliance’s key and allow your own integrations first.

agent.yml:

agent:
name: intranet-app-windows
display_name: "Intranet-app"
version: "1.0.0"
tier: custom
description: "Installs the certificate for the intranet app"
channel: pull-service-agent
compatibility:
os: ["Windows"]
actions:
deploy:
description: "Import the certificate into the Windows certificate store"
script: deploy.ps1
shell: powershell
runtime:
location: target
interpreter: powershell
delivery:
mode: none
category: write
timeout: 120
cert_format: pfx_base64
parameters:
PFX_BASE64:
type: string
required: true
secret: true
source: certificate.pfx_base64
encoding: base64
content: opaque
max_decoded_bytes: 48000
validation: '^[A-Za-z0-9+/=\x09-\x0d ]+$'
PFX_PASSWORD:
type: string
required: true
secret: true
source: certificate.pfx_password
validation: "^[^\\x00-\\x08\\x0a-\\x1f]{1,1000}$"

deploy.ps1:

Terminal window
param([string]$PFX_BASE64, [string]$PFX_PASSWORD)
$ErrorActionPreference = 'Stop'
$tempFile = $null
try {
$tempFile = [System.IO.Path]::GetTempFileName()
[System.IO.File]::WriteAllBytes($tempFile, [Convert]::FromBase64String($PFX_BASE64))
Import-PfxCertificate -FilePath $tempFile -CertStoreLocation Cert:\LocalMachine\My `
-Password (ConvertTo-SecureString $PFX_PASSWORD -AsPlainText -Force) | Out-Null
Write-Output '{"status":"success"}'
} catch {
@{ status = 'error'; message = $_.Exception.Message } | ConvertTo-Json -Compress
exit 1
} finally {
if ($tempFile) {
Remove-Item -LiteralPath $tempFile -Force
}
}

The example writes the certificate and key to files and reloads a service.

agent.yml:

agent:
name: intranet-app-linux
display_name: "Intranet-app"
version: "1.0.0"
tier: custom
description: "Installs the certificate for the intranet app"
channel: push-ssh
actions:
deploy:
description: "Write the certificate and key, and reload the service"
script: deploy.sh
shell: bash
runtime:
location: target
interpreter: bash
delivery:
mode: stdin
category: write
timeout: 120
cert_format: pem
parameters:
CERT_PEM:
type: string
required: true
secret: true
source: certificate.pem
encoding: base64
content: opaque
max_decoded_bytes: 48000
validation: "[A-Za-z0-9+/]+={0,2}"
KEY_PEM:
type: string
required: true
secret: true
source: certificate.key
encoding: base64
content: opaque
max_decoded_bytes: 48000
validation: "[A-Za-z0-9+/]+={0,2}"

deploy.sh:

#!/usr/bin/env bash
set -euo pipefail
trap 'echo "{\"status\":\"error\",\"message\":\"deploy failed\"}"; exit 1' ERR
SUDO=""
[ "${SSLBRAIN_ELEVATE:-}" = "sudo" ] && SUDO="sudo -n"
umask 077
$SUDO mkdir -p /etc/intranet-app/tls
printf '%s' "$CERT_PEM" | base64 -d | $SUDO tee /etc/intranet-app/tls/cert.pem >/dev/null
printf '%s' "$KEY_PEM" | base64 -d | $SUDO tee /etc/intranet-app/tls/key.pem >/dev/null
$SUDO systemctl reload intranet-app
echo '{"status":"success"}'

A certificate chain is the intermediate certificates that link the server’s certificate to a root the browser trusts.

The script gets the parameters the action declares under parameters, under each parameter’s own name. On a server with a service agent, the script gets no other values.

In bash the values are variables in the script, for example $CERT_PEM. On a service agent they are not exported to programs the script starts. In PowerShell they are bound to the script’s param() by name. On a service agent that is the only way in, so declare them in param() as the example does.

Declare the certificate with source: certificate.pem, certificate.key, certificate.chain, certificate.pfx_base64, certificate.pfx_password, certificate.thumbprint, certificate.previous_thumbprint or certificate.fingerprint_sha256. For binary or PEM data, also set encoding: base64 on the parameter. The value then arrives base64-encoded, and the script decodes it as in the examples above.

The action’s cert_format chooses the certificate’s form. The values reach the script only through declared parameters. Without cert_format, an action that declares CERT_PEM, KEY_PEM or CHAIN_PEM gets the certificate as PEM.

cert_formatVariables
pemCERT_PEM, KEY_PEM, and CHAIN_PEM when the chain is delivered separately
pfx_base64PFX_BASE64, PFX_PASSWORD, PFX_ENCRYPTION and CERT_PEM

A script run over SSH (channel push-ssh, server without a service agent) also gets the values below. On a service agent, the script gets them only if the action declares them as parameters:

VariablesContent
HOSTNAME, HOST, SERVER_IP, SERVER_OS_TYPEThe server
CREDENTIAL_USER, CREDENTIAL_SECRETThe credential on the server, when it has one
SSLBRAIN_ELEVATEsudo, when the credential has Elevate via sudo turned on. A service agent runs the action as root and never sets it
CERTIFICATE_CN, CERTIFICATE_SERIAL, CERTIFICATE_FINGERPRINT_SHA256, CERTIFICATE_NOT_AFTER, CERTIFICATE_ISSUER, NEW_THUMBPRINT, NEW_FRIENDLY_NAMEThe certificate being installed
OLD_THUMBPRINT, OLD_FRIENDLY_NAME, OLD_FINGERPRINT_SHA256, OLD_CERTIFICATE_SERIALThe certificate being replaced
ENDPOINT_NAME, ENDPOINT_AGENT_TYPE, DEPLOYMENT_MODEThe service in the installation plan
CERT_PATH, KEY_PATH, CHAIN_PATH, RELOAD_COMMAND, INIT_SYSTEM, SOFTWARE_VERSIONWhat discovery found on the service

Result: the script always writes a JSON object with status set to success or error, and optionally message. The last object with a status counts. The action fails on error, even if the exit code is 0, and on an exit code other than 0.

The appliance signs your own integration with its own ECDSA P-256 key when it is uploaded. The service agent runs the integration only when you have trusted that key on the server and allowed your own integrations as described above.

Integrations from FairSSL have a manifest with the SHA-384 of each file, signed with ECDSA P-384 on a hardware key at FairSSL. The appliance trusts only FairSSL’s fixed production keys.

Appliance › Integrations › Catalogue shows for each version Verified, Invalid or Unsigned.