Skip to content

Commit

Permalink
key: remove Manager and export Cache
Browse files Browse the repository at this point in the history
This commit is a refactoring of the
`internal/key` package that removes
the `Manager` type and exports the
`Cache` type.

Now, an arbitrary key store can be
wrapped by a cache like this:

```
cache := key.NewCache(store, key.CacheConfig{
   Expiry:        5 * time.Minute,
   ExpiryUnused: 30 * time.Second,
})
```

Furthermore, a `Cache` satisfies the
`key.Store` interface. This is an important
property that will be relevant later on
when we add a stateful implementation.

Signed-off-by: Andreas Auernhammer <hi@aead.dev>
  • Loading branch information
aead committed Jan 12, 2022
1 parent 2629439 commit 4073c5f
Show file tree
Hide file tree
Showing 8 changed files with 303 additions and 298 deletions.
16 changes: 8 additions & 8 deletions cmd/kes/server.go
Expand Up @@ -206,12 +206,12 @@ func server(args []string) {
if err != nil {
stdlog.Fatalf("Error: %v", err)
}
manager := &key.Manager{
CacheExpiryAny: config.Cache.Expiry.Any.Value(),
CacheExpiryUnused: config.Cache.Expiry.Unused.Value(),
CacheExpiryOffline: config.Cache.Expiry.Offline.Value(),
Store: store,
}
var cache = key.NewCache(store, &key.CacheConfig{
Expiry: config.Cache.Expiry.Any.Value(),
ExpiryUnused: config.Cache.Expiry.Unused.Value(),
ExpiryOffline: config.Cache.Expiry.Offline.Value(),
})
defer cache.Stop()

for _, k := range config.Keys {
bytes, err := sioutil.Random(key.Size)
Expand All @@ -238,7 +238,7 @@ func server(args []string) {
Addr: config.Address.Value(),
Handler: xhttp.NewServerMux(&xhttp.ServerConfig{
Version: version,
Manager: manager,
Store: cache,
Roles: roles,
Proxy: proxy,
AuditLog: auditLog,
Expand Down Expand Up @@ -303,7 +303,7 @@ func server(args []string) {
}
}()
go certificate.ReloadAfter(ctx, 5*time.Minute) // 5min is a quite reasonable reload interval
go key.LogStoreStatus(ctx, manager.Store, 1*time.Minute, errorLog.Log())
go key.LogStoreStatus(ctx, cache, 1*time.Minute, errorLog.Log())

// The following code prints a server startup message similar to:
//
Expand Down
32 changes: 16 additions & 16 deletions internal/http/handler.go
Expand Up @@ -123,7 +123,7 @@ func handleVersion(version string) http.HandlerFunc {
// handleStatus returns a handler function that returns status
// information, like server version and server up-time, as JSON
// object to the client.
func handleStatus(version string, manager *key.Manager, log *xlog.Target) http.HandlerFunc {
func handleStatus(version string, store key.Store, log *xlog.Target) http.HandlerFunc {
type Status struct {
Version string `json:"version"`
UpTime time.Duration `json:"uptime"`
Expand All @@ -135,7 +135,7 @@ func handleStatus(version string, manager *key.Manager, log *xlog.Target) http.H
}
var startTime = time.Now()
return func(w http.ResponseWriter, r *http.Request) {
kmsState, err := manager.Store.Status(r.Context())
kmsState, err := store.Status(r.Context())
if err != nil {
kmsState = key.StoreState{
State: key.StoreUnreachable,
Expand All @@ -162,7 +162,7 @@ func handleStatus(version string, manager *key.Manager, log *xlog.Target) http.H
// It infers the name of the new Secret from the request URL - in
// particular from the URL's path base.
// See: https://golang.org/pkg/path/#Base
func handleCreateKey(manager *key.Manager) http.HandlerFunc {
func handleCreateKey(store key.Store) http.HandlerFunc {
var ErrInvalidKeyName = kes.NewError(http.StatusBadRequest, "invalid key name")

return func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -178,7 +178,7 @@ func handleCreateKey(manager *key.Manager) http.HandlerFunc {
return
}

if err := manager.Create(r.Context(), name, key.New(bytes)); err != nil {
if err := store.Create(r.Context(), name, key.New(bytes)); err != nil {
Error(w, err)
}
w.WriteHeader(http.StatusOK)
Expand All @@ -192,7 +192,7 @@ func handleCreateKey(manager *key.Manager) http.HandlerFunc {
// It infers the name of the new Secret from the request URL - in
// particular from the URL's path base.
// See: https://golang.org/pkg/path/#Base
func handleImportKey(manager *key.Manager) http.HandlerFunc {
func handleImportKey(store key.Store) http.HandlerFunc {
var (
ErrInvalidKeyName = kes.NewError(http.StatusBadRequest, "invalid key name")
ErrInvalidJSON = kes.NewError(http.StatusBadRequest, "invalid json")
Expand Down Expand Up @@ -220,15 +220,15 @@ func handleImportKey(manager *key.Manager) http.HandlerFunc {
return
}

if err := manager.Create(r.Context(), name, key.New(req.Bytes)); err != nil {
if err := store.Create(r.Context(), name, key.New(req.Bytes)); err != nil {
Error(w, err)
return
}
w.WriteHeader(http.StatusOK)
}
}

func handleDeleteKey(manager *key.Manager) http.HandlerFunc {
func handleDeleteKey(store key.Store) http.HandlerFunc {
var ErrInvalidKeyName = kes.NewError(http.StatusBadRequest, "invalid key name")

return func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -237,7 +237,7 @@ func handleDeleteKey(manager *key.Manager) http.HandlerFunc {
Error(w, ErrInvalidKeyName)
return
}
if err := manager.Delete(r.Context(), name); err != nil {
if err := store.Delete(r.Context(), name); err != nil {
Error(w, err)
return
}
Expand All @@ -257,7 +257,7 @@ func handleDeleteKey(manager *key.Manager) http.HandlerFunc {
// returned http.HandlerFunc will authenticate but not encrypt
// the context value. The client has to provide the same
// context value again for decryption.
func handleGenerateKey(manager *key.Manager) http.HandlerFunc {
func handleGenerateKey(store key.Store) http.HandlerFunc {
var (
ErrInvalidJSON = kes.NewError(http.StatusBadRequest, "invalid json")
ErrInvalidKeyName = kes.NewError(http.StatusBadRequest, "invalid key name")
Expand All @@ -281,7 +281,7 @@ func handleGenerateKey(manager *key.Manager) http.HandlerFunc {
Error(w, ErrInvalidKeyName)
return
}
secret, err := manager.Get(r.Context(), name)
secret, err := store.Get(r.Context(), name)
if err != nil {
Error(w, err)
return
Expand Down Expand Up @@ -316,7 +316,7 @@ func handleGenerateKey(manager *key.Manager) http.HandlerFunc {
// returned http.HandlerFunc will authenticate but not encrypt
// the context value. The client has to provide the same
// context value again for decryption.
func handleEncryptKey(manager *key.Manager) http.HandlerFunc {
func handleEncryptKey(store key.Store) http.HandlerFunc {
var (
ErrInvalidJSON = kes.NewError(http.StatusBadRequest, "invalid json")
ErrInvalidKeyName = kes.NewError(http.StatusBadRequest, "invalid key name")
Expand All @@ -340,7 +340,7 @@ func handleEncryptKey(manager *key.Manager) http.HandlerFunc {
Error(w, ErrInvalidKeyName)
return
}
secret, err := manager.Get(r.Context(), name)
secret, err := store.Get(r.Context(), name)
if err != nil {
Error(w, err)
return
Expand All @@ -363,7 +363,7 @@ func handleEncryptKey(manager *key.Manager) http.HandlerFunc {
// If the client has provided a context value during
// encryption / key generation then the client has to provide
// the same context value again.
func handleDecryptKey(manager *key.Manager) http.HandlerFunc {
func handleDecryptKey(store key.Store) http.HandlerFunc {
var (
ErrInvalidJSON = kes.NewError(http.StatusBadRequest, "invalid json")
ErrInvalidKeyName = kes.NewError(http.StatusBadRequest, "invalid key name")
Expand All @@ -387,7 +387,7 @@ func handleDecryptKey(manager *key.Manager) http.HandlerFunc {
Error(w, ErrInvalidKeyName)
return
}
secret, err := manager.Get(r.Context(), name)
secret, err := store.Get(r.Context(), name)
if err != nil {
Error(w, err)
return
Expand All @@ -413,14 +413,14 @@ func handleDecryptKey(manager *key.Manager) http.HandlerFunc {
// The client is expected to check for an error trailer
// and only consider the listing complete if it receives
// no such trailer.
func handleListKeys(manager *key.Manager) http.HandlerFunc {
func handleListKeys(store key.Store) http.HandlerFunc {
type Response struct {
Name string
}
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Trailer", "Status,Error")

iterator, err := manager.List(r.Context())
iterator, err := store.List(r.Context())
if err != nil {
Error(w, err)
return
Expand Down
25 changes: 12 additions & 13 deletions internal/http/server.go
Expand Up @@ -21,10 +21,9 @@ type ServerConfig struct {
// If empty, it defaults to v0.0.0-dev.
Version string

// Manager is the key manager that fetches
// keys from a key store and stores them
// in a local in-memory cache.
Manager *key.Manager
// Store is the key store holding the cryptographic
// keys.
Store key.Store

// Roles is the authorization system that
// contains identities and the associated
Expand Down Expand Up @@ -60,7 +59,7 @@ type ServerConfig struct {
func NewServerMux(config *ServerConfig) *http.ServeMux {
var (
version = config.Version
manager = config.Manager
store = config.Store
roles = config.Roles
proxy = config.Proxy
auditLog = config.AuditLog
Expand All @@ -73,13 +72,13 @@ func NewServerMux(config *ServerConfig) *http.ServeMux {

const MaxBody = 1 << 20
var mux = http.NewServeMux()
mux.Handle("/v1/key/create/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodPost, validatePath("/v1/key/create/*", limitRequestBody(0, tlsProxy(proxy, enforcePolicies(roles, handleCreateKey(manager)))))))))))
mux.Handle("/v1/key/import/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodPost, validatePath("/v1/key/import/*", limitRequestBody(MaxBody, tlsProxy(proxy, enforcePolicies(roles, handleImportKey(manager)))))))))))
mux.Handle("/v1/key/delete/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodDelete, validatePath("/v1/key/delete/*", limitRequestBody(0, tlsProxy(proxy, enforcePolicies(roles, handleDeleteKey(manager)))))))))))
mux.Handle("/v1/key/generate/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodPost, validatePath("/v1/key/generate/*", limitRequestBody(MaxBody, tlsProxy(proxy, enforcePolicies(roles, handleGenerateKey(manager)))))))))))
mux.Handle("/v1/key/encrypt/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodPost, validatePath("/v1/key/encrypt/*", limitRequestBody(MaxBody/2, tlsProxy(proxy, enforcePolicies(roles, handleEncryptKey(manager)))))))))))
mux.Handle("/v1/key/decrypt/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodPost, validatePath("/v1/key/decrypt/*", limitRequestBody(MaxBody, tlsProxy(proxy, enforcePolicies(roles, handleDecryptKey(manager)))))))))))
mux.Handle("/v1/key/list/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodGet, validatePath("/v1/key/list/*", limitRequestBody(0, tlsProxy(proxy, enforcePolicies(roles, handleListKeys(manager)))))))))))
mux.Handle("/v1/key/create/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodPost, validatePath("/v1/key/create/*", limitRequestBody(0, tlsProxy(proxy, enforcePolicies(roles, handleCreateKey(store)))))))))))
mux.Handle("/v1/key/import/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodPost, validatePath("/v1/key/import/*", limitRequestBody(MaxBody, tlsProxy(proxy, enforcePolicies(roles, handleImportKey(store)))))))))))
mux.Handle("/v1/key/delete/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodDelete, validatePath("/v1/key/delete/*", limitRequestBody(0, tlsProxy(proxy, enforcePolicies(roles, handleDeleteKey(store)))))))))))
mux.Handle("/v1/key/generate/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodPost, validatePath("/v1/key/generate/*", limitRequestBody(MaxBody, tlsProxy(proxy, enforcePolicies(roles, handleGenerateKey(store)))))))))))
mux.Handle("/v1/key/encrypt/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodPost, validatePath("/v1/key/encrypt/*", limitRequestBody(MaxBody/2, tlsProxy(proxy, enforcePolicies(roles, handleEncryptKey(store)))))))))))
mux.Handle("/v1/key/decrypt/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodPost, validatePath("/v1/key/decrypt/*", limitRequestBody(MaxBody, tlsProxy(proxy, enforcePolicies(roles, handleDecryptKey(store)))))))))))
mux.Handle("/v1/key/list/", timeout(15*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodGet, validatePath("/v1/key/list/*", limitRequestBody(0, tlsProxy(proxy, enforcePolicies(roles, handleListKeys(store)))))))))))

mux.Handle("/v1/policy/write/", timeout(10*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodPost, validatePath("/v1/policy/write/*", limitRequestBody(MaxBody, tlsProxy(proxy, enforcePolicies(roles, handleWritePolicy(roles)))))))))))
mux.Handle("/v1/policy/read/", timeout(10*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodGet, validatePath("/v1/policy/read/*", limitRequestBody(0, tlsProxy(proxy, enforcePolicies(roles, handleReadPolicy(roles)))))))))))
Expand All @@ -93,7 +92,7 @@ func NewServerMux(config *ServerConfig) *http.ServeMux {
mux.Handle("/v1/log/audit/trace", metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodGet, validatePath("/v1/log/audit/trace", limitRequestBody(0, tlsProxy(proxy, enforcePolicies(roles, handleTraceAuditLog(auditLog))))))))))
mux.Handle("/v1/log/error/trace", metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodGet, validatePath("/v1/log/error/trace", limitRequestBody(0, tlsProxy(proxy, enforcePolicies(roles, handleTraceErrorLog(errorLog))))))))))

mux.Handle("/v1/status", timeout(10*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodGet, validatePath("/v1/status", limitRequestBody(0, tlsProxy(proxy, enforcePolicies(roles, handleStatus(version, manager, errorLog)))))))))))
mux.Handle("/v1/status", timeout(10*time.Second, metrics.Count(metrics.Latency(audit(auditLog.Log(), roles, requireMethod(http.MethodGet, validatePath("/v1/status", limitRequestBody(0, tlsProxy(proxy, enforcePolicies(roles, handleStatus(version, store, errorLog)))))))))))

// Scrapping /v1/metrics should not change the metrics itself.
// Further, scrapping /v1/metrics should, by default, not produce
Expand Down

0 comments on commit 4073c5f

Please sign in to comment.