-
Notifications
You must be signed in to change notification settings - Fork 3
Using HTTPS and WebAPI
Since the CernVM WebAPI
daemon runs an HTTP server, bound to the localhost address it's not possible to use SSL encryption. That's because it's not possible to issue an SSL certificate for the localhost address, and installing our own CA in user's computer implies additional security risks.
Unfortunately, due to the latest HTML5 security policies, that restrict the mixing of HTTP and HTTPS content, the javascript library cannot establish a websocket connection to the WebAPI
Daemon if it's served under HTTPS.
There is a simple solution to this problem, but it only works if you do not need to have real-time feedback to the hosting website:
- Prepare your VMCP response while in the secure session
- Store it under a key with unique ID and
- open an HTTP pop-up window to handle the request.
You can read more in the next section:
As mentioned before, the easiest trick is to compile the configuration of your VM while in a secure session and open an insecure pop-up window to handle the launching process. Let's explore this option in a step-by-step example:
Let's say that the user is in your website https://website.com/repository
and picks to start a particular VM. Since we are using SSL, we cannot use WebAPI, but we can still open a pop-up window under http:
. Therefore we are focusing on creating a secure mechanism to deliver the required information from the https:
version of the website to the http:
version of the website.
Therefore, upon the start request, we can use the session information (ex. current user's name, preferences etc.) and the user's choice to compile the specifications of the VM we want to serve as a VMCP object:
{
"name": "John__UbuntuVM",
"secret": "us3rspassword",
"vcpus": 1,
"memory": 512,
"cernvmVersion": "latest",
"flags": 8,
"userData": "[amiconfig]\nplugins=cernvm\n[cernvm]\nusers=user:users:usersecret",
}
Then create a cryptographically unique ID and store this object in a key/value store under this ID.
Let's say for our example that the ID is 4DC05982-614C-4539-8E0E-D2C4B37C6C92
In order to pass these data to CernVM WebAPI
you will need a VMCP endpoint. Since we are going to serve it under an HTTP session you will need to expose these information under a dedicated URL. This URL will be composed of a fixed prefix and the unique ID generated in the previous step. For example: http://website.com/vmcp/4DC05982-614C-4539-8E0E-D2C4B37C6C92
For improved user experience it's a good idea to have this URL completely exposed to the public, session-less, without any restriction. The data are protected since the ID is unique. As an additional security measure, you should delete the key after the URL is accessed once.
This URL should properly respond with a signed VMCP response according to the guidelines found in the Calculating VMCP Signature page.
Having your VMCP endpoint available under an insecure URL you can now safely host the rest of your WebAPI javascript code in a separate URL, served under http. Upon visiting the URL, the VM should be immediately launched.
This way, we have a URL in the following form: http://website.com/launch?id=4DC05982-614C-4539-8E0E-D2C4B37C6C92
that upon visiting will immediately start the VM.
As a reference, you can check the javascript function we are using in CernVM Online:
/**
* Launch a VM using the specified VMCP URL
*/
window.launchMachine = function(vmcp_url) {
// Initialize CernVM WebAPI
CVM.startCVMWebAPI(function(api) {
$("#lbl-status").text("CernVM WebAPI Ready");
// Bind progress listeners on the plugin instance
api.addEventListener('started', progress_started);
api.addEventListener('completed', progress_completed);
api.addEventListener('progress', progress_updated);
api.addEventListener('failed', progress_error);
api.addEventListener('disconnected', disconnected);
// Request a session through our specified VMCP endpoint
api.requestSession(vmcp_url, function(session) {
$("#lbl-status").text("Session open");
// Bind progress listeners on the session instance
session.addEventListener('started', progress_started);
session.addEventListener('completed', progress_completed);
session.addEventListener('progress', progress_updated);
session.addEventListener('failed', progress_error);
// Listen for state changed events
session.addEventListener('stateChanged', function(newState) {
// When we are running we don't need the window any more
if (newState == 5) {
window.close();
}
});
// We just start the session the moment we get it
session.start();
});
});
}
We are passing the VM ID from the GET parameter as a first argument to the javascript function. Again the following snipped is from CernVM Online:
<script type="text/javascript">launchMachine('{{vmcp}}');</script>
Now that we have all of our components in place, we can create a pop-up window to handle user's request in the following steps:
- When clicking
Start
, open a pop-up window, pointing to an https 'bootstrap' url. - Compile the VMCP data seen in Step 1.
- Redirect to the HTTP URL of Step 3.
- Upon successful launch, close the pop-up window.
You can see in CernVM Online how we are opening the bootstrap URL. Be aware that you need to allocate enough space for the in-page pop-up windows to be visible. 700x500 pixels is a good starting point.
As an example, you can see the webapi application in the CernVM Online django app : https://github.com/cernvm/cernvm-online/tree/master/src/cvmo/webapi