How-tos

Reaching Enterprise Backend with Bluemix Secure Gateway via SDK API

Share this post:

It is often necessary for a mobile application to obtain information from databases hosted in a customer’s on-premises secure location. IBM Secure Gateway for Bluemix SDK makes this easy programmatically (Binh Nguyen’s article Reaching enterprise backend with Bluemix Secure Gateway via console explains how to do this via the UI).

This document uses a simple hypothetical scenario in which an educational institution wants to develop a mobile or web application to access on-premises information contained in a MongoDB. The user develops an application that will be pushed into Bluemix and uses the Secure Gateway service to access the database. The application will connect to an on-premises instance of the Secure Gateway client that is running in a Docker image. When the client is connected, it will provide a secure connection from the user’s application to their backend database.

Getting Started

The user starts by downloading the Secure Gateway SDK package from the npm website,
www.npmjs.com/package/bluemix-secure-gateway. The package can be installed locally by issuing the npm installation command. The package also contains a package.json file which will be used by the npm command to install all required node modules. See the enclosed README.md for specific instructions on setting up your environment.

When the SDK is installed, we are ready to write some JavaScript. The examples in this document uses Node.js. First, we must concentrate on creating a gateway. To do this we can either reference the JavaScript in the lib subdirectory or the Swagger documentation that is provided as part of the Bluemix documentation “REST API for Secure Gateway Configuration“.

Creating a Secure Gateway

For this example, we use a simple org_id and space_id, along with some other server simplifications. To find your own org and space id, login into Bluemix and add the Secure Gateway Service to your dashboard. Click on the tile in order to invoke the service, you will find your orgGuid and spaceGuid in the URL for that page, the strings will look something like the following:

https://console.ng.bluemix.net/?ace_base=true#/resources/serviceGuid=cfa831e7-3d9b-4704-b869-29756b9c24d9&amp;<strong>orgGuid=2ab132ce-884f-4467-a4e0-04a4eb875ccd&amp;spaceGuid=8eddeede-3ed9-47ed-C7A2-f4169006f5cc</strong>

Use the two values along with your userID and password to update the secgw.js module defaults variable, e.g.:
// Defaults to setup the SDK
var defaults = { "username" : "myusername",
"password" : "mypassword",
"orgID" : "MyOrgID",
"spaceID" : "MySpaceID",
"basepath" : URL
}

We now write some simple code to create a configuration and run the mode to see whether it works. First, a peek at the code:
//
// Create a gateway
//
create_SecGW = function(desc, cb) {
sdk.createGateway(desc, function(error, configObject) {
if (error) {
console.error("There was an error creating a gateway- " + error);
cb(error, null);
} else {
config = configObject;
cb("OK", config);
}
});
}

In the preceding example, we created a simple function that we can call to create the configuration. The following calls the create config function:
//
// Main
//
create_SecGW("Our Secure Gateway configuration", function(error, _config) {
if (error == "OK" &amp;&amp; _config != null) {
console.info("A configuration object has been created: " + JSON.stringify(_config));
}
});

Next, we run the Node application to test if we can create a gateway. Note that in the following example, the host information will be very different from your actual application. Also note the inclusion of several generated artifacts such as a JSON Web Token (that is, jwt), which will be used later in this scenario to use other APIs.

If you have run the JavaScript provided with just the default json updates, you will notice more output. You will also notice, if you are logged into your Bluemix account, that your Secure Gateway instance will load automatically in the User Interface. Since the client is not connected it will show a status of disconnected. The following is a partial screenshot of this event.

Listing our Secure Gateways

Next, we use the API to list gateways that we have created. Note the changes to the calling code to handle simple error conditions:

//
// List Gateways
//
list_SecGWs = function(cb) {
sdk.listGateways("enabled", function(error, list) {
if (error) {
console.error("Cannot list gateways.");
cb(error, null);
} else {
console.info("list len: " + list.length);
cb("OK", list);
}
});
}

Next, we use the API to list gateways that we have created, updating our main routine. Note the changes to the calling code to handle simple error conditions:
//
// Main
//
create_SecGW("Our Secure Gateway configuration", function(error, _config) {
if (error == "OK" &amp;&amp; _config != null) {
console.info("A configuration object has been created: " + JSON.stringify(_config));

list_SecGWs(function(error, _list) {
if (error == "OK" &amp;&amp; _list != null) {
for (var ii = 0; ii &lt; _list.length; ii++) {
console.info("Gateway["+ii+"]: " + JSON.stringify(_list[ii]));
}
}
});
}
});


Now we execute our new code and see the results, or new gateway is created and appears in the array returned by the call.

Creating a Destination

Secure Gateways need to work with a specific on-premises destination. Next, we consider adding logic to create a destination for our database endpoint. To do this, we change the code to handle creating a destination for our gateway configuration. The destination IP address for our MongoDB server is 192.168.1.13 and the default port is 27017.

//
// Create a Destination
//
create_Destination = function(config_obj, desc, ip, port, uname, passwd, tls, cb) { // Please note, uname and passwd not supported this version
config_obj.createDestination(desc, ip, port, uname, passwd, tls, function(error, _endpoint) {
if (error) {
console.error("Could not create a destination for configuration: " + config_id);
cb(error, null);
} else {
cb("OK", _endpoint);
}
});
}

