UiPath Documentation
cicd-integrations
2025.10
true

Guía del usuario de integraciones de CI/CD

Última actualización 5 de may. de 2026

Trusting custom certificates

Trusting custom certificates

The CLI accepts two optional parameters on every authenticated command that let you control how the Orchestrator and Identity Server TLS certificates are validated. They are most useful when connecting to UiPath Automation Suite or other Orchestrator deployments whose host certificate is signed by a private (internal, self-signed) Certificate Authority that the operating system does not already trust.

When neither parameter is provided, the CLI behaves exactly as before - it validates the server certificate against the operating system's trust store. The parameters described below are additive; they extend or constrain the trust decision but never weaken it.

The --ca-cert parameter

Adds one or more trusted root CA certificate files to the trust decision. Whatever the operating system already trusts continues to work; the certificates you provide here are accepted in addition to that.

Sintaxis:

--ca-cert <path>
--ca-cert <path1>,<path2>,...
--ca-cert <path1> --ca-cert <path2>
--ca-cert <path>
--ca-cert <path1>,<path2>,...
--ca-cert <path1> --ca-cert <path2>

Supported certificate file formats

FormatoTypical extensionsNotas
PEM.pem, .crt, .cerText format with -----BEGIN CERTIFICATE----- markers. A single file can contain multiple concatenated certificates (a "bundle").
DER.der, .cer, .crtBinary X.509. Single certificate per file.
PKCS#7.p7b, .p7cCert collection without private keys. The format Windows Certificate Manager (certmgr.msc) exports by default.

The format is auto-detected from file content, not from the extension - a .cer file containing a PEM block and a .cer file containing DER bytes are both handled.

Not supported: PFX/PKCS#12 (.pfx, .p12). These files carry private keys and are intended for client identity, not as trust anchors. The CLI rejects them with an explicit error.

Multiple certificates

You can provide as many roots as you need. The flag may be repeated, comma-separated, or both forms can be combined. The three commands below are equivalent:

--ca-cert "C:\certs\as-root.pem" --ca-cert "C:\certs\corp-root.pem"
--ca-cert "C:\certs\as-root.pem,C:\certs\corp-root.pem"
--ca-cert "C:\certs\bundle.pem"
--ca-cert "C:\certs\as-root.pem" --ca-cert "C:\certs\corp-root.pem"
--ca-cert "C:\certs\as-root.pem,C:\certs\corp-root.pem"
--ca-cert "C:\certs\bundle.pem"

In the third form, bundle.pem is a single PEM file containing both certificates concatenated.


The --pinnedpubkey parameter

Pins the server leaf certificate's public key to a specific SHA-256 hash. The format is curl-compatible: the literal string sha256// followed by the base64-encoded SHA-256 of the certificate's SubjectPublicKeyInfo.

Sintaxis:

--pinnedpubkey "sha256//<base64 hash>"
--pinnedpubkey "sha256//<base64 hash>"

The pin is checked in addition to standard certificate validation, not instead of it. The certificate must still chain to a trusted root and pass the hostname check; on top of that, its public key must match the pin. Both conditions are required - matching the curl behavior.

What pinning adds beyond chain validation

Chain validation alone says: "trust any cert signed by these CAs." The pin adds: "…but only if its public key matches this exact hash." Different threats are caught by each layer.

ThreatChain aloneChain + pin
Random attacker with no CA-issued certblockedblocked
Attacker with a cert from any CA your system already trusts (e.g., misissued or compromised public CA)acceptedblocked
Your own CA issues a new cert for the same hostname, reusing the same key (legitimate renewal)acceptedaccepted
Your own CA issues a new cert for the same hostname with a different key (re-keying or attack)acceptedblocked

When pinning is worth the operational cost:

  • Defense-in-depth on a publicly trusted server. If your Orchestrator uses a publicly issued certificate, chain validation accepts any cert any of the ~150 public CAs your operating system trusts decides to issue for that hostname. The pin narrows that down to the one cert you intend to accept.
  • You don't fully trust your own internal CA team. Pinning the leaf's public key narrows trust to the one cert you intend to accept rather than the entire CA's signing authority.

When pinning is overkill:

  • You're already using --ca-cert against a private CA you fully control. The chain anchor is the same root that signs the cluster's leaf, and there is no second CA in play, so pinning prevents a class of attack (rogue CA-issued cert) that cannot happen in your setup.

