Git Product home page Git Product logo

rvault's Introduction

RVault

codecov Build GitHub license GitHub top language GitHub tag (latest SemVer) Docker Pulls Github All Releases

Summary

RVault (standing for 'recursive vault') is a small cli utility aiming to perform some recursive actions over Hashicorp's Vault.

The supported actions are:

  • Listing secrets from a kv engine
  • Reading secrets from a kv engine

Read secrets can be saved as files (each key/value will be stored to a separate file), or written to stdout in json/yaml format.

Motivation

On a scenario where I had to download multiple secrets from Vault, I realized this is currently not supported by vault cli. There is an open issue to request recursive key listing. According to the discussion, recursivity is complex as current list operations are not optimized for recursion. So this is just a workaround until a proper approach is implemented in Vault.

Pre-requirements

In order for this tool to work you will need:

  • A Vault instance to read from (kind of useless without it). I have tested it with Vault 1.4.2 but I guess it should work with any Vault 1.x version.
  • A Token with enough priviledges to list the secrets from the selected engine. Additionally, the tool relies on listing current mounts (through the v1/sys/mounts endpoint) to determine the kv version for the engine. If the token doesn't have enough priviledges the version value should be provided either via the configuration or as cli argument.

Installation

You can download the binary from the releases and uncompress it somewhere in your path.

For instance, to download the latest release to /usr/local/bin on Linux/MacOS:

