Search code examples
google-cloud-platformjupyter-notebookgoogle-compute-enginessh-tunnel

How to run Jupyter, locally, connecting to Google Cloud VM using only internal IP address?


I configured a Compute Engine instance with only an internal IP (10.X.X.10). I am able to ssh into it via gcloud with IAP with tunneling, access and copy files storage via Private Google Access and VPC was set up with no conflicting IP ranges:

gcloud compute ssh --zone "us-central1-c" "vm_name"  --tunnel-through-iap --project "projectXXX"

Now I want to open Jupyter notebook without creating an external IP in the VM.

Identity-Aware Proxy (IAP) is working well, Private Google Access also. After that I enabled a NAT Gateway, that generated an external IP (35.X.X.155).

I configured Jupyter by running jupyter notebook --generate-config, set up a password "sha"

Now I run Jupyter by typing this on gcloud SSH:

python /usr/local/bin/jupyter-notebook --ip=0.0.0.0 --port=8080 --no-browser &

Replacing:http://instance-XXX/?token=abcd

By:http://35.X.X.155/?token=abcd

But the external IP is not accessible, not even in the browser, neither in http nor in https. Note that I'm not considering using a Network Load Balancing, because it's not necessary.

Ping 35.X.X.155 works perfectly

I also tried jupyter notebook --gateway-url=http://NAT-gateway:8888 without success

Jupyter Notebook

Look at this as an alternative to a bastion (VM with external IP)

Any ideas on how to solve this issue ?

UPDATE: Looks like I have to find a way to SSH into the NAT Gateway.


Solution

  • What you are trying to do can be accomplished using IAP for TCP forwarding, and there is no need to use NAT at all in this scenario. Here are the steps to follow:

    1. Ensure you have ports 22 and 8080 allowed in the project's firewall:
    gcloud compute firewall-rules list
    NAME                         NETWORK  DIRECTION  PRIORITY  ALLOW                         DENY  DISABLED
    allow-8080-ingress-from-iap  default  INGRESS    1000      tcp:8080                            False
    allow-ssh-ingress-from-iap   default  INGRESS    1000      tcp:22                              False
    
    1. On your endpoint's gcloud CLI, log in to GCP and set the project to where the instance is running:
    gcloud config set project $GCP_PROJECT_NAME
    
    1. Check if you already have SSH keys generated in your system:
    ls -1 ~/.ssh/*
    
    #=>
    
    /. . ./id_rsa
    /. . ./id_rsa.pub
    

    If you don't have any, you can generate them with the command: ssh-keygen -t rsa -f ~/.ssh/id_rsa -C id_rsa

    1. Add the SSH keys to your project's metadata:
    gcloud compute project-info add-metadata \
    --metadata ssh-keys="$(gcloud compute project-info describe \
    --format="value(commonInstanceMetadata.items.filter(key:ssh-keys).firstof(value))")
    $(whoami):$(cat ~/.ssh/id_rsa.pub)"
    
    #=>
    
    Updated [https://www.googleapis.com/compute/v1/projects/$GCP_PROJECT_NAME].
    
    1. Assign the iap.tunnelResourceAccessor role to the user:
    gcloud projects add-iam-policy-binding $GCP_PROJECT_NAME \
        --member=user:$USER_ID \
        --role=roles/iap.tunnelResourceAccessor
    
    1. Start an IAP tunnel pointing to your instance:port and bind it to your desired localhost port (in this case, 9000):
    gcloud compute start-iap-tunnel $INSTANCE_NAME 8080 \
        --local-host-port=localhost:9000
    
    Testing if tunnel connection works.
    Listening on port [9000].
    

    At this point, you should be able to access your Jupyter Notebook in http://127.0.0.1:9000?token=abcd.

    Note: The start-iap-tunnel command is not a one-time running command and should be issued and kept running every time you want to access your Jupyter Notebook implementation.