https://github.com/pacphi/cloudfoundry-and-nodejs-with-vault-demo
This is a simple example of an integration between a REST API powered by NodeJS and Hashicorp Vault.
https://github.com/pacphi/cloudfoundry-and-nodejs-with-vault-demo
hashicorp-vault nodejs rest-api
Last synced: 8 months ago
JSON representation
This is a simple example of an integration between a REST API powered by NodeJS and Hashicorp Vault.
- Host: GitHub
- URL: https://github.com/pacphi/cloudfoundry-and-nodejs-with-vault-demo
- Owner: pacphi
- Created: 2018-06-13T07:53:30.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2021-06-24T13:12:48.000Z (almost 5 years ago)
- Last Synced: 2025-07-05T18:37:39.605Z (10 months ago)
- Topics: hashicorp-vault, nodejs, rest-api
- Language: JavaScript
- Size: 5.86 KB
- Stars: 1
- Watchers: 0
- Forks: 1
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Using NodeJS and HashiCorp Vault with Cloud Foundry
This is a simple example of an integration between REST API powered by NodeJS and [Hashicorp Vault](https://www.vaultproject.io).
A riff off the Spring Boot 2 and Spring Cloud Finchley implementation [here](https://github.com/pacphi/cloudfoundry-with-vault-demo).
## Prerequisites
* [CF CLI](https://github.com/cloudfoundry/cli#downloads) 6.37.0 or better if you want to push the application to a Cloud Foundry (CF) instance
* [httpie](https://httpie.org/#installation) 0.9.9 or better to simplify interaction with API endpoints
* Hashicorp [Vault](https://www.vaultproject.io/downloads.html) 0.12.0 or better
* [NodeJS](https://nodejs.org/en/download/) 10.4.0 or better
* [jq](https://stedolan.github.io/jq/) 1.5 or better to
* [ngrok](https://ngrok.com) 2.28 or better to expose local servers behind NATs and firewalls to the public internet over secure tunnels
## Clone
```
git clone https://github.com/pacphi/cloudfoundry-and-nodejs-with-vault-demo.git
```
## How to build
```
cd cloudfoundry-and-nodejs-with-vault-demo
npm install
```
## How to run locally
1. Start vault
```bash
vault server -config inmemory.conf
```
2. In another terminal set the VAULT_ADDR before initializing Vault
```bash
export VAULT_ADDR=http://127.0.0.1:8200
```
2. Initialize vault
```bash
vault operator init -key-shares=5 -key-threshold=2
```
3. Copy the `Initial Root Token`
> We will need it later.
```bash
export VAULT_TOKEN=
```
Vault requires an authenticated access to proceed from here on.
Vault uses tokens as generic authentication on its transport level.
4. Vault is in `sealed` mode, let's unseal it
```
vault operator unseal
vault operator unseal
```
5. Verify that Vault is in `unsealed` mode
```bash
vault status | grep Sealed
Sealed: false
```
6. Write a secret into the `secret` backend
```bash
vault write secret/nodejs-vault-demo message='I find your lack of faith disturbing.'
```
7. Start the application in another terminal
```bash
export VAULT_ADDR=http://127.0.0.1:8200
export VAULT_TOKEN=
node app.js
```
8. Make a GET request to http://localhost:3000
```bash
http :3000
I find your lack of faith disturbing.
```
9. Update the secret inside Vault
```bash
vault write secret/nodejs-vault-demo message='Now, young Skywalker, you will die.'
```
> Changes to configuration are immediate
12. Verify that the application knows about the latest secret
```bash
http :3000
Now, young Skywalker, you will die.
```
## How to run on Cloud Foundry
1. Using [Pivotal Web Services](https://run.pivotal.io/)
> This is Pivotal's Cloud Foundry as a Service offering
```bash
cf login -a api.run.pivotal.io
```
2. Get the [Open Service Broker API](https://www.openservicebrokerapi.org/) implementation from HashiCorp
```bash
git clone https://github.com/hashicorp/vault-service-broker
```
3. You will to change the `DefaultServiceID` and `DefaultServiceName` in the `main.go` file
4. Deploy the broker
```bash
cf push my-vault-broker-service -m 256M --random-route --no-start
```
The `--no-start` makes sure it is not started after it is deployed.
5. Expose the locally running vault instance via [ngrok](https://ngrok.com/)
```
ngrok http 8200
Forwarding http://3db1eef2.ngrok.io -> localhost:8200
Forwarding https://3db1eef2.ngrok.io -> localhost:8200
```
> Note your ngrok URL will be different
6. Open a browser and verify ngrok's web interface is available at `http://localhost:4040`
7. Set the following environment variables
```bash
VAULT_ADDR=
VAULT_TOKEN=
```
The broker is configured to use basic authentication
```bash
VAULT_USERNAME=vault
VAULT_PASSWORD=secret
```
> You'll want to replace the username and password values above with your own. Password must not contain `@`.
8. Configure the environment variables
```bash
cf set-env my-vault-broker-service VAULT_ADDR ${VAULT_ADDR}
cf set-env my-vault-broker-service VAULT_TOKEN ${VAULT_TOKEN}
cf set-env my-vault-broker-service SECURITY_USER_NAME ${VAULT_USERNAME}
cf set-env my-vault-broker-service SECURITY_USER_PASSWORD ${VAULT_PASSWORD}
```
9. Verify the configured environment variables
```bash
cf env my-vault-broker-service
```
10. Start the broker:
```bash
cf start my-vault-broker-service
```
11. Check the logs to verify a successful start
```bash
cf logs --recent my-vault-broker-service
```
12. Verify in the Ngrok Inspect UI the activity requests sent to the exposed Vault broker
```bash
GET /v1/sys/mounts
PUT /v1/auth/token/renew-self
POST /v1/sys/mounts/cf/broker
GET /v1/cf/broker
```
13. The service broker created a new mount
```
vault secrets list
...
cf/broker/ generic generic_4c6ea7ec n/a system system false replicated
...
```
14. View the running broker:
```
cf apps
name requested state instances memory disk urls
my-vault-broker-service started 1/1 256M 1G vault-demo-twiggiest-sennit.cfapps.io
```
15. Get the broker url
```bash
VAULT_BROKER_URL=$(cf app my-vault-broker-service | grep routes: | awk '{print $2}')
```
16. Get the catalog information:
```bash
curl ${VAULT_USERNAME}:${VAULT_PASSWORD}@${VAULT_BROKER_URL}/v2/catalog | jq
```
```json
{
"services": [
{
"id": "42ff1ff1-244d-413a-87ab-b2334b801134",
"name": "my-hashicorp-vault",
"description": "HashiCorp Vault Service Broker",
"bindable": true,
"tags": [
""
],
"plan_updateable": false,
"plans": [
{
"id": "42ff1ff1-244d-413a-87ab-b2334b801134.shared",
"name": "shared",
"description": "Secure access to Vault's storage and transit backends",
"free": true
}
]
}
]
}
```
17. Create a service broker:
```bash
cf service-brokers
cf create-service-broker my-vault-service-broker "${VAULT_USERNAME}" "${VAULT_PASSWORD}" "https://${VAULT_BROKER_URL}" --space-scoped
```
> You need to specify the `--space-scoped` and the `service ids` and `service name` must be unique. See `https://docs.cloudfoundry.org/services/managing-service-brokers.html`
18. Create a service instance
```bash
cf create-service my-hashicorp-vault shared my-vault-service
```
> Note that the first parameter to `cf create-service` must match the value of `DefaultServiceName` that you set in Step 3 above
19. Verify the result
```bash
cf services
name service plan bound apps last operation
my-vault-service my-hashicorp-vault shared create succeeded
```
20. Verify the HTTP requests sent the exposed Vault service using the Ngrok Inspect UI:
```bash
POST /v1/sys/mounts/cf/0b24f466-9a54-4215-852e-2bcfab428a82/secret
PUT /v1/cf/broker/0b24f466-9a54-4215-852e-2bcfab428a82
GET /v1/sys/mounts
POST /v1/sys/mounts/cf/0b24f466-9a54-4215-852e-2bcfab428a82/transit
POST /v1/sys/mounts/cf/be7eedf8-c813-49e1-98f8-2fc19370ee4d/secret
POST /v1/sys/mounts/cf/5f7b0811-d90a-47f2-a194-951eb324f867/secret
PUT /v1/sys/policy/cf-0b24f466-9a54-4215-852e-2bcfab428a82
PUT /v1/auth/token/roles/cf-0b24f466-9a54-4215-852e-2bcfab428a82
```
When a new service instance is provisioned using the broker, the following paths will be mounted:
Mount the generic backend at /cf//secret/
Mount the generic backend at /cf//secret/
Mount the generic backend at /cf//secret/
Mount the transit backend at /cf//transit/
A policy named `cf-` is also created for this service instance which grants read-only access to `cf//*`, read-write access to `cf//*` and full access to `cf//*`
21. Create a service key
> (This failed in Swisscom's Cloud Foundry)
```bash
cf create-service-key my-vault-service my-vault-service-key
cf service-keys my-vault-service
```
18. Verify the received requests for Vault using the Ngrok Inspect UI
```bash
PUT /v1/auth/token/renew-self
PUT /v1/auth/token/renew-self
PUT /v1/cf/broker/0b24f466-9a54-4215-852e-2bcfab428a82/5cf104c9-4515-40f3-94de-a63ab77cb84b
POST /v1/auth/token/create/cf-0b24f466-9a54-4215-852e-2bcfab428a82
```
19. Retrieve credentials for this instance
```bash
cf service-key my-vault-service my-vault-service-key
```
```json
{
"address": "https://1f81e0d3.ngrok.io/",
"auth": {
"accessor": "3705e5b2-c0bb-6398-ecff-e05a9e6a7b28",
"token": "d5971c27-cf77-6ff0-f5c9-430fdfe07066"
},
"backends": {
"generic": "cf/0b24f466-9a54-4215-852e-2bcfab428a82/secret",
"transit": "cf/0b24f466-9a54-4215-852e-2bcfab428a82/transit"
},
"backends_shared": {
"organization": "cf/be7eedf8-c813-49e1-98f8-2fc19370ee4d/secret",
"space": "cf/5f7b0811-d90a-47f2-a194-951eb324f867/secret"
}
}
```
20. Deploy the Vault client application
```bash
cf push --random-route --no-start
```
21. Bind the `my-vault-service` to the `nodejs-vault-demo` application
```bash
cf bind-service nodejs-vault-demo my-vault-service
```
22. Start the Vault client application
```bash
cf start nodejs-vault-demo
```
23. Verify that the application has started successfully and environment variables are as expected
```bash
cf logs --recent nodejs-vault-demo
cf env nodejs-vault-demo
```
24. Let's write a secret into the Vault to the given generic backend and send a refresh command.
```bash
vault write cf/0b24f466-9a54-4215-852e-2bcfab428a82/secret/vault-demo message='Vault Rocks'
```
> Replace application URL with your own
25. We can verify that the secret is retrieved via
```bash
http get http://vault-demo-twiggiest-sennit.cfapps.io
message: Vault Rocks
```
> Replace application URL with your own