version=$(curl -s https://api.github.com/repos/kir4h/rvault/releases/latest | jq -r .tag_name)
platform=$(uname | tr '[:upper:]' '[:lower:]')
curl -L -s https://github.com/kir4h/rvault/releases/latest/download/rvault-${version}-${platform}-amd64.tar.gz \
| sudo tar xz -C /usr/local/bin

You can also simply run the tool from the kir4h/rvault Docker image.

Available commands

List

The list allows recursively listing secrets from a given path.

$ rvault list --help

Recursively list secrets for a given path

Usage:
  rvault list <engine> [flags]

Flags:
  -h, --help                help for list
  -k, --kv-version string   KV Version
  -p, --path string         Path to look for secrets (default "/")

Global Flags:
  -a, --address string          Vault address
      --alsologtostderr         log to standard error as well as files
  -c, --concurrency uint32      Maximum number of concurrent queries to Vault (default 20)
      --config string           config file (default is $HOME/.config/rvault/config.yaml)
  -e, --exclude-paths strings   KV paths to be excluded (Applied on 'include-paths' output
  -i, --include-paths strings   KV paths to be included (default [*])
      --insecure                Enables or disables SSL verification
      --log_dir string          If non-empty, write log files in this directory
      --log_file string         If non-empty, use this log file
      --logtostderr             log to standard error instead of files (default true)
  -t, --token string            Vault token
  -v, --v Level                 number for the log level verbosity

For instance, in order to list secrets under v2 secret engine (default one when Vault is launched in dev mode), for the spain subpath:

$ rvault list secret -k 2 -p spain -v=0
/spain/central/ssh.key
/spain/south/passwd.conf

Read

The read command allows recursive read of secrets from a given path. Read secrets can be written to files or to stdout in json/yaml format.

$ rvault read --help

Recursively read secrets for a given path

Usage:
  rvault read <engine> [flags]

Flags:
      --file-permission uint32     Permissions for created secret files (file format only) (default 384)
      --folder-permission uint32   Permissions for newly created folders (file format only) (default 448)
  -f, --format string              Output format ('file', 'yaml', 'json') (default "file")
  -h, --help                       help for read
  -k, --kv-version string          KV Version
  -o, --output string              Output folder for 'file' format  (default ".")
  -w, --overwrite                  Overwrite existing files (file format only)
  -p, --path string                Path to look for secrets (default "/")

Global Flags:
  -a, --address string          Vault address
      --alsologtostderr         log to standard error as well as files
  -c, --concurrency uint32      Maximum number of concurrent queries to Vault (default 20)
      --config string           config file (default is $HOME/.config/rvault/config.yaml)
  -e, --exclude-paths strings   KV paths to be excluded (Applied on 'include-paths' output
  -i, --include-paths strings   KV paths to be included (default [*])
      --insecure                Enables or disables SSL verification
      --log_dir string          If non-empty, write log files in this directory
      --log_file string         If non-empty, use this log file
      --logtostderr             log to standard error instead of files (default true)
  -t, --token string            Vault token
  -v, --v Level                 number for the log level verbosity

File output

  • Reading all secrets under v2 secret engine for the spain subpath and store them as files under the /tmp/secret folder

    $ rvault read secret -f file -k 2 -o /tmp/secret -p spain
    I0712 19:04:03.791067   27410 root.go:84] Using config file: '/home/user/.config/rvault/config.toml'
    I0712 19:04:03.795243   27410 secrets.go:193] Secrets written: 2
    
    $ find /tmp/secret -type f
    /tmp/secret/spain/north/ssh.key/key
    /tmp/secret/spain/south/passwd.conf/key

    Please note that in above example, key is just the key name of the only key/value in the secret. If more than one key/value is found in the secret multiple files are created, each one having as name the corresponding key name.

JSON output

  • Reading all secrets under v2 secret engine for the spain subpath, returning them as json

    Running

    rvault read secret -f json -k 2 -p spain 2>/dev/null | jq .

    Will produce the output

    {
        "spain/north/ssh.key": {
            "key": "This is north's secret key"
        },
        "spain/south/passwd.conf": {
            "key": "This is south's secret key"
        }
    }

YAML output

  • Reading all secrets under v2 secret engine for the spain subpath, returning them as yaml

    Running

    rvault read secret -f json -k 2 -p spain 2>/dev/null | jq .

    Will produce the output

    spain/north/ssh.key:
        value: "This is north's secret key"
    spain/south/passwd.conf:
        value: "This is south's secret key"

Filtering results

The include-paths and exclude-paths flags can be used in both list and read commands to return only secrets matching a set of given patterns through wildcard patterns.

Let's say we have a secret engine with the following secrets:

$ rvault list secret -k 2 -v=0
/france/paris/id_rsa
/france/vault.kdbx
/spain/north/id_rsa
/spain/south/shadow
/uk/london/bigben.crypt

We could return only secrets with the id_rsa name:

$ rvault list secret -k 2 -v=0 -i */id_rsa
/france/paris/id_rsa
/spain/north/id_rsa

Or secrets in france and uk:

$ rvault list secret -k 2 -v=0 -i /france/*,/uk/*
/france/paris/id_rsa
/france/vault.kdbx
/uk/london/bigben.crypt

The include filter can also be expressed as a repeteable flag:

$ rvault list secret -k 2 -v=0 -i /france/* -i /uk/*
/france/paris/id_rsa
/france/vault.kdbx
/uk/london/bigben.crypt

We can use the exclude-paths to perform a second filter:

$ rvault list secret -k 2 -v=0 -i /france/* -i /uk/* -e **/*.kdbx
/france/paris/id_rsa
/uk/london/bigben.crypt

The pattern matching is done through the gobwas/go globbing library, so you can refer to its documentation for further reference and valid syntax.

Configuration

Arguments can be provided as cli arguments but also through means of a configuration file. Viper is used for configuration management so configuration can be stored in any of the formats supported by it (JSON, TOML, YAML, HCL, envfile and Java properties config files).

The default path for the configuration file is $HOME/.config/rvault/config.<ext>, where <ext> represents the extension for the configuration format (json, toml, yaml, ...)

A sample of the configuration in TOML format:

[global]
# Vault address
address = "http://127.0.0.1:8200"
# Vault token
token = "devtoken"
# Log verbosity. 0 (less verbose) to 5 (more verbose)
verbosity = 2
# Maximum number of concurrent queries to Vault. '0' for unlimited (use with care)
concurrency = 20
# List of path patterns to return
include_paths = ["*"]
# List of paths to be excluded from the selected 'include_paths'
exclude_paths = []
# Default kv version to use
kv_version = ""
# Enables or disables SSL Verification
insecure = false

[list]
# Default path to use for listing
path = "/"

[read]
# Default path to use for reading
path = "/"
# Whether to overwrite existing secrets or not when using 'file' format
overwrite = false
# Permissions for newly created files when using 'file' format
file_permission = 0o0600
# Permissions for newly created folders when using 'file' format
folder_permission = 0o0700

#[engines]
## Properties for an engine named 'secret'
#[engines.secret]
## Set engine 'secret' as kv version '2'
## Please note that this takes precedence over 'global.kv_version'
#kv_version=2
## Properties for an engine named 'secret'
#[engines.secretkv1]
## Set engine 'secret' as kv version '1'
## Please note that this takes precedence over 'global.kv_version'
#kv_version=1

Additionally, environment variables VAULT_ADDR and VAULT_TOKEN are bound to global.address and global.token configuration variables for convenience, since they might be already in place under a shell using vault cli. As a last option, token can be retrieved from the ~/.vault-token helper file.

NOTE: If the token are specified in both the vault token helper and configuration files the latter has higher precedence.

Running in Docker

A Docker image is built with this repository and pushed to Docker Hub (see rvault Docker image)

There is nothing special about running it in docker other than bind mounting your configuration if desired, or the output folder if using the read command with the file format.

Listing secrets for the secret engine with our custom configuration and the spain path:

$ docker run -it --rm -v ${HOME}/.config/rvault/:/config kir4h/rvault  --config /config/config.toml list secret -p spain
I0715 22:19:36.175957       1 root.go:85] Using config file: '/config/config.toml'
/spain/central/ssh.key
/spain/south/passwd.conf

