Last active
January 5, 2026 15:08
-
-
Save mikesparr/6ffe13079505b598d98d55a2088411c3 to your computer and use it in GitHub Desktop.
Example of granting access to select compute engine instance and enabling audit logs on Google Cloud Platform (GCP)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| ##################################################################### | |
| # REFERENCES | |
| # - https://cloud.google.com/compute/docs/oslogin/manage-oslogin-in-an-org | |
| # - https://cloud.google.com/compute/docs/instances/managing-instance-access#configure_users | |
| # - https://cloud.google.com/iam/docs/configuring-resource-based-access | |
| # - https://cloud.google.com/iap/docs/using-tcp-forwarding#grant-permission | |
| # - https://cloud.google.com/iap/docs/audit-log-howto | |
| # - https://cloud.google.com/compute/docs/oslogin/view-audit-logs#view-logs | |
| ##################################################################### | |
| export PROJECT_ID=$(gcloud config get-value project) | |
| export PROJECT_USER=$(gcloud config get-value core/account) # set current user | |
| export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)") | |
| export IDNS=${PROJECT_ID}.svc.id.goog # workload identity domain | |
| export GCP_REGION="us-central1" # CHANGEME (OPT) | |
| export GCP_ZONE="us-central1-a" # CHANGEME (OPT) | |
| export NETWORK_NAME="default" | |
| # enable apis | |
| gcloud services enable compute.googleapis.com \ | |
| iap.googleapis.com | |
| # configure gcloud sdk | |
| gcloud config set compute/region $GCP_REGION | |
| gcloud config set compute/zone $GCP_ZONE | |
| # ideally require OS Login at org level but did at instance for demo | |
| # gcloud beta resource-manager org-policies enable-enforce compute.requireOsLogin \ | |
| # --organization=$ORGANIZATION | |
| # create two compute instances | |
| export INSTANCE_1_NAME="accessible" | |
| export INSTANCE_2_NAME="inaccessible" | |
| gcloud compute instances create $INSTANCE_1_NAME \ | |
| --project=$PROJECT_ID \ | |
| --zone=$GCP_ZONE \ | |
| --machine-type=e2-micro \ | |
| --network-interface=subnet=default,no-address \ | |
| --scopes=https://www.googleapis.com/auth/cloud-platform \ | |
| --metadata enable-oslogin=TRUE | |
| gcloud compute instances create $INSTANCE_2_NAME \ | |
| --project=$PROJECT_ID \ | |
| --zone=$GCP_ZONE \ | |
| --machine-type=e2-micro \ | |
| --network-interface=subnet=default,no-address \ | |
| --scopes=https://www.googleapis.com/auth/cloud-platform \ | |
| --metadata enable-oslogin=TRUE | |
| # grant SSH access | |
| gcloud compute firewall-rules create allow-ssh-ingress-from-iap \ | |
| --direction=INGRESS \ | |
| --action=allow \ | |
| --rules=tcp:22 \ | |
| --source-ranges=35.235.240.0/20 | |
| # enable IAP audit logs | |
| gcloud projects get-iam-policy $PROJECT_ID > policy.yaml | |
| cat >> policy.yaml << EOF | |
| auditConfigs: | |
| - auditLogConfigs: | |
| - logType: ADMIN_READ | |
| - logType: DATA_READ | |
| - logType: DATA_WRITE | |
| service: iap.googleapis.com | |
| EOF | |
| gcloud projects set-iam-policy $PROJECT_ID policy.yaml | |
| # test access with non-owner user (realistic) | |
| export TEST_EMAIL="you@youremail.com" # CHANGEME | |
| # org scope (optional: since I used external user in demo) | |
| gcloud organizations add-iam-policy-binding $ORGANIZATION \ | |
| --member user:$TEST_EMAIL \ | |
| --role roles/compute.osLoginExternalUser \ | |
| --condition=None | |
| # project scope | |
| gcloud projects add-iam-policy-binding $PROJECT_ID \ | |
| --member user:$TEST_EMAIL \ | |
| --role roles/iap.tunnelResourceAccessor \ | |
| --condition \ | |
| 'title=allow-ssh-only,expression=destination.port==22' | |
| gcloud projects add-iam-policy-binding $PROJECT_ID \ | |
| --member user:$TEST_EMAIL \ | |
| --role roles/browser \ | |
| --condition=None | |
| # service account scope | |
| export DEFAULT_SA="$PROJECT_NUMBER-compute@developer.gserviceaccount.com" | |
| gcloud iam service-accounts add-iam-policy-binding $DEFAULT_SA \ | |
| --member user:$TEST_EMAIL \ | |
| --role roles/iam.serviceAccountUser \ | |
| --condition=None | |
| # instance scope (instance-level roles for least privilege) | |
| gcloud compute instances add-iam-policy-binding $INSTANCE_1_NAME \ | |
| --member user:$TEST_EMAIL \ | |
| --role roles/compute.instanceAdmin \ | |
| --condition=None | |
| gcloud compute instances add-iam-policy-binding $INSTANCE_1_NAME \ | |
| --member user:$TEST_EMAIL \ | |
| --role roles/compute.osLogin \ | |
| --condition=None | |
| # change to test user | |
| gcloud config set account $TEST_EMAIL | |
| # test login on accessible instance | |
| gcloud compute ssh $INSTANCE_1_NAME # success | |
| # test login on inaccessible instance | |
| gcloud compute ssh $INSTANCE_2_NAME # failed | |
| # switch back to original user | |
| gcloud config set account $PROJECT_USER | |
| # view logs | |
| gcloud logging read --freshness=1h 'protoPayload.serviceName="oslogin.googleapis.com"' | |
Author
Author
Clean up
Don't forget to clean up to avoid unexpected cloud costs. The easiest way is to delete the GCP project, but you can also perform the following:
gcloud compute instances delete $INSTANCE_1_NAME --zone $GCP_ZONE
gcloud compute instances delete $INSTANCE_2_NAME --zone $GCP_ZONE
And optionally reverse the IAM permissions, and audit logging config.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Controlling Compute Engine Access
Many organizations may spin up compute engine instances (VMs) on Google Cloud Platform, but want to restrict access to specific users and specific instances. This example illustrates how you can avoid external IP addresses, but leverage Google's Identity Aware Proxy (IAP) tunneling via the
gcloud compute ssh <instance-id>command, and restrict access using OS Login to individual instances.In addition, it illustrates how to enable data access audit logs and view logins for individual users.
Experiment
This experiment creates 2 compute engine instances, and only grants OS Login access to an external user for one instance. Upon trying to log in using IAP tunneling, the user is only granted access to one of the two instances.
Result (access to only 1 instance)
Result (audit logs)