使用 SSH 密钥身份验证

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019 | TFS 2018

可以在 macOS、Linux 或 Windows 上通过 SSH 连接到 Git 存储库,以使用 HTTPS 身份验证安全连接。

重要

SSH URL 已更改,但旧的 SSH URL 将继续工作。 如果已设置 SSH,请将远程 URL 更新为新格式:

最新的 SSH URL 以 ssh.dev.azure.com 开头。 先前的 URL 使用 vs-ssh.visualstudio.com

  • 验证哪些远程库正在使用 SSH。 请改为在 shell 中运行 git remote -v 或使用 GUI 客户端。
  • 访问 Web 上的存储库并选择“克隆”。
  • 选择 SSH 并复制新的 SSH URL。
  • 在 shell 中,针对要更新的每个存储库的远程库运行 git remote set-url <remote name> <new SSH URL>。 或者,使用 GUI 客户端更新远程 URL。

SSH 密钥身份验证的工作原理

SSH 公钥身份验证使用生成的加密密钥的非对称对。 公钥与 Azure DevOps 共享,用于验证初始 SSH 连接。 私钥在系统上保持安全。

设置 SSH 密钥身份验证

以下步骤介绍了在以下平台上使用命令行(也称为 shell)配置 SSH 密钥身份验证:

注意

从 Visual Studio 2017 开始,可以使用 SSH 连接到 Azure DevOps Git 存储库。

提示

在 Windows 上,建议使用 Git 凭据管理器个人访问令牌

步骤 1:创建 SSH 密钥

注意

如果已在系统上创建了 RSA SSH 密钥,请跳过此步骤并配置 SSH 密钥。 若要验证这一点,请转到主目录并查看 .ssh 文件夹(在 Windows 上为 %UserProfile%\.ssh\,在带有 Git Bash 的 Linux、macOS 和 Windows 上为 ~/.ssh/)。 如果看到两个分别名为 id_rsaid_rsa.pub 的文件,请继续配置 SSH 密钥

若要使用基于密钥的身份验证,首先需要为客户端生成公钥/私钥对。 ssh-keygen.exe 用于生成密钥文件,可以指定 DSA、RSA、ECDSA 或 Ed25519 算法。 如果未指定算法,则使用 RSA。

注意

Azure DevOps 支持的唯一 SSH 密钥类型是 RSA。

若要使用 RSA 算法生成密钥文件,请从 PowerShell 或其他 shell(例如客户端上的 bash)运行以下命令:

ssh-keygen

命令的输出应显示以下输出(其中 username 替换为用户名):

Generating public/private rsa key pair.
Enter file in which to save the key (C:\Users\username/.ssh/id_rsa):

你可以按 Enter 来接受默认值,或指定要在其中生成密钥的路径和/或文件名。 此时,系统会提示你使用密码来加密你的私钥文件。 通行短语可以为空,但不建议这样做。 将密码与密钥文件一起使用来提供双因素身份验证。

Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in C:\Users\username/.ssh/id_rsa.
Your public key has been saved in C:\Users\username/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:FHK6WjcUkcfQjdorarzlak1Ob/x7AmqQmmx5ryYYV+8 username@LOCAL-HOSTNAME
The key's randomart image is:
+---[RSA 3072]----+
|      . ** o     |
|       +.o= .    |
|      . o+       |
|      .+. .      |
|     .ooS  .     |
|  . .oo.=.o      |
|   =.= O.= .     |
|  . B BoE + . .  |
|   . *+*o. .o+   |
+----[SHA256]-----+

现在,在指定的位置中有一个公共/专用 RSA 密钥对。 .pub 文件是公钥,没有扩展名的文件是私钥:

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        10/11/2022   6:29 PM           2610 id_rsa
-a----        10/11/2022   6:29 PM            578 id_rsa.pub

重要

切勿共享私钥的内容。 如果私钥已泄露,攻击者可以使用它来欺骗服务器认为连接来自你。 私钥文件等效于密码,应以相同的方式进行保护。

步骤 2:将公钥添加到 Azure DevOps

将上一步中生成的公钥与用户 ID 相关联。

注意

