At Seety, we recently switched from self-hosted Mongo cluster to Mongo Atlas, the hosted and managed MongoDB cluster. It’s a relief for me as they manage the cluster, the backups, the updates, the security, etc.
Mongo Atlas comes with great features but the one that convinced me to switch was the ability to peer the cluster directly with an existing VPC (Google, Azure or AWS). That enhances the security of the communication as everything is routed on a private network and no access is given on a public IP address. However, it also locks the developers out. Access to the DB is always interesting for maintenances or debugging.
Previously, I was simply using a port forwarding to our mongo servers in our Kubernetes cluster, but it’s not possible anymore as the Mongo Atlas cluster isn’t accessible directly. The solution I found is using SSH tunneling to a machine connected to the VPC, and I thought it can help some others!
Connect via the URL ?
To connect to the mongo atlas cluster, we use the mongodb URI (in this form):
This URI refers to 3 different servers (the members of the cluster):
Trying to get their IPs, will only show private IPs (only accessible from within the VPC). Here is an example of a
dig output on one of the servers:
; <<>> DiG 9.11.5-P4-5.1ubuntu2.1-Ubuntu <<>> your-cluster-00-00-abc.gcp.mongodb.net ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49806 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 65494 ;; QUESTION SECTION: ;your-cluster-00-00-abc.gcp.mongodb.net. IN A ;; ANSWER SECTION: your-cluster-00-00-abc.gcp.mongodb.net. 60 IN A 192.168.144.12 ;; Query time: 20 msec ;; SERVER: 127.0.0.53#53(127.0.0.53) ;; WHEN: Sat Mar 21 14:42:21 CET 2020 ;; MSG SIZE rcvd: 91
The returned IP is 192.168.144.12 (obviously not accessible from my computer). Thus, you’ll need a connexion inside your VPC to access this IP.
The SSH Tunnel
The solution to be able to connect to those local IPs is an SSH tunnel to a machine connected to the VPC. To do so, we have a VM connected to our VPC, for back-office access, only accessible from the office’s IP or via our VPN, this instance is only running an SSH server.
We create an SSH tunnel with the following command (assuming 22.214.171.124 is the SSH server’s IP):
ssh 126.96.36.199 -N \ -L 127.0.1.1:27017:your-cluster-00-00-abc.gcp.mongodb.net:27017 \ -L 127.0.1.2:27017:your-cluster-00-01-abc.gcp.mongodb.net:27017 \ -L 127.0.2.3:27017:your-cluster-00-02-abc.gcp.mongodb.net:27017
This command actually redirects requests you make from your local machine to 127.0.1.1 to your-cluster-00-00-abc.gcp.mongodb.net (on the SSH server), 127.0.1.2 to your-cluster-00-01-abc.gcp.mongodb.net and 127.0.1.3 to your-cluster-00-02-abc.gcp.mongodb.net.
We can now connect to the mongo cluster, through the SSH tunnel with the following URL (via the local IPs):
You’ll, however, receive a warning about the certificates not matching the domain names.
For that, you have two possibilities, either you ignore it simply with the
--tlsAllowInvalidHostnames parameter of the mongo CLI, or you edit your /etc/hosts file to resolve your-cluster-00-00-abc.gcp.mongodb.net to 127.0.1.1 etc. That’s the solution I followed and added those lines to my
127.0.1.1 your-cluster-00-00-abc.gcp.mongodb.net 127.0.1.2 your-cluster-00-01-abc.gcp.mongodb.net 127.0.1.3 your-cluster-00-02-abc.gcp.mongodb.net
A script that does it for you ?
Because I want the whole development team to be able to connect to the production and/or preproduction database cluster, I created a small script that automates the tunnel and asks for the
/etc/hosts edit if not done already:
#!/bin/bash # Infos about ssh server (tunnel) SSH_SERVER=188.8.131.52 # <== IP of your SSH server here PORT=22 # <== Port of your SSH server here (default is 22) # Local subnet to use (Local subnet to avoid conflicts) SUBNET=127.0.1 # Infos about Mongo Atlas Cluster (Prod cluster) SERV0=your-cluster-00-00-abc.gcp.mongodb.net SERV1=your-cluster-00-01-abc.gcp.mongodb.net SERV2=your-cluster-00-02-abc.gcp.mongodb.net # Check the /etc/hosts file and aask changes if needed if grep -q $SERV0 "/etc/hosts"; then echo "/etc/hosts is already OK" else echo "Be sure to have those lines in your /etc/hosts file" echo "$SUBNET.1 $SERV0" echo "$SUBNET.2 $SERV1" echo "$SUBNET.3 $SERV2" read -p "Press [Enter] when it's in /etc/hosts" fi; echo "Connected! Use Ctrl+C to exit." ssh $SSH_SERVER -p $PORT -N \ -L $SUBNET.1:27017:$SERV0:27017 \ -L $SUBNET.2:27017:$SERV1:27017 \ -L $SUBNET.3:27017:$SERV2:27017 echo "Disconnected!"
I hope this post will be useful for you! Don’t hesitate to give feedback and follow me on Twitter!