Skip to content

CertIntel Agent workflow usage

Use a modular workflow to export an issued certificate, update an application, and verify the certificate it serves. This guide covers the Agent 1.3 beta workflow builder on Windows and the same workflow definitions on Linux. See certificate workflows and deployment for certificate policy setup and the action reference for all inputs.

Templates, workflows, and steps

On Windows, select a certificate in Workflows → Build modular workflow. Choose a bundled template or Create blank workflow, then edit the saved copy under My modular workflows. Bundled templates are immutable starting points; your copy is a user-owned workflow with its own variables, secrets, and steps. Agent upgrades do not overwrite those customizations. Remote template packages are not currently supported.

Steps run sequentially, from top to bottom. They do not run in parallel. The certificate policy still owns names, ACME account, DNS delegations, and renewal scheduling. ACME issuance completes before modular steps start. The action acme.obtain_certificate exposes that already-issued certificate to the workflow; moving it lower in the list does not postpone issuance.

Each step has two identities:

Field Purpose
Label (name in JSON) Human-readable description, such as “Inspect updated endpoint”; this is what the UI primarily displays.
Advanced reference ID (id in JSON) Generated, stable identifier used by later inputs and conditions. Expand this section in the step editor to view it.

Renaming a label does not change its reference ID. Adding the same action again generates a distinct ID. Prefer the condition/output picker wherever offered, especially Previous yes/no result, instead of manually typing references. For fields that require a reference by hand, copy the actual advanced ID and use an output declared by that action. The IDs in the examples below are explicit example IDs, not labels to type into the editor.

Variables and references

References use ${namespace.field} syntax. Names and output spelling must match the saved definition. These are the currently supported namespaces:

Namespace Available values and practical examples
${variables.name} Your workflow's variables object. Set host to app.example.com, port to numeric 8443, then use ${variables.host} and ${variables.port} in endpoint inputs.
${secrets.name} A declared secret_refs name stored separately in the protected secret store. Use ${secrets.output_password} as the complete export password value.
${steps.<reference-id>.<output-name>} A declared output from a completed earlier step, such as ${steps.after.thumbprint} or ${steps.check-directory.exists}.
${certificate.*} Current issued certificate: thumbprint, subject, issuer, serial, notBefore, notAfter, domains, generation. For example, compare ${certificate.thumbprint} with an endpoint thumbprint, or pass ${certificate.domains} as expected SANs. These are the issued artifact's facts, not a live endpoint probe.
${renewal.*} Currently ${renewal.id} only: the certificate policy's stable renewal ID. For example, use server-${renewal.id} as an export filename prefix.
${workflow.*} id, name, version of this workflow. For example, use backup-${workflow.id} as a directory component.
${system.*} os, arch, date, dateCompact, timestamp, timestampUtc. For example, C:\Backups\server-${system.dateCompact}.pfx.

System dates use UTC and are captured at workflow start: date is YYYY-MM-DD, dateCompact is YYYYMMDD, timestamp is YYYYMMDD-HHMMSS, and timestampUtc is RFC 3339. os is windows or linux; arch identifies the Agent build's architecture. Certificate and renewal values require an issued artifact, so they may be unavailable during preflight before first issuance.

Reading a step reference

In ${steps.issue.thumbprint}:

  1. steps selects results of prior steps in this run.
  2. issue is the earlier step's stable reference ID, not its label.
  3. thumbprint is an output declared by that step's action.

For an acme.obtain_certificate step with ID issue, this is the issued certificate's thumbprint. For an endpoint inspection with ID after, ${steps.after.thumbprint} is the certificate the server actually presented. For directory.exists with ID check-directory, ${steps.check-directory.exists} is a boolean.

Only completed earlier steps can supply action outputs. A future step, the current step, or a previous run cannot supply them. Skipped steps have no action outputs, and a failed step continued by policy does not make its diagnostic outputs available to later references. Guard dependent steps appropriately; an unavailable reference fails resolution. Deleting or reordering a producer can invalidate later references even though renaming its label is safe.

Types and common mistakes

