Managing stores of secret things

Latest on Hackage:

This package is not currently in any snapshots. If you're interested in using it, we recommend adding it to Stackage Nightly. Doing so will make builds more reliable, and allow to host generated Haddocks.

BSD-3-Clause licensed by Chris Dornan
Maintained by

Writing deployment scripts is a critical yet error-prone activity which we would rather do in Haskell. One of the most difficult aspect of deployment scripts is the management of credentials: they cannot be stored in the VCS like almost everything else, but need to be organised and accessed while under lock and key. This is the problem that keystore is trying to solve: flexible, secure and well-typed deployment scripts.

All Haskell

This package is written purely in Haskell and all of the cryptographic packages it relies upon are written in Haskell.

JSON Format

It stores everything in a JSON format that has proven to be stable. We can can use migrations in future should the store need to be reorganized.

Simple and Flexible Underlying Model

  • Named Keys: every key has an name within the store that is associated with some secret data. If the secret data for that key is to be stored then it must identify another key in the store that will be used to encrypt the data. (Some keys -- the passwords -- will typically be auto-loaded from environment variables.)

  • *Functional model*: keys can be deleted and added again but the design encourages the retention of the history. The old keys remain available but deployment scripts will naturally select the latest version of a key. When a key is rotated this merely loads a new generation for the rotated key.

  • Simple Metadata: oher information, such as the identity of the key with its originating system (e.g., the identifier of an AWS IAM key) and some arbitrary textual information (the comment) may be associated with a key and accessible without recourse to the key or password needed to access the secret information.

  • PKS: the seret may be a RSA provate key with the public key stored separately in the cler.

  • *MFA*: a secret may be protected with multiple named keys, all of which will be needed to recover the secret text.

  • Hashing: all keys can be hashed with an appropriate PBKDF-2 function and the hashes stored in the clear. These hashes may be sued to verify passwords but also can be inserted directly into configuration files for deployment. Precise control of the PBKDF-2 hash paramers is avaiable.

  • Hierarchical Organization: keys can be stored in different sections with each key being protected by a master key for that section. Sections can be configured to store the master keys of other sections thereby gaining acces to all of the keys in those sections and the keys they have access to.

  • Systems Integration: keys can automatically loaded from Environment variables. Typically a keystore session will start by settingb up an environment variable for the deployment section corresponding for the node that you need to deploy to. This will provide access to precisely the keys whose secrets you need to carry out the deployment and no more. It only needs access to the hashes of admin keys then they can be placed in separate higher-level admin sections. Provided care is taken preparing the environment you will not deploy to the wrong host (e.g., a live server rather than a staging server, or the wrong live server) because those keys will not be accessible.

  • Configuration Control: the parameters controling the encryption and hashing functions can be set up independently in each section of the store, allowing for heavier hashing to be used on live servers and light hashing to be used on development and staging servers where authentication needs to be quick.

  • Keystore Integrity: the keystore can be signed and every operation made to check that the keystore matches its signature (and the public signing key matches an independent copy on the client).

  • External Crypto Operations: keys in the keystore can be used to sign or encrypt external obejcts (provided they can be loaded into memory).

The Layers

The keystore package has several layers. Most users will probably need only the top "batteries-included" layer:

  • Data.KeyStore.Sections: this provides a high-level model that allows a flexible hierarchical keystore to be set up relatively easily. See the deploy example for details.

  • Data.KeyStore.CLI : This provides a stanalone program for inspecting and editing your keystores. It can also be embedded into your own deployment app. See the deploy example for details.

  • Data.KeyStore.PasswordManager provides a password manager which each user can use to setup their own local password store for holding the deployment passwords and session tokens used to autheticate the server.

  • Data.KeyStore.IO: this library provides general programatic access to a keystore through IO primitives. See the source code for the Sections for an example of this module in use.

  • Data.KeyStore.KS: this library provides general programatic access to a keystore through functional KS primitives. See the source code for the IO for an exteded example this system in action.

  • Data.KeyStore.Types: This provides access to keystores at the types level.

Launch Instructions

See the bottom README on GitHub home page for launch instructions for the deploy example.


