keystore ======== KeyStore holds *unencrypted* secrets on behalf of users in memory for a short time (of the order of a SSO session lifespan). User secrets can be *opened* with a password (used to decrypt the key, which is stored encrypted in a database), *queried* by presenting a suitable authentication token, and *closed* (wiped and forgotten). The database can provide multiple versions of the encrypted key (to support multiple decryption passwords), in which case we'll try them all sequentially until one of them decrypts successfully with the provided password. In order to query the KeyStore, you need to present a valid SSO token for the user whose secrets you would like to obtain. # API The server exports an API over HTTP/HTTPS. All requests should be made using the POST method and a Content-Type of *application/json*. The request body should contain a JSON-encoded object. Responses will be similarly JSON-encoded. `/api/open` (*OpenRequest*) Retrieve the encrypted key for a user, decrypt it with the provided password, and store it in memory. OpenRequest is an object with the following attributes: * `username` * `password` to decrypt the user's key with * `ttl` (seconds) time after which the credentials are automatically forgotten `/api/get` (*GetRequest*) -> *GetResponse* Retrieve the key for a user. GetRequest must contain the following attributes: * `username` whose key you wish to retrieve * `sso_ticket` with a valid SSO ticket for the *keystore* service If the request is successfully authenticated, GetResponse will contain a single attribute *key*. `/api/close` (*CloseRequest*) Forget the key for a given user. # Dovecot integration The final consumer for user encryption keys is the Dovecot service. The *dovecot-keylookupd* daemon can read the user public and private keys from LDAP, and serve the *unencrypted* keys to Dovecot using its [dict proxy protocol](https://wiki2.dovecot.org/AuthDatabase/Dict). TODO: explain the lookup protocol. # Configuration The *keystored* daemon loads its configuration from a YAML-encoded file, */etc/keystore/config.yml* by default. It can contain the following attributes: * `sso_public_key_file`: path to the SSO Ed25519 public key * `sso_service`: SSO service for this application * `sso_domain`: SSO domain * `ldap`: LDAP backend configuration * `uri`: LDAP server URI * `bind_dn`: bind DN (for simple bind, SASL is not supported) * `bind_pw`: bind password * `bind_pw_file`: bind password (load from this file), in alternative to *bind_pw* * `query`: Parameters for the LDAP search query * `search_base`: base DN for the search * `search_filter`: search filter. The filter string may contain a literal `%s` token somewhere, that will be replaced with the (escaped) username. * `scope`: search scope, one of *sub* (default), *one* or *base* * `public_key_attr`: attribute that contains the user's public key * `private_key_attr`: attribute that contains the user's encrypted key(s) * `http_server`: HTTP server configuration * `tls`: contains the server-side TLS configuration: * `cert`: path to the server certificate * `key`: path to the server's private key * `ca`: path to the CA used to validate clients * `acl`: specifies TLS-based access controls, a list of entries with the following attributes: * `path`: regular expression to match the request URL path * `cn`: regular expression that must match the CommonName part of the subject of the client certificate * `max_inflight_requests`: maximum number of in-flight requests to allow before server-side throttling kicks in The *dovecot-keylookupd* daemon uses a similar configuration, read by default from */etc/keystore/dovecot.yml*: * `ldap`: LDAP backend configuration, see above * `keystore`: configures the connection to the keystore service * `url`: URL for the keystore service * `sharded`: if true, requests to the keystore service will be partitioned according to the user's *shard* attribute * `tls_config`: client TLS configuration * `cert`: path to the client certificate * `key`: path to the private key * `ca`: path to the CA used to validate the server * `shard`: shard identifier for the local host. Must be set if keystore.sharded is true.