Type Correct usage and common mistake
String "app.example.com", or "server-${system.dateCompact}". Embedding a reference in surrounding text produces a string.
Boolean Use the UI yes/no control or JSON true / false, not strings "true" / "false". True/false conditions require actual booleans.
Integer Use JSON 8443, not "8443". A whole-value reference such as "${variables.port}" preserves the referenced numeric type.
Array Use ["--reload"] for process arguments, [0, 2] for allowed exit codes, or "${certificate.domains}" for a SAN array. Comma-separated text is not an array.
Object Use an environment map such as {"MODE":"production","PASSWORD":"${secrets.app_password}"}. Do not stringify the whole object.
Date/time Inspection and certificate expiration outputs can be passed directly to comparison inputs. Literal dates for those inputs must be RFC 3339, such as 2026-09-20T12:00:00Z.
Artifact acme.obtain_certificate declares a certificate artifact output. It is an opaque handle, not certificate bytes, a filename, or a password. Export/install actions consume the Agent's current issued artifact internally.

A reference occupying the entire JSON string preserves its original type; interpolating an array or object into larger text does not produce usable JSON. Keep generation as an opaque generation identifier rather than doing arithmetic on it. Use the action reference and local capabilities to check expected input and output types.

Secrets must occupy an entire input value, including when nested in an environment map. "prefix-${secrets.output_password}" is invalid. Declare secret names and set their values through the editor or an elevated local prompt:

certintel-agent secret set workflow tomcat-p12:output_password

Do not put secrets in workflow variables or process arguments. process.execute supports protected values in its environment map instead.

Conditions and failure handling

Run this step offers:

  • Always run: no condition; runs when execution reaches this step. It does not override an earlier failure that stopped the workflow.
  • Run when prior result is true or Run when prior result is false: select an earlier boolean output in Previous yes/no result.
  • Advanced JSON condition: supply an object with operator, left, and where needed right. This is a condition language, not a script.

To create a directory only when missing, first add Check directory (directory.exists) and set its path. Add Create directory (directory.create) with the same path, choose Run when prior result is false, and pick the first step's Exists result. With the example ID check-directory, the equivalent steps are:

[
  {
    "id": "check-directory", "name": "Check certificate directory",
    "action": "directory.exists", "action_version": 1,
    "with": {"path": "${variables.directory}"}
  },
  {
    "id": "create-directory", "name": "Create missing directory",
    "action": "directory.create", "action_version": 1,
    "with": {"path": "${variables.directory}"},
    "when": {"operator": "false", "left": "${steps.check-directory.exists}"}
  }
]

Advanced operators are equals, notEquals, exists, notExists, true, false, greaterThan, lessThan, contains, matches, and certificateChanged. For example, after successful before and after inspection steps:

{
  "operator": "certificateChanged",
  "left": "${steps.before.thumbprint}",
  "right": "${steps.after.thumbprint}"
}

certificateChanged compares the supplied values for inequality; it does not inspect a certificate itself. exists / notExists test a resolved value for null/empty content, not the filesystem, and cannot rescue a missing reference. Use directory.exists or file.exists for filesystem checks. contains is a text containment check; matches uses a regular expression. Numeric comparisons require numeric values; equality compares text representations.

Setting Behavior
Failure fail (default) Stop after the action exhausts retries.
Failure continue Record the failed action and proceed; the run is partially successful if subsequent steps finish.
Failure rollback Stop and undo successfully completed rollback-aware actions in reverse order.
Retries 0–10 additional attempts; 3 means up to four executions.
Retry delay 0–600 seconds configured base delay. Zero uses a one-second delay when retrying.
Exponential retry backoff Doubles the base delay for successive retries: for example 5, 10, 20 seconds.
Timeout 1–3,600 seconds per attempt, default 300. Retries and their delays can make total step time longer.

Invalid conditions or unresolved inputs stop execution before action retries and failure policies apply. Rollback is limited: file.copy, file.move, and file.backup advertise it; certificate exports, IIS/store/JKS changes, directory creation, and service restarts do not provide full workflow rollback. Atomic export/write recovery does not mean a later failed health check restores the old certificate. Rollback of a copy removes its destination; it does not restore an overwritten destination. A backup in copy mode is also removed by its rollback; move mode restores its source. Use explicit backups and check rollback results.

Complete example: renew and deploy Tomcat with P12

The Tomcat + PKCS#12 (.p12) template provides export, restart, endpoint inspection, and thumbprint verification. Save certificate as PKCS#12 (.p12) only exports. P12 and PFX use the same PKCS#12 encoding; p12 produces .p12 and pfx produces .pfx.

