vault

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 6, 2022 License: BSD-3-Clause Imports: 12 Imported by: 0

README

Golang helper library to interact with Hashicorp Vault

Helper library to manage connection to Hashicorp Vault, allowing it to be used as a generic datastore using key/value store. Vault was not meant to be used as such however it fits the bill in some cases, especially with regards to storing identities and credentials of users for applications. Vault is tried and tested with regards to its security that re-implementing its features in our own application is a moot point.

NOTE: This library relies on VAULT_* environment variables to configure Vault. Some of the key Vault environment variables that can be configured are

  • VAULT_ADDR = address of the Vault instance (REQUIRED)
  • VAULT_CACERT = path to pem encoded CA file to verify Vault server by client (this takes precedence over VAULT_CACERT)
  • VAULT_CAPATH = path to directory storing pem encoded CA files to verify Vault server by client
  • VAULT_CLIENT_CERT = path to pem encoded client certificate for communication with Vault server
  • VAULT_CLIENT_KEY = path to pem encoded client key for communication with Vault server
  • VAULT_CLIENT_TIMEOUT = timeout by client
  • VAULT_SKIP_VERIFY = skip verifying Vault server certificate
  • VAULT_TLS_SERVER_NAME = name to use as Server Name Indication (SNI) when connecting over TLS
  • VAULT_HTTP_PROXY = proxy to be used by client when connecting to Vault server

Usage example

Some examples of using this library is given below. It is recommended to use AppRole over Token when possible however do take note on the generation of secret_id and token. These values are not meant to be long lived therefore it could expire for a long lived application. It would mean having to create new secret_id and restarting the application periodically OR using vault agent to write a token to a file to be read by the library. Please choose the best way to distribute and store these information for your own applications.

Instructions are given at the end of this document on how to generate really long lived secret_id.

Authentication

Access to Vault is tightly controlled, which requires a valid token. These tokens will be renewed as needed, should the tokens expire or its maximum use is reached.

Use either AppRole or Token, depending on preference or need

Using AppRole

role_name MUST match the role given during creation of this AppRole.

auth := vault.NewAppRole(vault.AppRolePath, role_name, role_id)
auth.SetSecretID(secret_id)
Using Token
auth := vault.NewToken(token)
auth.SetToken(token)

Creating new client

store represents the Vault Key/Value store where the data is stored. This helps the library narrow down the scope without being overly verbose in reading, writing or deleting.

client, err := vault.New(auth, store, os.Stdout)
if nil != err {
    fmt.Println(err)
    os.Exit(1)
}
Using TLS with Vault

Ideally, Vault is secured using TLS certificates for information exchange. Setting up TLS is done using the following environment VAULT_* variables.

To setup spefific CA for verifying Vault TLS certificate, set either of the following environment variables

  • VAULT_CACERT = path to pem encoded CA file to verify Vault server by client (this takes precedence over VAULT_CACERT)
  • VAULT_CAPATH = path to directory storing pem encoded CA files to verify Vault server by client

For optional TLS authentication against Vault server, the client cert can be specified

  • VAULT_CLIENT_CERT = path to pem encoded client certificate for communication with Vault server
  • VAULT_CLIENT_KEY = path to pem encoded client key for communication with Vault server

If the client wishes to skip verifying the Vault server cert, set the following environment variable. This should not be done in most cases. If a custom CA is used, specify the CA file as above.

  • VAULT_SKIP_VERIFY = skip verifying Vault server certificate

Specify how long the client should wait

  • VAULT_CLIENT_TIMEOUT = timeout by client

Specify an SNI if connecting to a server serving multiple certs under a single IP address

  • VAULT_TLS_SERVER_NAME = name to use as Server Name Indication (SNI) when connecting over TLS

Adding data to Vault key/value store

// create new data to write
data := vault.NewData()
data.SetString("hello", "world!")
data.SetBool("enabled", true)
data.SetUint64("duration", 1234)

blk = make([]byte, 32)
_, err = rand.Read(blk)
data.SetBytes("bytes", blk)

_, err = client.Write("test", data)
if nil != err {
    fmt.Println(err)
    os.Exit(1)
}

Reading data from Vault key/value store

result, err := client.Read("test")
if nil != err {
    fmt.Println(err)
    os.Exit(1)
}

fmt.Println(result.GetString("test"))
fmt.Println(result.GetBool("enabled"))
fmt.Println(result.GetUint64("duration"))

