Skip to content

Commit

Permalink
kes: add support for API key authentication
Browse files Browse the repository at this point in the history
This commit adds support for KES<->KES authentication
via API keys. Now, a KES edge server can authenticate
to a KES server (stateful) via API keys - not just
via TLS private key / certificate files.
  • Loading branch information
aead committed Mar 7, 2023
1 parent 89f3fa7 commit 2e9ab7a
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 8 deletions.
38 changes: 30 additions & 8 deletions internal/keystore/kes/kes.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ type Config struct {
// If empty, the default enclave is used.
Enclave string

// APIKey is an API key to authenticate to the
// KES server. Either an API key or a mTLS private
// key and certificate can be used for authentication.
APIKey kes.APIKey

// PrivateKey is a path to a file containing
// a X.509 private key for mTLS authentication.
PrivateKey string
Expand All @@ -50,17 +55,34 @@ func Connect(ctx context.Context, config *Config) (*Conn, error) {
if len(config.Endpoints) == 0 {
return nil, errors.New("kes: no endpoints provided")
}
if config.Certificate == "" {
return nil, errors.New("kes: no certificate provided")
}
if config.PrivateKey == "" {
return nil, errors.New("kes: no private key provided")
if config.APIKey != nil && (config.PrivateKey != "" || config.Certificate != "") {
return nil, errors.New("kes: ambiguous configuration: API key as well as mTLS private key and certificate provided")
}

cert, err := https.CertificateFromFile(config.Certificate, config.PrivateKey, "")
if err != nil {
return nil, err
var (
err error
cert tls.Certificate
)
switch {
case config.APIKey != nil:
cert, err = kes.GenerateCertificate(config.APIKey)
if err != nil {
}
case config.PrivateKey != "" || config.Certificate != "":
if config.Certificate == "" {
return nil, errors.New("kes: no certificate provided")
}
if config.PrivateKey == "" {
return nil, errors.New("kes: no private key provided")
}
cert, err = https.CertificateFromFile(config.Certificate, config.PrivateKey, "")
if err != nil {
return nil, err
}
default:
return nil, errors.New("kes: no API key nor private key and certificate provided")
}

var rootCAs *x509.CertPool
if config.CAPath != "" {
rootCAs, err = https.CertPoolFromFile(config.CAPath)
Expand Down
16 changes: 16 additions & 0 deletions keserv/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,10 @@ type KESConfig struct {
// the default enclave name will be used.
Enclave Env[string]

// APIKey is an API key to authenticate to the
// KES server.
APIKey Env[string]

// CertificateFile is a path to a mTLS client
// certificate file used to authenticate to
// the KES server.
Expand All @@ -362,9 +366,19 @@ func (c *KESConfig) Connect(ctx context.Context) (kms.Conn, error) {
for _, endpoint := range c.Endpoints {
endpoints = append(endpoints, endpoint.Value)
}

var key kes.APIKey
if c.APIKey.Value != "" {
k, err := kes.ParseAPIKey(c.APIKey.Value)
if err != nil {
return nil, err
}
key = k
}
return kesstore.Connect(ctx, &kesstore.Config{
Endpoints: endpoints,
Enclave: c.Enclave.Value,
APIKey: key,
Certificate: c.CertificateFile.Value,
PrivateKey: c.PrivateKeyFile.Value,
CAPath: c.CAPath.Value,
Expand All @@ -373,6 +387,7 @@ func (c *KESConfig) Connect(ctx context.Context) (kms.Conn, error) {

func (c *KESConfig) toYAML(yml *serverConfigYAML) {
yml.KeyStore.KES.Endpoint = c.Endpoints
yml.KeyStore.KES.APIKey = c.APIKey
yml.KeyStore.KES.TLS.Certificate = c.CertificateFile
yml.KeyStore.KES.TLS.PrivateKey = c.PrivateKeyFile
yml.KeyStore.KES.TLS.CAPath = c.CAPath
Expand All @@ -381,6 +396,7 @@ func (c *KESConfig) toYAML(yml *serverConfigYAML) {
func (c *KESConfig) fromYAML(yml *serverConfigYAML) {
c.Endpoints = yml.KeyStore.KES.Endpoint
c.Enclave = yml.KeyStore.KES.Enclave
c.APIKey = yml.KeyStore.KES.APIKey
c.CertificateFile = yml.KeyStore.KES.TLS.Certificate
c.PrivateKeyFile = yml.KeyStore.KES.TLS.PrivateKey
c.CAPath = yml.KeyStore.KES.TLS.CAPath
Expand Down
1 change: 1 addition & 0 deletions keserv/yml.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type serverConfigYAML struct {
KES struct {
Endpoint []Env[string] `yaml:"endpoint,omitempty"`
Enclave Env[string] `yaml:"enclave,omitempty"`
APIKey Env[string] `yaml:"api_key,omitempty"`
TLS struct {
Certificate Env[string] `yaml:"cert,omitempty"`
PrivateKey Env[string] `yaml:"key,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions server-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ keystore:
endpoint:
- "" # The endpoint (or list of endpoints) to the KES server(s)
enclave: "" # An optional enclave name. If empty, the default enclave will be used
api_key: "" # The KES API key to authenticate to KES server
tls: # The KES mTLS authentication credentials - i.e. client certificate.
cert: "" # Path to the TLS client certificate for mTLS authentication
key: "" # Path to the TLS client private key for mTLS authentication
Expand Down

0 comments on commit 2e9ab7a

Please sign in to comment.