Essential Patterns of Vault — Part 2

Jake Lundberg
Jul 28 · 14 min read

In Part 1 of this series, I laid out the abstract Essential Patterns of Vault. In this part, we’ll dive deep into piloting a Vault solution using those patterns. WARNING: This is a long blog post, I promise it will be worth it.

All prerequisites and code examples can be found in this repo: Code examples used for the Essential Patterns of Vault — Pt 2. All commands used for this blog are done from a checkout of this repo.

git clone https://github.com/grove-mountain/vault_essential_patterns_blog.gitcd vault_essential_patterns_blog/

However, not all commands contained in the scripts are displayed here to save space. Reference or run the scripts for more detailed runs.

For non-Mac users, you can follow along if you install Vagrant and a supported Virtual Machine software suite like VirtualBox . See the instructions in the repo.

You can run the entire demo for this blog post using two scripts in two terminal windows.

Window 1

./0_launch_vault.sh

Window 2

./run_all.sh

You need to hit <enter> or <return> after each command to go to the next one.

Scenario

OurCorp is a business designed by us, for us. Like any business, we have a need to securely store data and prevent unauthorized access to company or customer information. We’ve chosen HashiCorp Vault because it provides the most flexible platform for doing secrets management across operating environments.

The business units most interested in using Vault are below and listed out some of their basic needs.

Engineering

  • Needs to store static passwords for Create application
  • Needs SSH access to compute cluster nodes
  • Needs to store catalog data in the Mother DB engineering schema

Finance

  • Needs to store passwords for application Fine Nancy
  • Needs read/write access to mother DB finance schema

HR

  • Needs to securely store PII data encrypted in hr schema
  • Needs read/write access to mother DB hr schema

IT

  • Needs to store systems passwords
  • Needs SSH key management
  • Needs read/write access to mother it schema

Security

  • Needs to store security passwords
  • Needs read access to all databases and schemas to scan for unprotected data

For this pilot program, we’re going to focus on four objectives for three business units:

  • Authenticate all users with LDAP
  • Store static passwords for IT Systems in KV V2 Secret Engine
  • Provide Dynamic DB credentials for Engineering applications
  • Store Encrypted PII data for HR using Dynamic DB credentials and Transit

Reflecting back to Part 1, we recall the Essential Patterns of Vault, but made specific to this use case:

  1. Be familiar with the documentation for KV V2, Transit and Dynamic Postgres secret engines as well as LDAP Authentication Methods and basic policy management
  2. Enable/Configure KV V2, Transit and Dynamic Database Secret Engines
  3. Enable LDAP Authentication Method
  4. Define and create policies to access specific paths within each secret engine
  5. Map policies to LDAP authentication method
  6. Do positive and negative policy tests

Documentation

Let’s start by listing out the documentation that can help us here. While this isn’t meant to be exhaustive, it’s a good list of first-level docs we can use to both understand what we’re doing, as well as assist with crafting the commands to implement our solution. Remember, the HTTP API docs have all parameters available per endpoint as well as return values from Vault.

Vault Dev Server

Dev Server Mode

vault server — Command

KV V2 Secret Engine

Versioned Key/Value Secret Engine — Learn

KV — Secrets Engines

KV — Secrets Engines — HTTP API

Dynamic Database & Postgres Secret Engine

Secrets as a Service: Dynamic Secrets | Learn

Database — Secrets Engines

Database — Secrets Engines — HTTP API

PostgreSQL — Database — Secrets Engines

PostgreSQL — Database — Secrets Engines — HTTP API

Transit Secret Engine

Encryption as a Service: Transit Secrets Engine — Learn

Transit — Secrets Engines

Transit — Secrets Engines — HTTP API

LDAP Authentication Method

LDAP — Auth Methods

LDAP — Auth Methods — HTTP API

Policy Information

Policies | Learn

Policies

Now that we have our docs open or at least ready to be opened, let’s get to work!

Local Development Environments

As discussed in Part 1, running local dev environments makes it possible to create throw-away systems to test out new capabilities and to speed up development of automation.

WARNING: All of the passwords below are very insecure (and published on the internet). Remember DO NOT RUN THIS EXACT DEMO IN PRODUCTION.

NOTE: I have run into issues on-site with certain customers where ports were blocked due to firewall rules. If you’re having connection issues with one of the tools here, try binding to loopback addresses.

Demo Magic

