Security is always present in today's information technology, specifically Cloud environments. Oracle Autonomous Database provides a secure environment with manifold controls for the access of your database and tools. One is configuring your database with a private endpoint, allowing access only within your tenancy's Virtual Cloud Network (VCN).
While a private network is perfect for isolating your database and applications, there is sometimes the need to connect to such a database from "somewhere else", might this be a developer's laptop in your corporate network, or a more permanent connection to your on-premises Data Center, using FastConnect or VPN Connect.
While ample documentation and blogs discuss how to do this for SQL*Net (and sometimes APEX), we still need the equivalent for the Mongo API. Yes, we're working on the doc, but quickly cobbling together a short blog won't hurt in the interim. And that's precisely what you are reading right now.
There is specifically one blog post that has pretty much everything you need to know about how to get started with private endpoints for Autonomous Database. However, since it was written prior to the existence of the Mongo API, it does not cover it. So let's augment this blog post with the missing information of how to set up the Mongo API. I will refer to it for brevity and to keep the information the same.
Well, as the title says, your database is private, meaning it is only accessible in a virtual cloud network, residing most commonly in a private VCN subnet that is only accessible from other subnets within the VCN. Your database is protected through the firewall rules of your subnet, whether you are using Network Security Groups or Security Lists. (There are some differences between those two, but fundamentally, they're doing the same - protecting your resources (your database in that case) with a firewall. Your networking people will likely have a strong opinion of what to use, so I will not take that bait. I use network security groups for this example, but unlike the example in the blog, I use stateful rules. Note that whatever technique you pick for your firewall rules, the tasks at hand are the same.
Let's start with my VCN setup and walk you through the steps necessary to securely use the Mongo API on the machines you want. (Picture courtesy of the referenced blog):
As you see, my Autonomous Database is in a private subnet (SUBNET A), and the network security rules only access from my second public subnet (SUBNET B). (Details on this in a moment.) Here is what my database looks like in detail. You can see that its private IP address is 10.0.2.71 and the network security group is DatabaseNSG. We will look at that one in a second.
Let's look what needs to be done to access your Autonomous Database using the Mongo API.
Sounds kind of obvious, doesn't it? Yes, it does .. but we spend numerous times talking to people that simply forget to check this.
Out of the box, only Autonomous JSON Database has the Mongo API enabled. All other Autonomous Database Services need to enable it.
To ensure that the Mongo API is enabled, go the the OCI Console and look under the Tool configuration tab. It will show you whether your Mongo API is enabled or not. Now is also a good time to copy the connect string, which can be done conventiently on the same screen:
The database and Mongo API is ready for you. I copy the connect string as shown on the console:
If I want to use it later on I only have to replace 'user' and 'password' in the connect string.
But your environment is not ready to be used yet. Not yet.
By default, the firewall setting is very restrictive and lacks the proper database firewall setting. We need to allow the communication (ingress/egress) for our database. You will not be able to connect to your database in any way without further actions.
The only thing on the database side you have to do is adjust your ingress/egress rules to allow the usage of Mongo API. Your database has to be able to (A) be talked to on the port used for the Mongo API (ingress) and be able to answer (egress). As in real life, there's no good conversation if neither party contributes.
When doing this with my sample VCN setup, I add TCP port 27017 to the list of allowed ports/protocols to my network security group DatabaseNSG to communicate between my private subnet (10.0.2.0/24) and my public subnet (10.0.1.0/24). So my network security rules look as follows with the inclusion of port 27017 for the Mongo API:
You see that I also added rules for both SQL Net one-way TLS (1521) and APEX (443), but we won't delve into those. That's what the other blog post is good for.
We are ready to connect to our Autonomous Database with the Mongo API. The allowed CIDR block in this example is 10.0.1.0/24, which covers the IP address space of 10.0.1.0 - 10.0.1.255. Connecting to a VM within this range (which happens to be the range of my public subnet within the VCN), I can connect using the Mongo API:
There are a couple of things to point out:
Let us check what the fully qualified hostname is mapping to:
It's the private IP address of our Autonomous Database. (The name is on the detail page of the Autonomous Database above as well - the private endpoint URL - but not legible in our screenshot.
My VM can do proper DNS name resolution to access my Oracle database, so no further actions are required, and I am all set to use the MongoAPI (or one-way TLS sqlnet or APEX with the network security list shown above). We are all set for our production environment. But now, what do I do for my developer's (local) laptop?
Establish a bastion (jump) host
A bastion host is a server that serves as a gateway between your local laptop (outside the VPN) to work with your autonomous database without compromising your security setup. All communication will go through ssh tunneling from your laptop to your VM, which then will route the traffic to your Autonomous Database.
We will use our test VM for this exercise. Let's quickly check the firewall settings of this VM to see whether my laptop can connect:
As you see, the default security list of our public subnet allows ssh connection from everywhere to our VM, so we are covered. (Egress is set to communicate with everybody on all ports and protocols.) Don't worry, good luck to everybody out there to get my private key.
If your security list is defined differently and does not allow an ssh connection from the laptop to your bastion host, you need to enable TCP to ingress/egress on port 22 for your laptop. If you cannot connect via ssh to your bastion, you cannot use it as a tunnel.
Tunneling through ssh is conceptually pretty simple: SSH tunneling involves forwarding local ports on your local machine to remote ports on servers behind the bastion host. So to use my VM as bastion(ssh tunnel) for the Mongo API, I have to open an ssh shell and tell it what local port to forward to a remote port on my bastion. The most simple command for my environment would look as follows:
ssh -i ~/.ssh/id_rsa -v -C -L 27017:10.0.2.71:27017 opc@<the public IP address of my bastion>
From the unix man pages:
We are mapping the local port 27017 to being forwarded through the ssh tunnel to my trusted VM to map to the private endpoint IP address of my Autonomous Database from the trusted VM. With that, any communication to my localhost on port 27017 will be forwarded through the ssh tunnel to my trusted VM (the bastion) and within there it is communicating with the private endpoint of my Autonomous Database on port 27017.
We are now almost ready to connect. But there is one more important step for us: we need to ensure that we can use the FQDN of our Autonomous Database to connect.
My laptop has not the slightest clue about the names of hosts inside the private VCN in the Oracle Cloud. So, I need to teach it to map the necessary name to the IP address I have to use for communication.
This is because an SSL certificate is typically issued to a Fully Qualified Domain Name (FQDN) such as "https://www.domain.com". That's what the Oracle Cloud does, so if you want to use any communication based on SSL, you must ensure that you communicate using a fully qualified hostname and not an IP address. Try it yourself:
The simplest way for this is to add the fully qualified hostname of your Autonomous Database - the private endpoint URI - to your local /etc/hosts file as a name for your localhost. We need to map it to localhost since the ssh tunneling communication through our bastion will forward the communication from the localhost through the bastion to our Autonomous Database.
With that, we are ready to try it:
Port binding works fine, That's about it. We connected to our Autonomous Database with a private endpoint using the Mongo API from a laptop not in the private VNC using a bastion. As always, if you know what to do, it's not that hard ;-)
To quickly recap the to-do list:
The blog post I praised at the beginning talks in great detail about setting up an Autonomous Database with a private endpoint for SQL Net mutual TLS and APEX. The conceptual details and configuration steps are the same. (As a side note, the necessity to configure the local mapping of the fully qualified name exists for APEX, too.)
It also talks about configuring a setup with an on-premises data center, which is conceptually exactly the same as connecting a developer's laptop, as discussed in this blog. It just involves a couple of more networking components to make the connection happen.
While I was focusing on the Mongo API so far, I mentioned other ports as well, such as the port for one-way TLS SQL Net (1521) and the standard HTTPS (443) as APEX uses it. So the question begs whether you need to look at those in isolation when using a bastion host. The short (and long) answer is no, but there's a subtlety I want to point out:
Linux ssh lets you tunnel to more than one port with a single ssh tunnel, but you need to bear in mind that the TCP/IP port numbers below 1024 are special in that normal users are not allowed to run servers on them. So when you want tunnel any of these ports - like 443 - you either need to grant access to the relevant ports, or much simpler, run the tunneling command as a privileged user.
While the command now looks as follows, you need to run it as privileged user:
ssh -i ~/.ssh/id_rsa -v -C -L 27017:10.0.2.71:27017 -L 443:10.0.2.71:443 opc@<the public IP address of my bastion>
If you don't do this, you will see a binding error in the debug mode I used in this blog:
I am just using 'sudo' now, and voila, it binds both ports properly in one go, and you're ready to use the Mongo API and APEX with one tunnel.
sudo ssh -i ~/.ssh/id_rsa -v -C -L 27017:10.0.2.71:27017 -L 443:10.0.2.71:443 opc@<the public IP address of my bastion>
And there is one more thing ....
You do not have to use the original port 443 if you don't want to run the tunnel as a privileged user. Just use a port above 1024 locally to communicate with the bastion, which by itself will route it to the right port of your autonomous database, e.g.
ssh -i ~/.ssh/id_rsa -v -C -L 27017:10.0.2.71:27017 -L 1966:10.0.2.71:443 opc@<the public IP address of my bastion>
In this example, we are tunneling two ports through the bastion, and we even use the local port 1966 to the bastion, which itself forwards the traffic to the original port 443. The only thing to remember here is that you now need to use the local part to connect to APEX or Database Studio, as shown in the screenshot below.
I hope that the blog is helpful for you. Please let us know what you think about it, what's missing, what needs more clarification, or what you feel is wrong. We also love to hear from you about future things we should blog about to keep our communication and education ongoing.
Hermann is a Senior Director of Product Management in the Oracle Database organization. He and his team focus on Oracle's core functionality, such as Oracle Partitioning, the Oracle Optimizer, and analytical SQL. His team also looks after semi-structured data processing, such as the relational SQL/JSON capabilities, Oracle Text, and more recently Autonomous JSON Database and the Oracle Database API for Mongo DB.
Hermann has held several positions at Oracle in Sales Consulting and Consulting, dealing with the database for quite some time