How to obtain the SHA-256 pin

The pin is the SHA-256 hash of the certificate's SubjectPublicKeyInfo (SPKI), base64-encoded, prefixed with sha256//. The SPKI is the part of an X.509 certificate that holds the public key together with its algorithm identifier - it is not the full certificate, and it is not just the raw modulus.

Pinning the SPKI rather than the full certificate has a useful property: if the server reissues its certificate with the same key (a renewal), the pin still matches. The pin only has to change when the server actually rotates to a new key pair.

You can compute the pin in three ways, depending on what you have access to.

From a certificate file (PEM, DER, or .cer)

PowerShell - works on Windows out of the box, no extra tools needed:

$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
    'C:\certs\orchestrator-leaf.cer')
$spki = $cert.PublicKey.ExportSubjectPublicKeyInfo()
$hash = [System.Security.Cryptography.SHA256]::HashData([byte[]]$spki)
"sha256//" + [Convert]::ToBase64String($hash)
$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
    'C:\certs\orchestrator-leaf.cer')
$spki = $cert.PublicKey.ExportSubjectPublicKeyInfo()
$hash = [System.Security.Cryptography.SHA256]::HashData([byte[]]$spki)
"sha256//" + [Convert]::ToBase64String($hash)

Salida de ejemplo:

sha256//5FAF491D9F7AC8274B1353B9E2E9317733033EFC22341ABAEA6466037D5123EE=
sha256//5FAF491D9F7AC8274B1353B9E2E9317733033EFC22341ABAEA6466037D5123EE=

OpenSSL - works on Linux, macOS, Windows with OpenSSL installed:

openssl x509 -in cert.pem -pubkey -noout |
  openssl pkey -pubin -outform der |
  openssl dgst -sha256 -binary |
  openssl base64
openssl x509 -in cert.pem -pubkey -noout |
  openssl pkey -pubin -outform der |
  openssl dgst -sha256 -binary |
  openssl base64

Then prepend sha256// to the resulting base64 string. If your file is in DER format (binary), add -inform der to the first command:

openssl x509 -in cert.der -inform der -pubkey -noout |
  openssl pkey -pubin -outform der |
  openssl dgst -sha256 -binary |
  openssl base64
openssl x509 -in cert.der -inform der -pubkey -noout |
  openssl pkey -pubin -outform der |
  openssl dgst -sha256 -binary |
  openssl base64

Directly from a live server

When you don't have the certificate file but the server is reachable, retrieve it through the TLS handshake itself.

OpenSSL:

HOST=orchestrator.your-cluster.internal
openssl s_client -servername $HOST -connect $HOST:443 < /dev/null 2>/dev/null |
  openssl x509 -pubkey -noout |
  openssl pkey -pubin -outform der |
  openssl dgst -sha256 -binary |
  openssl base64
HOST=orchestrator.your-cluster.internal
openssl s_client -servername $HOST -connect $HOST:443 < /dev/null 2>/dev/null |
  openssl x509 -pubkey -noout |
  openssl pkey -pubin -outform der |
  openssl dgst -sha256 -binary |
  openssl base64

PowerShell (no openssl required):

$h = 'orchestrator.your-cluster.internal'
$tcp = [Net.Sockets.TcpClient]::new($h, 443)
$cb  = [Net.Security.RemoteCertificateValidationCallback]{ param($s,$c,$ch,$e) $script:cert=$c; $true }
$ssl = [Net.Security.SslStream]::new($tcp.GetStream(), $false, $cb)
$ssl.AuthenticateAsClient($h); $ssl.Close(); $tcp.Close()
$cert2 = [Security.Cryptography.X509Certificates.X509Certificate2]::new($script:cert)
$spki  = $cert2.PublicKey.ExportSubjectPublicKeyInfo()
$hash  = [Security.Cryptography.SHA256]::HashData([byte[]]$spki)
"sha256//" + [Convert]::ToBase64String($hash)
$h = 'orchestrator.your-cluster.internal'
$tcp = [Net.Sockets.TcpClient]::new($h, 443)
$cb  = [Net.Security.RemoteCertificateValidationCallback]{ param($s,$c,$ch,$e) $script:cert=$c; $true }
$ssl = [Net.Security.SslStream]::new($tcp.GetStream(), $false, $cb)
$ssl.AuthenticateAsClient($h); $ssl.Close(); $tcp.Close()
$cert2 = [Security.Cryptography.X509Certificates.X509Certificate2]::new($script:cert)
$spki  = $cert2.PublicKey.ExportSubjectPublicKeyInfo()
$hash  = [Security.Cryptography.SHA256]::HashData([byte[]]$spki)
"sha256//" + [Convert]::ToBase64String($hash)

