Connecting Applications to Instances Using SSH

If you use Service Accounts on your instances to run automated tasks and interact with other Google Cloud Platform APIs, that service account might also require SSH access to other Compute Engine instances. This tutorial demonstrates how to configure applications to access your instances over SSH connections. The sample application in this tutorial uses a service account and OS Login for SSH key management.

To skip the exercise and view the full code sample, visit the GoogleCloudPlatform/python-docs-samples GitHub page.


The tutorial teaches you how to achieve the following objectives:

  • Create a service account and configure it to provide OS Login SSH access for applications that connect to your instances.
  • Create an instance that is associated with your service account.
  • Configure the sample application on your instance to use the service account for managing its own SSH keys and establishing SSH connections.
  • Run the application on an instance where the service account is associated.
  • Run the application outside of a Compute Engine where you must provide the service account key manually and specify additional SSH parameters.


This tutorial uses billable components of Cloud Platform including Compute Engine.

New Cloud Platform users might be eligible for a free trial.

Before you begin

  1. Sign in to your Google Account.

    If you don't already have one, sign up for a new account.

  2. Select or create a GCP project.

    Go to the project selector page

  3. Make sure that billing is enabled for your Google Cloud Platform project. Learn how to enable billing.

  4. Your user account must have permission to create, delete, and modify several Compute Engine resources. This tutorial assumes that you have the following IAM roles for your project:
    • compute.instanceAdmin.v1
    • compute.networkAdmin
    • compute.osAdminLogin
    • iam.serviceAccountAdmin
    • iam.serviceAccountKeyAdmin
    • iam.serviceAccountUser
  5. This tutorial assumes that you are using Cloud Shell to run gcloud commands.

Create and configure the service account and the example instances

This tutorial uses a service account and two instances to demonstrate how your applications can run SSH commands on remote instances.

Use the following commands to configure the test environment:

  1. Open Cloud Shell in the console:

    Open Cloud Shell

  2. Export an environment variable to set your project ID for future commands:

    export PROJECT_ID='[PROJECT_ID]'
  3. Create a new service account in your project. For this example, create a service account named ssh-account:

    gcloud iam service-accounts create ssh-account --project $PROJECT_ID \
       --display-name "ssh-account"
  4. Create a temporary network named ssh-example to use just for this example:

    gcloud compute networks create ssh-example --project $PROJECT_ID
  5. Create create a firewall rule that allows all SSH connections to instances on the ssh-example network:

    gcloud compute firewall-rules create ssh-all --project $PROJECT_ID \
       --network ssh-example --allow tcp:22
  6. Create an instance in us-central1-f named target. This instance serves as the remote instance that your service account will connect to over SSH. The instance must have OS Login enabled either at the project level or at the instance level. This example demonstrates how to use the --metadata flag to enable OS Login on this specific instance. Include the --no-service-account and --no-scopes flags because this instance does not need to run any API requests for this specific example:

    gcloud compute instances create target --project $PROJECT_ID \
       --zone us-central1-f --network ssh-example \
       --no-service-account --no-scopes \
       --machine-type f1-micro --metadata=enable-oslogin=TRUE
  7. Grant the compute.osAdminLogin IAM role to the service account so it can establish SSH connections specifically to the instance named target. The compute.osAdminLogin role also grants your service account superuser privileges on the instance. Although you could grant this role at the project level so that it applies to all instances in your project, grant the role specifically at the instance level to keep permissions limited in this example:

    gcloud compute instances add-iam-policy-binding target \
       --project $PROJECT_ID --zone us-central1-f \
       --member serviceAccount:ssh-account@$ \
       --role roles/compute.osAdminLogin
  8. Create an instance in us-central1-f named source. Associate the instance with the ssh-account service account. Also, specify the cloud-platform scope, which is required for the service account to execute API requests on this instance:

    gcloud compute instances create source \
       --project $PROJECT_ID --zone us-central1-f \
       --service-account ssh-account@$  \
       --scopes \
       --network ssh-example --machine-type f1-micro

The service account can now manage its own SSH key pairs and can use SSH to connect specifically to the target instance. Because the source instance is associated with the ssh-account service account that you created, the Python client library can use Application Default Credentials to authenticate as the service account and use the roles that you granted to that service account earlier.

Next, configure and run an application that can SSH from one instance to another instance.

Run an SSH application on an instance

