When developing projects on Google Compute Engine, there are a variety of
scenarios in which you want to keep the instances from being reached from the
public Internet:
- Web services are still under development and not ready to be exposed to external
users because they are feature incomplete or have not yet been configured with
HTTPS.
- Instance might be providing services designed to be only consumed by other
instances in the project.
- Instances should only be reached through dedicated interconnect options from
company offices or data centers.
Even when a service is intentionally Internet-facing, it is important that
communication with the service be restricted to the target user groups, and
occur over secure channels, such as SSH or HTTPS, to protect sensitive
information.
This article demonstrates several methods for securing communications with
Compute Engine instances with or without external IP addresses.
Protecting services on machines with external IP addresses
Connecting to instances without external IP addresses
Protecting services on machines with external IP addresses
When instances have a public IP address, it is important that only the
services and traffic you intend to be exposed are reachable, and for those that
are exposed, any sensitive information is secured in transit.
Firewalls
Your first line of defense is to restrict who can reach the instance using
firewalls.
By creating firewall rules, you can restrict all traffic to a network or
target machines on a given set of ports to specific source IP addresses.
Firewalls are not a standalone solution. Restricting traffic to
specific source IPs does not protect sensitive information, such as
login credentials, commands that create or destroy resources or files, or
logs. When running a web service on a publicly-accessible machine, such
as a Google Compute Engine instance with an external IP, you need to
encrypt all communication between your host and the deployed instance
to ensure proper security.
In addition, firewalls aren't always the appropriate solution. For example,
firewalls are not ideal for development environments that do not have static
IP addresses, such as roaming laptops.
HTTPS and SSL
For production web systems, you should configure HTTPS/SSL. HTTPS/SSL can be
set up either by setting up an instance to terminate HTTPS or by configuring
HTTPS load balancing. HTTPS/SSL does involve some initial complexity,
requiring you to perform the following tasks:
If you have set up SSL-serving domains before, it should be straightforward to
do the same with Google Compute Engine. If not, you might find it easier to use
a different security method, such as
port forwarding or
SOCKS proxy.
Port forwarding over SSH
You can use the
gcloud command-line tool
to start a server on a given local port that forwards all traffic to a
remote host over an SSH connection.
First, take note of the instance and port that are providing the service
to which you would like to establish a secure connection. Next, run the
following command:
gcloud compute ssh example-instance \
--project my-project \
--zone us-central1-a \
--ssh-flag="-L" \
--ssh-flag="2222:localhost:8888"
In the above command, the parameters are defined as follows:
example-instance is the name of the instance to which you'd like to connect.
my-project is your
Google Cloud Platform project ID.
us-central1-a is the zone in which your instance is running.
2222 is the local port you're listening on.
8888 is the remote port you're connecting to.
With these example settings, if you open http://localhost:2222/ in your browser,
the HTTP connection will go over the SSH tunnel you have just created over to
your remote host and connect to the specified instance via SSH and then connect
to port 8888 on the same machine, but over an encrypted, secure SSH connection.
The
gcloud command creates and maintains an SSH connection, and this
approach only works while the SSH session is active. As soon as you exit the
SSH session that
gcloud creates, port forwarding via http://localhost:2222/
will stop working.
If you want to create more than one port forwarding rule, you can specify
multiple rules on a single command line by repeating the flags:
gcloud compute ssh example-instance \
--project my-project \
--zone us-central1-a \
--ssh-flag="-L" \
--ssh-flag="2222:localhost:8888" \
--ssh-flag="-L" \
--ssh-flag="2299:localhost:8000"
Alternatively, you can run a new
gcloud command each time to create a
separate tunnel. Note that you cannot add or remove port forwarding from
an existing connection without exiting and re-establishing the connection
from scratch.
SOCKS proxy over SSH
If you want to connect to a number of different hosts in your cloud
deployment, the easiest way to do so is to change your browser to do the
lookups directly from your
network. This approach
allows you to use the short name of the hosts instead of looking up each
host's IP address, opening up ports for each service, or creating an SSH tunnel
for each host/port pair.
The approach that you use here is as follows:
- Set up a single SSH tunnel to one of the hosts on the network, and create a
SOCKS proxy on that host.
- Change the browser configuration to do all the lookups via that SOCKS proxy
host.
Note that because you are tunneling
all traffic via that host, you don't want
to browse the web in general using that browser or that specific profile, as you
will use your cloud service's bandwidth for this. In general, you might want
to use a separate browser profile and switch to it when necessary.
Start the SOCKS proxy
To start your SOCKS proxy, run the following command:
gcloud compute ssh example-instance \
--project my-project \
--zone us-central1-a \
--ssh-flag="-D" \
--ssh-flag="1080" \
--ssh-flag="-N"
In the above command, the parameters are defined as follows:
example-instance is the name of the instance to which you would like to
connect.
my-project is your Google Cloud Platform project ID.
us-central1-a is the zone in which your instance is running.
1080 is the local port you're listening on.
Note that, in this case, you don't need to specify a remote port. Because a
SOCKS proxy does not bind to any specific remote port, any connection you
make via the SOCKS proxy will be resolved relative to the host you connect
to.
By using a SOCKS proxy, you can connect to any instance that shares a Compute
Engine network with your proxy instance by using the instance's short name.
In addition, you can connect to any port on a given instance.
This approach is much more flexible than the simple port-forwarding method, but
will also require you to change the settings in your web browser to utilize the
proxy.
Next, configure your browser to use the proxy.
Chrome setup for SOCKS proxy
Chrome uses system-wide proxy settings by default, so you need to specify a
different proxy using command-line flags. Launching Chrome by default creates an
instance of an already-running profile, so to enable you to run multiple copies
of Chrome simultaneously, one which is using the proxy and others which are not,
you need a new profile.
Launch Chrome using a new profile. It will be created automatically if it
does not exist.
Linux:
/usr/bin/google-chrome \
--user-data-dir="$HOME/chrome-proxy-profile" \
--proxy-server="socks5://localhost:1080"
Mac OS X:
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
--user-data-dir="$HOME/chrome-proxy-profile" \
--proxy-server="socks5://localhost:1080"
Windows:
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" ^
--user-data-dir="%USERPROFILE%\chrome-proxy-profile" ^
--proxy-server="socks5://localhost:1080"
Be sure to set the localhost port to the same value that you used in the
gcloud command earlier (1080 in our example).
Firefox setup for SOCKS proxy
Before changing these settings, you may want to
create a new Firefox profile.
Otherwise, it will affect all instances of Firefox to use that host as a proxy,
which is very likely not what you want.
After you have Firefox running with a separate profile, you can set up the SOCKS
proxy:
- Open Preferences.
- Click Advanced > Networks >
Settings to open the Connection Settings dialog.
- Choose the option Manual proxy configuration
- In the SOCKS Host section, fill in
localhost as the host and the
port you selected when you ran the gcloud command earlier.
- Choose SOCKS v5.
- Check the box Remote DNS.
- Leave all other entries blank.
- Click OK and close the Preferences dialog box.
Connecting to instances without external IP addresses
When instances do not have external IP addresses they can only be reached by
other instances on the network, or via managed VPN gateway. You can provision
instances in your network to act as trusted relays for inbound connections
(bastion hosts) or network egress (NAT Gateways). For more transparent
connectivity without setting up such connections, you can use a managed VPN
gateway resource.
Bastion hosts
Bastion hosts
provide an external facing point of entry into a network containing private
network instances. This host can provide a single point of fortification or
audit and can be started and stopped to enable or disable inbound SSH
communication from the Internet.