//
// Main
//
create_SecGW("Our Secure Gateway configuration", function(error, _config) {
if (error == "OK" &amp;&amp; _config != null) {
console.info("A configuration object has been created: " + JSON.stringify(_config));

list_SecGWs(function(error, _list) {
if (error == "OK" &amp;&amp; _list != null) {
for (var ii = 0; ii &lt; _list.length; ii++) {
console.info("Gateway["+ii+"]: " + JSON.stringify(_list[ii]));
}
}
create_Destination(_config,
"Our Secure Gateway DB destination",
DBHost,
27017,
null,
null,
"none", function(error, _ep) {
if (error == "OK" &amp;&amp; _ep != null) {
console.info("Endpoint created: " + JSON.stringify(_ep));
} else {
console.error("Error thrown: " + error);
}
});
});
}
});


Running this code creates the destination on the created Secure Gateway and yields the following output. The last line shows the destination endpoint that was created along with the correct on-premises connection information (see connection_info object within the output). It should also be noted that this is considered a user-defined destination and the cloud side port that has been defined is 1156.

We have now finished creating the Secure Gateway connection and destination. Next, we move on to our on-premises database.

MongoDB Setup

The educational institution has setup a database that contains the names of all the universities in the United States along with other collections that contain departments and account information for their own students. The following image is an example of what the sample database included in the download package looks like in RoboMongo.

There are currently three collections. For this scenario, we are interested the departments and collection of universities as shown in the previous screen capture. First, some MongoDB initialization code must be written to accept a database host (DBHost) and database port (DBPort), as these will change from prototyping on localhost and then finally using the Bluemix host name and port:

//
// Setup our Database connection
//
fs_mongo = {
"hostname" : DBHost,
"port" : DBPort,
"username" : "",
"password" : "",
"name" : "",
"db" : DBName,
"url" : "mongodb://" + DBHost + ":" + DBPort + "/" + DBName
};

//
// DB Initialization
//
function doGetDb(collections) {
var db;
db = mongojs.connect(fs_mongo.url, collections);

// This prevents main node app from crashing entirely if MongoDB becomes unavailable.
db.on("error", function(err) {
console.log(err);
});
return db;
}


Next we create a function to query the database, which for matters of this example we shall simply call ‘student-test’. The collection of interest is called ‘university’.
//
// get university call
//
_get_university = function(id, cb) {

console.log("Get university: " + id);
var collections = ["university"];
var db = doGetDb(collections);

// Find the username in persistence
db.university.find({
_id : parseInt(id)
}, function(err, uni) {
// if a general db error occurred report a persistence error
if (err) {
console.log("Failed to query database. " + err);
cb(err, null);
// university returned in an array
} else if (uni[0]) {
console.log("University: " + util.inspect(uni[0]));
cb("OK", uni[0]);
} else {
console.log("University not found.");
cb("Not Found", null);
}
});
}


More code is written to call the previous function to reveal database information by ID. Our sample code, when run, demonstrates its ability to access the database by using the on-premises host name or IP and port.

Putting the Pieces Together

We now have code that is written and tested to create a Secure Gateway and a destination to our on-premises application. We also have code that we can use to access our database, either on-premises or by using access that is granted through the cloud. Now, we will demonstrate how to use both sets of code to access the database collections by using the cloud and the IBM Secure Gateway for Bluemix.

A Few Code Changes First

First, we need to make a few code changes to our application to connect to the database. Our code has to take into account the host name and port that is returned from our create destination call. This is either done automatically by our calling function, or in our case we use the destination information that is supplied by the first application call to create the gateway and destination to access the database. First, we update the host name and port for the connection.

var DBHost = "bluemix-sample-cloud";
var DBPort = 15007;
var DBName = "student-test";

Then a simple call to query the specific university in question.
getuni("1");

Accessing the Database through the Secure Gateway Destination

We attempt to run our cloud application to connect to the database. However, the connection fails and no universities are found. It’s time to start the Secure Gateway client.

Starting the Secure Gateway Client

To start the Secure Gateway client we use the docker run command. After installing Docker, we run the following command. It includes the configuration ID for the last parameter: sudo docker run -it bluemix/secure-gateway-client Yfsr8iTnQwQ_local_ng

The Docker instance starts up and we see the following output.

Then we run the database portion of the application by using the cloud host name and port information. We see the same information that is transmitted over the cloud that uses the Secure Gateway.

The university information is returned correctly. On the client side, we see the following output, which indicates that several successful connections were made to transfer the information to our application.

Conclusion

In this example, we have demonstrated how to create a secure gateway and destination, and how to connect it to an on-premises database. These steps can be easily integrated into an existing JavaScript application or new development. Let us know what you think, and how the service can be improved to meet your needs. Join the conversation at Bluemix Developers Community for Secure Gateway, using the tag securegateway.

Useful Links

More stories
May 1, 2019

Two Tutorials: Plan, Create, and Update Deployment Environments with Terraform

Multiple environments are pretty common in a project when building a solution. They support the different phases of the development cycle and the slight differences between the environments, like capacity, networking, credentials, and log verbosity. These two tutorials will show you how to manage the environments with Terraform.

Continue reading

April 29, 2019

Transforming Customer Experiences with AI Services (Part 1)

This is an experience from a recent customer engagement on transcribing customer conversations using IBM Watson AI services.

Continue reading

April 26, 2019

Analyze Logs and Monitor the Health of a Kubernetes Application with LogDNA and Sysdig

This post is an excerpt from a tutorial that shows how the IBM Log Analysis with LogDNA service can be used to configure and access logs of a Kubernetes application that is deployed on IBM Cloud.

Continue reading