- 概述
- UiPath CLI
- Azure DevOps 扩展程序
- Jenkins 插件
CI/CD 集成用户指南
信任自定义证书
CLI 在每个经过身份验证的命令中接受两个可选参数,这些参数可让您控制如何验证 Orchestrator TLS 证书和 Identity Server 证书。当连接到主机证书由操作系统尚未信任的私有(内部、自签名)证书颁发机构签名的 UiPath Automation Suite 或其他 Orchestrator 部署时,它们非常有用。
如果两个参数均未提供,则 CLI 的行为与以前完全相同 - 它根据操作系统的信任存储区验证服务器证书。下面描述的参数是可添加的;但绝不会弱化信任决策。
--ca-cert参数
将一个或多个受信任的根 CA 证书文件添加到信任决策中。无论操作系统已信任什么内容,该内容都将继续运行;除此之外,还接受您在此处提供的证书。
语法
--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>
支持的证书文件格式
| 格式 | 典型扩展名 | 注意 |
|---|---|---|
| 质子交换模型 | .pem, .crt, .cer | 带有-----BEGIN CERTIFICATE-----标记的文本格式。单个文件可以包含多个级联证书(“捆绑包”)。 |
| DER | .der, .cer, .crt | 二进制 X.509。每个文件一个证书。 |
| PKCS#7 | .p7b, .p7c | 不使用私钥的证书集合。Windows 证书管理器 ( certmgr.msc ) 默认导出的格式。 |
格式是根据文件内容自动检测的,而不是根据扩展名。包含 PEM 块的.cer文件和包含 DER 字节的.cer文件都会处理。
不支持: PFX/PKCS#12(
.pfx、.p12)。这些文件带有私钥,仅用于识别客户端身份,而非作为信任锚点。CLI 会拒绝它们,并显示明确的错误。
多个证书
您可以根据需要提供任意数量的根。标志可以重复,也可以用逗号分隔,也可以结合使用这两种形式。以下三个命令等效:
--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"
在第三种形式中, bundle.pem是包含连接的两个证书的单个 PEM 文件。
--pinnedpubkey参数
将服务器叶证书的公钥固定到特定 SHA-256 哈希值。格式与 curl 兼容:文本字符串sha256// ,后跟证书主题公钥信息的 base64 编码的 SHA-256。
语法
--pinnedpubkey "sha256//<base64 hash>"
--pinnedpubkey "sha256//<base64 hash>"
除了标准证书验证外,系统还会检查 PIN 码,而不是替代证书验证。证书仍必须链接到受信任的根,并通过主机名检查;除此之外,其公钥必须与 PIN 码匹配。两个条件都是必需的 - 与 curl 行为匹配。
除了链验证之外,固定还添加了哪些要素
仅链验证会说: “信任由这些 CA 签名的任何证书。”固定会添加: “……但前提是其公钥与此确切哈希值匹配。”每层捕获的威胁不同。
| 威胁 | 单独的链式连接器 | 链 + 固定 |
|---|---|---|
| 没有 CA 颁发的证书的随机攻击者 | 已阻止 | 已阻止 |
| 攻击者拥有来自您的系统已经信任的任何 CA 的证书(例如,公共 CA 颁发错误或被入侵) | 已接受 | 已阻止 |
| 您自己的 CA 为同一主机名颁发新证书,重用同一密钥(合法续订) | 已接受 | 已接受 |
| 您自己的 CA 使用不同密钥为同一主机名颁发新证书(重新创建密钥或攻击) | 已接受 | 已阻止 |
当固定值得为之付出运营成本时:
- 在公众信任的服务器上进行纵深防御。如果 Orchestrator 使用公开颁发的证书,则链验证会接受操作系统决定为该主机名颁发的约 150 个公共 CA 中任何一个证书。PIN 码可将范围缩小到您打算接受的一个证书。
- 您未完全信任自己的内部 CA 团队。固定叶的公钥可将信任范围缩小到您打算接受的一个证书,而不是整个 CA 的签名授权机构。
当固定过度时:
- 您已在对您完全控制的私有 CA 使用
--ca-cert。链锚点是对集群叶子进行签名的同一根,并且没有第二个 CA,因此固定可以防止一类攻击(恶意 CA 颁发的证书),而这在您的设置中不会发生。
如何获取 SHA-256 PIN
PIN 码是证书主题公钥信息(SPKI) 的 SHA-256 哈希值(base64 编码),以sha256//为前缀。SPKI 是 X.509 证书的一部分,用于保存公钥及其算法标识符,它不是完整的证书,也不仅仅是原始模数。
固定 SPKI 而非完整证书有一个很有用的属性:如果服务器使用相同的密钥(续订)重新颁发其证书,则 PIN 码仍匹配。仅当服务器实际轮换到新的密钥对时, PIN 码才必须更改。
您可以通过三种方式计算 PIN,具体取决于您有权访问的内容。
From a certificate file (PEM, DER, or .cer)
PowerShell - Windows 上开箱即用,无需额外工具:
$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)
示例输出:
sha256//5FAF491D9F7AC8274B1353B9E2E9317733033EFC22341ABAEA6466037D5123EE=
sha256//5FAF491D9F7AC8274B1353B9E2E9317733033EFC22341ABAEA6466037D5123EE=
OpenSSL - 适用于已安装 OpenSSL 的 Linux、macOS、Windows:
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
然后将sha256//附加到生成的 Base64 字符串。如果文件为 DER 格式(二进制),请将-inform der添加到第一个命令中:
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
直接来自实时服务器
当您没有证书文件,但可以访问服务器时,请通过 TLS 握手本身进行检索。
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(无需 openssl):
$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)
从实时服务器获取的优点是,您不必查找和导出证书文件 - CLI 将看到并验证服务器在端口 443 上显示的所有内容。
来自 Windows 信任存储中的已有证书
如果证书在证书管理器中( certmgr.msc或certlm.msc ),您可以通过指纹获取证书,无需将其导出到文件:
$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)
将指纹替换为您在要固定的证书的certmgr.msc中看到的指纹。如果证书位于其他存储中,则替换为Cert:\CurrentUser\Root 、 \My或\CA 。
验证 PIN 码
在 CI 中使用新计算的 PIN 之前,请使用curl对其进行健全性检查:
curl -I --pinnedpubkey 'sha256//<base64>=' https://orchestrator.your-cluster.internal/
curl -I --pinnedpubkey 'sha256//<base64>=' https://orchestrator.your-cluster.internal/
- 如果连接成功(或由于不相关原因而失败,例如 401),则 PIN 是正确的。
- 如果
curl失败并显示SSL: public key does not match pinned public key,请重新计算 - 您很可能固定了与服务器实际提供的证书不同的证书。
结合使用两个参数
--ca-cert和--pinnedpubkey撰写。每项启用的检查必须独立通过,连接才能成功。
--ca-cert 已提供 | --pinnedpubkey 已提供 | 需要接受 |
|---|---|---|
| 否 | 否 | 系统信任验证服务器(当前行为) |
| 是 | 否 | 服务器会根据系统信任或任何提供的根进行验证 |
| 否 | 是 | 系统信任验证服务器和叶公钥与 PIN 码匹配 |
| 是 | 是 | 信任路径经过验证,并且叶公钥与 PIN 码匹配 |
始终针对叶证书的使用者替代名称(如果不存在 SAN,则针对通用名称)执行主机名检查,与您设置的其他标志无关。
场景
正在连接到 UiPath Automation Suite
Automation Suite 集群在安装过程中会生成各自的自签名UiPath AS Root CA证书。要验证集群的主机证书,请导出该根证书并通过--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 运行程序
CI/CD 代理通常以无法修改操作系统信任存储区的非管理员服务帐户运行。--ca-cert仅将信任的范围限定到当前 CLI 调用。
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"
智能体仅需要对证书文件的读取权限 - 无需提升权限,无需更改计算机状态。
单个管道中的多个 Orchestrator 目标
当管道部署到由不同内部 CA 签名的多个 Orchestrator 实例时,请一次性提供每个集群的根目录。系统信任存储仍然适用,因此同一管道中的公共 Orchestrator 可以继续工作,无需进一步配置。
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"
在公共受信任的服务器上进行深度防御
即使服务器由操作系统已信任的公共 CA 签名,您也可以固定公钥,以检测系统信任存储区中任何 CA 遭到的泄露。如果为同一主机名提供了错误颁发的证书,则即使链验证已通过,PIN 码也会拒绝该证书。
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>"
固定在私有 CA 后面
当服务器使用私有 CA 时,两个标志都是必需的。单独使用 PIN 码不会绕过链验证。
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 持久性
PIN 码跟踪公钥,而不是证书。当续订服务器证书但重用其私钥时,主题公钥信息的 SHA-256 保持不变,您的 PIN 码会继续工作。当服务器生成新的密钥对时,PIN 码将损坏,您需要重新计算并更新 PIN 码。
具体来说,对于 Automation Suite,证书轮换行为取决于集群的cert-manager配置。第一次轮换后测试一次:如果重新计算的 PIN 与旧的匹配,则您已确认集群重用密钥,并且 PIN 持久;如果不同,则固定会在每次旋转时刷新。
故障排除
--ca-cert file not found: ./certs/root.pem (resolved to /actual/cwd/certs/root.pem)
针对当前工作目录解析的相对路径,该绝对路径不存在文件。请传递绝对路径,或确保 CLI 从预期目录运行。
--ca-cert expects certificates only; '<path>' contains a private key block.
除证书外,您提供的 PEM 文件还包含私钥块。移除密钥(没有信任锚点)并重试。
Could not parse '<path>' as a certificate (PEM/DER/PKCS#7 supported, PFX/PKCS#12 is not).
该文件很可能是 PFX/PKCS#12。在不带私钥的情况下将其重新导出,或使用openssl pkcs12 -in cert.pfx -nokeys -out cert.pem将其转换为 PEM。
--pinnedpubkey must be a SHA-256 hash (32 bytes); got <N> bytes after base64-decoding.
sha256//之后的字符串未经过 base64 解码正好为 32 字节。使用上述方法之一重新计算 PIN。
Connection still fails with --pinnedpubkey set against an internal server
单独使用 PIN 码不会绕过链验证。添加--ca-cert <root> ,以便链具有信任锚点。
- 信任自定义证书
--ca-cert参数- 语法
- 支持的证书文件格式
- 多个证书
--pinnedpubkey参数- 语法
- 除了链验证之外,固定还添加了哪些要素
- 如何获取 SHA-256 PIN
- 结合使用两个参数
- 场景
- 正在连接到 UiPath Automation Suite
- 没有在系统范围内安装证书的权限的 CI/CD 运行程序
- 单个管道中的多个 Orchestrator 目标
- 在公共受信任的服务器上进行深度防御
- 固定在私有 CA 后面
- 证书轮换期间的 PIN 持久性
- 故障排除
--ca-cert file not found: ./certs/root.pem (resolved to /actual/cwd/certs/root.pem)--ca-cert expects certificates only; '<path>' contains a private key block.Could not parse '<path>' as a certificate (PEM/DER/PKCS#7 supported, PFX/PKCS#12 is not).--pinnedpubkey must be a SHA-256 hash (32 bytes); got <N> bytes after base64-decoding.- Connection still fails with
--pinnedpubkeyset against an internal server