对于你有权访问且想要对其使用 SSH 的每个组织,必须重复此操作。

  1. 浏览到 Web 门户,并选择用户界面右上角的头像旁边的图标来打开安全设置。 在显示的菜单中选择“SSH 公钥”。

    Screenshot that shows the SSH public keys menu item and the user avatar selected in Azure DevOps.

  2. 选择“+ 新建密钥”。

    Screenshot showing access to Security Configuration in Azure DevOps.

  3. 将生成的公钥(例如 id_rsa.pub)的内容复制到“公钥数据”字段中。

    重要

    不要在“密钥数据”字段中添加空格或换行符,它们可能会导致 Azure DevOps 使用无效的公钥。 粘贴密钥时,通常会在末尾添加换行符。 如果出现此换行符,请务必将其删除。

    Screenshot showing configuring a Public Key in Azure DevOps.

  4. 为密钥提供一个有用的说明(此说明将显示在配置文件的“SSH 公钥”页上),方便在以后记起密码。 选择“保存”以存储公钥。 密钥一旦保存就无法更改。 可以删除密钥,也可以为另一个密钥创建新条目。 可以添加到用户配置文件的密钥数没有限制。 另请注意,存储在 Azure DevOps 中的 SSH 密钥一年后过期。 如果密钥过期,可以上传新密钥或同一密钥,以继续通过 SSH 访问 Azure DevOps。

  5. 在概述页面上,会在包含服务器指纹的顶部显示一个注释。 请记下它们,因为在首次通过 SSH 连接到 Azure DevOps 时需要使用它们。

    Screenshot of accessing security configuration in Azure DevOps Services.

  6. 通过运行以下命令来测试连接:

    ssh -T git@ssh.dev.azure.com
    

    如果这是第一次连接,应该会收到以下输出:

    The authenticity of host 'ssh.dev.azure.com (<IP>)' can't be established.
    RSA key fingerprint is SHA256:ohD8VZEXGWo6Ez8GSEJQ9WpafgLFsOfLOtGGQCQo6Og.
    This key is not known by any other names
    Are you sure you want to continue connecting (yes/no/[fingerprint])?
    

    将给定的指纹与上述提到的设置页上提供的指纹进行比较。 只在两者匹配时才继续!

    如果正确配置了所有内容,输出应如下所示:

    remote: Shell access is not supported.
    

    如果没有,请参阅有关问题和故障排除的部分。

步骤 2:将公钥添加到 Azure DevOps

将上一步中生成的公钥与用户 ID 相关联。

注意

对于你有权访问且想要将 SSH 用于的每个组织,必须重复此操作。

  1. 通过浏览到 Web 门户并选择用户界面右上角的头像来打开安全设置。 在显示的菜单中选择“安全性”。

    Screenshot showing User Profile access in Azure DevOps.

  2. 选择“+ 新建密钥”。

    Screenshot showing Security Configuration in Azure DevOps.

  3. 将生成的公钥(例如 id_rsa.pub)的内容复制到“公钥数据”字段中。

    注意

    可使用 $ cat ~/.ssh/id_rsa.pub 命令在终端中输出 id_rsa.pub 文件的内容,然后将其复制到剪贴板。 如果您的 SSH 公钥文件与示例代码不同,请修改文件名以匹配您当前的设置。 复制密钥时,请勿添加任何新的换行符或空格。 或者,你也可以找到隐藏的 .ssh 文件夹,在你首选的文本编辑器中打开该文件,并将其复制到剪贴板。

    Screenshot showing configuration of a Public Key in Azure DevOps.

    重要

    请勿在“密钥数据”字段中添加空格或换行符,它们可能会导致 Azure DevOps 使用无效的公钥。 粘贴密钥时,通常会在末尾添加一个新的换行符。 如果出现此换行符,请务必将其删除。

  4. 为密钥提供一个有用的说明(此说明将显示在配置文件的“SSH 公钥”页上),方便在以后记起密码。 选择“保存”以存储公钥。 密钥一旦保存就无法更改。 可以删除密钥,也可以为另一个密钥创建新条目。 可以添加到用户配置文件的密钥数没有限制。

  5. 在概述页面上,会在包含服务器指纹的顶部显示一个注释。 请记下它们,因为在首次通过 SSH 连接到 Azure DevOps 时需要使用它们。

    Screenshot showing where to locate server fingerprints in Azure DevOps Services.

  6. 通过运行以下命令来测试连接:

    ssh -T git@ssh.dev.azure.com
    

    如果这是第一次连接,应该会收到以下输出:

    The authenticity of host 'ssh.dev.azure.com (<IP>)' can't be established.
    RSA key fingerprint is SHA256:ohD8VZEXGWo6Ez8GSEJQ9WpafgLFsOfLOtGGQCQo6Og.
    This key is not known by any other names
    Are you sure you want to continue connecting (yes/no/[fingerprint])?
    

    将给定的指纹与上述提到的设置页上提供的指纹进行比较。 只在两者匹配时才继续!

    如果正确配置了所有内容,输出应如下所示:

    remote: Shell access is not supported.
    

    如果没有,请参阅有关问题和故障排除的部分。

