透過 OS 登入功能啟用安全金鑰


本文件說明如何使用在 Google 帳戶中註冊的實體安全金鑰,連線至使用 OS 登入功能的虛擬機器 (VM) 執行個體。

實體安全性金鑰可用於產生私密安全殼層金鑰檔案,以便連線至 VM。當您使用 Google Cloud 控制台瀏覽器內 SSH 工具或 Google Cloud CLI 連線至使用安全性金鑰的 VM 時,OS Login 會擷取與安全性金鑰相關聯的私密安全殼層金鑰檔案,並為您設定安全殼層金鑰檔案。使用第三方工具進行連線時,您必須使用 OS Login API 擷取安全殼層金鑰資訊,並自行設定安全殼層金鑰檔案。

事前準備

  • 為 Google 帳戶新增安全金鑰
  • 設定 OS 登入
  • 如果尚未設定,請先設定驗證機制。驗證是指驗證身分,以便存取 Google Cloud 服務和 API 的程序。如要在本機開發環境中執行程式碼或範例,您可以選取下列任一選項,向 Compute Engine 進行驗證:

    Select the tab for how you plan to use the samples on this page:

    Console

    When you use the Google Cloud console to access Google Cloud services and APIs, you don't need to set up authentication.

    gcloud

    1. After installing the Google Cloud CLI, initialize it by running the following command:

      gcloud init

      If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

    2. Set a default region and zone.

    REST

    To use the REST API samples on this page in a local development environment, you use the credentials you provide to the gcloud CLI.

      After installing the Google Cloud CLI, initialize it by running the following command:

      gcloud init

      If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

    For more information, see Authenticate for using REST in the Google Cloud authentication documentation.

限制

  • 已啟用安全金鑰的 VM 僅接受已連結至 Google 帳戶中註冊的實體安全金鑰的 SSH 金鑰連線。
  • 您無法使用 Cloud Shell 連線至已啟用安全性金鑰的 VM。
  • 您要連線的 VM 和要連線的電腦工作站,都必須使用支援安全金鑰 SSH 類型的 OpenSSH 8.2 以上版本。下列 Compute Engine VM 作業系統支援安全性金鑰:

    • Debian 11 (或以上版本)
    • SUSE Linux Enterprise Server (SLES) 15 (或以上版本)
    • Ubuntu 20.04 LTS (或更新版本)
    • Container-Optimized OS 93 LTS (或更新版本)
    • Rocky Linux 9 (或更高版本)

    如要檢查環境是否支援安全金鑰,請執行下列指令:

    ssh -Q key | grep ^sk-
    

    如果指令未傳回任何輸出內容,表示環境不支援安全金鑰。

  • 您所連線工作站上的 SSH 用戶端必須支援安全性金鑰,並包含必要的程式庫,例如 libfido2

透過 OS 登入功能啟用安全金鑰

您可以為專案中所有使用 OS 登入功能的 VM 或單一 VM 啟用安全金鑰。

針對專案中所有啟用 OS 登入功能的 VM 啟用安全金鑰

如要在專案中,為所有使用 OS 登入功能的 VM 啟用安全金鑰,請使用 Google Cloud 控制台或 gcloud CLI。

主控台

如要為所有已啟用 OS 登入功能的 VM 啟用安全金鑰,請使用 Google Cloud 控制台,將專案中繼資料中的 enable-osloginenable-oslogin-sk 設為 TRUE

  1. 前往「中繼資料」頁面。

    前往「中繼資料」

  2. 按一下 [編輯]

  3. 按一下 [新增項目]。

    1. 在「Key」欄位中輸入 enable-oslogin
    2. 在「Value」欄位中輸入 TRUE
  4. 按一下 [新增項目]。

    1. 在「Key」欄位中輸入 enable-oslogin-sk
    2. 在「Value」欄位中輸入 TRUE
  5. 按一下 [儲存]

gcloud

如要為所有已啟用 OS 登入功能的 VM 啟用安全金鑰,請使用 gcloud compute project-info add-metadata 指令,在專案中繼資料中設定 enable-oslogin=TRUEenable-oslogin-sk=TRUE

gcloud compute project-info add-metadata \
    --metadata enable-oslogin=TRUE,enable-oslogin-sk=TRUE

在單一已啟用 OS 登入功能的 VM 上啟用安全金鑰

如要在使用 OS 登入功能的 VM 上啟用安全金鑰,請使用 Google Cloud 控制台或 gcloud CLI。

主控台

如要在單一 VM 上啟用安全性金鑰,請使用 Google Cloud 控制台,將 enable-osloginenable-oslogin-sk 設為執行個體中繼資料中的 TRUE

  1. 前往「VM instances」(VM 執行個體) 頁面。

    前往 VM 執行個體

  2. 按一下要啟用安全金鑰的 VM 名稱。

  3. 按一下 [編輯]

  4. 在「中繼資料」專區中,按一下「新增項目」

    1. 在「Key」欄位中輸入 enable-oslogin
    2. 在「Value」欄位中輸入 TRUE
  5. 按一下 [新增項目]。

    1. 在「Key」欄位中輸入 enable-oslogin-sk
    2. 在「Value」欄位中輸入 TRUE
  6. 按一下 [儲存]

gcloud

如要在單一 VM 上啟用安全金鑰,請使用 gcloud compute instances add-metadata 指令,在執行個體中繼資料中設定 enable-oslogin=TRUEenable-oslogin-sk=TRUE

gcloud compute instances add-metadata VM_NAME \
    --metadata enable-oslogin=TRUE,enable-oslogin-sk=TRUE

VM_NAME 替換為您的 VM 名稱。

使用安全金鑰連線至 VM

您可以使用 Google Cloud 控制台、gcloud CLI 或第三方工具,連線至使用安全性金鑰的 VM。如果您使用 Google Cloud 控制台或 gcloud CLI 連線至 VM,Compute Engine 會為您設定 SSH 金鑰。如果您使用第三方工具連線至 VM,則必須自行執行設定。

主控台

當您使用 Google Cloud 控制台的 SSH-in-browser 工具連線至 VM 時,SSH-in-browser 會擷取與安全性金鑰相關聯的私密金鑰。

如要連線至已啟用安全金鑰的 VM,請執行下列操作:

  1. 前往 Google Cloud 控制台的「VM instances」(VM 執行個體) 頁面

  2. 在 VM 清單中,按一下要連線的 VM 那一列的「SSH」

  3. 在系統提示時輕觸安全金鑰。

gcloud

當您使用 gcloud CLI 連線至 VM 時,gcloud CLI 會擷取與安全性金鑰相關聯的私密金鑰,並設定私密金鑰檔案。這項設定會持續存在,並套用至所有使用安全金鑰的 VM。

使用 gcloud beta compute ssh 指令連線至已啟用安全金鑰的 VM:

gcloud beta compute ssh VM_NAME

第三方工具

連線至已啟用安全金鑰的 VM 前,您必須擷取與安全金鑰相關聯的私密金鑰,並設定私密金鑰檔案。本範例使用 Python 用戶端程式庫執行設定。

您只需要在首次連線至 VM 時執行這項設定。這項設定會持續存在,並套用至專案中所有使用安全金鑰的 VM。

