Semi-Custom Domains for OpenWhisk Web Apps

rodric rabbah
Apache OpenWhisk
Published in
6 min readFeb 17, 2017

In recent articles, I introduced a new serverless programming feature that is now available in Apache Openwhisk: web actions.

Web actions are quite powerful for web and API developers because they allow you to write HTTP handlers that execute in response to API calls, without deploying or managing servers. It’s even possible to build both front-end and back-end logic using web actions, as I showed using a QR code generator web app.

I noted in the previous article that:

Web actions are served from a URL that is structured as follows: https://{APIHOST}/api/v1/web/{QUALIFIED ACTION NAME}.{EXT}. The fully qualified name of an action consists of three parts: the namespace, the package name, and the action name. An example is guest/qr/ui. The last part of the URI is the extension which is typically .http although other values are permitted.

It’s evident from the URL structure above that web actions also come with long and ugly URLs that are bound to the OpenWhisk API host. This exposes some considerations that I address in the rest of the article.

  1. HTTP cookies may be inadvertently exposed to any other web app also running as a web action.
  2. The same-origin policy applies to all web actions hosted on the same domain. On the one hand, this means a web app may use XMLHttpRequest to invoke other web actions also hosted by OpenWhisk. On the other, it makes local storage essentially accessible to the entire domain as well.
  3. Static content (e.g., HTML, JavaScript functions) will need to hard code the full path for web actions.

For these reasons, it is at least desirable to have a semi-custom domain name, if not a fully custom domain name. By semi-custom, I mean a subdomain name that a developer can specify even if he or she cannot specify the top level domain name. For example https://rabbah-demos.mybluemix.net. The mapping of web actions to a specific subdomain allows the actions to use cookies and local storage with fewer client-side security concerns.

Another benefit of using a subdomain is to allow static content (e.g., an HTML page) to reference other OpenWhisk artifacts more simply, to make Ajax requests for example. It is far more convenient to refer to a short relative URL path compared to a complete URL like the one shown above where at best, one can eschew the APIHOST.

<script>
$("button").click(function() {
$.ajax({
url: "/public/index.html", // path now relative to subdomain
success: function(result) {
...
}
})
})
</script>

An obvious answer to get some control over the domain name is to deploy a reverse proxy. But then this is no longer “serverless” — you have to host the proxy somewhere, pay for it, operate it, etc. From a developer perspective, this is precisely what is appealing about serverless: someone else carries the burden of operating the server. I for one simply want to develop and deploy my code, and just my code.

This is also what an “API gateway” for serverless does for you in general, and, the idea of a proxy to OpenWhisk is not new, as others have already done it for themselves, or as part of the Apache OpenWhisk project (also on Bluemix).

I’m going to describe how you can deploy your own programmable API gateway, with administrative operations to list, add and delete subdomains in Bluemix. You may use this to customize your own proxy to OpenWhisk, for example, or if you’re using a private deployment that is shared with other OpenWhisk developers.

Facilitating this work is the observation that a web application, using web actions, is comprised of assets that are deployed in a single OpenWhisk namespace. This means the long API path really only varies starting with the the package and action names. Hence, the namespace can serve as the subdomain name and provide a trivial mapping to the web action path. So the URL https://rabbah-demos.mybluemix.net/public/index.html is now an alias for https://openwhisk.ng.bluemix.net/api/v1/web/rabbah_demos/public/index.html but with the advantages of client-side security, and relative path support as in the Ajax example.

I used Bluemix to host my proxy service and I will describe in a future article how you may use it without deploying your own (hence serverless for you). The service is a good case study in building a secured application with web actions. If you are already running a reverse proxy elsewhere (or want to run your own to have more control), then adding a proxy rule to redirect traffic to OpenWhisk in the same way will allow you to use your namespace as the subdomain name.

Deploying a reverse proxy for web actions

With Bluemix, there is a fairly convenient way to deploy a proxy like NGINX using a Cloud Foundry (CF) app and mapping routes to it. This will permit one to create routes with some control over the subdomain name, hosted on mybluemix.net.

The following assumes some familiarity with the cf command line tool. Using the standard static content build pack, one can provide a custom NGINX configuration file to proxy incoming requests to OpenWhisk web actions. I created a configuration file to perform the following:

  1. Redirect all HTTP traffic to HTTPS.
  2. Extract the CF organization (org) and space (space) from the request server_name ~^(?<org>[0–9a-zA-Z-]+)-(?<space>[0–9a-zA-Z-]+)\.*$;.
  3. Rewrite the request to a web action URI /(.*) /api/v1/web/${org}_${space}/$1. The rewrite rule allows for a general mapping from org/space pairs to OpenWhisk namespaces, treating the rest of the URL as the package name, action name, and extension.
  4. Proxy the request to https://openwhisk.ng.bluemix.net which is the OpenWhisk API host on Bluemix.

With the configuration file in hand, I enabled the reverse proxy by pushing the CF app.

# fetch NGINX configuration file
$ curl https://raw.githubusercontent.com/rabbah/wsk-router/master/cf/router/nginx.conf > nginx.conf
# login to cf endpoint, if necessary
$ cf login
# push the app, replacing APP_NAME below with your preferred name
$ cf push APP_NAME -m 64m -b \
https://github.com/cloudfoundry/staticfile-buildpack.git

Mapping subdomains to web action namespaces

The reverse proxy as configured allows for a mapping from multiple org/space pairs to OpenWhisk namespaces. So given a pair of values, I used an OpenWhisk action and the CF Node.js client to create a CF route and map it with my proxy. I shared the code for adding and removing routes on GitHub. There’s an action to add (map) routes, and similarly one to delete (unmap) routes.

$ wsk action invoke -br router/map -p org rabbah -p space demos
{ "status": [ { "ok": true, "route": "rabbah-demos" } ]

Running the router/map action as shown above will create the route rabbah-demos.mybluemix.net. And just like that, the route is live!

Some caveats: the subdomain must be 63 characters or less and may only contain alphanumeric characters or dashes. This is more restrictive than a Bluemix org/space in general. Further the way OpenWhisk maps org/spaces to namespace is to concatenate them with an underscore. The proxy is configured to rewrite the dash to an underscore, and will only match conforming names (i.e., org-space).

Actions with a purpose

Once I deployed the web action reverse proxy, I wanted to make it more generally accessible so that other OpenWhisk developers (you!) on Bluemix can take advantage of the benefits it affords. So naturally, I turned to web actions to build a web application that allows users to:

  1. Authenticate with Bluemix.
  2. Select a conforming org/space that is also an OpenWhisk namespace.
  3. Perform the route creation and mapping.

An important consideration in developing the service is that the route mapping (i.e., invoking the router/map action) must be protected and accessible only to authenticated and authorized developers.

In this article, I focused on the client-side security of web actions and showed you how using a programmable reverse proxy, to map subdomains to OpenWhisk namespaces, allows web actions to use cookies and local storage with greater access control.

In a future article, I will address the “server-side” security of web actions, which by themselves offer no built-in authentication or access control. I will cover the front-end UI for the mapping service and its back-end API, as well as authentication, authorization, and all that good stuff.

Apache OpenWhisk is available on GitHub. You can try it on Bluemix, and reach us on Slack.

--

--