步骤 3:通过 SSH 克隆 Git 存储库

注意

若要将 SSH 与以前通过 HTTPS 克隆的存储库配合使用,请参阅将远程库更新为 SSH

  1. 从 Web 门户复制 SSH 克隆 URL。 在此示例中,SSH 克隆 URL 用于组织中名为 fabrikam-fiber 的存储库,如 dev.azure.com 后面的 URL 第一部分所示。

    Screenshot showing Azure Repos SSH cloned URL

    注意

    使用 Azure DevOps Services 时,项目 URL 的格式为 dev.azure.com/{your organization}/{your project}。 但是,仍然支持以前引用 visualstudio.com 格式的格式。 有关详细信息,请参阅 Azure DevOps 简介 - 将现有组织切换为使用新的域名 URL

  2. 通过命令提示符运行 git clone

    git clone git@ssh.dev.azure.com:v3/fabrikam-fiber/FabrikamFiber/FabrikamFiber
    

    现在,系统应该会提示你输入 SSH 密钥的密码,然后才能继续,除非该密钥由 SSH 代理进行管理:

    Cloning into 'FabrikamFiber'...
    Enter passphrase for key '/c/Users/username/.ssh/id_rsa':
    remote: Azure Repos
    remote: Found 127 objects to send. (50 ms)
    Receiving objects: 100% (127/127), 56.67 KiB | 2.58 MiB/s, done.
    Resolving deltas: 100% (15/15), done.
    

    如果系统转而提示你验证指纹,请阅读步骤 2:再次将公钥添加到 Azure DevOps。 有关其他问题,请阅读有关问题和故障排除的部分。

提示

要充分利用 SSH,常见的方法是使用 SSH 代理来管理 SSH 密钥。 不过,设置代理不在本文讲解范围内。

问题和故障排除

答:你可能会看到两种不同的警告信息:

ssh-rsa is about to be deprecated and your request has been throttled. Please use rsa-sha2-256 or rsa-sha2-512 instead. Your session will continue automatically. For more details see https://devblogs.microsoft.com/devops/ssh-rsa-deprecation.

You’re using ssh-rsa that is about to be deprecated and your request has been blocked intentionally. Any SSH session using SSH-RSA is subject to brown out (failure during random time periods). Please use rsa-sha2-256 or rsa-sha2-512 instead. For more details see https://devblogs.microsoft.com/devops/ssh-rsa-deprecation.

你以前可能修改过 SSH 配置,以降低 Azure DevOps 的安全设置,方法是在 ~/.ssh/config%UserProfile%\.ssh\configWindows 上)文件中添加以下内容:

Host ssh.dev.azure.com vs-ssh.visualstudio.com
  HostkeyAlgorithms +ssh-rsa

请立即删除这些行,并确保允许 rsa-sha2-256 和/或 rsa-sha2-512

有关详细信息,请参阅博客文章

问:SSH 无法建立连接。 应采取何种操作?

答:你可能会遇到多种不同的问题:

  • 使用不支持的 SSH-RSA

    You’re using ssh-rsa that is unsupported. Please use rsa-sha2-256 or rsa-sha2-512 instead. For more details see https://devblogs.microsoft.com/devops/ssh-rsa-deprecation.
    

    你以前可能修改过 SSH 配置,以降低 Azure DevOps 的安全设置,方法是在 ~/.ssh/config%UserProfile%\.ssh\configWindows 上)文件中添加以下内容:

    Host ssh.dev.azure.com vs-ssh.visualstudio.com
       HostkeyAlgorithms +ssh-rsa
    

    请立即删除这些行,并确保允许 rsa-sha2-256 和/或 rsa-sha2-512

    有关详细信息,请参阅博客文章

  • 没有匹配的主机密钥

    博客文章所述,这种情况既不会发生在 Azure DevOps 服务上,也不会发生在最新的 Azure DevOps Server 版本上。

    Unable to negotiate with <IP> port 22: no matching host key type found. Their offer: ssh-rsa
    

    通过将以下内容添加到 ~/.ssh/config 文件(在 Windows 中为 %UserProfile%\.ssh\config 文件),修改 SSH 配置以降级 Azure DevOps 的安全设置:

    Host ssh.dev.azure.com vs-ssh.visualstudio.com
       HostkeyAlgorithms +ssh-rsa
    

    重要

    OpenSSH 在版本 8.2 中弃用了 ssh-rsa 公钥签名算法,并在版本 8.8 中默认禁用了该算法。

  • 没有匹配的 MAC

    Unable to negotiate with <IP> port 22: no matching MAC found. Their offer: hmac-sha2-256,hmac-sha2-512
    

    通过将以下内容添加到 ~/.ssh/config 文件(在 Windows 中为 %UserProfile%\.ssh\config 文件),修改 SSH 配置以降级 Azure DevOps 的安全设置:

    Host ssh.dev.azure.com vs-ssh.visualstudio.com
       MACs +hmac-sha2-512,+hmac-sha2-256
    
  • 没有匹配的密钥交换方法

    Unable to negotiate with <IP> 22: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha256
    

    通过将以下内容添加到 ~/.ssh/config 文件(在 Windows 中为 %UserProfile%\.ssh\config 文件),修改 SSH 配置以降级 Azure DevOps 的安全设置:

    Host ssh.dev.azure.com vs-ssh.visualstudio.com
       KexAlgorithms +diffie-hellman-group-exchange-sha256,+diffie-hellman-group14-sha1,+diffie-hellman-group1-sha1
    

    重要

    在 OpenSSH 版本 6.9 中和版本 8.2diffie-hellman-group14-sha1 中,密钥交换算法 diffie-hellman-group1-sha1 默认处于禁用状态。

提示

对于 Azure DevOps Server 和 TFS 的自承载实例,请使用 Host 行中的相应主机名,而不是 ssh.dev.azure.com vs-ssh.visualstudio.com

问:如何让 Git 记住我的密钥的密码?

答:可以为此使用 SSH 代理。 Linux、macOS 和 Windows(从 Windows 10 [内部版本 1809] 开始或通过将 Git for Windows 与 Git Bash 配合使用)均随 SSH 代理一起提供。 SSH 代理可用于缓存 SSH 密钥以供重复使用。 若要详细了解它的使用方式,请参阅 SSH 供应商的手册。

问:我使用 PuTTY 作为 SSH 客户端,并使用 PuTTYgen 生成了密钥。 是否可以将这些密钥用于 Azure DevOps Services?

答: 是的。 使用 PuTTYgen 加载私钥,转到“转换”菜单,然后选择“导出 OpenSSH 密钥”。 保存私钥文件,然后按照步骤设置非默认密钥。 直接从 PuTTYgen 窗口复制公钥,并粘贴到安全设置中的“密钥数据”字段中。

问:如何验证我上传的公钥是否与我的本地密钥相同?

答:可以使用命令行对公钥运行以下 ssh-keygen 命令来验证上传的公钥的指纹是否与配置文件中显示的指纹匹配。 如果不使用默认值,需要更改路径和公钥文件名。

ssh-keygen -l -E md5 -f ~/.ssh/id_rsa.pub

然后,可以将 MD5 签名与配置文件中的签名进行比较。 此检查非常适合以下情况:将密钥添加到 Azure DevOps 时遇到连接问题或担心将公钥错误地粘贴到“密钥数据”字段中。

问:如何在当前使用 HTTPS 的存储库中开始使用 SSH?

答:需要更新 Git 中的 origin 远程 URL,以便从 HTTPS 切换到 SSH URL。 获得 SSH 克隆 URL 后,运行以下命令:

git remote set-url origin <SSH URL to your repository>

访问名为 origin 的远程库的 Git 命令现在将使用 SSH。

问:我在将 Git LFS 与 Azure DevOps Services 配合使用,并拉取 Git LFS 跟踪的文件时收到错误。

答:Azure DevOps Services 目前不支持通过 SSH 使用 LFS。 使用 HTTPS 连接到包含 Git LFS 跟踪文件的存储库。

问:如何使用非默认密钥位置,即不使用 ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub?

答:若要使用并非存储在默认位置的密钥,请执行以下两个任务:

  1. 密钥必须位于只有你可以读取或编辑的文件夹中。 如果文件夹的权限范围更广,SSH 不会使用这些密钥。

  2. 必须让 SSH 知道密钥的位置,例如,在 SSH 配置中将其指定为“标识”:

    Host ssh.dev.azure.com
      IdentityFile ~/.ssh/id_rsa_azure
      IdentitiesOnly yes
    

IdentitiesOnly yes 设置可确保 SSH 不会使用任何其他可用标识进行身份验证。 如果有多个标识可用,这一点尤其重要。

问:我有多个 SSH 密钥。 如何为 Azure DevOps 使用正确的 SSH 密钥?

答:通常,如果为 SSH 客户端配置多个密钥并连接到 SSH 服务器,客户端可以一次尝试一个密钥,直到服务器接受密钥。