When applications running on your instances require SSH access to other instances, you can manage the SSH key pairs for your service account and execute SSH commands programmatically. For this example, run a sample application using the following process:

  1. Connect to the source instance using the gcloud command-line tool:

    gcloud compute ssh source --project $PROJECT_ID --zone us-central1-f
  2. On the source instance, install pip and the Python client library:

    my-username@source:~$ sudo apt update && sudo apt install python-pip -y && pip install --upgrade google-api-python-client
  3. Download the sample application from GoogleCloudPlatform/python-docs-samples:

    my-username@source:~$ curl -O
  4. Run the sample application, which uses argparse to accept variables from the command line. In this example, instruct the application to install and run cowsay on the target instance. For this command, add your project ID manually:

    my-username@source:~$ python \
        --cmd 'sudo apt install cowsay -y && cowsay "It works!"' \
        --project [PROJECT_ID] --zone us-central1-f --instance target
      It works!
           \   ^__^
            \  (oo)\_______
               (__)\       )\/\
                   ||----w |
                   ||     ||

If the application runs correctly, you will receive the output from the cowsay application. You can modify the --cmd flag to include any command that you want. Alternatively, you can write your own application that imports and calls it directly.

Run exit to disconnect from the source instance and return to Cloud Shell.

Run an SSH application outside of Compute Engine

In the previous example, you ran the application on a Compute Engine instance where the Python client library could use Application Default Credentials to use the service account that was associated with the source instance. If you run this application outside of a Compute Engine instance, the client library cannot access the service account and its permissions unless you provide the service account key manually.

  1. Obtain the external IP address for the target instance that you created earlier in this tutorial. You can find this address either in the console on the Instances page or by running the following command from the gcloud command-line tool:

    gcloud compute instances describe target \
       --project $PROJECT_ID --zone us-central1-f
  2. Create a service account key for the ssh-account service account that you used in the previous example and download the key file to your local workstation.

  3. Copy the service account key to the system where you want to run this example.

  4. Open a terminal on the system where you want to run this example.

  5. Set the GOOGLE_APPLICATION_CREDENTIALS environment variable to point to the path where your service account key .json file is located. If your key is in your Downloads folder, you might set an environment variable like the following example:

    $ export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/key.json"
  6. Install the prerequisites on this system:

    1. Install Python and pip. On Debian-based systems, you can use apt to complete this step:

      $ sudo apt update && sudo apt install python python-pip -y
    2. Use pip to install the Python client library:

      $ pip install --upgrade google-api-python-client
  7. Download the sample application:

    $ curl -O
  8. Run the sample application. When you run the application outside of Compute Engine, the metadata server is not available, so you must specify the service account email manually. You must also specify the external IP address for the target instance that you obtained earlier.

    $ python \
        --cmd 'sudo apt install cowsay -y && cowsay "It works!"' \
        --account ssh-account@[PROJECT_ID] \
        --project [PROJECT_ID] --hostname [TARGET_EXTERNAL_IP]
      It works!
           \   ^__^
            \  (oo)\_______
               (__)\       )\/\
                   ||----w |
                   ||     ||

If the application runs correctly, you will receive the output from the cowsay application.

How the sample application works

The sample application operates using the following process:

  1. Initialize the OS Login API object.
  2. If you do not provide the service account email address manually, the application reads instance metadata to identify the service account that is associated with the instance. If you run this application outside of Compute Engine, you must provide the service account address manually.
  3. Call the create_ssh_key() method to generate a temporary SSH key for the service account on the instance where this example runs and add the public key to the service account with an expiration timer that you can specify.
  4. Call the getLoginProfile() method from the OS Login API to get the POSIX user name that the service account uses.
  5. Call the run_ssh() method to execute a remote SSH command as the service account.
  6. Print the response from the remote SSH command.
  7. Remove the temporary SSH key files.
  8. OS Login removes the public key files automatically when they pass the expiration time.
