Skip to content

Secrets Management

Alec Vishmidt edited this page Jan 11, 2022 · 24 revisions

Introduction

We all have secrets, and we keep them, you know, in secret. But when it comes to our clients' secrets, we need to keep them twice more thoroughly. That's why we use Vault by HashiCorp, an enterprise-grade secrets repository. It allows to securely store all passwords, tokens, certificates, and smoothly integrate them into the codebase.

Access

You can access a web-based interface here: BN Vault

For authentication, generate Github Token as discussed

Structure

vault.bndigital.dev
├── accounts
│   └── <service uri>
│       └── <account identifier>
│           └── [key-value]
├── projects
│   └── <project name> - same as repository name
│       ├── global
│       │   └── <account identifier>
│       │       └── [key-value]
│       ├── infra-stage
│       │   └── <account identifier>
│       │       └── [key-value]
│       ├── infra-prod
│       │   └── <account identifier>
│       │       └── [key-value]
│       ├── infra-xxx
│       │   └── <account identifier>
│       │       └── [key-value]
│       └── extras
│           └── <service uri>
│               └── <account identifier>
│                   └── [key-value]
├── personal
│   ├── [certificate 1]
│   ├── [certificate 2]
│   └── [certificate x]
└── templates
    ├── project
    │   └── ...
    └── <service>
        └── ...

Overview

In the vault, there are the next root directories:

  • accounts folder stores all credentials to log into somewhere. If you need to have login/pass to an external or internal system, you would mostly find credentials right here.
  • projects folder stores all project-specific credentials. They should be applicable to this and only this project.
  • personal folder stores all secure data of you as a BN Digital Engineer.
  • templates folder doesn't store actual credentials but provide a straightforward structure that you are encouraged to copy.

Accounts structure

In the accounts folder, you will find all unique resource identifiers folders. Search for figma if you want to log into Figma account. Inside the folder, you would find the account ID and key-value pairs inside.

Accounts structure example
accounts
├── figma
│   └── [email protected]
│       └── login    > [email protected]
│       └── password > ********
├── mailgun
│   └── [email protected]
│       └── login    > [email protected]
│       └── token    > ****************
│       └── password > ********
└── ...

Projects structure

In the projects folder, you will find all project identifiers folders. Their names should correspond to github repository and PM tool name. Inside the folder, you could find the next structure:

<project name>
├── global
│   └── <account identifier>
│       └── [key-value]
├── infra-stage
│   └── <account identifier>
│       └── [key-value]
├── infra-prod
│   └── <account identifier>
│       └── [key-value]
├── infra-xxx
│   └── <account identifier>
│       └── [key-value]
└── extras
    └── <account identifier>
        └── [key-value]
  • global folder stores all credentials that are common to the whole project. For instance, it could be BN Digital Strapi credentials, or Google API key. The folder should not contain anything infrastructure-related.
  • infra-stage is a mandatory folder that stores all secrets regarding the staging environment and is exclusive to it. Databases, login/password pairs should go there if they are not common throughout the whole project.
  • infra-prod is a folder to keep if we took the responsibility to go production.
  • If we need to have another environment, a separate folder could be created with the name "infra-" and an identifier. It could be infra-qa, infra-stage2, etc.
  • All other secrets that for any reason don't match with the pattern go to the *extras folder.
Project structure example ``` demoproject ├── global │ └── strapi │ └── login > [email protected] │ └── password > ******** ├── infra-stage │ ├── digitalocean │ │ └── domain > s.example.com │ │ └── token > **************** │ └── smtp │ └── host > smtp.example.com │ └── port > 587 │ └── user > [email protected] │ └── password > ********** └── extras └── temp-certificate └── public > ********** ```

Conventions

Use kebab-case for all folder names.
Use camelCase for secrets naming.
Avoid symbols of all kinds except for - and @.

Consistent naming desired, as well as environment naming convention. Also, credentials are grouped by application, avoiding extra prefixing

Usage

When we store secrets in the vault, we need to retrieve them when we need them.

Step 1. We need an npm package be installed into the project. To do that, add @bn-digital/vault in package.json to devDependencies section.

package.json part
"devDependencies": {
  "@bn-digital/vault-env": "^1.4.0"
}

Step 2. Now, we need to propagate the information from the vault into the project. All secrets should go to .env file first, then you would be able to use it in your code. To get vault secrets to the .env file, you would need to create a .env.dist template file, declare variables, and assign a secret per variable. Your .env.dist file should look like:

DOMAIN=${{projects/demoproject/infra-stage/digitalocean/domain}}
TOKEN=${{projects/demoproject/infra-stage/digitalocean/token}}

DOMAIN is the name of a variable, you can name it as you wish. projects/demoproject/infra-stage/digitalocean/domain is a link to a vault secret value. The structure is super-straightforward:

 projects / demoproject / infra-stage / digitalocean / domain
└───────── └──────────── └─────────── └───────────── └───────
   root     project name   "folder"       service     key

Step 3. From now on, you would be able to use a secret with simple process.env.DOMAIN and process.env.TOKEN calls.

Step 4. To test the project locally, you would need to create your local .env file. It should look like:

VAULT_ENDPOINT=https://vault.bndigital.dev
GITHUB_TOKEN=${{ YOUR_GITHUB_TOKEN }}

It should look like

VAULT_ENDPOINT=https://vault.bndigital.dev
GITHUB_TOKEN=supersecrettoken102934920

Attention! .env file should not go to git. By default it is ignored, and so should it be.

After that, prepend that command in start script for your convenience:

{
  "scripts": {
    "start": "vault-env && strapi develop"
  }
}

Q&A

Why can't we store all secrets in a repository? — Cause it is insecure, especially for the front-end part. You can't store any secret on the front-end side, as it could be simply reverse-engineered and stolen.

Why can't we store secrets on local machines? – Cause it is both insecure and not scalable. Remember, we work as a team, and sharing passwords securely is important. You can't just send a password in an email or a slack channel, even a client does that.

Why it is so important? – Cause it is a security issue, and security is treated as one of the most important human needs. That is our obligation as a team and as an organisation to keep clients' secrets as secure as possible.