但是,涉及到 SSH 协议以及 Git SSH URL 结构方式方面的技术原因,此操作不适用于 Azure DevOps。 Azure DevOps 将盲目接受客户端在身份验证期间提供的第一个密钥。 如果该密钥对于请求的存储库来说无效,请求将失败,且由于出现以下错误,不会尝试其他可用密钥:

remote: Public key authentication failed.
fatal: Could not read from remote repository.

对于 Azure DevOps,需要将 SSH 配置为显式使用特定密钥文件。 此过程与使用存储在非默认位置中的密钥时的过程相同。 只需指示 SSH 为 Azure DevOps 主机使用正确的 SSH 密钥即可。

问:如何对 Azure DevOps 上的不同组织使用不同的 SSH 密钥?

答:Azure DevOps 将盲目接受客户端在身份验证期间提供的第一个密钥。 如果该密钥对于请求的存储库来说无效,请求将失败并出现以下错误:

remote: Public key authentication failed.
fatal: Could not read from remote repository.

不过,可以修改 SSH 配置来区分不同的组织,并为每个组织提供不同的密钥。 为此,需要使用主机别名在 SSH 配置中创建单独的 Host 部分。 这是因为所有托管的 Azure DevOps URL 都具有相同的主机名 (ssh.dev.azure.com),因此在默认情况下,SSH 无法区分它们。

# The settings in each Host section are applied to any Git SSH remote URL with a
# matching hostname.
# Generally:
# * SSH uses the first matching line for each parameter name, e.g. if there's
#   multiple values for a parameter across multiple matching Host sections
# * "IdentitiesOnly yes" prevents keys cached in ssh-agent from being tried before
#   the IdentityFile values we explicitly set.
# * On Windows, ~/.ssh/your_private_key maps to %USERPROFILE%\.ssh\your_private_key,
#   e.g. C:\Users\<username>\.ssh\your_private_key.

# Imagine that we have the following two SSH URLs:
# * git@ssh.dev.azure.com:v3/Fabrikam/Project1/fab_repo
#   * For this, we want to use `fabrikamkey`, so we'll create `devops_fabrikam` as
#     a Host alias and tell SSH to use `fabrikamkey`.
# * git@ssh.dev.azure.com:v3/Contoso/Project2/con_repo
#   * For this, we want to use `contosokey`, so we'll create `devops_contoso` as
#     a Host alias and tell SSH to use `contosokey`.
#
# To set explicit keys for the two host aliases and to tell SSH to use the correct
# actual hostname, add the next two Host sections:
Host devops_fabrikam
  HostName ssh.dev.azure.com
  IdentityFile ~/.ssh/private_key_for_fabrikam
  IdentitiesOnly yes

Host devops_contoso
  HostName ssh.dev.azure.com
  IdentityFile ~/.ssh/private_key_for_contoso
  IdentitiesOnly yes

之后,不要使用实际 URL,而是通过分别将现有远程库中的主机名替换为 devops_fabrikamdevops_contoso,指示 Git 要将每个存储库的这些 URL 用作远程库。 例如,git@ssh.dev.azure.com:v3/Fabrikam/Project1/fab_repo 将称为 git@devops_fabrikam:v3/Fabrikam/Project1/fab_repo

问:我可能会收到哪些有关 SSH 密钥的通知?

答:每当向 Azure DevOps Services 注册新的 SSH 密钥时,你都会收到一封电子邮件通知,提醒你已将新的 SSH 密钥添加到帐户。

SSH notification example

问:如果认为其他人正在我的帐户上添加 SSH 密钥,我该怎么办?

答:如果收到正在注册 SSH 密钥的通知,但未手动将其上传到服务,则凭据可能已泄露。

下一步是调查密码是否已泄露。 更改密码始终是抵御此攻击途径建议的第一步。 如果你是 Microsoft Entra 用户,请与管理员联系,检查帐户是否从未知源/位置使用。

问:如果系统仍提示输入密码,并且 GIT_SSH_COMMAND="ssh -v" git fetch 显示 no mutual signature algorithmcorresponding algo not in PubkeyAcceptedAlgorithms,我该怎么办?

答:某些 Linux 发行版(例如 Fedora Linux)的加密策略需要比 Azure DevOps 支持的更强大的 SSH 签名算法(截至 2021 年 1 月)。 有一个开放功能请求可用于添加此支持。

可通过将以下代码添加到 SSH 配置 (~/.ssh/config) 来解决此问题:

Host ssh.dev.azure.com vs-ssh.visualstudio.com
  PubkeyAcceptedKeyTypes +ssh-rsa

提示

对于 Azure DevOps Server 和 TFS 的自承载实例,请使用 Host 行中的相应主机名,而不是 ssh.dev.azure.com vs-ssh.visualstudio.com