Secrets are sensitive data that you want to store securely and tightly control access to. Examples of secrets include API keys, encryption keys, Oauth tokens, certificates, PEM files, passwords, and passphrases. Secrets are one of the most valuable items in your source code, because you need them to access resources and make changes to your code.
Anyone could make a mistake and have their secrets exposed. Social media giant Facebook mistakenly stored ‘hundreds of millions’ of user passwords as plaintext. A recent study from researchers at NC State University (PDF) found that over 100,000 public Github repositories are unknowingly leaking secret keys, and thousands of new, unique secret keys are being leaked every day.
If you do not store your secrets in an encrypted and secure way, they could easily be exposed and compromised! The consequences can be devastating – your company might be extorted or worse, like what happened to Codespaces. This is why you need to pay a special attention to securing your secrets.
Everything should be encrypted both in transit and at rest. When your secret is encrypted, it is not available to the attacker and you can cut off access and rotate the plaintext secret to remedy the situation.
When there are secrets in your source control git repositories, anyone who clones your repositories will have those secrets in plain text in their local computer. Even worse, when the code containing secrets is pushed into production, your secrets are now on the production servers. If any those servers suffer from a security breach, or a computer gets stolen, you will be compromised.
One of the best practices around handling configuration according to the twelve-factor app methodology is to have it injected via an environment variable into your application. You should do this for your secrets. If you use Node.js like we do at Datree, you can use the confignpm package in order to do so.
$ npm install config$ mkdir config$ vi config/default.json{ "Customer": { "dbConfig": { "host": "localhost", "port": 5984, "user": "dbuser", "pass": "4jf8235D4x#", "dbName": "customers" }, }}
view rawdbconfig.js hosted with ❤ by GitHub
Vault is a very popular solution by Hashicorp that provides a solution for securely accessing secrets, and it is open-source. It provides a unified interface to any secret, while providing tight access control and recording a detailed audit log.
You have to install and manage Vault within your environment. Follow the Getting Started guide in order to learn how to install and manage your Vault server.
AWS Secrets Manager helps you protect secrets needed to access your applications, services, and IT resources. The service enables you to easily rotate, manage, and retrieve database credentials, API keys, and other secrets throughout their lifecycle.
With AWS Secrets Manager, you can manage access to secrets using fine-grained AWS Identity and Access Management (IAM) policies. For example, you can create a policy where you allow developers to retrieve certain secrets only when they are used for the development environment.
AWS Systems Manager Parameter Store provides a centralized store to manage your configuration data, whether plain-text data such as database strings or secrets such as passwords. This allows you to separate your secrets and configuration data from your code.
Every microservice has its own encryption key in IAM KMS. This is the solution we use at Datree. We use the key to encrypt/decrypt a unique configuration per service.
ProductPriceManagedHashicorp VaultFree / Pro / Enterprise ($100- to $2000 per license)NoAWS Secrets Manager$0.05 per 10,000 API calls.YesAWS Parameter StoreFree (limitations)Yes
At Datree we have code for fetching secrets and configuration for a service, written in Node.js. The code determines the service name by reading it from package.json, then it attempts to fetch the secret configuration with the corresponding service name in Parameter Store by using its IAM policy and unique KMS encryption key. See our code here:
const fs = require('fs')const path = require('path')try { fs.unlinkSync(path.join(__dirname, 'local.json'))} catch (err) {}const AWS = require('aws-sdk')AWS.config.update({ region: 'us-east-1' })const ssm = new AWS.SSM()var serviceName = require('../package.json').nameasync function getConfig() { var params = { Name: serviceName, WithDecryption: true } let res = await ssm.getParameter(params).promise() let settings = res.Parameter.Value writeLocalConfig(settings)}function writeLocalConfig(settings) { fs.writeFileSync(path.join(__dirname, 'local.json'), settings)}getConfig()
view rawconfiguration.js hosted with ❤ by GitHub
A quick and easy way to find out if you have any secrets inadvertently exposed to the public – and you should want to find out – is to take advantage of Datree’s repository visibility report.
The process is quick and easy. Sign up for Datree to connect it to your Github account then install it. Datree is free for personal repos and organization repos with less than five developers.
Once installed, you will get a status report listing all insights gathered from all your repositories’ metadata, including any exposed secrets.
Once you install the Datree GitHub app you can specify which policies would you like to enable for your GitHub organization. When you enable the separate secret credentials from source code policy rule, every pull request whose code contains secrets will be automatically blocked, and a developer will need to resolve the issue before they can merge the changes to your default branch. Like so: