securestorage

package module
v1.13.0 Latest Latest
Warning

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

Go to latest
Published: Jun 10, 2022 License: MIT Imports: 6 Imported by: 11

README

Secure Storage Package

Overview

The hms-securestorage package is an adapter for access to Hashicorp Vault. It provides methods for:

  • Adapter initialization,
  • Key/value store, fetch, and delete
  • K8s and Vault authorization setup
  • Methods for more direct interaction with the Vault K/V store (typically not directly used by applications)

This package is used by the higher-level hms-compcredentials package to further abstract away the details of Vault interactions.

Environment Variables

This package depends heavily on environment variables to provide various pieces of configuration information needed by the Hashicorp Vault API.
Fortunately, the defaults suffice for nearly all of them. The variables are listed below, with explanations of the few that are needed by most applications:

  • VAULT_ADDR - URL of Hashicorp Vault service, e.g. http://cray-vault.vault:8200
  • VAULT_SKIP_VERIFY -- Typically set to 'true'
  • VAULT_TOKEN -- Specify key space. HMS services set this to 'hms'

The following are typically set according to defaults generated by a system's configuration mechanism, including k8s sealed secrets, and are thus available to and already set in a microservice's environment.

  • CRAY_VAULT_JWT_FILE -- Specifies the path of a file containing an access token used for k8s authN/authZ. The default is /var/run/secrets/kubernetes.io/serviceaccount/token.
  • CRAY_VAULT_ROLE_FILE -- Specifies the path of a file containing a name space used by k8s. Default is /var/run/secrets/kubernetes.io/serviceaccount/namespace.
  • CRAY_VAULT_AUTH_PATH -- Used for k8s access. Default will suffice for production deployments. Default is auth/kubernetes/login. In testing environments it can be set to auth/token/create.

The following are typically not set in HMS services; default values are safe:

  • VAULT_AGENT_ADDR
  • VAULT_CACERT
  • VAULT_CAPATH
  • VAULT_CLIENT_CERT
  • VAULT_CLIENT_KEY
  • VAULT_CLIENT_TIMEOUT
  • VAULT_NAMESPACE
  • VAULT_TLS_SERVER_NAME
  • VAULT_WRAP_TTL
  • VAULT_MAX_RETRIES
  • VAULT_MFA
  • VAULT_RATE_LIMIT

Adapter Initialization

Typical usage by applications begins by creating and initializing a Vault adapter, assuming the environment variables specified above have been set:

...
	ss,err := securestorage.NewVaultAdapter("secret")
	if (err != nil) {
		log.Printf("Unable to create Vault adapter: %v",err)
	}
...

The string "secret" is a path within the overall key space used by the application, and is the typical value used by HMS microservices.

The returned handle can then be used for storing/fetching/deleting key/value entries.

Most-Used Methods

The following methods are the ones most used by applications.

// Create a new SecureStorage interface that uses Vault. This connects an
// application to Vault.
func NewVaultAdapter(basePath string) (SecureStorage, error)


// Write a value to Vault at the location specified by 'key'. This function
// prepends the basePath. Retries are implemented for token renewal.  The
// specified value should not be marshalled or encoded in any way.
func (ss *VaultAdapter) Store(key string, value interface{}) error


// Read a value from Vault at the location specified by key. This function
// prepends the basePath. Retries are automatically done for token renewal.
// Note that the resulting value is unmarshalled and returned in the 
// 'output' argument.
func (ss *VaultAdapter) Lookup(key string, output interface{}) error {


// Get a list of keys that exsist in Vault at the path specified by keyPath.
// This function prepends the basePath. Retries are automatically done for
// token renewal.
func (ss *VaultAdapter) LookupKeys(keyPath string) ([]string, error)


// Remove a value from Vault at the location specified by key. This function
// prepends the basePath. Retries are implemented for token renewal.
func (ss *VaultAdapter) Delete(key string) error

Lower Level Mechanisms

In addition to the above typically-used methods there are also lower-level methods that can be directly used by applications. Note that these lower-level mechanisms are used by the higher-level ones outlined above so there is typically no need to use them.

K8s Authentication Support

The following are used for authN support for Kubernetes.

// AuthConfig struct for vault k8s authentication
type AuthConfig struct {
	JWTFile  string
	RoleFile string
	Path     string
	jwt      string
	role     string
}


// ReadEnvironment Update an AuthConfig object with environment variables
//   CRAY_VAULT_JWT_FILE
//   CRAY_VAULT_ROLE_FILE
//   CRAY_VAULT_AUTH_PATH
func (authConfig *AuthConfig) ReadEnvironment() error


// LoadJWT save contents of JWT file to the AuthConfig jwt field.  This is
// used for manual JWT token refresh.
func (authConfig *AuthConfig) LoadJWT() error


// Manually load contents of RoleFile into the role field
func (authConfig *AuthConfig) LoadRole() error


// Getter method for auth path key
func (authConfig *AuthConfig) GetAuthPath() string


// Generates the args required for generating an auth token
func (authConfig *AuthConfig) GetAuthArgs() map[string]interface{}
Low-Level Vault Access

This package provides a mechanism for a more direct access to the Vault API. This is generally not used by applications; using it will require code changes if Vault is ever swapped out for another secure storage system.

These methods and data structures use the Vault 'api' object directly.

///////////////////////////////////////////////////////////////////////////////
// Vault API interface - This interface wraps only a subset of functions for
// api.Client so as to reduce the amount of functions that need to be mocked
// for unit testing.
///////////////////////////////////////////////////////////////////////////////
type VaultApi interface {
	Read(path string) (*api.Secret, error)
	Write(path string, data map[string]interface{}) (*api.Secret, error)
	Delete(path string) (*api.Secret, error)
	List(path string) (*api.Secret, error)
	SetToken(t string)
}

type RealVaultApi struct {
	Client *api.Client
}


// Create a low-level Vault API object
func NewRealVaultApi(client *api.Client) VaultApi


// Apply a JWT token to the low-level Vault
func (v *RealVaultApi) SetToken(t string)


// Read a K/V from low-level Vault.  Returns a secret record containing the
// key's value.
func (v *RealVaultApi) Read(path string) (*api.Secret, error)


// Write a K/V to low-level Vault.  Returns the secret record modified by
// the write operation.
func (v *RealVaultApi) Write(path string, data map[string]interface{}) (*api.Secret, error)


// Delete a key in low-level Vault.  
func (v *RealVaultApi) Delete(path string) (*api.Secret, error)


// List all keys in the specified key space.  Returns secret record 
// containing all keys in the space.
func (v *RealVaultApi) List(path string) (*api.Secret, error)

Typical Usage

Following is an example of the hms-securestorage package. Note that this example is mostly centered around the hms-compcredentials package, as that package is the one predominantly used in HMS services.

...
import (
    sstorage "github.com/Cray-HPE/hms-securestorage"
    compcreds "github.com/Cray-HPE/hms-compcredentials"
)
...

    // Create the Vault adapter and connect to Vault

    ss, err := sstorage.NewVaultAdapter("secret")
    if err != nil {
        return fmt.Errorf("Error: %v", err)
    }

    // Initialize the CompCredStore struct with the Vault adapter.
	// Use the 'hms-creds' key space

    ccs := compcreds.NewCompCredStore("hms-creds", ss)

    // Create a new set of credentials for a component.

    compCred := compcreds.CompCredentials{
        Xname: "x0c0s21b0"
        URL: "10.4.0.8/redfish/v1/UpdateService"
        Username: "test"
        Password: "123"
    }

    // Store the credentials in the CompCredStore (backed by Vault).

    err = ccs.StoreCompCred(compCred)
    if err != nil {
        return fmt.Errorf("Error: %v", err)
        
    }

    // Read the credentials for a component from the CompCredStore
    // (backed by Vault).

    var ccred CompCredentials
    ccred, err = ccs.GetCompCred(compCred.Xname)
    if err != nil {
        return fmt.Errorf("Error: %v", err)
    }

    log.Printf("%v", ccred)
...

Documentation

Index

Constants

View Source
const DefaultBasePath = "secret"
View Source
const EnvVaultAuthPath = "CRAY_VAULT_AUTH_PATH"
View Source
const EnvVaultJWTFile = "CRAY_VAULT_JWT_FILE"

These Env var are provided globally to pods

View Source
const EnvVaultRoleFile = "CRAY_VAULT_ROLE_FILE"

Variables

This section is empty.

Functions

func NewMockAdapter

func NewMockAdapter() (SecureStorage, *MockAdapter)

Types

type AuthConfig

type AuthConfig struct {
	JWTFile  string
	RoleFile string
	Path     string
	// contains filtered or unexported fields
}

AuthConfig struct for vault k8s authentication

func DefaultAuthConfig

func DefaultAuthConfig() *AuthConfig

DefaultAuthConfig Create the default auth config that will work for almost all scenarios

func (*AuthConfig) GetAuthArgs

func (authConfig *AuthConfig) GetAuthArgs() map[string]interface{}

GetAuthArgs generates the ars required for generating an auth token

func (*AuthConfig) GetAuthPath

func (authConfig *AuthConfig) GetAuthPath() string

GetAuthPath Getter for auth path key

func (*AuthConfig) LoadJWT

func (authConfig *AuthConfig) LoadJWT() error

LoadJWT save contents of JWTFile to the jwt field

func (*AuthConfig) LoadRole

func (authConfig *AuthConfig) LoadRole() error

LoadRole save contents of RoleFile to the role field

func (*AuthConfig) ReadEnvironment

func (authConfig *AuthConfig) ReadEnvironment() error

ReadEnvironment Update an authConfig with environment variables

type InputDelete

type InputDelete struct {
	Key string
}

type InputLookup

type InputLookup struct {
	Key string
}

type InputLookupKeys

type InputLookupKeys struct {
	KeyPath string
}

type InputStore

type InputStore struct {
	Key   string
	Value interface{}
}

type MockAdapter

type MockAdapter struct {
	StoreNum       int
	StoreData      []MockStore
	StoreWDataNum  int
	StoreWData     []MockStoreWithData
	LookupNum      int
	LookupData     []MockLookup
	DeleteNum      int
	DeleteData     []MockDelete
	LookupKeysNum  int
	LookupKeysData []MockLookupKeys
}

func (*MockAdapter) Delete

func (ss *MockAdapter) Delete(key string) error

func (*MockAdapter) Lookup

func (ss *MockAdapter) Lookup(key string, output interface{}) error

func (*MockAdapter) LookupKeys

func (ss *MockAdapter) LookupKeys(keyPath string) ([]string, error)

func (*MockAdapter) Store

func (ss *MockAdapter) Store(key string, value interface{}) error

func (*MockAdapter) StoreWithData added in v1.13.0

func (ss *MockAdapter) StoreWithData(key string, value interface{}, output interface{}) error

type MockDelete

type MockDelete struct {
	Input  InputDelete
	Output OutputDelete
}

type MockLookup

type MockLookup struct {
	Input  InputLookup
	Output OutputLookup
}

type MockLookupKeys

type MockLookupKeys struct {
	Input  InputLookupKeys
	Output OutputLookupKeys
}

type MockStore

type MockStore struct {
	Input  InputStore
	Output OutputStore
}

type MockStoreWithData added in v1.13.0

type MockStoreWithData struct {
	Input  InputStore
	Output OutputLookup
}

type OutputDelete

type OutputDelete struct {
	Err error
}

type OutputLookup

type OutputLookup struct {
	Output interface{}
	Err    error
}

type OutputLookupKeys

type OutputLookupKeys struct {
	Klist []string
	Err   error
}

type OutputStore

type OutputStore struct {
	Err error
}

type RealVaultApi

type RealVaultApi struct {
	Client *api.Client
}

func (*RealVaultApi) Delete

func (v *RealVaultApi) Delete(path string) (*api.Secret, error)

func (*RealVaultApi) List

func (v *RealVaultApi) List(path string) (*api.Secret, error)

func (*RealVaultApi) Read

func (v *RealVaultApi) Read(path string) (*api.Secret, error)

func (*RealVaultApi) SetToken

func (v *RealVaultApi) SetToken(t string)

func (*RealVaultApi) Write

func (v *RealVaultApi) Write(path string, data map[string]interface{}) (*api.Secret, error)

type SecureStorage

type SecureStorage interface {
	Store(key string, value interface{}) error
	StoreWithData(key string, value interface{}, output interface{}) error
	Lookup(key string, output interface{}) error
	Delete(key string) error
	LookupKeys(keyPath string) ([]string, error)
}

func NewVaultAdapter

func NewVaultAdapter(basePath string) (SecureStorage, error)

Create a new SecureStorage interface that uses Vault. This connects to vault.

func NewVaultAdapterAs added in v1.13.0

func NewVaultAdapterAs(basePath string, role string) (SecureStorage, error)

type VaultAdapter

type VaultAdapter struct {
	Config     *api.Config
	Client     VaultApi
	AuthConfig *AuthConfig
	BasePath   string
	VaultRetry int
	Role       string
}

func (*VaultAdapter) Delete

func (ss *VaultAdapter) Delete(key string) error

Remove a struct from Vault at the location specified by key. This function prepends the basePath. Retries are implemented for token renewal.

func (*VaultAdapter) Lookup

func (ss *VaultAdapter) Lookup(key string, output interface{}) error

Read a struct from Vault at the location specified by key. This function prepends the basePath. Retries are implemented for token renewal.

func (*VaultAdapter) LookupKeys

func (ss *VaultAdapter) LookupKeys(keyPath string) ([]string, error)

Get a list of keys that exsist in Vault at the path specified by keyPath. This function prepends the basePath. Retries are implemented for token renewal.

func (*VaultAdapter) Store

func (ss *VaultAdapter) Store(key string, value interface{}) error

Write a struct to Vault at the location specified by key. This function prepends the basePath. Retries are implemented for token renewal.

func (*VaultAdapter) StoreWithData added in v1.13.0

func (ss *VaultAdapter) StoreWithData(key string, value interface{}, output interface{}) error

Write a struct to Vault at the location specified by key and return the response. This function prepends the basePath. Retries are implemented for token renewal. Note: Unlike Lookup(), this returns the entire response body. Not just secretValues.Data.

type VaultApi

type VaultApi interface {
	Read(path string) (*api.Secret, error)
	Write(path string, data map[string]interface{}) (*api.Secret, error)
	Delete(path string) (*api.Secret, error)
	List(path string) (*api.Secret, error)
	SetToken(t string)
}

///////////////////////////////////////////////////////////////////////////// Vault API interface - This interface wraps only a subset of functions for api.Client so as to reduce the amount of functions that need to be mocked for unit testing. /////////////////////////////////////////////////////////////////////////////

func NewRealVaultApi

func NewRealVaultApi(client *api.Client) VaultApi

Jump to

Keyboard shortcuts

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