Community

Keeping secrets – how your cloud application should access credentials and other private data

Share this post:

If you’re building a web app, you probably have secrets you have to deal with:

  • database credentials
  • session keys
  • etc

So, where do you keep these secrets? Typical ways are:

  • hard-code them into your source
  • require them to be passed on the command-line of your program
  • get them from a configuration file
  • get them from environment variables

Developers using Cloud Foundry based systems have another option:

This blog post will go over the advantages and disadvantages of these approaches. Examples are provided for node.js, but are applicable to any language.

secrets via hard-coding

The documentation for the express-session package shows the following example of hard-coding your secrets into your code:

This is awful:

  • If you need to change the secret, you need to change the code; apply
    some separation of concerns, and keep your code separate from your
    configuration.
  • If you happen to check this code into a source code management (SCM) system,
    like GitHub, then everyone with access to that SCM will have access to your
    password. That might be literally everyone.

Please, DO NOT DO THIS!

Don’t be one of these people. Instead, use one of the techniques below.

secrets via configuration files

Here is an example using require() to get a secret from
a JSON file:

This example takes advantage of the node.js feature of being able to load
a JSON file and get the parsed object as a result.

If you’re going to go this route, you should do the following:

  • Do NOT store the config file in your SCM, because otherwise you may still
    be making your secret available to everyone who has access to your SCM.
  • To keep the configuration file from being stored, add the file to your
    .gitignore file (or equivalent for your SCM).
  • Create an example configuration file, say secret-config-sample.json, which other developers
    can copy to the actual secret-config.json file, and use as an example.
  • Document the example configuration file usage.

You now have an issue of how to “manage” or save this file, since it’s not
being stored in an SCM.

secrets via command-line arguments

Here is an example using the nopt package to get a secret from a command-line argument:

You can then invoke your program using either of these commands:

<code>node secret-arg.js --sessionSecret "keyboard cat"
node secret-arg.js -s "keyboard cat"
</code>

This is certainly nicer than having secrets hard-coded in your app, but it also means you will be typing the secrets a lot. If you decide to “script” the command invocation, keep in mind your script now has your secrets in it. Use the “example file” pattern described above in “secrets via config files” to keep the secret out of your SCM.

secrets via environment variables

Here is an example using process.env to get a secret from an environment variable:

You can then invoke your program using the following command:

<code>SESSION_SECRET="keyboard cat" node secret-env.js
</code>

Like using command-line arguments, if you decide to create a script like this, keep in mind your secret will be visible to those having access to the script.

You likely have other ways of setting environment variables when you run your program. For instance, in Cloud Foundry, you can set environment variables via a manifest.yml file or with the cf set-env command.

If you decide to set the environment variable in your manifest.yml file, keep in mind your secret will be in the manifest. Use the “example file” pattern described above in “secrets via configuration files” to keep the secret out of your SCM. That is, put manifest.yml in your .gitignore file, and ship a manifest-sample.yml file instead.

secrets via Cloud Foundry user-provided services

Here is an example using the cfenv package to get a secret from a user-provided service:

This is my favorite way to store secrets for Cloud Foundry. In the example above, the code is expecting a service whose name matches the regular expression /session-secret/ to contain the secret in the credentials property named secret. You can create the user-provided service with the cf cups command:

<code>cf cups a-session-secret-of-mine -p secret
</code>

This will prompt you for the value of the property secret, and then create a new service named a-session-secret-of-mine. You will need to cf bind the service to your application to get access to it.

There are a number of advantages to storing your secrets in user-provided services:

  • A service can be bound to multiple applications; this is a great way to store secrets that need to be shared by “micro-services”, if you’re into that kind of thing.
  • Once created, these values are persistent until you delete the service or use the new cf uups command to update them.
  • These values are only visible to users who have the appropriate access to the service.
  • Using regular expression matching for services makes it easy to switch services by having multiple services with regexp matchable names, and binding only the one you want. See my project bluemix-service-switcher for an example of doing this.

secrets via multiple methods

Of course, for your all singing, all dancing wunder-app, you’ll want to allow folks to configure secrets in a variety of ways. Here’s an example that uses all of the techniques above – including hard-coding an undefined value in the code! That should be the only value you ever hard-code. 🙂

The example uses the defaults() function from underscore to apply precedence for obtaining a secret from multiple techniques.

Add Comment
2 Comments

Leave a Reply

Your email address will not be published.Required fields are marked *


Mark B

Is there a way to create a user provided service (and credentials) in the bluemix UI or can it only be done from the CF command line?

Reply

pmuellr_ibm

As far as I know, it can only be done with the `cf` command-line. You can set env vars (eg, `cf set-env …`) via the Bluemix UI.

Reply
More How-tos Stories

Build and deploy a MEAN stack application on IBM Cloud

MEAN is a collection of JavaScript-based technologies — MongoDB, Express.js, AngularJS, and Node.js — used to develop web applications. From the client and server sides to databases, MEAN is a full-stack development toolkit. This tutorial walks you through the creation of a web application using the popular MEAN stack. It is composed of a Mongo DB, Express web framework, Angular front-end framework and a Node.js runtime.

Continue reading

A hybrid Cordova mobile app with Push and Analytics in minutes

As promised while introducing "Tutorials to get your mobile development up and running", we are continuing our efforts to add more mobile solution tutorials. After quickly scaffolding a native iOS-Swift and Android mobile app with Push and Analytics, it's time to bring in the hybrid mobile app development flavor to the game with Cordova - Apache Cordova is an open-source mobile development framework. It allows you to use standard web technologies - HTML5, CSS3, and JavaScript for cross-platform development.

Continue reading

Use your own branded UI for user sign-in with App ID

With IBM Cloud App ID’s Cloud Directory feature, you can create a user registry, and add sign-up and email/password sign-in to your mobile or web app. Cloud Directory comes with a pre-built sign-in widget that you can use, or if you prefer to use your own branding, you can replace it with your own custom UI. This blog will show you how to use Cloud Directory APIs and add your own custom sign-in screen to an Android application. You can find the Android Cloud Land App on GitHub.

Continue reading