blk,err = result.GetUint64("bytes")
if nil != err {
    fmt.Println(err)
    os.Exit(1)
}

fmt.Println(blk)

Deleting data from Vault key/value store

_, err = client.Delete("test")
if nil != err {
    fmt.Println(err)
    os.Exit(1)
}

Create approle role_id and secret_id

This library prefers the usage of the AppRole authentication method to interact with items in Vault. Below is a simple guide to setup AppRole to acquire the role_id and secret_id.

For a full guide, refer to https://learn.hashicorp.com/tutorials/vault/approle.

  1. Export the necessary variables to connect to the required Vault instance.
  2. Make sure to have the root (or similar) token to configure the authentication methods.
  3. Enable the AppRole auth method
vault auth enable approle
  1. Create a new policy and attach the role to that policy, in this example the policy name is policy-keystore
vault policy write policy-keystore -<<EOF
path "keystore/*" {  capabilities = ["create", "read", "update", "delete", "list"]}
path "keystore/config" {  capabilities = ["read", "list"]}
EOF
  1. Create a named role for the application (app-keystore in this example), modifying the values as needed. Consider limiting secret_id_num_uses if needed, however that means another way to provide the new secret_id must be managed
vault write auth/approle/role/app-keystore \
    token_policies="policy-keystore" \
    secret_id_ttl=8760h \
    token_ttl=30m \
    token_max_ttl=2h \
    token_num_uses=5 \
    secret_id_num_uses=0

6.Fetch the role_id of the newly created AppRole, replacing app-keystore with the name given for the role in step (5). role_id is similar to a username so the value will be the same everytime this is called

vault read auth/approle/role/app-keystore/role-id
  1. Get secret_id for this approle, this information must be kept private and secure. Replace app-keystore with the name given for the role in step (5)
vault write -f auth/approle/role/app-keystore/secret-id
  1. Supply the role_id and secret_id to the library to faciliate interaction between this library and the Vault instance.
  2. To test if the role_id and secret_id works, try to login from the command line. If it returns a bunch of information such as token, lifetime, etc then it is working as intended
vault write auth/approle/login role_id="role_id" secret_id="secret_id"
  1. Alternatively, instead of providing the secret_id directly, it can be obtained using the response wrapping feature of Vault. To get the wrapping_token, run the following instead of step (7), replacing app-keystore with the name given for the role in step (5)
vault write -wrap-ttl=1h -f auth/approle/role/app-keystore/secret-id
Creating extremely long lived secret ids

USE THIS CAREFULLY. Know what you are doing and why you need this before proceeding.

While Vault expects a limited lifetime for secret_id and token, sometimes it could be necessary to create extremely long lived secret_id and token especially if using Vault as a datastore.

The TTL for secret ids cannot be more than what is configured for Vault. To override this, we need to instruct Vault to change the TTL for a specific authentication method. Below are instructions for creating extremely long lived secret ids.

  1. Tune the endpoint for AppRole, replace approle with the path configured for your AppRole Vault instance. The maximum value Vault supports is 999999999 seconds.
vault auth tune -default-lease-ttl=8760h -max-lease-ttl=17520h approle/
  1. Now when you create secret ids, it will use the TTL specified here or in step (5) above, whichever is lower.

Documentation

Index

Constants

View Source
const AppRolePath = "approle"

AppRolePath - default approle path

Variables

This section is empty.

Functions

func ErrFieldNotFound

func ErrFieldNotFound(key string) error

ErrFieldNotFound - specific error message indicating field is not found

func ErrKeyNotFound

func ErrKeyNotFound(key string) error

ErrKeyNotFound - specific error message indicating key is not found

func ErrListPathNotFound

func ErrListPathNotFound(path string) error

ErrListPathNotFound - specific error message indicating list path is not found

Types

type AppRole

type AppRole struct {
	// contains filtered or unexported fields
}

AppRole - vault AppRole information

func NewAppRole

func NewAppRole(path, appRoleName, role_id string) (approle *AppRole)

NewAppRole - creates a new instance of AppRole

func (*AppRole) GetToken

func (ar *AppRole) GetToken(c *hvault.Client) (token string, err error)

GetToken - returns a token for configured `role_id`

func (*AppRole) SetSecretID

func (ar *AppRole) SetSecretID(secret_id string)

SetSecretID - sets a secret id for a given AppRole for a configured `role_id`

func (*AppRole) SetUnwrapToken

func (ar *AppRole) SetUnwrapToken(unwrap_token string)