When doing demos for customers, I always use a slightly modified version of demo-magic (included in the repo). This allows me to script out runs in a predictable and reproducible manner to help reduce human error around copy pasta or typing and to output the commands being run. All of the commands given below are wrapped into numbered scripts that can be run in order to accomplish all the tasks here.

Vault

I’m using a specific IP address to allow communication with other processes that might connect over TCP/IP like Vagrant hosts or non-bridged containers. If you’re only working with Vault, you can probably just use the loopback address. Use the right function for getting your IP_ADDRESS for your system, or just set it manually.

export IP_ADDRESS=$(ipconfig getifaddr en0)
export VAULT_ADDR="http://${IP_ADDRESS}:8200"
export VAULT_TOKEN=${VAULT_ROOT_TOKEN:-"notsosecure"}
# Dev server environment variables
export VAULT_DEV_LISTEN_ADDRESS="${IP_ADDRESS}:8200"
export VAULT_DEV_ROOT_TOKEN_ID=${VAULT_TOKEN}
vault server -dev

Make sure to carry IP_ADDRESS, VAULT_ADDR and VAULT_TOKEN into any other terminal windows you’re using as you’ll need them for your connections to Vault and other scripts. Sourcing env.sh will set these for you. If you need to start over, just ctrl-c and re-run vault server -dev

You can also just run

./0_launch_vault.sh

Postgres Server

Since we will be working with Dynamic Database credentials, we’ll need a database. I like to use the official Docker Hub Postgres Image.

./1_launch_db.sh

LDAP Server

This particular LDAP server allows for customization of an LDAP tree (the default will work just fine, however). It comes with MemberOf overlay enabled and the default setup populates these entries in user records.

./2_launch_ldap.sh

See Dockerized OpenLDAP server with quick setup examples for instructions on creating your own customized LDAP trees.

Enable and Configure Secret Engines

The first step is to enable and configure secret engines. To highlight some features of secret engines, we’ll be using non-standard paths. We’ll also do them one at a time so as not to confuse configuration between sections

KV V2

./3_enable_kv.shvault secrets enable -path=kv-blog -version=2 kv

KV is pretty simple, so for now, that’s it. We’ll put data in there later.

Dynamic Database

./4_enable_db.sh

Dynamic DB is a bit more involved. Enabling is similar:

vault secrets enable -path=db-blog database

Configuring the database engine requires us to have access as some form of administrator to the database we are going to broker secrets for. Using parameters also allows us to rotate the admin credentials later so only Vault knows them going forward.

vault write db-blog/config/mother \
plugin_name=postgresql-database-plugin \
allowed_roles=* \
connection_url="postgresql://{{username}}:{{password}}@10.0.2.15:5432/mother?sslmode=disable"username="vault_admin" \
password="notsosecure"

Once we’ve configured an admin user, we can now start creating role mappings inside of Vault. In this case, we’re granting full access to the HR schema for 1 minute for anyone that can access the db-blog/roles/mother-hr-full-1m endpoint. We’ll talk about giving access shortly. Notice the placeholder template variables for name, password, and expiration. Vault will fill in these values during run time and return the credentials to you.

vault write db-blog/roles/mother-hr-full-1m \
db_name=mother \
creation_statements="CREATE ROLE "{{name}}" WITH LOGIN PASSWORD ‘{{password}}’ VALID UNTIL ‘{{expiration}}’; GRANT USAGE ON SCHEMA hr TO "{{name}}"; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA hr TO "{{name}}";" \
default_ttl=1m \
max_ttl=24h

Here is the root credential rotation command. We won’t be using it during this demo, but it’s handy to know that it’s there. This can give you some peace of mind when having to have a human provide the initial set of credentials to Vault in that once rotated, only Vault knows the credentials.

# vault write -force db-blog/rotate-root/mother

Transit

./5_enable_transit.sh

Next, we’ll enable Transit which is Vault’s Encryption as a Service engine. We’ll also create a key for the HR team to encrypt/decrypt their data.

vault secrets enable -path=transit-blog transit
vault write -f transit-blog/keys/hr

Enable Authentication Methods

LDAP

./6_enable_ldap_auth.sh

First, we will enable ldap at two paths. This allows us to customize the group filtering mechanism to return different types of LDAP group lookups. In this case, we’ll look for either “uniqueMember” records or “memberOf” records.

NOTE: The Distinguished Name (DN) is the unique identifier for LDAP/AD records. Try to use this to link up records as much as possible.

