AzureDevOps - 關於 SSH Key

16 November 2020 — Written by Sky Chang
#AzureDevOps#SSH#Git

前言

這幾天,遇到一個很有趣的問題,原本不想記錄的 XDDD,但覺得實在太有趣了,所以紀錄一下,不然大概過 21 天後,大概就忘記了 ( 誤 ),而且 Google 要查到我這種特殊的情況,可能也查不到 ( 但有類似的~ ),所以想說,那就把關於 SSH Public Key 的豆知識,簡單紀錄一下。

問題 SSH Public Key 重複

這個的問題起源在如下圖,我使用了 SkyS 帳號,登入 S Organization,想加入 SSH Public Key,但他出現了底下的錯誤。

An error occurred while adding the Macbook key: It may be a duplicate of another key. Please check the current list and try again.

2020 11 16 22 32 18

簡單的說,就是這個 Key 已經重複了,所以不能新增,請確認列表。但...等等啊,底下是空的啊啊啊啊!!!!!

好,基本上,這就是問題的起源。

來看看 Azure DevOps Public Key 的機制

首先,根據小弟查到的資料,在 Azure DevOps Service 的 Public Key 機制,不同帳號的 Public Key 是不可重複的,所以,其實網路上,有些人遇到上述的狀況。一個原因就是,很不幸的,剛好你的 Key 和別人的 Key 重複到 ( 買樂透都沒那麼準 ),另外一種狀況就是,自己可能用了別的帳號,並且將 SSH Public Key 填入,但忘記了 ( 這小弟自己倒是滿容易遇到的 XDD )。

所以,遇到這一個問題,最簡單的解法,重新產生一個 SSH Public Key,或是用盡荒蕪之力,想出以前是否有用這個 Key 註冊過。

好玩的問題

知道了這個限制後,小弟用了荒蕪之力,想到我有另外一個帳號 SkyM,因為已經在其他的 Organization 上 ( M Organization ) ,用了這個 Key,所以自然在 SkyA 的 S Organization ,不能註冊 SSH Public Key。

好,那我就用 SkyM 帳號,去登入 S Organization,並註冊 SSH Public Key,總可以了吧!!!

結果..... 使用 SkyM 帳號去 S Organization 還是不行啊!!!!!!!!! ( 翻 )

2020 11 16 22 43 59

真正的答案

後來發現,不行的原因,是因為,在 S Organization 的 SkyM 帳號,和 M Organization 的 SkyM 帳號,雖然 EMail 完全一樣,但實際上完全不一樣 Orz...

S Organization 的帳號如下。 2020 11 16 23 14 17

M Organization 的帳號如下。 2020 11 16 23 15 52

乍看下,都一樣,但其實 S Organization 有加入 Study4.TW 的 AAD

2020 11 16 23 19 46

所以~~

  • S Organization - SkyM 代表的是 Study4.TW 的 SkyM 帳號
  • M Organization - SkyM 代表的是 另外一個 AAD 的 SkyM 帳號

所以雖然 EMail 一樣,但本質是不一樣的,也因此在 S Organization 使用 SkyM 帳號來註冊 SSH Public Key,依舊是錯誤,因為會被 Azure DevOps Service 認為是不同的帳號。

另外,在延伸一下,小弟還有一個 P Organization,裡面也有 SkyM 帳號,而這時 M Organization - SkyM 和 P Organization - SkyM 都是可以正常重複註冊 SSH Public Key 的,但其實 M Organization 也是有加入 AAD,而 P Organization 沒有加入 AAD,為什麼可以 ??

原因是因為 P Organization 因為沒有加入 AAD,所以等同於 M Organization 的 SkyM,因為都是同一個 ( 都是 AAD 原生的 ),而 S Organization 的 Study4.TW AAD 為了要讓 SkyM 加入,但又不是同一個 AAD,所以 SkyM 其實不是原生的 AAD 加入進去,而是以 Study4.TW 來賓的身份加入,也因此形成了不一樣的結果。

