locket

package module
v0.10.4 Latest Latest
Warning

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

Go to latest
Published: Jun 22, 2025 License: MIT Imports: 27 Imported by: 0

README

🔐 locket ❤️

Go - Test

secrets management service

Purpose

Locket is a secrets cache for production services. It stores secrets in memory, loaded from external secrets cache, environment, or .env file as source. Why? Because the 1password GUI is great for business use, but the sacntioned 1password cache was flaky, and I wanted a go based soluton that abstracts away secret origin while providing tight access control and integration with existing deployment.

Overview

sequenceDiagram
    autonumber

    box rgb(0, 40, 0) External 
    participant CI
    participant source
    end

    box rgb(40, 0, 0) Locket Server
    participant secrets
    participant registry
    participant handler
    end

    box rgb(0, 0, 40) Locket Client
    participant client
    end

    activate CI
    CI->>registry: public signing keys
    CI->>client: private signing key
    CI->>secrets: source access key (or source files)
    note over CI: depoy complete
    deactivate CI

    secrets->>source: request all secrets
    activate secrets
    source->>secrets: all secrets
    note over secrets: server init complete
    deactivate secrets

    client->>handler: GET - public key
    activate client
    handler->>client: server public encryption key
    note over client: client init complete
    deactivate client

    client->>handler: GET - public key
    activate client
    handler->>client: server public encryption key
    client->>handler: POST - secret (encrypted & signed)
    handler->>registry: authenticate signing key
    activate handler
    registry->>handler: verify identity
    note over handler: auth & access control
    handler--x client: forbidden
    deactivate handler
    handler->>secrets: request secret
    secrets->>handler: secret value
    handler-->>client: encrypted secret
    note over client: secret fetched
    deactivate client
1-3 Deploy

Create registry and distribute signing keys.

4-5 Init Server

Load secrets using any struct that satisfies the source interface.

struct source
env local environment
dotenv .env file
onepass 1password server
6-7 Init Client

Fetch server public encryption key.

8-9 Refetch public encryption key

Server may generate a new public key upon restart. No caching is currently implemented. 🤷

10-12 Enforce Access Control
  • clients must encrypt and sign every request
  • clients can only requeest their own secrets
13-15 Fetch & Return Secret
  • responses are encrypted

Examples

See tests for examples, and checkout docstings for extensive descriptions.

Future Work

See issues.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Defaults = defaults{
	AllowCIDR:  "10.0.0.0/24",
	BitsizeRSA: 2048,
}
View Source
var OnePasswordVar = "LOCKET_OP_SERVICE_ACCOUNT_TOKEN"

1password service account token environment variable name

Functions

func NewPairEd25519

func NewPairEd25519() (string, string, error)

NewPairEd25519 generates a new Ed25519 key pair used to authenticate clients requests to the server. Returns: publicKeyPEM, privateKeyPEM, error.

func Register added in v0.8.0

func Register(name string, registryPath string) (string, string, error)

Register reads the existing registry file, upserts service key, and rewrites. If the registry file does not exist, it will be created. If no registry for the named service exists, a new entry will be created. An existing entry for the named service will be updated with new public key. Each new call of Register will generate new key pair, returning: public key, private key, or any error.

func WriteRegistry

func WriteRegistry(path string, data []RegEntry) error

WriteRegistry creates a yaml file with a registry of allowed clients.

Types

type Client

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

Client makes requests to a locket server, and must know the server address. serverPubkey is the server's encryption public key, and will be fetched on creation of NewClient(). Rsa and Ed25519 key pairs are also generated on creation of NewClient().

func NewClient

func NewClient(serverURL, keyPub, keyPriv string) (*Client, error)

NewClient creates a new client, fetches the server's encryption public key, and generates RSA key pairs for encrypting k/v secret requests.

Pre-computed ed25519 signing keys (via NewPairEd25519() or any other means) must be passed to a new client, with the expectation that the public key be made available to the server to facilitate authentication. see: WriteRegistry() for details

func (*Client) FetchSecret added in v0.6.6

func (c *Client) FetchSecret(name string) (string, error)

fetchSecret produces an ecrypted and signed request to the server, containing the name of the secret to fetch and the client's own public key (to be used for encrypting the response).

type Dotenv added in v0.0.2

type Dotenv struct {
	Path           string              // path to .env file to read
	ServiceSecrets map[string][]string // service names and a list of their secrets
}

Dotenv satisfies the source interface, loading secrets from a specified path to .env file.

func (Dotenv) Load added in v0.2.1

func (d Dotenv) Load() (map[string]Secrets, error)

Load k=v pairs from a .env file, ignoring any #comments. Service name will be set by the keys in ServiceSecrets map.

type Env added in v0.2.1

type Env struct {
	ServiceSecrets map[string][]string // service name mapped to list of service secret names
}

Env satisfies the source interface, loading secrets from the local environment.

func (Env) Load added in v0.2.1

func (e Env) Load() (map[string]Secrets, error)

Load k=v pairs from local environment.

Expect environment variables to be prefixed with the service name. e.g. SERVICE1_FOO=bar will be interpreted as:

  • service name: SERVICE1
  • secret name: SERVICE1_FOO
  • secret value: bar

type KeysPrivateSigning added in v0.2.0

type KeysPrivateSigning map[string]string

map[serviceName]keyPrivateSigning

type Onepass added in v0.0.2

type Onepass struct {
	Vault string // name of the vault containig service secrets
}

Onepass satisfies the source interface, loading secrets from a 1password vault over the net with 1password API. Service account token must be set environment as locket.OnePasswordVar.

func (Onepass) Load added in v0.2.1

func (o Onepass) Load() (map[string]Secrets, error)

Load all service secrets from a named 1password vault, returning a map of service names to their set of k/v secrets.

type RegEntry

type RegEntry struct {
	Name   string `yaml:"name"`
	KeyPub string `yaml:"keypub"`
}

RegEntry is a single registry item, representing a single client which the server should recognize and authorize

func ReadRegistryFile added in v0.3.0

func ReadRegistryFile(filepath string) ([]RegEntry, error)

ReadRegistryFile turns a yaml file into a list of RegEntry for use in server authenticating client requests.

func UnmarshalRegistry added in v0.8.0

func UnmarshalRegistry(bytes []byte) ([]RegEntry, error)

UnmarshalRegistry turns a byte slice into a list of RegEntry for use in server authenticating client requests. Bytes format easier for embed.FS

type Secrets added in v0.0.2

type Secrets map[string]string // all key/value secrets for a single service

type Server

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

func NewServer

func NewServer(opts source, registry []RegEntry) (*Server, error)

NewServer sets up a new secrets server when provided source options and registry of allowed services (and their public signing keys), expected to be read from file or embed before calling NewServer().

func (*Server) Handler

func (s *Server) Handler(w http.ResponseWriter, r *http.Request)

Jump to

Keyboard shortcuts

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