Create the certificate policy and DNS delegation first. Configure Tomcat's TLS connector to read C:\Tomcat\conf\tls\server.p12 as type PKCS12, using the same password stored as output_password. Grant the Tomcat service identity read access. This workflow writes a complete archive containing the certificate, private key, and supplied chain; it does not merge unrelated keystore entries. It does not configure the connector for you.

This complete workflow document combines before/after inspection, obtain, export, restart, thumbprint comparison, and an HTTPS check. Replace the example host, paths, exact service name, and health URL. For Linux, change platforms to ["linux"], use absolute Linux paths and the exact systemd unit.

{
  "schema_version": 1,
  "id": "tomcat-p12",
  "name": "Renew and verify Tomcat",
  "version": 1,
  "platforms": ["windows"],
  "variables": {
    "directory": "C:\\Tomcat\\conf\\tls",
    "host": "app.example.com",
    "port": 8443,
    "service": "Tomcat10",
    "health_url": "https://app.example.com:8443/health"
  },
  "secret_refs": ["output_password"],
  "steps": [
    {
      "id": "before", "name": "Inspect currently served certificate",
      "action": "certificate.inspect_endpoint", "action_version": 1,
      "with": {"host": "${variables.host}", "port": "${variables.port}"},
      "failure": {"mode": "continue"}
    },
    {
      "id": "issue", "name": "Use issued certificate",
      "action": "acme.obtain_certificate", "action_version": 1
    },
    {
      "id": "export", "name": "Export Tomcat P12",
      "action": "certificate.export", "action_version": 1,
      "with": {
        "format": "p12", "directory": "${variables.directory}",
        "name": "server", "password": "${secrets.output_password}",
        "backup_directory": "C:\\Tomcat\\certificate-backups"
      }
    },
    {
      "id": "restart", "name": "Restart Tomcat",
      "action": "service.restart", "action_version": 1,
      "with": {"service": "${variables.service}"}
    },
    {
      "id": "ready", "name": "Wait for TLS port",
      "action": "tcp.check", "action_version": 1,
      "with": {"host": "${variables.host}", "port": "${variables.port}"},
      "failure": {"mode": "fail", "retries": 5, "retry_delay_seconds": 3}
    },
    {
      "id": "after", "name": "Inspect updated endpoint",
      "action": "certificate.inspect_endpoint", "action_version": 1,
      "with": {"host": "${variables.host}", "port": "${variables.port}"},
      "failure": {"mode": "fail", "retries": 3, "retry_delay_seconds": 5}
    },
    {
      "id": "confirm", "name": "Confirm issued certificate is served",
      "action": "certificate.compare", "action_version": 1,
      "with": {
        "expected_thumbprint": "${steps.issue.thumbprint}",
        "actual_thumbprint": "${steps.after.thumbprint}"
      }
    },
    {
      "id": "https", "name": "Verify HTTPS health",
      "action": "http.check", "action_version": 1,
      "with": {"url": "${variables.health_url}", "expected_status": 200},
      "failure": {"mode": "fail", "retries": 3, "retry_delay_seconds": 5}
    }
  ]
}

The before inspection captures the certificate served before installation of the renewal, not before the ACME order. For an observation strictly before renewal begins, inspect the endpoint through Monitors before selecting Renew now. There is no modular pre-issuance hook. The optional continue on before permits first installation on an endpoint that is not yet serving TLS; if it fails, the final run is partially successful.

After a successful run, compare the before and after public facts in the job. The confirm step asserts that the newly issued thumbprint equals the served thumbprint and fails on mismatch. It is stronger than just checking that the old and new thumbprints differ. A comparison failure can return diagnostic matches: false, but that failed output is not available to subsequent steps. Retrying only the comparison reuses the same inspection result; rerun inspection to obtain a fresh one. The HTTPS check separately validates the HTTP response and requires the configured status; it does not follow redirects.

To assert a later expiry as well, make before mandatory (remove its continue policy) and add "old_not_after": "${steps.before.notAfter}" and "new_not_after": "${steps.after.notAfter}" to confirm.with.

Complete example: back up a file before replacing it