Reading those secrets and dumping them into files:

$ docker run -it --rm -v ${HOME}/.config/rvault/:/config -v $(pwd)/out:/out kir4h/rvault --config /config/config.toml read secret -o /out
I0715 22:21:46.676216       1 root.go:85] Using config file: '/config/config.toml'
I0715 22:21:46.683996       1 output.go:77] Secrets written: 2

Detecting KV version

If KV version is not provided, rvault will try to list the mounts by using the v1/sys/mounts endpoint. In order to do so, the provided token must have enough priviledges for that query.

There is an alternative unauthenticated endpoint at /sys/internal/ui/mounts that could be used instead to retrieve KV version, but since it's an internal endpoint it's not exposed by vault library and its usage is discouraged as there is no guarantee on its backwards compatibility.

rvault's People

Contributors

cmur2 avatar dependabot[bot] avatar kir4h avatar rabb1t avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

rvault's Issues

No secrets found

Hey there. Tried to use the rvaul list secret -p appgo , but it is not finding any secret in there.

So i tried to debug it a little bit and it seems that it is hitting the secret/metadata/appgo endpoint... and the correct one should be appgo/metadata, since my root kv name is appgo...

rvault list secret -k 2 -p appgo  -v=0 -v 5
I0901 07:43:38.892336  698249 kv.go:77] Using kv version '2' for engine 'secret'
I0901 07:43:38.892423  698249 list.go:35] Listing for secret/metadata/appgo/
I0901 07:43:39.165269  698249 list.go:48] No secrets found for path appgo

Got the right endpoint by using the vault -output-curl-string.

vault kv list -output-curl-string appgo
curl -H "X-Vault-Request: true" -H "X-Vault-Token: $(vault print token)" https://${VAULT_ADDR}/v1/appgo/metadata?list=true

Think i am using the lastest version:

rvault --version
rvault version 0.2.1 
Commit: 5e6163d
Date: 2020-07-28T17:21:50Z

Thanks for the help.

Unable to use wildcard/* when running rvault read commands

I'm trying to read the secret from vault using rvault read commands following the instructions provided in the documentations.

I'm able to read secrets for a specified path
ex: rvault read secret -f json -k 2 -p "A/B/"

{"A/B/test":{"test":"value"},"A/B/test2":{"test2":"value"},"A/B/test3":{"test3":"value"}, "A/B/sample":{"sample":"value"}}

but I'm not able to run this command using a wildcard /* so that I don't have to enter the full path.
Ex:
rvault read secret -f json -k 2 -p "A/B/"
ADDRESS IS https://
I0228 20:21:17.652282 1756279 list.go:48] No secrets found for path A/B/

{}

also I'm getting parse errors when I'm using this command as per the document.

rvault read secret -f json -k 2 -p secret/A/* 2>/dev/null | jq .

Is there anyway that I could read the secrets just based on key instead of providing the full path? like it works for rvault list

Feature request: support Enterprise vault namespace

I have a need to sync secrets from opensource vault to enterprise vault which uses namespaces. It would be very nice to have the client support this option in its configuration.
Possible Solution

Provide an ability to specify the 'namespace' option in the config, and modify client code to be namespace aware.

[global]
# Vault address
address = "http://127.0.0.1:8200"
# Specify namespace for Vault Enterprise (optional)
namespace = "<VAULT_NAMESPACE>"

Sourcing credentials with an external process

Problem

I have a special binary which implements custom logic of obtaining Vault token in clouds. It would be very nice to have an ability to sourcing Vault credentials (token) with an external process, like it's implemented in AWS CLI for seamless integration with custom binaries.

Possible Solution

Provide an ability to specify the credential_process option in the config, and if it's specified sourcing Vault token with an external process, e.g.

[global]
# Vault address
address = "http://127.0.0.1:8200"
# Process to retrieve vault token
credential_process = "get-vault-token -f credential-process"

Custom binary should produce the token in the following format (like in AWS CLI):

{
  "Version": 1,
  "TokenId": "an Vault access token"
} 

So, it's pretty straightforward to implement such a logic, but it opens ability to plenty of custom integrations.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.