The advantage of fetching from the live server is that you don't have to find and export the certificate file - whatever the server presents on port 443 is exactly what the CLI will see and validate against.

From a certificate already in the Windows trust store

If the certificate is in your Certificate Manager (certmgr.msc or certlm.msc), you can grab it by thumbprint without exporting it to a file:

$cert = Get-ChildItem -Path Cert:\LocalMachine\Root |
    Where-Object { $_.Thumbprint -eq 'AD2C67543E1A2A347B13E4471FA945EC77566FC1' } |
    Select-Object -First 1
$spki = $cert.PublicKey.ExportSubjectPublicKeyInfo()
$hash = [System.Security.Cryptography.SHA256]::HashData([byte[]]$spki)
"sha256//" + [Convert]::ToBase64String($hash)
$cert = Get-ChildItem -Path Cert:\LocalMachine\Root |
    Where-Object { $_.Thumbprint -eq 'AD2C67543E1A2A347B13E4471FA945EC77566FC1' } |
    Select-Object -First 1
$spki = $cert.PublicKey.ExportSubjectPublicKeyInfo()
$hash = [System.Security.Cryptography.SHA256]::HashData([byte[]]$spki)
"sha256//" + [Convert]::ToBase64String($hash)

Replace the thumbprint with the one you see in certmgr.msc for the certificate you want to pin. Substitute Cert:\CurrentUser\Root, \My, or \CA if the certificate is in a different store.

Verifying the pin

Before using a freshly computed pin in CI, sanity-check it with curl:

curl -I --pinnedpubkey 'sha256//<base64>=' https://orchestrator.your-cluster.internal/
curl -I --pinnedpubkey 'sha256//<base64>=' https://orchestrator.your-cluster.internal/
  • If the connection succeeds (or fails for an unrelated reason like 401), the pin is correct.
  • If curl fails with SSL: public key does not match pinned public key, recompute - you most likely pinned a different cert than the one the server actually presents.

Combining the two parameters

--ca-cert and --pinnedpubkey compose. Each enabled check must pass independently for the connection to succeed.

--ca-cert provided--pinnedpubkey providedRequired to accept
NoNoSystem trust validates the server (current behavior)
NoServer validates against system trust or any provided root
NoSystem trust validates the server and leaf public key matches the pin
Trust path validates and leaf public key matches the pin

The hostname check is always performed against the leaf certificate's Subject Alternative Name (or Common Name if no SAN is present), independently of which other flags you set.


Scenarios

Connecting to UiPath Automation Suite

Automation Suite clusters generate their own self-signed UiPath AS Root CA certificate during installation. To validate the cluster's host certificate, export that root and pass it via --ca-cert.

uipcli solution upload-package "C:\Work\MySolution.1.0.0.zip" `
  -U "https://orchestrator.your-cluster.internal/" `
  -T "DefaultTenant" `
  -A "Default" `
  -I "<your application id>" `
  -S "<your application secret>" `
  --ca-cert "C:\certs\uipath-as-root.crt" `
  --traceLevel Information
uipcli solution upload-package "C:\Work\MySolution.1.0.0.zip" `
  -U "https://orchestrator.your-cluster.internal/" `
  -T "DefaultTenant" `
  -A "Default" `
  -I "<your application id>" `
  -S "<your application secret>" `
  --ca-cert "C:\certs\uipath-as-root.crt" `
  --traceLevel Information

CI/CD runner without permission to install certificates system-wide

CI/CD agents often run as non-administrator service accounts that cannot modify the operating system trust store. --ca-cert scopes the trust to the current CLI invocation only.

uipcli package deploy "./output/MyPackage.1.0.0.nupkg" "https://orchestrator.internal/" "DefaultTenant" `
  -A "Default" -I "$env:APP_ID" -S "$env:APP_SECRET" `
  -o "Production" `
  --ca-cert "$env:CI_WORKSPACE/certs/internal-root.pem"
uipcli package deploy "./output/MyPackage.1.0.0.nupkg" "https://orchestrator.internal/" "DefaultTenant" `
  -A "Default" -I "$env:APP_ID" -S "$env:APP_SECRET" `
  -o "Production" `
  --ca-cert "$env:CI_WORKSPACE/certs/internal-root.pem"

The agent only needs read access to the certificate file - no elevated privileges, no changes to machine state.

Multiple Orchestrator targets in a single pipeline

When a pipeline deploys to several Orchestrator instances signed by different internal CAs, supply each cluster's root in one go. The system trust store still applies, so public Orchestrators in the same pipeline keep working without further configuration.

uipcli package deploy "./pkg.nupkg" "https://orch-1.internal/" "Tenant1" `
  -A "Org" -I "<id>" -S "<secret>" -o "Folder" `
  --ca-cert "./certs/orch-1.pem,./certs/orch-2.pem"
uipcli package deploy "./pkg.nupkg" "https://orch-1.internal/" "Tenant1" `
  -A "Org" -I "<id>" -S "<secret>" -o "Folder" `
  --ca-cert "./certs/orch-1.pem,./certs/orch-2.pem"

Defense-in-depth on a publicly trusted server

Even when the server is signed by a public CA the operating system already trusts, you can pin the public key to detect a compromise of any CA in the system trust store. If a misissued certificate is presented for the same hostname, the pin rejects it even though chain validation would have passed.

uipcli job run MyProcess "https://cloud.uipath.com/" "Tenant" `
  -A "OrgName" -I "<id>" -S "<secret>" -o "Folder" `
  --pinnedpubkey "sha256//<base64 hash>"
uipcli job run MyProcess "https://cloud.uipath.com/" "Tenant" `
  -A "OrgName" -I "<id>" -S "<secret>" -o "Folder" `
  --pinnedpubkey "sha256//<base64 hash>"

Pinning behind a private CA

When the server uses a private CA, both flags are required. The pin alone does not bypass chain validation.

uipcli solution upload-package "MyPackage.1.0.0.zip" `
  -U "https://orchestrator.internal/" -T "Tenant" `
  -A "Org" -I "<id>" -S "<secret>" `
  --ca-cert "./certs/internal-root.pem" `
  --pinnedpubkey "sha256//<base64 hash>"
uipcli solution upload-package "MyPackage.1.0.0.zip" `
  -U "https://orchestrator.internal/" -T "Tenant" `
  -A "Org" -I "<id>" -S "<secret>" `
  --ca-cert "./certs/internal-root.pem" `
  --pinnedpubkey "sha256//<base64 hash>"

Pin durability across certificate rotation

The pin tracks the public key, not the certificate. When the server's certificate is renewed but its private key is reused, the SHA-256 of the SubjectPublicKeyInfo stays the same and your pin keeps working. When the server generates a new key pair, the pin breaks and you'll need to recompute and update it.

For Automation Suite specifically, certificate rotation behavior depends on the cluster's cert-manager configuration. Test once after the first rotation: if the recomputed pin matches the old one, you've confirmed the cluster reuses keys and the pin is durable; if it differs, expect to refresh the pin on every rotation.


Solución de problemas

--ca-cert file not found: ./certs/root.pem (resolved to /actual/cwd/certs/root.pem)

The relative path resolved against the current working directory and no file exists at that absolute path. Either pass an absolute path or ensure the CLI runs from the expected directory.

--ca-cert expects certificates only; '<path>' contains a private key block.

The PEM file you provided contains a private key block in addition to the certificate. Strip the key (it has no role as a trust anchor) and retry.

Could not parse '<path>' as a certificate (PEM/DER/PKCS#7 supported, PFX/PKCS#12 is not).

The file is most likely a PFX/PKCS#12. Re-export it without the private key, or convert it to PEM with openssl pkcs12 -in cert.pfx -nokeys -out cert.pem.

--pinnedpubkey must be a SHA-256 hash (32 bytes); got <N> bytes after base64-decoding.

The string after sha256// did not base64-decode to exactly 32 bytes. Recompute the pin using one of the recipes above.

Connection still fails with --pinnedpubkey set against an internal server

The pin alone does not bypass chain validation. Add --ca-cert <root> so the chain has a trust anchor.

¿Te ha resultado útil esta página?

Conectar

¿Necesita ayuda? Soporte

¿Quiere aprender? UiPath Academy

¿Tiene alguna pregunta? Foro de UiPath

Manténgase actualizado