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

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

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

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

מגבלות

  • מכונות וירטואליות שמופעלים בהן מפתחות אבטחה מקבלות רק חיבורים ממפתחות SSH שמצורפים למפתחות האבטחה הפיזיים שרשומים בחשבון Google שלכם.
  • אי אפשר להשתמש ב-Cloud Shell כדי להתחבר למכונות וירטואליות שמופעל בהן מפתח אבטחה.
  • גם ה-VM שאליו מתחברים וגם תחנת העבודה שממנה מתחברים צריכים להשתמש בגרסה 8.2 ומעלה של OpenSSH, שתומכת בסוגי 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. בשדה Key, מזינים enable-oslogin.
    2. בשדה ערך, מזינים TRUE.
  4. לוחצים על Add item.

    1. בשדה Key (מפתח), מזינים 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

הפעלת מפתחות אבטחה במכונה וירטואלית אחת שמופעל בה 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. בשדה Key (מפתח), מזינים enable-oslogin.
    2. בשדה ערך, מזינים TRUE.
  5. לוחצים על Add item.

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

מה השלב הבא?