This workflow preserves an existing Tomcat configuration before copying a staged replacement. Prepare the staged file first. It runs under the Agent service identity and does not generate or edit the configuration content.

{
  "schema_version": 1,
  "id": "replace-tomcat-config",
  "name": "Back up and replace Tomcat configuration",
  "version": 1,
  "platforms": ["windows"],
  "variables": {
    "target": "C:\\Tomcat\\conf\\server.xml",
    "staged": "C:\\Tomcat\\staging\\server.xml",
    "backup_directory": "C:\\Tomcat\\config-backups"
  },
  "steps": [
    {
      "id": "check-file", "name": "Check existing configuration",
      "action": "file.exists", "action_version": 1,
      "with": {"path": "${variables.target}"}
    },
    {
      "id": "backup", "name": "Keep existing configuration",
      "action": "file.backup", "action_version": 1,
      "with": {
        "source": "${variables.target}",
        "directory": "${variables.backup_directory}", "mode": "copy"
      },
      "when": {"operator": "true", "left": "${steps.check-file.exists}"}
    },
    {
      "id": "replace", "name": "Install staged configuration",
      "action": "file.copy", "action_version": 1,
      "with": {
        "source": "${variables.staged}",
        "destination": "${variables.target}", "overwrite": true
      },
      "failure": {"mode": "fail"}
    }
  ]
}

file.backup creates its backup directory and adds a UTC timestamp by default. Its backupPath output identifies the saved file. An optional filename, such as server-${system.dateCompact}.xml, must be one filename, not a path; an existing backup is never overwritten, so a daily filename can collide on reruns. copy preserves the source; move removes it after backing it up. File actions require absolute paths and regular files, reject symlinks, and cap copies at 64 MiB. The fail policy here keeps a completed backup for manual recovery if replacement fails. This example does not promise automatic restoration.

Save, validate, and run

On Windows, Save workflow validates the unsaved definition and keeps errors in the editor for correction. Set protected secrets, run preflight, and attach the workflow to the intended certificate. On Linux, use the versioned configuration transaction described in the reference: place the document in workflows[], select it with the certificate's workflow_id, preserve the configuration revision, validate, and apply. The example JSON documents are workflow entries, not complete Agent configurations.

certintel-agent --json workflows capabilities
certintel-agent --json workflows templates
certintel-agent workflows preflight tomcat-p12

Preflight checks what actions can inspect without performing installation; it is not proof of a successful live deployment. Review results in My modular workflows, Jobs, and Activity. Renew now performs renewal and delivery; Retry installation reuses the issued certificate without another ACME order or DNS challenge. Repeated installation also reruns your custom steps.

Publishing ACME DNS TXT records

The Agent's DNS provider is part of native ACME DNS-01 issuance and renewal. It is not a general-purpose arbitrary TXT publishing action or script hook. You configure a scoped delegation; the Agent computes and manages each ACME challenge value automatically.

Add or replace a delegation

  1. Create a delegation in Manage → Delegated DNS-01 in CertIntel. Copy its record ID/username and one-time update secret.
  2. In Workflows → New certificate, enter the delegation on the DNS step. For an existing policy, use Manage workflow → DNS delegations → Add / replace delegation. Enter the record ID/username and protected secret. The advanced API base is the deployment's HTTPS delegated DNS API base, including /api/v1; it is not the CNAME destination or CA directory URL.
  3. Select Verify credentials. The Agent authenticates and retrieves the exact CNAME destination assigned to that credential. Use the displayed values, not a target copied from another delegation.
  4. At your authoritative DNS provider, create the displayed record:
_acme-challenge.app.example.com.  CNAME  <assigned-name>.dns01.certin.tel.
  1. Wait for the CNAME to be published by the authoritative nameservers and pass the Agent's check. A successful credential test alone does not establish DNS readiness. Use DNS only for Cloudflare and the trailing-dot convention required by your DNS provider.

On Linux, configure id, domain, api_base, and cname_target in delegations[] and save the secret separately with certintel-agent secret set dns DELEGATION-ID. This command also replaces only the protected key of an existing mapping. It prompts without echoing; --stdin is available for protected automation. Test mappings in the Windows management dialog after rotation. See Agent DNS setup and dashboard delegation management.