在工作站的終端機中執行下列操作:

  1. 如果尚未安裝 Python 適用的 Google 用戶端程式庫,請執行下列指令安裝:

    pip3 install google-api-python-client
    
  2. 儲存下列 Python 指令碼範例,這會擷取與安全金鑰相關聯的私密金鑰、設定私密金鑰檔案,並連線至 VM。

    import argparse
    import os
    import subprocess
    from typing import Optional
    
    import googleapiclient.discovery
    
    
    def write_ssh_key_files(security_keys: list[dict], directory: str) -> list[str]:
        """
        Store the SSH key files.
    
        Saves the SSH keys into files inside specified directory. Using the naming
        template of `google_sk_{i}`.
    
        Args:
            security_keys: list of dictionaries representing security keys retrieved
                from the OSLogin API.
            directory: path to directory in which the security keys will be stored.
    
        Returns:
            List of paths to the saved keys.
        """
        key_files = []
        for index, key in enumerate(security_keys):
            key_file = os.path.join(directory, f"google_sk_{index}")
            with open(key_file, "w") as f:
                f.write(key.get("privateKey"))
                os.chmod(key_file, 0o600)
                key_files.append(key_file)
        return key_files
    
    
    def ssh_command(key_files: list[str], username: str, ip_address: str) -> list[str]:
        """
        Construct the SSH command for a given IP address and key files.
    
        Args:
            key_files: SSH keys to be used for authentication.
            username: username used to authenticate.
            ip_address: the IP address or hostname of the remote system.
    
        Returns:
            SSH command as a list of strings.
        """
        command = ["ssh"]
        for key_file in key_files:
            command.extend(["-i", key_file])
        command.append(f"{username}@{ip_address}")
        return command
    
    
    def main(
        user_key: str, ip_address: str, dryrun: bool, directory: Optional[str] = None
    ) -> None:
        """
        Configure SSH key files and print SSH command.
    
        Args:
            user_key: name of the user you want to authenticate as. Usually an email address.
            ip_address: the IP address of the machine you want to connect to.
            dryrun: bool flag to do dry run, without connecting to the remote machine.
            directory: the directory to store SSH private keys.
        """
        directory = directory or os.path.join(os.path.expanduser("~"), ".ssh")
    
        # Create the OS Login API object.
        oslogin = googleapiclient.discovery.build("oslogin", "v1beta")
    
        # Retrieve security keys and OS Login username from a user's Google account.
        profile = (
            oslogin.users()
            .getLoginProfile(name=f"users/{user_key}", view="SECURITY_KEY")
            .execute()
        )
    
        if "posixAccounts" not in profile:
            print("You don't have a POSIX account configured.")
            print("Please make sure that you have enabled OS Login for your VM.")
            return
    
        username = profile.get("posixAccounts")[0].get("username")
    
        # Write the SSH private key files.
        security_keys = profile.get("securityKeys")
    
        if security_keys is None:
            print(
                "The account you are using to authenticate does not have any security keys assigned to it."
            )
            print(
                "Please check your Application Default Credentials "
                "(https://cloud.google.com/docs/authentication/application-default-credentials)."
            )
            print(
                "More info about using security keys: https://cloud.google.com/compute/docs/oslogin/security-keys"
            )
            return
    
        key_files = write_ssh_key_files(security_keys, directory)
    
        # Compose the SSH command.
        command = ssh_command(key_files, username, ip_address)
    
        if dryrun:
            # Print the SSH command.
            print(" ".join(command))
        else:
            # Connect to the IP address over SSH.
            subprocess.call(command)
    
    
    if __name__ == "__main__":
        parser = argparse.ArgumentParser(
            description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
        )
        parser.add_argument("--user_key", help="Your primary email address.")
        parser.add_argument(
            "--ip_address", help="The external IP address of the VM you want to connect to."
        )
        parser.add_argument("--directory", help="The directory to store SSH private keys.")
        parser.add_argument(
            "--dryrun",
            dest="dryrun",
            default=False,
            action="store_true",
            help="Turn off dryrun mode to execute the SSH command",
        )
        args = parser.parse_args()
    
        main(args.user_key, args.ip_address, args.dryrun, args.directory)
  3. 執行指令碼來設定金鑰,並視需要連線至 VM。

    python3 SCRIPT_NAME.py --user_key=USER_KEY --ip_address=IP_ADDRESS [--dryrun]
    

    更改下列內容:

    • SCRIPT_NAME:設定指令碼的名稱。
    • USER_KEY:您的主要電子郵件地址。
    • IP_ADDRESS:您要連線的 VM 的外部 IP 位址。
    • [--dryrun]:(選用) 新增 --dryrun 標記,即可在不連線至 VM 的情況下列印連線指令。如果未指定此旗標,指令碼會執行連線指令。

後續步驟