SetUnwrapToken - sets an unwrap token to get the secret ID from vault for a configured `role_id`

type Auth

type Auth interface {
	GetToken(*hvault.Client) (string, error)
}

Auth - interface for different types of authentication supported by this library, standard is `token` and `approle`

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client - Vault Client instance and its related information

func New

func New(auth Auth, store string, output io.Writer) (v *Client, err error)

New - creates new instance of vault using the given information, other key pieces of information are based on the `VAULT_*` environment variables func New(config *hvault.Config, auth Auth, store string, output io.Writer) (v *Client, err error) {

func (*Client) Delete

func (v *Client) Delete(path string) (data Data, err error)

Delete - delete the given key

func (*Client) IsSealed

func (v *Client) IsSealed() (sealed bool, err error)

IsSealed - checks if Vault is currently sealed

func (*Client) List

func (v *Client) List(path string) (keys []string, err error)

List - list keys under a given path

func (*Client) Read

func (v *Client) Read(path string) (data Data, err error)

Read - reads all the fields under the given path

func (*Client) ReadKey

func (v *Client) ReadKey(path string, field string) (value string, err error)

ReadKey - reads the specific key under the given path and returns a string value

func (*Client) Write

func (v *Client) Write(path string, d Data) (data Data, err error)

Write - writes the vault data to the given path, this will **COMPLETELY** replace all values in the path

func (*Client) WriteKey

func (v *Client) WriteKey(path, field, value string) (data Data, err error)

WriteKey - writes the given string value to the specific key under the given path

type Data

type Data map[string]interface{}

Data - vault data format

func NewData

func NewData() (d Data)

NewData - creates new instance of vault data

func (Data) Exist

func (d Data) Exist(field string) bool

Exist - checks if a given field exists

func (Data) GetBool

func (d Data) GetBool(field string) (value bool)

GetBool - returns bool value from a given field

func (Data) GetBytes

func (d Data) GetBytes(field string) (bytes []byte, err error)

GetBytes - returns bytes value from a given field (decoded from base64 URLEncoding)

func (Data) GetString

func (d Data) GetString(field string) (value string)

GetString - returns string value from a given field

func (Data) GetUint64

func (d Data) GetUint64(field string) (value uint64)

GetUint64 - returns uint64 value from a given field

func (Data) SetBool

func (d Data) SetBool(field string, value bool)

SetBool - sets a field and value in boolean format

func (Data) SetBytes

func (d Data) SetBytes(field string, value []byte)

SetBytes - sets a field and value in bytes encoded using base64 URLEncoding

func (Data) SetString

func (d Data) SetString(field, value string)

SetString - sets a field and value in string format

func (Data) SetUint64

func (d Data) SetUint64(field string, value uint64)

SetUint64 - sets a field and value in uint64 format

type FieldError

type FieldError struct {
	// contains filtered or unexported fields
}

FieldError - custom error for fields under a key not found

func NewFieldError

func NewFieldError(field string) (f *FieldError)

NewFieldError - creates a new instance of field error

func (*FieldError) Error

func (f *FieldError) Error() string

Error - returns the error string

func (*FieldError) Is

func (f *FieldError) Is(target error) bool

type KeyError

type KeyError struct {
	// contains filtered or unexported fields
}

KeyError - custom error for indicating a given key is not found

func NewKeyError

func NewKeyError(key string) (k *KeyError)

NewKeyError - creates a new instance of key error

func (*KeyError) Error

func (k *KeyError) Error() string

Error - returns the error string

func (*KeyError) Is

func (k *KeyError) Is(target error) bool

type ListError

type ListError struct {
	// contains filtered or unexported fields
}

ListError - custom error for listing paths under a key

func NewListError

func NewListError(rootPath, path string) (l *ListError)

NewListError - creates a new instance of list error

func (*ListError) Error

func (l *ListError) Error() string

Error - returns the error string

func (*ListError) Is

func (l *ListError) Is(target error) bool

type Token

type Token struct {
	// contains filtered or unexported fields
}

Token - vault token information

func NewToken

func NewToken(token string) (t *Token)

NewToken - creates a new instance of Token

func (*Token) GetToken

func (t *Token) GetToken(c *hvault.Client) (token string, err error)

GetToken - returns the token

func (*Token) SetToken

func (t *Token) SetToken(token string)

SetToken - sets a token

func (*Token) SetTokenFile

func (t *Token) SetTokenFile(token_file string) (err error)

SetTokenFile - sets a file to read the token from

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL