How Versus pushes an issued managed certificate and its private key to the ADCs and cloud edges that serve it — target discovery, overwrite vs. rename-and-rebind modes, per-vendor deployment, TLS verification, and the built-in deploy workflow.
Issuing a certificate is only half the job. The other half is getting the leaf, its chain, and the private key onto every device that terminates TLS for that name — and rebinding the SSL profile if you're rotating to a new object. Versus treats deployment as a distinct, auditable stage of certificate lifecycle: a managed certificate that has been issued is pushed to its deployment targets through a vendor-aware dispatcher, recorded per target, and verified over the wire.
This page covers what happens when a certificate is deployed, the two deployment modes, how targets are discovered, and how the built-in deploy workflow ties it together. For issuance (CSR generation, ACME DNS-01, the Versus CA) see Certificates.
A deploy takes an issued ManagedCertificate and, for each target, writes the certificate material onto the device and makes the SSL profile serve it. Everything flows through one dispatcher, deploy_client.push(), which routes to a per-vendor deployer based on the device's vendor:
push(device, profile_name, cert_pem, chain_pem, key_pem,
deployment_mode='overwrite', new_cert_name='', cert_object_name='')
→ { "success": bool, "message": str, "cert_object_name": str }
cert_pem / chain_pem — the leaf and the intermediate chain, stored separately on the certificate record and recombined per vendor (F5 wants a bundled leaf+chain; NetScaler wants them split).key_pem — the private key. Only certificates issued with a Versus-generated key (key_source = versus) can be deployed this way; the key is held encrypted at rest in Versus. Certificates whose key was generated on the device never leave the box and take a different install path.cert_object_name — the exact cert object on the device to overwrite, resolved by the discovery step from the profile's current binding.The dispatcher catches per-device failures and returns a structured result rather than raising, so one unreachable device doesn't abort a multi-target deploy.
Every deploy runs in one of two modes, carried on the certificate as deployment_mode and overridable per run:
| Mode | What it does | When to use it |
|---|---|---|
overwrite | Replaces the certificate object the profile is already bound to, in place. No profile change. | Straight renewal of the same name — the fastest, lowest-risk path. |
rename_update | Creates a new cert object (default name <cert>_<year>, a Venafi-style date suffix) and rebinds the SSL profile to it. | You want the old object retained for rollback, or your change process requires a new object per rotation. |
In overwrite mode the deployer writes to the resolved bound object and touches nothing else. In rename_update mode it uploads the new object, then rebinds the profile (or virtual server, or vserver) to point at it — so the switchover is a single binding change you can back out by rebinding to the previous object.
Deployment is vendor-specific under the hood but presents the same two-mode contract everywhere. The dispatcher supports on-prem ADCs and cloud WAF/CDN edges alike:
Vendor (device.vendor) | Cert object | Notes |
|---|---|---|
f5 (BIG-IP) | /Partition/name SSL cert + key | Leaf + chain bundled into one cert file; uploads cert and key to the file store, rebinds the client-ssl profile on rename. Collector-aware (see below). |
netscaler | sslcertkey | Requires the leaf split from intermediates; profile_name is the certkey name; rename rebinds the vserver. |
avi (NSX ALB) | sslkeyandcertificate | Tenant-scoped (extra_config.tenant, default admin); rename rebinds the virtual service. |
a10, kemp | SSL cert object | Upload leaf + key; name is the profile name (or the new name on rename). |
f5_xc | Namespaced cert object | F5 Distributed Cloud; conventionally the shared namespace; upserts (overwrite-in-place when it already exists); name normalized to DNS-1035. |
cloudflare | Zone custom certificate | Hostname/zone resolved from the certificate's CN. |
imperva | Site certificate | site_id from extra_config, or resolved from the CN against protected sites. |
akamai | CPS enrollment | Third-party enrollment via EdgeGrid; uploads the CA-signed leaf + trust chain (Akamai holds the key). |
radware_cloud | Application certificate | Cloud WAAP; scoped by application_id. |
azure_front_door | AFD secret | AAD service-principal auth; secret name normalized to DNS-safe. |
For the F5 BIG-IP path, the deployer routes through the collector plane automatically when the target is a site-bound, private-LAN device — the same outbound-only tunnel used for every other F5 operation — and falls back to a direct REST call otherwise. The tunnel is always closed after the push. See F5 BIG-IP Integration for how those devices are enrolled.
Cloud edges are treated as ordinary devices in inventory, so a renewal reaches an Azure Front Door secret or a Cloudflare zone certificate exactly the way it reaches an F5 virtual server. See Cloud WAF & CDN.
You can name deployment targets explicitly, or let Versus find them.
A deployment target is a small record:
{
"device_id": 42,
"profile_name": "/Common/app-clientssl",
"cert_object_name": "app_example_com",
"new_cert_name": ""
}
deployment_targets, they're used as-is and auto-discovery is skipped.cert.discover_targets step matches the managed certificate's CN and SANs against every discovered device certificate in inventory, then finds the SSL profiles bound to those certs. It resolves each profile's currently bound cert object into cert_object_name, so an overwrite lands on exactly the object already in service. Discovery covers F5 today, and you can restrict it to client, server, or both profile sides.Auto-discovery means "renew the cert for app.example.com" fans out to every F5 profile actually serving that name, without you maintaining a device list by hand.
cert.deploy_to_adcs is the worker. For each target it:
deploy_client.push() with the certificate's stored leaf, chain, and private key.CertificateDeployment row — one per (certificate, device, profile_name) — capturing the actual object written (the resolved bound object, or the year-suffixed name on a rename), the status, who deployed it, and the workflow run.A per-run deployment_mode_override takes precedence over the certificate's stored mode, so an operator can force a rename_update for one rotation from the Deploy button without changing the record. The step needs both an issued certificate (pem_certificate) and a private key on the record; if either is missing it fails fast. When every target succeeds, the certificate advances to deployed.
Each deployment is tracked durably:
| Field | Meaning |
|---|---|
profile_name | F5: /Partition/profile-name; NetScaler: certkey name. |
cert_object_name | The object actually written on the device (may differ from the profile name). |
status | deployed, failed, or removed. |
deployed_at / deployed_by | When and by whom. |
last_verified | Last successful TLS verification (see below). |
error | Failure message, when the push failed. |
After a deploy, cert.verify_tls opens a TLS connection to each deployed target on port 443 and confirms the endpoint presents a certificate, stamping last_verified on success. It's a liveness check that the rebind took effect end-to-end — a failed verification is surfaced as a warning on the run without rolling anything back, so you can investigate a target that didn't come up cleanly.
Versus ships a built-in Deploy Managed Certificate workflow (cert-deploy) that wires these steps together:
Deploy Certificate (trigger)
→ Discover cert-using devices
→ Approval required? ──yes──► Await Deploy Approval
└──no───┐ │
▼ ▼
Deploy to ADCs
→ Verify TLS
→ Done
Because the workflow is marked production, the Versus Desk change gate and back-out light up automatically: if the workflow is configured under a change window, triggering it opens a Change ticket and the deploy runs only once that change is approved and scheduled. The approval branch also pauses the run in-flight so a reviewer can inspect the discovered targets and the deployment mode before anything is pushed.
You run it from the certificate's Deploy action in the UI, or over the API like any other workflow.
Trigger the deploy workflow by name and pass the certificate id in context:
POST /api/workflow-trigger/
Authorization: Bearer …
Content-Type: application/json
{
"workflow": "Deploy Managed Certificate",
"run_name": "Renew app.example.com",
"context": {
"cert_id": 128,
"deployment_mode_override": "rename_update"
}
}
201 Created
{ "run_id": 91, "status": "pending", "status_url": "/api/workflow-status/91/" }
Poll GET /api/workflow-status/91/ for the per-step, per-device breakdown, and clear the approval gate with resume_approval if the workflow is gated. The full request/response contract — authentication, staged execution with stop_after_section, approvals, retries, and back-out — is in Running Workflows via the API.
Deployment reuses the platform's existing planes rather than introducing its own: device credentials come from the Versus Vault, private keys are held encrypted on the certificate record, private-LAN devices are reached over the outbound-only collector plane, and the whole operation runs as a durable, auditable workflow with change-gating and back-out. Every push leaves a CertificateDeployment record, so at any moment you can answer "which devices serve this certificate, and when were they last verified?" — the same question that drives renewal.
Because renewals carry the certificate's deployment_mode and deployment_targets forward, a renewal re-runs the identical deploy against the identical targets — the operator effort is front-loaded into the first deploy, and every rotation after that is hands-off.