所以~

  • S Organization - SkyM 代表的是 Study4.TW 的 SkyM 帳號 ( 為 Study4.TW 的來賓帳號 )
  • M Organization - SkyM 代表的是 另外一個 AAD 的 SkyM 帳號 ( 原生的 AAD 帳號 )
  • P Organization - SkyM 此組織沒加入 AAD,所以直接使用原生的 AAD SkyM 帳號 ( 原生的 AAD 帳號 )

但是,以上的情境,目前測試下來,有一個例外...

那就是原生的 Microsoft Account ... ( Hotmail , livemail 等....),目前測試的情況下,若遇到 MSA 帳號,這個 MSA 帳號無論加到哪個 AAD 裡面,還是都可以加入 SSH Public Key,這是滿特別的現象...

Note : 不要想說刪掉 SSH Public Key 就可以重複使用喔 XDDD,就算已經刪掉,還是不能和那個被刪掉的重複~~

Note : 我有用 REST API 去取得 originId,的確,在 SkyM 的帳號下, M , P Organization 的 ID 是一樣的,而 S Organization 則不同,但 MSA 情境下,originId 雖然全部不同,但還是可以新增,或許有什麼沒猜想到的邏輯吧。

解法

當然,還是有解法。那就是產生不同的 SSH Public Key,來對應不同的 Organization。

我們可以在 SSH Public Key 的目錄底下 ( 通常為 .ssh 目錄底下 ) 加入 config 檔案,內容如下:

這邊利用了別名的方式來處理,分別為

  • devopsfabrikam 對應到 ~/.ssh/privatekeyforfabrikam
  • devopscontoso 對應到 ~/.ssh/privatekeyforcontoso

但因為對於 Azure DevOps Service 下,位置都是一樣 ( ssh.dev.azure.com ),所以 HostName 不變。 但其實因為 SSH Public Key 切開了,所以就可以分別用到不同的 Organization 底下。

不過這個做法有一個壞處,就是 Git Remote 的位置,要改成上述的別名。

  • git@devopsfabrikam:v3/Fabrikam/Project1/fabrepo
  • git@devopscontoso:v3/Contoso/Project2/conrepo

不過,至少也是官方文件的標準解法。

# 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.

# Most common scenario: to use the same key across all hosted Azure DevOps
# organizations, add a Host entry like this:
Host ssh.dev.azure.com
  IdentityFile ~/.ssh/id_rsa
  IdentitiesOnly yes

# This model will also work if you still use the older SSH URLs with a
# hostname of vs-ssh.visualstudio.com:
Host vs-ssh.visualstudio.com
  IdentityFile ~/.ssh/id_rsa
  IdentitiesOnly yes

# Less common scenario: if you need different keys for different organizations,
# you'll need to use host aliases to create separate Host sections.
# This is because all hosted Azure DevOps URLs have the same hostname
# (ssh.dev.azure.com), so SSH has no way to distinguish them by default.
#
# 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
#
# Then, instead of using the real URLs, tell Git you want to use these URLs:
# * git@devops_fabrikam:v3/Fabrikam/Project1/fab_repo
# * git@devops_contoso:v3/Contoso/Project2/con_repo
#

# At the end of the file, you can put global defaults for other SSH hosts you
# may connect to.  Note that "*" also matches any hosts that match the sections
# above, and remember that SSH uses the first matching line for each parameter name.
Host *

後記

滿有意思的一個問題,其實開始找問題的時候,一直圍繞在,為什麼不能使用,當下也認定了,可能是因為就算帳號不同,Key 可能也不能相同的錯誤認真,後來看了 config 裡面的 to use the same key across all hosted Azure DevOps organizations, add a Host entry like this: 才重新思考,是不是有哪個細節錯了,所以有了這篇文章的產生。但畢竟這是實驗出來的結果,小弟是沒找到任何的文件敘述,也沒辦法看 Source Code,所以這邊就給大家一個參考方向... ( 或許文章還是錯的呢 QQ ),但至少目前從這個方向,是解決了小弟的問題,或許有一日,遇到 Azure DevOps 的工程師,到時候再問問看,有沒有正確解答 XDDD

總之,結案!! 謝謝大家~~

參考資料

Sky & Study4.TW