“uniqueMember” attributes belong to an LDAP class: “groupOfUniqueNames” which in this LDAP directory are mapped under “ou=um_group,dc=ourcorp,dc=com”. We’ll match the DN of the user who is authenticating with Vault to any groups the user belongs to. In large LDAP/AD directories, these searches can be slower than looking up directly in a user’s attributes like with the memberOf overlay.

vault auth enable -path=ldap-um ldapvault write auth/ldap-um/config \
url="ldap://10.0.2.15" \
binddn="cn=read-only,dc=ourcorp,dc=com" \
bindpass=”devsecopsFTW” \
userdn=”ou=people,dc=ourcorp,dc=com” \
userattr=”cn” \
groupdn=”ou=um_group,dc=ourcorp,dc=com”
groupfilter=”(&(objectClass=groupOfUniqueNames)(uniqueMember={{.UserDN}}))” \
groupattr=”cn” \
insecure_tls=true

“memberOf” is an operational attribute that belongs to the “person” objectClass. The current user will have one memberOf entry for any LDAP attribute whose value is equal to the user’s DN. These lookups are generally much faster.

e.g.

Group attribute/Distinguished Name mapping:

“uniqueMember=cn=alice,ou=people,dc=ourcorp,dc=com” exists in groups

  • DN: cn=founders,ou=um_group,dc=ourcorp,dc=com
  • DN: cn=finance,ou=um_group,dc=ourcorp,dc=com

So user record:

DN: cn=alice,ou=people,dc=ourcorp,dc=com

Will have the following entries

  • memberOf: cn=founders,ou=um_group,dc=ourcorp,dc=com
  • memberOf: cn=finance,ou=um_group,dc=ourcorp,dc=com

Enable and configure LDAP for memberOf support.

vault auth enable -path=ldap-mo ldap
vault write auth/ldap-mo/config \
url=”ldap://10.0.2.15" \
binddn=”cn=read-only,dc=ourcorp,dc=com” \
bindpass=”devsecopsFTW” \
userdn=”ou=people,dc=ourcorp,dc=com” \
userattr=”cn” \
groupdn=”ou=people,dc=ourcorp,dc=com” \
groupfilter=”(&(objectClass=person)(uid={{.Username}}))” \
groupattr=”memberOf” \
insecure_tls=true

Define and Create Policies

./7_generate_dynamic_policy.sh./8_create_policies.sh

Policies allow access to paths within Vault. By default, a token has no access until granted by some kind of association with a set of policies.

Some example policies (see the policies/ directory for the complete policies).

This is a KV V2 policy fragment from policies/kv-it-policy.hcl. It’s giving full rights to the secrets in the kv-blog/it path in Vault. “Data” and “delete” paths here are operation paths for the KV V2 engine and need to be expressed directly. Refer to the KV V2 documentation.

