Team Collaboration and Secret-free Source on OpenShift

too many secrets

Experienced developers will tell you that keeping secrets (such as passwords and API keys) out of your source code is a good practice for a variety of reasons:

  • Leaked credentials can become a major security problem.
  • Projects often use different configurations when running in development mode, verses when in staging or production environments.
  • Establishing a consistent metaphor for accessing application-specific information - IP addresses, port numbers, passwords, and other details - is definitely something that will help your code stay clean and easy to read.

OpenShift can help with all of the above.

We offer cloud-based application hosting, supporting a wide variety of programming languages. Each hosted app is loaded into an OpenShift gear, which is automatically bundled with it's own git revision control repository.

Git helps you keep track of your changes as you work, and provides a simple and convenient way to make updates to your app.

Decentralized revision control

Git takes a peer-to-peer approach to software versioning, which is a great fit for Open Source development projects.

These projects often include distributed teams, each working independently on their own clone of the codebase.

Instead of relying on a central master, each cloned repository (or repo) contains it's own history of all known changes. Individual repos are then synchronized using push and pull commands to keep each project clone up-to-date.

Pushing changes to your Openshift gear will automatically update your app.

Team Collaboration

Within your OpenShift gear, your app's source is secure, and can only be accessed when the correct credentials are provided. In OpenShift's case, we use SSH keys to lock down access to your code. You can grant access to other users by adding their SSH public key to your OpenShift account, but this isn't usually necessary.

Be Careful: Adding another user's public key to your gear will not only grant them git access (and deployment capabilities), it will also provide them with ssh access as well.

Usually, production deployment responsibilities are managed by a select set of team members, and development collaboration is accomplished via an external Git hosting solution.

If you prefer to keep your source code private, use a private GitHub repo or any another private git address in the following section.

Send in the clones / configuring multiple remotes

These steps assume that you already have a working app on OpenShift. If you need help setting one up, our getting started guide is a great resource.

From within your local development codebase, you'll be able to check your existing list of remotes:

git remote -v

Your OpenShift gear's repo address should be listed in the output, under the name of origin.

Adding a new public remote is easy. This example shows how you might specify a new remote clone, hosted on GitHub:

git remote add github git@github.com:GITHUB_ACCOUNT/PROJECT_NAME.git

For the above line to work you'll need a valid GitHub account with ssh keys configured. You'll also have to provide your own GITHUB_ACCOUNT and PROJECT_NAME, which reference an empty GitHub project (no README or other starter files).

GitHub has plenty of great docs available to help with this step.

Pushing Changes to the Cloud

Once your new remote has been added, you'll be able to keep your local repo in sync with the GitHub-hosted remote clone:

git push github  # send your code to GitHub
git pull github  # pick up changes from your team

Updating your gear with your team's latest work is easy:

git pull github  # get the latest
git push origin  # and update your gear

Gearing up an application directly from source

With our latest command-line tools, your team members will be able to get a local clone of the project source, and their own OpenShift-hosted release of the app with a publicly addressable URL - all in a single command:

rhc app create APP_NAME CART_TYPE --from-code=https://github.com:GITHUB_ACCOUNT/PROJECT_NAME.git

Where APP_NAME is the name of your application, CART_TYPE is the name of an available cartridge type, and where --from-code points to an Openshift-compatible git project that you would like to include.

Keeping your source code secret-free

When you reach a point when you need to reference private data, such as API / Developer keys, DB passwords, user-authentication tokes, app or environment-specific data, or anything else that would benefit from abstraction - these steps should help provide a safe way to get the job done:

1. Connect to your application via ssh:

rhc ssh YOUR_APP_NAME

2. Add your environment variables to your ~/app-root/data/.bash_profile:

echo "export SECRET_PASS=12345678910" | tee -a ~/app-root/data/.bash_profile

Replace SECRET_PASS and the related value with whatever secret information that you would like to keep out of your code. The tee command above takes the export statement and appends it to the end of your .bash_profile file.

3. Make sure that your .bash_profile is sourced during startup:

If you are still logged in to your OpenShift gear, log out first. Then run the following locally on your laptop or desktop:

cd YOUR_LOCAL_REPO
echo "source ~/app-root/data/.bash_profile" | tee -a .openshift/action_hooks/pre_start_*
git add .openshift/action_hooks/pre_start_*
git commit -m 'importing bash profile during app init'
git push

4. Update your secondary (public) clone:

git push github

Once you have completed these steps, your app's source and project history should be available on GitHub.

Congrats!

You should also be able to reference your secret variables by checking your system environment from within your app.

NOTE: Applications that are configured to take advantage of OpenShift's auto-scaling features require a bit more work in order to keep your secrets in sync across each scaled environment.

Accessing environment variables

With node.js, environment variables can accessed via process.env.*. Specifically, the above example should make process.env.SECRET_PASS available in your code.

PHP users should be able to access the same variable as getenv('SECRET_PASS').

Python developers can import os and then check the contents of os.environ['SECRET_PASS'].

Ruby users should find the same value in ENV['SECRET_PASS'].

Now that you have successfully externalized your application secrets, you'll probably want to configure your local development environment, and any alternate deployment environments, with a matching set of variables. On a *nix-style operating system, this should work:

echo "export SECRET_PASS=12345678910" | tee -a ~/.bash_profile

Ancient Secrets - A final note

Removing secrets from source code which had been previously committed is definitely a move in the right direction. However, it's really best to keep secrets out of your source right from the start.

Public Git repositories allow people to view the entire history of your project's development. Even though the current version of your project may be clean, the it's history may not be. Make sure to think carefully and revoke old passwords and keys if needed before publishing your code.

What's Next?

Happy Hacking!