By using a bastion host, you can connect to an instance that does not
have an external IP address. This approach allows you to connect to a
development environment or manage the database instance for your
external application, for example, without configuring additional
firewall rules.
A complete hardening of
a bastion host is outside the scope of this article, but some initial steps
taken can include:
- Limit the CIDR range of source IPs that can communicate with the bastion.
- Configure firewall rules to allow SSH traffic to private instances from only
the bastion host.
By default, SSH on instances is configured to use private keys for
authentication. When using a bastion host, you log into the bastion host first,
and then into your target private instance. Because of this two-step login,
which is why bastion hosts are sometimes called "jump servers," you should use
ssh-agent forwarding instead of storing the target machine's private key on
the bastion host as a way of reaching the target machine. You need to do this
even if using the same key-pair for both bastion and target instances, as the
bastion has direct access to only the public half of the key-pair.
To learn how to use a bastion host instance to connect to other instances on
your Cloud Platform network, read
Connecting to instances that do not have external IP addresses.
VPN
Cloud VPN lets you connect your existing network to your
Google Cloud Platform network via an IPsec connection to a VPN gateway device. This
allows direct routing of traffic from your premises to the private IP
interfaces of Compute Engine instances. Traffic is encrypted as it transits
over public links to Google.
For details on setting up, configuring, and using VPN with Compute
Engine, see the
Cloud VPN
documentation.
To learn how to connect to instances on your Cloud Platform network through
an existing VPN rather than through external IP addresses of instances, read
Connecting to instances that do not have external IP addresses.
Traffic egress using NAT gateways
When an instance does not have an external IP address assigned it can not make
direct connections to external services, including other Cloud Platform
services. To allow these instances to reach services on the public Internet, you
can set up and configure a
NAT gateway
machine, which can route traffic on behalf of any instance on the network. Be
aware that a single instance should not be considered highly available, and can
not support high traffic throughput for multiple instances.
Interactive serial console access
When an instance doesn't have an external IP address, you might still
need to interact with the instance for troubleshooting or maintenance purposes.
Setting up a
Bastion host is one option but might require more setup
than worthwhile for your needs. If you want to troubleshoot an instance without
an external IP address, consider
enabling interactive access on the serial console,
which allows you to interact with an instance's serial console using SSH and
run commands against the serial console.