An apex name and its wildcard, such as example.com and *.example.com, share the base-domain delegation at _acme-challenge.example.com; do not create _acme-challenge.*.example.com. Other exact names need their configured mappings.

Automatic challenge lifecycle and ownership

For each authorization, the Agent authenticates the scoped credential, checks the expected CNAME, computes the ACME DNS-01 TXT digest, and merges its value into the delegation's existing set. It then checks authoritative TXT propagation before asking the CA to validate. API write success alone is insufficient. Once the authorization is terminal, it removes only its owned value, preserving other values. It uses deletion of the whole TXT set only when none remain.

The delegation holds at most two concurrent TXT values, allowing apex and wildcard validation together. A full set is rejected instead of evicting another active challenge. Use one issuing Agent host per delegation: local serialization does not coordinate replace-all API updates from multiple hosts. Do not share the update secret with unrelated issuers or delete an unknown challenge to make room.

After interrupted work, cleanup preserves challenges associated with resumable orders because the CA may still be validating them. Terminal work can resume owned cleanup after restart. An uncertain publication outcome requires reconciliation, not blind deletion. TXT values and delegation secrets are omitted from logs and progress details; diagnostics identify domains, phases, nameservers, attempts, and error categories instead.

Reading the job timeline

Actual entries depend on the CA's authorization state and your selected steps; reused authorization or Retry installation may skip DNS work. Cleanup can appear before final certificate issuance, as individual authorizations finish.

Entry or phase Meaning
Checking DNS delegation Confirming _acme-challenge.<domain> points to this credential's assigned destination.
Creating / created DNS TXT challenge record Publishing the owned challenge through the scoped API; does not yet mean DNS is ready.
Checking DNS propagation Looking for the expected TXT through DNS, with attempt count and elapsed time.
CA validation Asking/waiting for the CA to validate authorization; the CA performs its own DNS checks.
Issuance Finalizing/downloading and protecting the issued certificate locally; not proof that an application serves it.
Removing / removed DNS TXT challenge record Cleaning up only this operation's owned challenge value.
Installation / export Writing or installing the issued artifact using the selected plan or modular steps.
Service restart / reload Applying the configured service action; not by itself proof of HTTPS readiness.
Endpoint verification Inspecting the served certificate, comparing thumbprints, or running configured TCP/HTTP checks. Read each result to see which was tested.

DNS troubleshooting

The Agent prefers direct authoritative queries rather than OS/application answer caches. Public resolvers help discover authoritative servers. When public or authoritative DNS is unreachable, it can fall back to fresh wire queries to the device's configured DNS servers. Those recursive servers may still cache answers; reachable negative/conflicting authoritative answers cannot be overridden by fallback. TXT checks are spaced ten seconds apart, with at most 30 attempts and a five-minute propagation timeout. CNAME readiness also retries instead of failing on the first miss.

Symptom What to check
Incorrect CNAME target Copy the exact displayed owner and destination; check provider-added zone suffixes, trailing dots, proxying, and conflicting records at the owner. Replacing a delegation may require a new target.
Authentication failure Check that record ID and secret belong together, the delegation is active, and the HTTPS API base includes /api/v1. After rotation, replace the protected secret in the Agent.
Recursive resolver still shows old data Compare with authoritative answers. OS cache flushing cannot clear a remote recursive cache; wait for its cached positive or negative answer to expire.
Authoritative servers disagree Check every authoritative server for the domain and delegated target. Correct zone publication/replication; one updated server is not enough. Use the nameserver identified in Activity.
Propagation delay or timeout Check CNAME readiness and delegation health separately from successful TXT API publication. Allow DNS publication to finish, then retry retained work rather than repeatedly creating policies/orders.
TTL confusion TTL controls caching, not how quickly a provider publishes a zone. Lowering a TTL now does not expire an already cached answer early; negative caching can also delay visibility.
DNS servers unreachable Check the job's failing nameserver, outbound DNS routing/firewall rules, and device DNS settings. Permit the required UDP/TCP DNS traffic. Fallback is for unreachable DNS, not a way to bypass conflicting authoritative results.
Two TXT values already present Let the owning authorizations finish and their cleanup run. Confirm no second host uses the delegation; do not evict an active challenge.

Propagation failures retain the order, CSR, and key for safe retry. Inspect the job's DNS error category and timing without copying secrets or TXT values into support notes.