Vault Secrets in a Browser Plugin Challenge
Within your organization there is a need to help its members better manage their secrets. Vault centrally manages secrets to reduce secrets sprawl but may increase workflow friction. To make it easier for individuals to use Vault requires the development of tools to integrate best with their current workflow.
This developer focused tutorial challenges you to build a browser extension that authenticates with Vault and reads a secret through the API.
Prerequisites
This tutorial requires the Chrome browser and a code editor.
Retrieve the browser plugin by cloning the hashicorp/vault-guides repository from GitHub.
This repository contains supporting content for all of the Vault learn tutorials. The content specific to this tutorial can be found within a sub-directory.
Go into the vault-guides/secrets/browser-plugin
directory.
Working directory
This tutorial assumes that the remainder of commands are executed in this directory.
Start Vault
In a new terminal, start a Vault dev server.
Insecure operation
Do not run a Vault dev server in production. This approach is only used here to simplify the unsealing process for this demonstration.
Return to the first terminal and export an environment variable for the
vault
CLI to address the Vault server.
Login with the root token.
Setup Vault authentication
The browser plugin uses the Userpass authentication method.
Enable the userpass authentication method.
Create a user named browser
with the password browser
.
Load the plugin
Launch Chrome.
From the Extensions menu, select Manage Extensions.
From the Extensions page, enable Developer mode.
Select Load unpacked and open the
vault-guides/secrets/browser-plugin/chrome
directory.The plugin loads and appears in the extensions page.
From the Extensions menu, pin the VaultPass extension.
The plugin is loaded.
Perform stubbed authentication
The plugin implements an authentication form that performs a stubbed authentication.
Click the plugin to open it.
Select the Server tab.
Enter
http://localhost:8200
in the Vault server URL field.Enter
browser
in the Username field.Enter
browser
in the Password field.Enter
userpass
in the Auth Mountpoint field.Click Login to Vault.
The view displays a stubbed list of policies and a stubbed token.
Implement authentication
The options page contains the authentication form. This page is managed with an
HTML file, options.html
and a JavaScript file, options.js
.
Open options.js
in an editor.
The authToVault
function is stubbed. The Vault token and policies are
retrieved from an object that mimics the data returned from the Vault API.
The Vault token and policies are stored in the browser's local storage and
then those values are sent to the showAsLoggedInWith
function. A TODO
in
the function outlines the steps required to implement an actual
authentication request with Vault.
Create an authentication URL with the username.
The authentication URL is created from the
vaultServer
, theauthMount
and theusername
.Perform a fetch of the authenication URL.
The
fetch
function requires theloginUrl
as the first parameter. An object that describes the request is provided as a second parameter. The request'smethod
is aPOST
and theContent-Type
ensures that the response is formatted as JSON. Thebody
includes a JSON stringified object with thepassword
.With a successful response, read the body as JSON.
Append to the end of the
fetch
method an invocation ofthen
that is sent an anonymous function to extract the JSON data from the response. Then append another invocation ofthen
that is sent an anonymous function to parse the JSON data.The Vault token and policies are retrieved from the response, stored in to the browser storage and then those values are sent to the
showAsLoggedInWith
function.With an error, notify an error.
Append to the end of the
fetch
method an invocation ofcatch
that is sent an anonymous function to notify an error with an error message.This error catches any issues with the URL, failed authentication, or errors parsing the response data.
Save the changes to
options.js
.From Chrome's extension menu, select Update.
Click the plugin to open it.
Select the Server tab.
Select Logout.
Enter
http://localhost:8200
in the Vault server URL field.Enter
browser
in the Username field.Enter
browser
in the Password field.Enter
userpass
in the Auth Mountpoint field.Click Login to Vault.
The view displays the token's policies and the token.
Setup Vault for secrets
Every browser tab has a URL that maps to a browser specific page or a host. The plugin parses that URL for the hostname and then retrieves a secret from Vault with that value.
Browser Tab | Vault Secret |
---|---|
chrome://extensions/ | /v1/vaultpass/data/extensions |
https://learn.hashicorp.com/ | /v1/vaultpass/data/learn.hashicorp.com |
Enable a KV-V2 secrets engine with the path vaultpass
.
Create a secret for the extensions
page.
Create a policy named vault_pass-policy
that grants read access to all secrets
at the path vaultpass
.
Update the user named browser
to grant it the vault_pass-policy
policy.
Implement secret retrieval
The popup page contains the secrets retrieved for the current page. This page is
managed with an HTML file, popup.html
and a JavaScript file, popup.js
.
Open popup.js
in an editor.
The getSecretsAtUrl
function is stubbed. The function creates an Object that
mimics the secret response from the Vault API. The response is mapped to an
array of entries ([ [ 'username', 'stub_username' ], [ 'password', 'stub_password'] ]
)
and sent to the withSecrets
method. A TODO
in the function outlines the
steps required to implement this secrets request.
Perform a fetch of the secret URL
The
fetch
function requires thesecretsUrl
as the first parameter. An object that describes the request is provided as a second parameter. The request'smethod
is aGET
. Theheaders
include theContent-Type
to ensure the response is JSON andX-Vault-Token
for authentication.With a successful response, read the body as JSON and send the secrets to the
withSecrets
method.Append to the end of the
fetch
method an invocation ofthen
that is sent an anonymous function to extract the JSON data from the response. Then append another invocation ofthen
that is sent an anonymous function that maps the data to an array of entries that are sent to thewithSecrets
method.With an error, notify an error.
Append to the end of the
fetch
method an invocation ofcatch
that is sent an anonymous function to notify an error with an error message that contains thesecretsUrl
and theerror
.This error catches any issues with the request or errors parsing the response data.
Save the changes to
popup.js
.From Chrome's extension menu, select Update.
Click the plugin to open it.
Select Logout and login again with the same credentials.
Select the Secrets tab.
The secrets that appear are the ones set up at the secret path
vaultpass/extensions
.
Next Steps
You imported a browser plugin and then implemented authentication and secrets retrieval. Expand this plugin by providing:
support to create secrets in the plugin. The secrets that appear when on the extensions page were set through through CLI. When the response contains no secrets the plugin would display a form that allowed the user to enter their own secrets for the page.
support for multiple users to have unique secrets. All of the secrets are stored in the
vaultpass
path. Additional users would require the path schema to change.support for more than KV-V2 secrets. When a user visits a page for a cloud provider login (e.g. Amazon, Azure, Google) the plugin could request dynamic credentials to use for login.
support for secret entry on the page. Popular password plugins find the login fields on the page and insert the secrets. Learn more from the vaultPass project which expands on this plugin further.