הפעלת מפתחות אבטחה באמצעות OS Login

במאמר הזה מוסבר איך להשתמש במפתחות אבטחה פיזיים שרשומים בחשבון Google כדי להתחבר למכונות וירטואליות (VM) שמשתמשות ב-OS Login.

מפתחות אבטחה פיזיים משמשים ליצירת קובצי מפתחות SSH פרטיים לצורך התחברות למכונות וירטואליות. כשמשתמשים בכלי Google Cloud SSH בדפדפן במסוף או ב-Google Cloud CLI כדי להתחבר למכונות וירטואליות באמצעות מפתחות אבטחה, השירות OS Login מאחזר את קובץ המפתח הפרטי של SSH שמשויך למפתח האבטחה ומגדיר את קובץ מפתח ה-SSH בשבילכם. כשמשתמשים בכלים של צד שלישי כדי להתחבר, צריך להשתמש ב-OS Login API כדי לאחזר את פרטי מפתח ה-SSH ולהגדיר את קובץ מפתח ה-SSH בעצמכם.

לפני שמתחילים

מגבלות

  • מכונות וירטואליות שמופעל בהן מפתח אבטחה מקבלות רק חיבורים ממפתחות SSH שמצורפים למפתחות האבטחה הפיזיים שרשומים בחשבון Google שלכם.
  • אי אפשר להשתמש ב-Cloud Shell כדי להתחבר למכונות וירטואליות שמופעל בהן מפתח אבטחה.
  • גם המכונה הווירטואלית שאליה מתחברים וגם תחנת העבודה שממנה מתחברים צריכות להשתמש בגרסה OpenSSH 8.2 ואילך שתומכת בסוגי SSH של מפתחות אבטחה. מערכות ההפעלה הבאות של מכונות וירטואליות ב-Compute Engine תומכות במפתחות אבטחה:

    • ‫Debian 11 (או גרסה מתקדמת יותר)
    • ‫SUSE Linux Enterprise Server‏ (SLES) 15 (או גרסה מתקדמת יותר)
    • ‫Ubuntu 20.04 LTS (או גרסה מאוחרת יותר)
    • ‫מערכת הפעלה שמותאמת לקונטיינרים 93 LTS (או גרסה מתקדמת יותר)
    • ‫Rocky Linux 9 (או גרסה מאוחרת יותר)

    כדי לבדוק אם הסביבה שלכם תומכת במפתחות אבטחה, מריצים את הפקודה הבאה:

    ssh -Q key | grep ^sk-
    

    אם הפקודה לא מחזירה פלט, הסביבה שלכם לא תומכת במפתחות אבטחה.

  • לקוח ה-SSH בתחנת העבודה שממנה מתחברים צריך לתמוך במפתחות אבטחה ולכלול את הספריות הנדרשות, כמו libfido2.

הפעלת מפתחות אבטחה באמצעות OS Login

אתם יכולים להפעיל את השימוש במפתחות אבטחה בכל המכונות הווירטואליות שמשתמשות ב-OS Login בפרויקט, או במכונות וירטואליות בודדות.

הפעלת מפתחות אבטחה בכל המכונות הווירטואליות שמופעל בהן OS Login בפרויקט

כדי להפעיל מפתחות אבטחה בכל המכונות הווירטואליות שמשתמשות ב-OS Login בפרויקט, משתמשים במסוףGoogle Cloud או ב-CLI של gcloud.

המסוף

כדי להפעיל מפתחות אבטחה בכל המכונות הווירטואליות שמופעל בהן OS Login, משתמשים במסוףGoogle Cloud כדי להגדיר את enable-oslogin ואת enable-oslogin-sk לערך TRUE במטא-נתונים של הפרויקט:

  1. עוברים לדף מטא-נתונים.

    מעבר אל Metadata

  2. לוחצים על Edit.

  3. לוחצים על Add item.

    1. בשדה מפתח, מזינים enable-oslogin.
    2. בשדה ערך, מזינים TRUE.
  4. לוחצים על Add item.

    1. בשדה מפתח, מזינים enable-oslogin-sk.
    2. בשדה ערך, מזינים TRUE.
  5. לוחצים על Save.

gcloud

כדי להפעיל מפתחות אבטחה בכל המכונות הווירטואליות שמופעל בהן OS Login, משתמשים בפקודה gcloud compute project-info add-metadata כדי להגדיר את enable-oslogin=TRUE ואת enable-oslogin-sk=TRUE במטא-נתונים של הפרויקט:

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

הפעלת מפתחות אבטחה במכונת VM אחת שמופעל בה OS Login

כדי להפעיל מפתחות אבטחה במכונה וירטואלית שמשתמשת ב-OS Login, משתמשים במסוףGoogle Cloud או ב-CLI של gcloud.

המסוף

כדי להפעיל מפתחות אבטחה במכונה וירטואלית אחת, משתמשים במסוף Google Cloud כדי להגדיר את enable-oslogin ואת enable-oslogin-sk לערך TRUE במטא-נתונים של המכונה:

  1. נכנסים לדף VM instances.

    כניסה לדף VM instances

  2. לוחצים על שם המכונה הווירטואלית שרוצים להפעיל בה מפתחות אבטחה.

  3. לוחצים על Edit.

  4. בקטע מטא נתונים, לוחצים על הוספת פריט.

    1. בשדה מפתח, מזינים enable-oslogin.
    2. בשדה ערך, מזינים TRUE.
  5. לוחצים על Add item.

    1. בשדה מפתח, מזינים enable-oslogin-sk.
    2. בשדה ערך, מזינים TRUE.
  6. לוחצים על Save.

gcloud

כדי להפעיל מפתחות אבטחה במכונה וירטואלית אחת, משתמשים בפקודה gcloud compute instances add-metadata כדי להגדיר את enable-oslogin=TRUE ואת enable-oslogin-sk=TRUE במטא-נתונים של המכונה:

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

מחליפים את VM_NAME בשם של המכונה הווירטואלית.

התחברות למכונה וירטואלית באמצעות מפתח אבטחה

אפשר להתחבר למכונה וירטואלית שמשתמשת במפתחות אבטחה באמצעות המסוף Google Cloud , ה-CLI של gcloud או כלים של צד שלישי. אם מתחברים למכונות וירטואליות באמצעות מסוף Google Cloud או ה-CLI של gcloud, מערכת Compute Engine מגדירה את מפתח ה-SSH בשבילכם. אם אתם מתחברים למכונות וירטואליות באמצעות כלים של צד שלישי, אתם צריכים לבצע את ההגדרה בעצמכם.

המסוף

כשמתחברים למכונות וירטואליות באמצעות הכלי SSH בדפדפן של Google Cloud המסוף, הכלי מאחזר את המפתחות הפרטיים שמשויכים למפתחות האבטחה שלכם.

כדי להתחבר למכונה וירטואלית שמופעלים בה מפתחות אבטחה:

  1. נכנסים לדף VM instances במסוף Google Cloud .

  2. ברשימת המכונות הווירטואליות, לוחצים על SSH בשורה של המכונה שרוצים להתחבר אליה.

  3. כשתתבקשו, געו במפתח האבטחה.

gcloud

כשמתחברים למכונות וירטואליות באמצעות ה-CLI של gcloud, ה-CLI של gcloud מאחזר את המפתחות הפרטיים שמשויכים למפתחות האבטחה שלכם ומגדיר את קובצי המפתחות הפרטיים. ההגדרה הזו נשמרת וחלה על כל המכונות הווירטואליות שמשתמשות במפתחות אבטחה.

משתמשים בפקודה gcloud beta compute ssh כדי להתחבר למכונה וירטואלית שמופעלים בה מפתחות אבטחה:

gcloud beta compute ssh VM_NAME

כלי צד שלישי

לפני שמתחברים למכונה וירטואלית שמופעלים בה מפתחות אבטחה, צריך לאחזר את המפתחות הפרטיים שמשויכים למפתחות האבטחה ולהגדיר את קובצי המפתחות הפרטיים. בדוגמה הזו נעשה שימוש בספריית הלקוח של Python כדי לבצע את ההגדרה.

צריך לבצע את ההגדרה הזו רק בפעם הראשונה שמתחברים למכונה וירטואלית. ההגדרה נשמרת ומוחלת על כל המכונות הווירטואליות שמשתמשות במפתחות אבטחה בפרויקט.

בטרמינל בתחנת העבודה, מבצעים את הפעולות הבאות:

  1. אם עדיין לא התקנתם את ספריית הלקוח של Google ל-Python, מריצים את הפקודה הבאה כדי להתקין אותה:

    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: כתובת ה-IP החיצונית של המכונה הווירטואלית שאליה אתם מתחברים.
    • [--dryrun]: (אופציונלי) מוסיפים את הדגל --dryrun כדי להדפיס את פקודת החיבור בלי להתחבר למכונה הווירטואלית. אם לא מציינים את הדגל הזה, הסקריפט מריץ את פקודת החיבור.

מה השלב הבא?