-*-change-log-*- Chris Dornan <> 2014-03-30
* First public release Chris Dornan <> 2014-06-08
* Fix read-only behaviour, adding --read-only flag Chris Dornan <> 2014-07-06
* Reorganise module hierarchy and code base
* Add Data.KeyStore.Sections
* Replace 'psd' example with 'deploy' example Chris Dornan <> 2014-07-07
* Fix 'deploy' example Chris Dornan <> 2014-07-23
* Fix CLI organization
* Add hostRSection to Sections class Adam Gundry <> 2014-07-23
* Add GHC compatability Chris Dornan <> 2014-07-26
* Remove hostRSection from Sections class!
* Reorganise Sections simplifying and fixing host/section relationship
* Fix 'deploy' example to work with new sections
* Write Haddock annotations for Sections module.
* Tidy cabal file
* Revise readme and cabal documentation Chris Dornan <> 2014-07-27
* expose getKeystore, getState, getCtxState, putCtxState in Data.KeyStore.IO
* add proxy arguments to verifyKeystore & locateKeys in Data.KeyStore.Sections
* opened up the export of Data.KeyStore.Types
* added getSettingsOpt' to Data.KeyStore.KS.Opt
* Fix #1, (section, key and host prefixes)
* NB: this release will auto-migrate a keystore reformating the identifers
to life the 'no-prefixes' restrictions BUT:
+ the change of format will only persist when the store is written
back, which usually only happens on an edit operation that
changes the keystore (e.g., by rotating a key) or, better, by forcing
the kmeystore to be written back);
+ the keystore's (detached) signature will not be migrated
but you will have to re-sign the keystore after it has been
reformatted anyway; your best bet is to remove the signature (to prevent
an error arising from the failure to find the signing key under
its old name, (mis)identified in the signature) and resigning the

For example, to migrate the example store, you could do something like this:

$ rm deploy-keystore.hash
$ deploy -w sign Chris Dornan <> 2014-07-28
* fix default sectionPWEnvVar in Sections class Chris Dornan <> 2014-07-28
* improve build stability of Sections: list the things we need from Control.Lens Chris Dornan <> 2014-07-30
* fix key-formatting bug (gratuitious insertion of double '/'s before the
version number) Chris Dornan <> 2014-08-24
* improve diagnostics for internally used Sections.keySection
* add roateIfChanged to Sections (squashes vacuous rotations) Chris Dornan <> 2014-09-08
* fix the repo location in the cabal file
* fix smart rotate to not rotate keys it cannot access
* add password manager Chris Dornan <> 2014-09-08
* fix setEnv usage to work with GHCs 7.6.3 & 7.8.3 Chris Dornan <> 2014-09-21
* add dynamic passwords to the passowrd manager
* add password manager importing
* fix bugs in the PasswordManager `amLoggedIn` and `passwordValid`
(they were throwing exceptions rather than returning False)
* add support for shell prompts to the password manager
* expose the optparse-applicative PasswordManager CLI parser and abstract
syntax for cleaner embedding in optparse-applicative parsers
* hope dependent pacakges have stopped breaking the Hackage build Chris Dornan <> 2014-09-28
* expose ks optparse-applicative CLI parser
* adapt 'deploy' example to use 'ks' and 'pm' optparse-applicative parsers Chris Dornan <> 2014-09-28
* fix deploy example for GHC 7.6.3 (use System.Setenv) Chris Dornan <> 2014-10-19
* add listKeys and keyName_ to Sections
* add getKeyDataWithMode and rotate_ to Sections
* rotate reports the keys it is rotating Chris Dornan <> 2014-10-19
* switch to optprase-applicative 0.11 Chris Dornan <> 2014-11-07
* export 'login' and 'PMCommand' constructors from PasswordManager Chris Dornan <> 2014-11-08
* PM: add getStore (for debugging)
* PM: fix a curious regression in in the CLI parser
(possibly triggered by the upgrade of a dependent package)
* PM: add delete-all-plus-passwords
* PM: add filter-plus-passwords
* PM: add --exclude-plus-passwords switch to import Chris Dornan <> 2014-12-04
* Data.KeyStore.Sections: export mkSection
comments powered byDisqus