Your applications can use Service Accounts to run automated tasks and interact with other Google Cloud APIs. Allowing your applications to manage their own SSH keys and connect to instances can be useful for automating system management processes. This tutorial shows how to configure apps to access your instances over SSH connections. The sample app in this tutorial uses a service account and OS Login for SSH key management.
All code used in this tutorial is hosted on the GoogleCloudPlatform/python-docs-samples GitHub page.
Objectives
The tutorial covers the following tasks:
- Create a service account and configure it to provide OS Login SSH access for apps that connect to your instances.
- Create an instance that is associated with your service account.
- Configure the sample app on your instance to use the service account for managing its own SSH keys and establishing SSH connections.
- Run the app on an instance where the service account is associated.
- Run the app outside of a Compute Engine where you must provide the service account key manually and specify additional SSH parameters.
Costs
This tutorial uses billable components of Google Cloud including Compute Engine.
New Google Cloud users might be eligible for a free trial.Before you begin
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud Console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Cloud project. Learn how to confirm that billing is enabled for your project.
-
On your personal user account, obtain the following
IAM roles for your project:
compute.instanceAdmin.v1
compute.networkAdmin
compute.osAdminLogin
iam.serviceAccountAdmin
iam.serviceAccountKeyAdmin
iam.serviceAccountUser
-
Learn how to use
Cloud Shell
to run
gcloud
command-line tool commands.
Create and configure the service account and the example instances
Create a service account and two instances to use for this tutorial. You use the service account to grant SSH access to your application, and that application will connect from one instance to the other over SSH.
Use the following steps to configure the test environment:
In the Google Cloud Console, open Cloud Shell.
Export an environment variable to set your project ID for future commands:
export PROJECT_ID='[PROJECT_ID]'
Create a new service account named
ssh-account
:gcloud iam service-accounts create ssh-account --project $PROJECT_ID \ --display-name "ssh-account"
Create a network named
ssh-example
to use for this tutorial:gcloud compute networks create ssh-example --project $PROJECT_ID
Create a firewall rule that enables 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
Create an instance in
us-central1-f
namedtarget
. This instance serves as the remote instance that your service account will connect to over SSH. 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 e2-micro --metadata=enable-oslogin=TRUE
Grant the
compute.osAdminLogin
IAM role to the service account, so it can establish SSH connections specifically to the instance namedtarget
. Thecompute.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 this role at the instance level to control SSH access in a more granular way. You can grant additional permissions to your service account later if you find that your applications require access to other resources in your project:gcloud compute instances add-iam-policy-binding target \ --project $PROJECT_ID --zone us-central1-f \ --member serviceAccount:ssh-account@$PROJECT_ID.iam.gserviceaccount.com \ --role roles/compute.osAdminLogin
Create an instance in
us-central1-f
namedsource
. Associate the instance with thessh-account
service account. Also, specify thecloud-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@$PROJECT_ID.iam.gserviceaccount.com \ --scopes https://www.googleapis.com/auth/cloud-platform \ --network ssh-example --machine-type e2-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
Cloud Client Libraries for Python 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 app that can SSH from one instance to another instance.
Run an SSH app on an instance
When apps 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 app using the following process:
Connect to the
source
instance using thegcloud
command-line tool:gcloud compute ssh source --project $PROJECT_ID --zone us-central1-f
On the
source
instance, installpip
and the Python client library:my-username@source:~$ sudo apt update && sudo apt install python-pip -y && pip install --upgrade google-api-python-client
Download the
service_account_ssh.py
sample app from GoogleCloudPlatform/python-docs-samples:my-username@source:~$ curl -O https://raw.githubusercontent.com/GoogleCloudPlatform/python-docs-samples/master/compute/oslogin/service_account_ssh.py
Run the sample app, which uses
argparse
to accept variables from the command line. In this example, instruct the app to install and runcowsay
on thetarget
instance. For this command, add your project ID manually:my-username@source:~$ python service_account_ssh.py \ --cmd 'sudo apt install cowsay -y && cowsay "It works!"' \ --project [PROJECT_ID] --zone us-central1-f --instance target ⋮ ___________ It works! ----------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
If the app runs correctly, you receive the output from the
cowsay
app. You can modify the --cmd
flag to include any
command that you want. Alternatively, you can write your own app that
imports service_account_ssh.py
and calls it directly.
Run exit
to disconnect from the source
instance and return to
Cloud Shell.
Run an SSH app outside of Compute Engine
In the previous example, you ran the app on a Compute Engine
instance where the Cloud Client Libraries for Python could use
Application Default Credentials to use the
service account that is associated with the source
instance. If you run this
app outside of a Compute Engine instance,
the client library can't access the service account and its permissions unless
you provide the service account key manually.
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 thegcloud
command-line tool:gcloud compute instances describe target \ --project $PROJECT_ID --zone us-central1-f
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.Copy the service account key to the system where you want to run this example.
Open a terminal on the system where you want to run this example.
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 yourDownloads
folder, you might set an environment variable like the following example:$ export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/key.json"
Install the prerequisites on this system:
Download the sample app:
$ curl -O https://raw.githubusercontent.com/GoogleCloudPlatform/python-docs-samples/master/compute/oslogin/service_account_ssh.py
Run the sample app. When you run the app 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 service_account_ssh.py \ --cmd 'sudo apt install cowsay -y && cowsay "It works!"' \ --account ssh-account@[PROJECT_ID].iam.gserviceaccount.com \ --project [PROJECT_ID] --hostname [TARGET_EXTERNAL_IP] ⋮ ___________ It works! ----------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
If the app runs correctly, you receive the output from the
cowsay
app.
How the sample app works
The service_account_ssh.py
sample app operates using the following
process:
- Initialize the OS Login API object.
- If you don't provide the service account email address manually, the app reads instance metadata to identify the service account that's associated with the instance. If you run this app outside of Compute Engine, you must provide the service account address manually.
- 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. - Call the
getLoginProfile()
method from the OS Login API to get the POSIX user name that the service account uses. - Call the
run_ssh()
method to execute a remote SSH command as the service account. - Print the response from the remote SSH command.
- Remove the temporary SSH key files.
- OS Login removes the public key files automatically when they pass the expiration time.
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.
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 app.
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 app uses the run_ssh()
method to
execute a command on a remote instance and return the command output.
Cleaning up
To avoid incurring charges to your Google Cloud account for the resources used in this tutorial, either delete the project that contains the resources, or keep the project and delete the individual resources.
In the Google Cloud Console, open Cloud Shell.
Delete the instance named
source
:gcloud compute instances delete source \ --project $PROJECT_ID --zone us-central1-f
Delete the instance named
target
:gcloud compute instances delete target \ --project $PROJECT_ID --zone us-central1-f
Delete the
ssh-account
service account:gcloud iam service-accounts delete ssh-account --project $PROJECT_ID
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 apps.