Enable security keys with OS Login

This document describes how to use the physical security keys registered in your Google account to connect to virtual machine (VM) instances that use OS Login.

Before you begin

Limitations

  • VMs that have security keys enabled can't use the Google Cloud console SSH-in-browser tool.
  • VMs that have security keys enabled only accept connections from SSH keys that are attached to the physical security keys registered in your Google account.
  • Both the VM you're connecting to and the workstation you're connecting from must use a version of OpenSSH 8.2 or later that supports security key SSH types. The following Compute Engine VM operating systems support security keys:

    • Debian 11
    • SUSE Linux Enterprise Server (SLES) 15
    • Ubuntu 20.04 LTS (or later)
    • Container-Optimized OS 93 LTS (or later)

    To check if your environment supports security keys, run the following command:

    ssh -Q key | grep ^sk-
    

    If the command doesn't return any output, your environment doesn't support security keys.

Enable security keys with OS Login

You can enable use of security keys for all VMs that use OS Login in your project, or for single VMs.

Enable security keys for all OS Login-enabled VMs in a project

To enable security keys on all VMs that use OS Login in your project, use the Google Cloud console or the gcloud CLI.

Console

To enable security keys for all OS Login-enabled VMs, use the Google Cloud console to set enable-oslogin and enable-oslogin-sk to TRUE in project metadata:

  1. Go to the Metadata page.

    Go to Metadata

  2. Click Edit.

  3. Click Add item.

    1. In the Key field, enter enable-oslogin.
    2. In the Value field, enter TRUE.
  4. Click Add item.

    1. In the Key field, enter enable-oslogin-sk.
    2. In the Value field, enter TRUE.
  5. Click Save.

gcloud

To enable security keys for all OS Login-enabled VMs, use the gcloud compute project-info add-metadata command to set enable-oslogin=TRUE and enable-oslogin-sk=TRUE in project metadata:

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

Enable security keys on a single OS Login-enabled VM

To enable security keys on a VM that uses OS Login, use the Google Cloud console or the gcloud CLI.

Console

To enable security keys on a single VM, use the Google Cloud console to set enable-oslogin and enable-oslogin-sk to TRUE in instance metadata:

  1. Go to the VM instances page.

    Go to VM instances

  2. Click the name of the VM you want to enable security keys for.

  3. Click Edit.

  4. In the Metadata section, click Add item.

    1. In the Key field, enter enable-oslogin.
    2. In the Value field, enter TRUE.
  5. Click Add item.

    1. In the Key field, enter enable-oslogin-sk.
    2. In the Value field, enter TRUE.
  6. Click Save.

gcloud

To enable security keys on a single VM, use the gcloud compute instances add-metadata command to set enable-oslogin=TRUE and enable-oslogin-sk=TRUE in instance metadata:

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

Replace VM_NAME with the name of your VM.

Connect to a VM using a security key

You can connect to a VM that uses security keys using the gcloud CLI or third-party tools. If you connect to VMs using the gcloud CLI, the gcloud CLI configures your key for you. If you connect to VMs using third-party tools, you must perform the configuration yourself.

gcloud

When you connect to VMs using the gcloud CLI, the gcloud CLI retrieves the private keys associated with your security keys and configures the private key files. This configuration is persistent and applies to all VMs that use security keys.

Use the gcloud beta compute ssh command to connect to a VM that has security keys enabled:

gcloud beta compute ssh VM_NAME

Third-party tools

Before you connect to a VM that has security keys enabled, you must retrieve the private keys associated with your security keys and configure the private key files. This example uses the Python client library to perform the configuration.

You only need to perform this configuration the first time you connect to a VM. The configuration is persistent and applies to all VMs that use security keys in your project.

  1. Install the Google client library for Python, if you haven't already, by running the following command:

    pip3 install google-api-python-client
    
  2. Save the following sample Python script, which retrieves the private keys associated with your security keys, configures the private key files, and connects to the VM.

    import argparse
    import os
    import subprocess
    
    import googleapiclient.discovery
    
    
    def write_ssh_key_files(security_keys, directory):
        """Store the SSH key files."""
        key_files = []
        for index, key in enumerate(security_keys):
            key_file = os.path.join(directory, "google_sk_%s" % 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, username, ip_address):
        """Construct the SSH command for a given IP address and key files."""
        command = ["ssh"]
        for key_file in key_files:
            command.extend(["-i", key_file])
        command.append("{username}@{ip}".format(username=username, ip=ip_address))
        return command
    
    
    def main(user_key, ip_address, dryrun, directory=None):
        """Configure SSH key files and print SSH command."""
        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="users/{}".format(user_key), view="SECURITY_KEY")
            .execute()
        )
        security_keys = profile.get("securityKeys")
    
        if "posixAccounts" not in profile:
            print("You don't have a POSIX account configured.")
            return
    
        username = profile.get("posixAccounts")[0].get("username")
    
        # Write the SSH private key files.
        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. Run the script to configure your keys and optionally connect to the VM.

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

    Replace the following:

    • SCRIPT_NAME: the name of your configuration script.
    • USER_KEY: your primary email address.
    • IP_ADDRESS: the external IP address of the VM you're connecting to.
    • [--dryrun]: (Optional) add the --dryrun flag to print the connection command without connecting to the VM. If you don't specify this flag, the script runs the connection command.

What's next?