def main(cmd, project, instance=None, zone=None,
         oslogin=None, account=None, hostname=None):
    """Run a command on a remote system."""

    # Create the OS Login API object.
    oslogin = oslogin or'oslogin', 'v1')

    # Identify the service account ID if it is not already provided.
    account = account or requests.get(
    if not account.startswith('users/'):
        account = 'users/' + account

    # Create a new SSH key pair and associate it with the service account.
    private_key_file = create_ssh_key(oslogin, account)

    # Using the OS Login API, get the POSIX user name from the login profile
    # for the service account.
    profile = oslogin.users().getLoginProfile(name=account).execute()
    username = profile.get('posixAccounts')[0].get('username')

    # Create the hostname of the target instance using the instance name,
    # the zone where the instance is located, and the project that owns the
    # instance.
    hostname = hostname or '{instance}.{zone}.c.{project}.internal'.format(
        instance=instance, zone=zone, project=project)

    # Run a command on the remote instance over SSH.
    result = run_ssh(cmd, private_key_file, username, hostname)

    # Print the command line output from the remote instance.
    # Use .rstrip() rather than end='' for Python 2 compatability.
    for line in result:

    # Shred the private key and delete the pair.
    execute(['shred', private_key_file])
    execute(['rm', private_key_file])
    execute(['rm', private_key_file + '.pub'])

if __name__ == '__main__':

    parser = argparse.ArgumentParser(
        '--cmd', default='uname -a',
        help='The command to run on the remote instance.')
        help='Your Google Cloud project ID.')
        help='The zone where the target instance is locted.')
        help='The target instance for the ssh command.')
        help='The service account email.')
        help='The external IP address or hostname for the target instance.')
    args = parser.parse_args()

    main(args.cmd, args.project, instance=args.instance,,
         account=args.account, hostname=args.hostname)

The create_ssh_key() method generates a new SSH key pair. Then, the method calls users().importSshPublicKey() from the OS Login API to associate the public key with the service account. The users().importSshPublicKey() method also accepts an expiration value, which indicates how long the public key remains valid.

def create_ssh_key(oslogin, account, private_key_file=None, expire_time=300):
    """Generate an SSH key pair and apply it to the specified account."""
    private_key_file = private_key_file or '/tmp/key-' + str(uuid.uuid4())
    execute(['ssh-keygen', '-t', 'rsa', '-N', '', '-f', private_key_file])

    with open(private_key_file + '.pub', 'r') as original:
        public_key =

    # Expiration time is in microseconds.
    expiration = int((time.time() + expire_time) * 1000000)

    body = {
        'key': public_key,
        'expirationTimeUsec': expiration,
    oslogin.users().importSshPublicKey(parent=account, body=body).execute()
    return private_key_file

As a best practice, configure your service accounts to regularly generate new key pairs for themselves. In this example, the service account creates a new key pair for each SSH connection that it establishes, but you could modify this to run on a schedule that better meets the needs of your application.

The request body for users().importSshPublicKey() includes the expirationTimeUsec value, which tells OS Login when the key should expire. Each account can have only up to 32 KB of SSH key data, so it is best to configure your public SSH keys to expire shortly after your service account has completed its operations.

After your service account configures its SSH keys, it can execute remote commands. In this example, the application uses the run_ssh() method to execute a command on a remote instance and return the command output.

def run_ssh(cmd, private_key_file, username, hostname):
    """Run a command on a remote system."""
    ssh_command = [
        'ssh', '-i', private_key_file, '-o', 'StrictHostKeyChecking=no',
        '{username}@{hostname}'.format(username=username, hostname=hostname),
    ssh = subprocess.Popen(
        ssh_command, shell=False, stdout=subprocess.PIPE,
    result = ssh.stdout.readlines()
    return result if result else ssh.stderr.readlines()

Cleaning up

To avoid incurring charges to your Google Cloud Platform account for the resources used in this tutorial:

Use the following commands to clean up the resources in your test environment:

  1. Open Cloud Shell in the console:

    Open Cloud Shell

  2. Delete the instance named source:

    gcloud compute instances delete source \
       --project $PROJECT_ID --zone us-central1-f
  3. Delete the instance named target:

    gcloud compute instances delete target \
       --project $PROJECT_ID --zone us-central1-f
  4. Delete the ssh-account service account:

    gcloud iam service-accounts delete ssh-account --project $PROJECT_ID
  5. Delete the network named ssh-example:

    gcloud compute networks delete ssh-example --project $PROJECT_ID

What's next

  • Download and view the full code sample. The full sample includes a small example of using all of these methods together. Feel free to download it, change it, and run it to suit your needs.
  • Review the Compute Engine API reference and OS Login API reference to learn how to perform other tasks with these APIs.
  • Start creating your own applications!
Var denne side nyttig? Giv os en anmeldelse af den:

Send feedback om...

Compute Engine Documentation