# Allow full access to the current version of the kv-blog
path “kv-blog/data/it” {
capabilities = [“read”, “list”]
}
path “kv-blog/data/it/*” {
capabilities = [“create”, “read”, “update”, “delete”, “list”]
}
# Allow deletion of any kv-blog version
path “kv-blog/delete/it/*” {
capabilities = [“update”]
}

To add this policy with name “kv-it”:

vault policy write kv-it policies/kv-it-policy.hcl

This is a policy granting access to Transit operations for HR.

path "transit-blog/keys/hr" {
capabilities = [ "read" ]
}
path "transit-blog/encrypt/hr" {
capabilities = [ "create", "read", "update" ]
}
path "transit-blog/decrypt/hr" {
capabilities = [ "create", "read", "update" ]
}

To add this policy with name “transit-hr”:

vault policy write transit-hr policies/transit-hr-policy.hcl

ACL Templated Policies

ACL templating provides an extremely powerful method of writing one policy and providing least privilege to common path patterns like user name or group name. I won’t spend much time on it in this blog as it’s probably worth a whole post on its own (which I’m likely to do), but it’s worth pointing out, as policy creation/management can be far more cumbersome without it.

An example policy fragment:

path "kv/data/{{identity.entity.aliases.auth_ldap_741c3dba.name}}/*"
{
capabilities = ["create", "read", "update", "delete", "list"]
}

This particular policy allows any user to manage secrets under kv/data/$(LDAP_USERNAME). Notice the mount accessor identifier in the policy template. This means that when creating ACL templated policies, you have to do so after mounting your Authentication Methods. See 7_generate_dynamic_policy.sh for an example of how to do this.

Map policies to Authentication Methods

./9_associate_policies.sh

Once policies are written, they can be mapped to as many groups as needed. Authentication Methods usually have a concept of roles or groups to map to policies. For the LDAP Auth Method, you map policies to groups.

vault write auth/ldap-um/groups/it policies=kv-it,kv-user-templatevault write auth/ldap-mo/groups/cn=hr,ou=um_group,dc=ourcorp,dc=com policies=db-hr,transit-hr,kv-user-template

Notice the difference between the two records? One is a uniqueMember lookup while the other is a memberOf lookup. While memberOf group names are longer, they are also unique because they reference the full DN, not just an alias name.

Do Positive and Negative testing

IT KV V2 Tests

The IT group needs to test storing K/V entries for their sensitive data. They will use LDAP UniqueMember groups to assign policies.

./test_it.sh

First login to Vault after unsetting any previously set VAULT_TOKEN. Notice the policies this user gets.

unset VAULT_TOKEN
vault login -method=ldap -path=ldap-um \
username=deepak password=thispasswordsucks
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
Key Value
--- -----
token s.ToxyzTBfZIPfhEqZmMlnQQfK
token_accessor yWTwODsTNmla9WDhRL7GNqDy
token_duration 768h
token_renewable true
token_policies ["default" "kv-it" "kv-user-template"]
identity_policies []
policies ["default" "kv-it" "kv-user-template"]
token_meta_username deepak

Test KV Writes/Reads to allowed paths.

# Writes
vault kv put kv-blog/it/servers/hr/root password=rootntootn
Key Value
--- -----
created_time 2019-07-24T06:07:07.567289Z
deletion_time n/a
destroyed false
version 1
vault kv put kv-blog/it/routers/snmp/read-write password=snortymcsnortytonKey Value
--- -----
created_time 2019-07-24T06:07:08.008134Z
deletion_time n/a
destroyed false
version 1
# Readsvault kv get kv-blog/it/servers/hr/root====== Metadata ======
Key Value
--- -----
created_time 2019-07-24T06:07:07.567289Z
deletion_time n/a
destroyed false
version 1
====== Data ======
Key Value
--- -----
password rootntootn
vault kv get kv-blog/it/routers/snmp/read-write====== Metadata ======
Key Value
--- -----
created_time 2019-07-24T06:07:08.008134Z
deletion_time n/a
destroyed false
version 1
====== Data ======
Key Value
--- -----
password snortymcsnortyton

Try KV puts to paths outside the current policy set.


vault kv put kv-blog/hr/servers/hr/root password=rootntootn
Error writing data to kv-blog/data/hr/servers/hr/root: Error making API request.URL: PUT http://10.4.2.120:8200/v1/kv-blog/data/hr/servers/hr/root
Code: 403. Errors:
* 1 error occurred:
* permission denied
vault kv put kv-blog/hr/routers/snmp/read-write password=snortymcsnortytonError writing data to kv-blog/data/hr/routers/snmp/read-write: Error making API request.URL: PUT http://10.4.2.120:8200/v1/kv-blog/data/hr/routers/snmp/read-write
Code: 403. Errors:
* 1 error occurred:
* permission denied
# Test access to database endpoints[jake@Joi] vault read db-blog/creds/mother-full-read-1mError reading db-blog/creds/mother-full-read-1m: Error making API request.URL: GET http://10.4.2.120:8200/v1/db-blog/creds/mother-full-read-1m
Code: 403. Errors:
* 1 error occurred:
* permission denied

The assigned policies only allow access to “kv-blog/it”, not “kv-blog/hr”. Sure, HR probably doesn’t manage SNMP passwords, but it’s worth pointing out fun with copy pasta.

Engineering Dynamic DB tests

Then, the engineering group wants to test Dynamic DB credentials to access database tables in their schema. They will use LDAP memberOf records for policy mapping defined above.

./test_engineering.sh

Login with the LDAP memberOf Auth Method. Notice the policies this user gets.

unset VAULT_TOKEN
vault login -method=ldap -path=ldap-mo \
username=chun password=thispasswordsucks
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
Key Value
--- -----
token s.ba4u6V6Nouqo30CQruMJIzfU
token_accessor sqrtrXQNLEV8svmuMfkvxkHA
token_duration 768h
token_renewable true
token_policies ["db-engineering" "default" "kv-user-template"]
identity_policies []
policies ["db-engineering" "default" "kv-user-template"]
token_meta_username chun

Read out the dynamic DB credentials and store them as variables.

Getting dynamic DB credentials from Vault. There are more elegant ways of doing this, but OSX doesn't support process substitution in its version of Bash, so working around (e.g. source <(cmd))

vault read -format=json db-blog/creds/mother-engineering-full-1h | jq -r '.data | .["PGUSER"] = .username | .["PGPASSWORD"] = .password | del(.username, .password) | to_entries | .[] | .key + "=" + .value ' > .temp_db_creds. .temp_db_creds && rm .temp_db_creds# By setting the postgres environment variables to the dynamic creds, we can run PSQL with those dynamic credsecho "PGUSER=${PGUSER} PGPASSWORD=${PGPASSWORD}"
PGUSER=v-ldap-mo--mother-e-kui61Hgausx3bGfkgmk9-1563953366 PGPASSWORD=A1a-SWC5X7favH4xZs4F

QUERY='select name,description from engineering.catalog;'
psql
name | description
-------------------+-------------------------------------------
Thromdibulator | Complex machine, do not disassemble
Visi-Sonor | Musical instrument with visualizations
Deep Thought | Super Computer
Mithril Vest | Very Good Armor (TM)
Blaine the Mono | Psychopathic train, enjoys proper riddles
Millennium Falcon | Fastest Hunk-of-Junk in the Galaxy
Sonic Screwdriver | Multi-tool
(7 rows)

Negative Tests

# Can these DB credentials query other schema/tables?QUERY='select * from hr.people;'
psql
ERROR: permission denied for schema hr
LINE 1: select * from hr.people;
^
# Can the Vault token read from other areas?vault read db-blog/creds/mother-full-read-1hError reading db-blog/creds/mother-full-read-1h: Error making API request.URL: GET http://10.4.2.120:8200/v1/db-blog/creds/mother-full-read-1h
Code: 403. Errors:
* 1 error occurred:
* permission denied
vault kv get kv-blog/it/servers/hr/rootError reading kv-blog/data/it/servers/hr/root: Error making API request.URL: GET http://10.4.2.120:8200/v1/kv-blog/data/it/servers/hr/root
Code: 403. Errors:
* 1 error occurred:
* permission denied

HR Dynamic DB and transit tests

./test_hr.sh

This section brings up another kind of pattern in Vault, the Dynamic DB/Transit Pattern. Here, a user or application gets short-lived dynamic DB credentials from Vault and then use the Transit Encryption as a Service engine to encrypt plaintext values to store encrypted at rest. They will use LDAP memberOf records for policy mapping defined above.

Login to Vault as user Frank who belongs to the HR group. Notice the policies assigned.

unset VAULT_TOKEN
vault login -method=ldap -path=ldap-mo \
username=frank password=thispasswordsucks
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
Key Value
--- -----
token s.hu0rvRRPjzTUtpf1KrhWnhtF
token_accessor Is1vmEgna68eCZO13iWq3mdg
token_duration 768h
token_renewable true
token_policies ["db-hr" "default" "kv-user-template" "transit-hr"]
identity_policies []
policies ["db-hr" "default" "kv-user-template" "transit-hr"]
token_meta_username frank

Read in a set of Dynamic DB credentials and set them as Postgres environment variables. See disclaimer about technique above.

vault read -format=json db-blog/creds/mother-hr-full-1h | jq -r '.data | .["PGUSER"] = .username | .["PGPASSWORD"] = .password | del(.username, .password) | to_entries | .[] | .key + "=" + .value ' > .temp_db_creds. .temp_db_creds && rm .temp_db_creds# By setting the postgres environment variables to the dynamic creds, we can run PSQL with those dynamic credsecho "PGUSER=${PGUSER} PGPASSWORD=${PGPASSWORD}"PGUSER=v-ldap-mo--mother-h-Orz3oe2jQLJLn4VbMh3l-1563997339 PGPASSWORD=A1a-34ANtkBsN6CcSHP5

Next, we’ll retrieve some un-encrypted values, encrypt them and rewrite them encrypted back into the database.

QUERY='select email,id from hr.people;'
psql
email | id
--------------------+--------------------
alice@ourcorp.com | 123-45-6789
bob@ourcorp.com | 234-56-7890
chun@ourcorp.com | 350322197001015332
deepak@ourcorp.com | 0123 4567 8901
eve@ourcorp.com | AB 12 34 56 Z
frank@ourcorp.com | 678-90-1234
(6 rows)
Find an existing user id and encrypt it
WARNING! When doing this in production, it's best to schedule a maintenance window unless your application logic can consume both encrypted and unencrypted values
QUERY="select id from hr.people where email='alice@ourcorp.com'"
user_id=$(psql)
# user_id = 123-45-6789enc_id=$(vault write -field=ciphertext transit-blog/encrypt/hr plaintext=$( base64 <<< ${user_id} ) )
QUERY="UPDATE hr.people SET id='${enc_id}' WHERE email='alice@ourcorp.com'"
psql
UPDATE 1
QUERY="select email,id from hr.people"
psql
email | id
--------------------+-------------------------------------------------------------------
bob@ourcorp.com | 234-56-7890
chun@ourcorp.com | 350322197001015332
deepak@ourcorp.com | 0123 4567 8901
eve@ourcorp.com | AB 12 34 56 Z
frank@ourcorp.com | 678-90-1234
alice@ourcorp.com | vault:v1:CX2gvluidKHAw3BnfOqauoO7MDdAqR+jwbP7uzoqOdq9J7iXCY3HwlA=
(6 rows)

Now that we have data encrypted in the database, let’s simulate retrieving from an application. Transit’s “decrypt” operation will be used. You need to base64 decode the value as well.

QUERY="select id from hr.people where email='alice@ourcorp.com'"
enc_user_id=$(psql)
echo ${enc_user_id}
enc_user_id = vault:v1:CX2gvluidKHAw3BnfOqauoO7MDdAqR+jwbP7uzoqOdq9J7iXCY3HwlA=
user_id=$(vault write -field=plaintext transit-blog/decrypt/hr ciphertext=${enc_user_id} | base64 --decode)echo ${user_id}
123-45-6789

Notice the values are still encrypted in the DB.

QUERY="select email,id from hr.people"
psql
email | id
--------------------+-------------------------------------------------------------------
bob@ourcorp.com | 234-56-7890
chun@ourcorp.com | 350322197001015332
deepak@ourcorp.com | 0123 4567 8901
eve@ourcorp.com | AB 12 34 56 Z
frank@ourcorp.com | 678-90-1234
alice@ourcorp.com | vault:v1:CX2gvluidKHAw3BnfOqauoO7MDdAqR+jwbP7uzoqOdq9J7iXCY3HwlA=
(6 rows)

Negative Tests

# Try to query the engineering schema with these credentialsQUERY="select * from engineering.catalog"
psql
ERROR: permission denied for schema engineering
LINE 1: select * from engineering.catalog
^
# Can the Vault token read from other areas in Vault?vault read db-blog/creds/mother-full-read-1hError reading db-blog/creds/mother-full-read-1h: Error making API request.URL: GET http://10.4.2.120:8200/v1/db-blog/creds/mother-full-read-1h
Code: 403. Errors:
* 1 error occurred:
* permission denied
vault kv get kv-blog/it/servers/hr/rootError reading kv-blog/data/it/servers/hr/root: Error making API request.URL: GET http://10.4.2.120:8200/v1/kv-blog/data/it/servers/hr/root
Code: 403. Errors:
* 1 error occurred:
* permission denied

Cleanup

To stop all the things:

docker kill postgres openldap
kill $(ps | grep "vault server -dev" | grep -v grep | awk '{print $1}')

Summary

In the last blog post, I summarized the Essential Patterns of Vault:

  1. Be familiar with the documentation
  2. Enable and configure Secret Engines
  3. Enable and configure Authentication Methods
  4. Define and create policies
  5. Authorize by tying policies for accessing secret engines to authentication methods.
  6. Do positive and negative tests to prove your configurations allow access to the needed secrets as well as disallow access to unneeded secrets.

This post dove deeper into showing how to implement those Patterns based on a theoretical solution for the company, OurCorp. We also briefly touched on some advanced topics like Identity and ACL Templating to help streamline your automation processes. If you’re able to consume and understand this information, you’re one step closer to becoming a Vault expert.

Nice Work!

HashiCorp Solutions Engineering Blog

A Community Blog by the Solutions Engineers of HashiCorp and Invited Guests

Thanks to Kawsar Kamal

Jake Lundberg

Written by

Human

HashiCorp Solutions Engineering Blog

A Community Blog by the Solutions Engineers of HashiCorp and Invited Guests

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade