kes

package module
v0.21.0 Latest Latest
Warning

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

Go to latest
Published: Sep 12, 2022 License: AGPL-3.0 Imports: 18 Imported by: 20

README

KES

Go Reference build VulnCheck license latest GitHub Downloads

KES is a stateless and distributed key-management system for high-performance applications. We built KES as the bridge between modern applications - running as containers on Kubernetes - and centralized KMS solutions. Therefore, KES has been designed to be simple, scalable and secure by default. It has just a few knobs to tweak instead of a complex configuration and does not require a deep understanding of secure key-management or cryptography.

Architecture

KES

Install

Binary Releases
OS ARCH Binary
Linux amd64 linux-amd64
Linux arm64 linux-arm64
Linux ppc64le linux-ppc64le
Linux s390x linux-s390x
Apple M1 arm64 darwin-arm64
Apple amd64 darwin-amd64
Windows amd64 windows-amd64

You can also verify the binary with minisign by downloading the corresponding .minisig signature file. Then run:

minisign -Vm kes-<OS>-<ARCH> -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav
Docker

Pull the latest release via:

docker pull minio/kes
Build from source
GO111MODULE=on go get github.com/minio/kes/cmd/kes

You will need a working Go environment. Therefore, please follow How to install Go. Minimum version required is go1.18

Getting Started

We run a public KES server instance at https://play.min.io:7373 for you to experiment with. You can interact with our play instance either via the KES CLI or cURL. Alternatively, you can get started by setting up your own KES server in less than five minutes.

CLI
1. Fetch Admin Credentials

As an initial step, you will need to download the "private" key and certificate to authenticate to the KES server as the root identity.

curl -sSL --tlsv1.2 \
   -O 'https://raw.githubusercontent.com/minio/kes/master/root.key' \
   -O 'https://raw.githubusercontent.com/minio/kes/master/root.cert'
2. Configure CLI

Then we point the KES CLI to the KES server at https://play.min.io:7373 and use the root.key and root.cert as authentication credentials.

export KES_SERVER=https://play.min.io:7373
export KES_CLIENT_KEY=root.key
export KES_CLIENT_CERT=root.cert
3. Create a Key

Next, we can create a new master key - e.g. my-key.

kes key create my-key

Note that creating a new key will fail with key already exist if it already exist.

4. Generate a DEK

Now, you can use that master key to derive a new data encryption key (DEK).

kes key dek my-key

You will get a plaintext and a ciphertext data key. The ciphertext data key is the encrypted version of the plaintext key. Your application would use the plaintext key to e.g. encrypt some application data but only remember the ciphertext key version.

5. Further References

For more KES CLI commands run kes --help. For example, you can list all master keys at the KES server:

kes key ls
Server

For a quickstart setup take a look at our FS guide. For further references checkout our list of key store guides.

cURL
1. Fetch Admin Credentials

As an initial step, you will need to download the "private" key and certificate to authenticate to the KES server as the root identity.

curl -sSL --tlsv1.2 \
   -O 'https://raw.githubusercontent.com/minio/kes/master/root.key' \
   -O 'https://raw.githubusercontent.com/minio/kes/master/root.cert'
2. Create a Key

Then, you can create a new master key e.g. my-key.

curl -sSL --tlsv1.3 \
    --key root.key \
    --cert root.cert \
    -X POST 'https://play.min.io:7373/v1/key/create/my-key'

Note that creating a new key will fail with key already exist if it already exist.

3. Generate a DEK

Now, you can use that master key to derive a new data encryption key (DEK).

curl -sSL --tlsv1.3 \
    --key root.key \
    --cert root.cert \
    --data '{}' \
    -X POST 'https://play.min.io:7373/v1/key/generate/my-key'

You will get a plaintext and a ciphertext data key. The ciphertext data key is the encrypted version of the plaintext key. Your application would use the plaintext key to e.g. encrypt some application data but only remember the ciphertext key version.

4. Further References

For a comprehensive list of REST API endpoints refer to the KES API overview.


If you want to learn more about KES checkout our documentation.

License

Use of KES is governed by the AGPLv3 license that can be found in the LICENSE file.

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrSealed is returned by a KES server that got sealed.
	// Such a KES server will not process any requests until
	// unsealed again.
	ErrSealed = NewError(http.StatusForbidden, "system is sealed")

	// ErrNotAllowed is returned by a KES server when a client has
	// not sufficient permission to perform the API operation.
	ErrNotAllowed = NewError(http.StatusForbidden, "not authorized: insufficient permissions")

	// ErrKeyNotFound is returned by a KES server when a client tries to
	// access or use a cryptographic key which does not exist.
	ErrKeyNotFound = NewError(http.StatusNotFound, "key does not exist")

	// ErrKeyExists is returned by a KES server when a client tries
	// to create a cryptographic key which already exists.
	ErrKeyExists = NewError(http.StatusBadRequest, "key already exists")

	// ErrPolicyNotFound is returned by a KES server when a client
	// tries to access a policy which does not exist.
	ErrPolicyNotFound = NewError(http.StatusNotFound, "policy does not exist")

	// ErrPolicyNotFound is returned by a KES server when a client
	// tries to access a policy which does not exist.
	ErrIdentityNotFound = NewError(http.StatusNotFound, "identity does not exist")

	// ErrDecrypt is returned by a KES server when it fails to decrypt
	// a ciphertext. It may occur when a client uses the wrong key or
	// the ciphertext has been (maliciously) modified.
	ErrDecrypt = NewError(http.StatusBadRequest, "decryption failed: ciphertext is not authentic")

	// ErrEnclaveExists is returned by a KES server when a client tries
	// to create an enclave that already exists.
	ErrEnclaveExists = NewError(http.StatusBadRequest, "enclave already exists")

	// ErrEnclaveNotFound is returned by a KES server when a client tries
	// to access an enclave which does not exist.
	ErrEnclaveNotFound = NewError(http.StatusNotFound, "enclave does not exist")
)

KES server API errors

Functions

This section is empty.

Types

type API added in v0.19.0

type API struct {
	Method  string        // The HTTP method
	Path    string        // The API path without its arguments. For example: "/v1/status"
	MaxBody int64         // The max. size of request bodies accepted
	Timeout time.Duration // Amount of time after which request will time out
}

API describes a KES server API.

type AuditEvent added in v0.7.0

type AuditEvent struct {
	Timestamp time.Time // The point in time when the KES server received the request
	APIPath   string    // The API called by the client. May contain API arguments

	ClientIP       net.IP   // The client's IP address
	ClientIdentity Identity // The client's KES identity

	StatusCode   int           // The response status code sent to the client
	ResponseTime time.Duration // Time it took to process the request
}

AuditEvent is the event a KES server generates when it response to a request.

type AuditStream added in v0.7.0

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

AuditStream iterates over a stream of AuditEvents. Close the AuditStream to release associated resources.

func NewAuditStream added in v0.7.0

func NewAuditStream(r io.Reader) *AuditStream

NewAuditStream returns a new AuditStream that reads from r.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/minio/kes"
)

const AuditStream = `{"time":"2020-03-24T12:37:33Z","request":{"path":"/v1/log/audit","identity":"dd46485bedc9ad2909d2e8f9017216eec4413bc5c64b236d992f7ec19c843c5f"},"response":{"code":200, "time":12106}}
{"time":"2020-03-24T12:38:02Z","request":{"path":"/v1/policy/list/*","identity":"dd46485bedc9ad2909d2e8f9017216eec4413bc5c64b236d992f7ec19c843c5f"},"response":{"code":200, "time":15572}}
{"time":"2020-03-24T12:39:02Z","request":{"path":"/v1/identity/list/*","identity":"dd46485bedc9ad2909d2e8f9017216eec4413bc5c64b236d992f7ec19c843c5f"},"response":{"code":200, "time":15953}}`

func main() {
	reader := strings.NewReader(AuditStream)

	stream := kes.NewAuditStream(reader)
	defer stream.Close()

	for stream.Next() {
		event := stream.Event()

		fmt.Println(event.Timestamp)
	}
	if err := stream.Close(); err != nil {
		panic(err) // TODO: error handling
	}
}
Output:

2020-03-24 12:37:33 +0000 UTC
2020-03-24 12:38:02 +0000 UTC
2020-03-24 12:39:02 +0000 UTC

func (*AuditStream) Close added in v0.7.0

func (s *AuditStream) Close() (err error)

Close closes the AuditStream and releases any associated resources.

func (*AuditStream) Event added in v0.7.0

func (s *AuditStream) Event() AuditEvent

Event returns the most recent AuditEvent, generated by Next.

func (*AuditStream) Next added in v0.7.0

func (s *AuditStream) Next() bool

Next advances the stream to the next AuditEvent and returns true if there is another one. It returns false if there are no more AuditEvents or when the AuditStream encountered an error.

func (*AuditStream) WriteTo added in v0.18.0

func (s *AuditStream) WriteTo(w io.Writer) (int64, error)

WriteTo writes the entire AuditEvent stream to w. It returns the number of bytes written to w and the first error encountered, if any.

type CCP added in v0.19.0

type CCP struct {
	Ciphertext []byte // Ciphertext bytes
	Context    []byte // Decryption context
}

CCP is a structure wrapping a ciphertext / decryption context pair.

Its main purpose is to group a ciphertext and decryption context to improve API ergonomics.

type Client

type Client struct {
	// Endpoints contains one or multiple KES server
	// endpoints. For example: https://127.0.0.1:7373
	//
	// Each endpoint must be a HTTPS endpoint and
	// should point to different KES server replicas
	// with a common configuration.
	//
	// Multiple endpoints should only be specified
	// when multiple KES servers should be used, e.g.
	// for high availability, but no round-robin DNS
	// is used.
	Endpoints []string

	// HTTPClient is the HTTP client.
	//
	// The HTTP client uses its http.RoundTripper
	// to send requests resp. receive responses.
	//
	// It must not be modified concurrently.
	HTTPClient http.Client
}

Client is a KES client. Usually, a new client is instantiated via the NewClient or NewClientWithConfig functions.

In general, a client just requires:

  • a KES server endpoint
  • a X.509 certificate for authentication

However, custom transport protocols, timeouts, connection pooling, etc. can be specified via a custom http.RoundTripper. For example:

client := &Client{
    Endpoints:  []string{"https:127.0.0.1:7373"},
    HTTPClient: http.Client{
        Transport: &http.Transport{
           // specify custom behavior...

           TLSClientConfig: &tls.Config{
               Certificates: []tls.Certificates{clientCert},
           },
        },
    },
 }

A custom transport protocol can be used via a custom implemention of the http.RoundTripper interface.

func NewClient

func NewClient(endpoint string, cert tls.Certificate) *Client

NewClient returns a new KES client with the given KES server endpoint that uses the given TLS certificate mTLS authentication.

The TLS certificate must be valid for client authentication.

NewClient uses an http.Transport with reasonable defaults.

func NewClientWithConfig added in v0.8.0

func NewClientWithConfig(endpoint string, config *tls.Config) *Client

NewClientWithConfig returns a new KES client with the given KES server endpoint that uses the given TLS config for mTLS authentication.

Therefore, the config.Certificates must contain a TLS certificate that is valid for client authentication.

NewClientWithConfig uses an http.Transport with reasonable defaults.

func (*Client) APIs added in v0.19.0

func (c *Client) APIs(ctx context.Context) ([]API, error)

APIs returns a list of all API endpoints supported by the KES server.

It returns ErrNotAllowed if the client does not have sufficient permissions to fetch the server APIs.

func (*Client) AssignPolicy added in v0.18.0

func (c *Client) AssignPolicy(ctx context.Context, policy string, identity Identity) error

AssignPolicy assigns the policy to the identity. The KES admin identity cannot be assigned to any policy.

AssignPolicy returns PolicyNotFound if no such policy exists.

func (*Client) AuditLog added in v0.12.0

func (c *Client) AuditLog(ctx context.Context) (*AuditStream, error)

AuditLog returns a stream of audit events produced by the KES server. The stream does not contain any events that happened in the past.

It returns ErrNotAllowed if the client does not have sufficient permissions to subscribe to the audit log.

func (*Client) CreateEnclave added in v0.21.0

func (c *Client) CreateEnclave(ctx context.Context, name string, admin Identity) error

CreateEnclave creates a new enclave with the given identity as enclave admin. Only the KES system admin can create new enclaves.

It returns ErrEnclaveExists if the enclave already exists.

func (*Client) CreateKey

func (c *Client) CreateKey(ctx context.Context, name string) error

CreateKey creates a new cryptographic key. The key will be generated by the KES server.

It returns ErrKeyExists if a key with the same name already exists.

func (*Client) Decrypt added in v0.8.0

func (c *Client) Decrypt(ctx context.Context, name string, ciphertext, context []byte) ([]byte, error)

Decrypt decrypts the ciphertext with the named key at the KES server. The exact same context, used during Encrypt, must be provided.

Decrypt returns ErrKeyNotFound if no such key exists. It returns ErrDecrypt when the ciphertext has been modified or a different context value is provided.

func (*Client) DecryptAll added in v0.19.0

func (c *Client) DecryptAll(ctx context.Context, name string, ciphertexts ...CCP) ([]PCP, error)

DecryptAll decrypts all ciphertexts with the named key at the KES server. It either returns all decrypted plaintexts or the first decryption error.

DecryptAll returns ErrKeyNotFound if the specified key does not exist. It returns ErrDecrypt if any ciphertext has been modified or a different context value was used.

func (*Client) DeleteEnclave added in v0.21.0

func (c *Client) DeleteEnclave(ctx context.Context, name string) error

DeleteEnclave delete the specified enclave. Only the KES system admin can delete enclaves.

It returns ErrEnclaveNotFound if the enclave does not exist.

func (*Client) DeleteIdentity added in v0.18.0

func (c *Client) DeleteIdentity(ctx context.Context, identity Identity) error

DeleteIdentity removes the identity. Once removed, any operation issued by this identity will fail with ErrNotAllowed.

The KES admin identity cannot be removed.

func (*Client) DeleteKey

func (c *Client) DeleteKey(ctx context.Context, name string) error

DeleteKey deletes the key from a KES server. It returns ErrKeyNotFound if no such key exists.

func (*Client) DeletePolicy

func (c *Client) DeletePolicy(ctx context.Context, name string) error

DeletePolicy deletes the policy with the given name. Any assigned identities will be removed as well.

It returns ErrPolicyNotFound if no such policy exists.

func (*Client) DescribeIdentity added in v0.19.0

func (c *Client) DescribeIdentity(ctx context.Context, identity Identity) (*IdentityInfo, error)

DescribeIdentity returns an IdentityInfo describing the given identity.

func (*Client) DescribePolicy added in v0.20.0

func (c *Client) DescribePolicy(ctx context.Context, name string) (*PolicyInfo, error)

DescribePolicy returns the PolicyInfo for the given policy. It returns ErrPolicyNotFound if no such policy exists.

func (*Client) DescribeSelf added in v0.19.0

func (c *Client) DescribeSelf(ctx context.Context) (*IdentityInfo, *Policy, error)

DescribeSelf returns an IdentityInfo describing the identity making the API request. It also returns the assigned policy, if any.

DescribeSelf allows an application to obtain identity and policy information about itself.

func (*Client) Encrypt added in v0.10.0

func (c *Client) Encrypt(ctx context.Context, name string, plaintext, context []byte) ([]byte, error)

Encrypt encrypts the given plaintext with the named key at the KES server. The optional context is cryptographically bound to the returned ciphertext. The exact same context must be provided when decrypting the ciphertext again.

Encrypt returns ErrKeyNotFound if no such key exists at the KES server.

func (*Client) ErrorLog added in v0.12.0

func (c *Client) ErrorLog(ctx context.Context) (*ErrorStream, error)

ErrorLog returns a stream of error events produced by the KES server. The stream does not contain any events that happened in the past.

It returns ErrNotAllowed if the client does not have sufficient permissions to subscribe to the error log.

func (*Client) GenerateKey added in v0.8.0

func (c *Client) GenerateKey(ctx context.Context, name string, context []byte) (DEK, error)

GenerateKey returns a new generated data encryption key (DEK). A DEK has a plaintext and ciphertext representation.

The former should be used for cryptographic operations, like encrypting some data.

The later is the result of encrypting the plaintext with the named key at the KES server. It should be stored at a durable location but does not need to stay secret. The ciphertext can only be decrypted with the named key at the KES server.

The context is cryptographically bound to the ciphertext and the same context value must be provided when decrypting the ciphertext via Decrypt. Therefore, an application must either remember the context or must be able to re-generate it.

GenerateKey returns ErrKeyNotFound if no key with the given name exists.

Example
package main

import (
	"context"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/tls"
	"io"
	"log"

	"github.com/minio/kes"
)

func main() {
	// First, load the client TLS private key / certificate to
	// authenticate against the KES server.
	const (
		keyFile  = "./root.key"
		certFile = "./root.cert"
	)
	certificate, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		log.Fatalf("Failed to load TLS certificate for client (mTLS) authentication: %v", err)
	}

	// Then, generate a new data encryption key (DEK). The DEK contains a
	// plaintext key as well as a ciphertext version. The ciphertext is the
	// plaintext key encrypted by the KES server with the key named 'keyName'.
	// Only the KES server can decrypt the ciphertext key.
	const (
		endpoint = "https://play.min.io:7373"
		keyName  = "my-key"
	)
	client := kes.NewClient(endpoint, certificate)
	key, err := client.GenerateKey(context.Background(), keyName, nil)
	if err != nil {
		log.Fatalf("Failed to generate a new data encryption key: %v", err)
	}

	// Finally, use AES-GCM to encrypt a short message using the plaintext key.
	// The actual ciphertext, the encrypted key, the nonce and the associated data
	// can be stored on some untrusted location. The ciphertext can only be decrypted
	// by contacting the KES server - once the plaintext key is no longer accessible.
	block, err := aes.NewCipher(key.Plaintext)
	if err != nil {
		log.Fatalf("Failed to create AES instance: %v", err)
	}
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		log.Fatalf("Failed to create AES-GCM instance: %v", err)
	}

	var (
		message        = []byte("Hello World")
		nonce          = mustRandom(rand.Reader, gcm.NonceSize())
		associatedData = []byte("my-file.text")
	)
	ciphertext := gcm.Seal(nil, nonce, message, associatedData)

	// Now store the ciphertext as well as the key.Ciphertext, the nonce
	// and the associatedData. The key.Ciphertext contains the encrypted
	// version of the key used to encrypt the message.
	// It needs to be sent to the KES server to obtain the plaintext key
	// which is needed to decrypt the ciphertext (using the nonce and
	// associatedData) and obtain the message again.
	_, _, _, _ = ciphertext, key.Ciphertext, nonce, associatedData
}

func mustRandom(random io.Reader, size int) []byte {
	v := make([]byte, size)
	if _, err := io.ReadFull(random, v); err != nil {
		panic(err)
	}
	return v
}
Output:

func (*Client) GetPolicy added in v0.10.1

func (c *Client) GetPolicy(ctx context.Context, name string) (*Policy, error)

GetPolicy returns the policy with the given name. It returns ErrPolicyNotFound if no such policy exists.

func (*Client) ImportKey added in v0.5.0

func (c *Client) ImportKey(ctx context.Context, name string, key []byte) error

ImportKey imports the given key into a KES server. It returns ErrKeyExists if a key with the same key already exists.

func (*Client) ListIdentities

func (c *Client) ListIdentities(ctx context.Context, pattern string) (*IdentityIterator, error)

ListIdentities lists all identites that match the given pattern.

The pattern matching happens on the server side. If pattern is empty ListIdentities returns all identities.

func (*Client) ListKeys added in v0.13.0

func (c *Client) ListKeys(ctx context.Context, pattern string) (*KeyIterator, error)

ListKeys lists all names of cryptographic keys that match the given pattern. It returns a KeyIterator that iterates over all matched key names.

The pattern matching happens on the server side. If pattern is empty the KeyIterator iterates over all key names.

func (*Client) ListPolicies

func (c *Client) ListPolicies(ctx context.Context, pattern string) (*PolicyIterator, error)

ListPolicies lists all policy names that match the given pattern. It returns a PolicyIterator that iterates over all matched policies.

The pattern matching happens on the server side. If pattern is empty ListPolicies returns all policy names.

func (*Client) Metrics added in v0.13.2

func (c *Client) Metrics(ctx context.Context) (Metric, error)

Metrics returns a KES server metric snapshot.

It returns ErrNotAllowed if the client does not have sufficient permissions to fetch server metrics.

func (*Client) SetPolicy added in v0.10.1

func (c *Client) SetPolicy(ctx context.Context, name string, policy *Policy) error

SetPolicy creates the given policy. If a policy with the same name already exists, SetPolicy overwrites the existing policy with the given one. Any existing identites will be assigned to the given policy.

func (*Client) Status added in v0.18.0

func (c *Client) Status(ctx context.Context) (State, error)

Status returns the current state of the KES server.

func (*Client) Version added in v0.6.0

func (c *Client) Version(ctx context.Context) (string, error)

Version tries to fetch the version information from the KES server.

type ConnError added in v0.20.0

type ConnError struct {
	Host string // The host that couldn't be reached
	Err  error  // The underlying error, if any.
}

ConnError is a network connection error. It is returned by a Client or Enclave when a request fails due to a network or connection issue. For example, a temporary DNS error.

Calling code may check whether a returned error is of type ConnError:

if cErr, ok := kes.IsConnError(err) {
   // TODO: handle connection error
}

func IsConnError added in v0.20.0

func IsConnError(err error) (*ConnError, bool)

IsConnError reports whether err is or wraps a ConnError. In this case, it returns the ConnError.

func (*ConnError) Error added in v0.20.0

func (c *ConnError) Error() string

Error returns the string representation of the ConnError.

func (*ConnError) Temporary deprecated added in v0.20.0

func (c *ConnError) Temporary() bool

Temporary returns false. It is implemented such that ConnError implements the net.Error interface.

Deprecated: See the net.Error documentation

func (*ConnError) Timeout added in v0.20.0

func (c *ConnError) Timeout() bool

Timeout reports whether the error is caused by a timeout.

func (*ConnError) Unwrap added in v0.20.0

func (c *ConnError) Unwrap() error

Unwarp returns the underlying connection error.

type DEK added in v0.8.0

type DEK struct {
	Plaintext  []byte
	Ciphertext []byte
}

DEK is a data encryption key. It has a plaintext and a ciphertext representation.

Applications should use the plaintext for cryptographic operations and store the ciphertext at a durable location.

If the DEK is used to e.g. encrypt some data then it's safe to store the DEK's ciphertext representation next to the encrypted data. The ciphertext representation does not need to stay secret.

type Enclave added in v0.18.0

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

An Enclave is an isolated area within a KES server. It stores cryptographic keys, policies and other related information securely.

A KES server contains at least one Enclave and, depending upon its persistence layer, may be able to hold many Enclaves.

With Enclaves, a KES server implements multi-tenancy.

func (*Enclave) AssignPolicy added in v0.18.0

func (e *Enclave) AssignPolicy(ctx context.Context, policy string, identity Identity) error

AssignPolicy assigns the policy to the identity. The KES admin identity cannot be assigned to any policy.

AssignPolicy returns PolicyNotFound if no such policy exists.

func (*Enclave) CreateKey added in v0.18.0

func (e *Enclave) CreateKey(ctx context.Context, name string) error

CreateKey creates a new cryptographic key. The key will be generated by the KES server.

It returns ErrKeyExists if a key with the same name already exists.

func (*Enclave) Decrypt added in v0.18.0

func (e *Enclave) Decrypt(ctx context.Context, name string, ciphertext, context []byte) ([]byte, error)

Decrypt decrypts the ciphertext with the named key at the KES server. The exact same context, used during Encrypt, must be provided.

Decrypt returns ErrKeyNotFound if no such key exists. It returns ErrDecrypt when the ciphertext has been modified or a different context value is provided.

func (*Enclave) DecryptAll added in v0.19.0

func (e *Enclave) DecryptAll(ctx context.Context, name string, ciphertexts ...CCP) ([]PCP, error)

DecryptAll decrypts all ciphertexts with the named key at the KES server. It either returns all decrypted plaintexts or the first decryption error.

DecryptAll returns ErrKeyNotFound if the specified key does not exist. It returns ErrDecrypt if any ciphertext has been modified or a different context value was used.

func (*Enclave) DeleteIdentity added in v0.18.0

func (e *Enclave) DeleteIdentity(ctx context.Context, identity Identity) error

DeleteIdentity removes the identity. Once removed, any operation issued by this identity will fail with ErrNotAllowed.

The KES admin identity cannot be removed.

func (*Enclave) DeleteKey added in v0.18.0

func (e *Enclave) DeleteKey(ctx context.Context, name string) error

DeleteKey deletes the key from a KES server. It returns ErrKeyNotFound if no such key exists.

func (*Enclave) DeletePolicy added in v0.18.0

func (e *Enclave) DeletePolicy(ctx context.Context, name string) error

DeletePolicy deletes the policy with the given name. Any assigned identities will be removed as well.

It returns ErrPolicyNotFound if no such policy exists.

func (*Enclave) DescribeIdentity added in v0.19.0

func (e *Enclave) DescribeIdentity(ctx context.Context, identity Identity) (*IdentityInfo, error)

DescribeIdentity returns an IdentityInfo describing the given identity.

func (*Enclave) DescribePolicy added in v0.20.0

func (e *Enclave) DescribePolicy(ctx context.Context, name string) (*PolicyInfo, error)

DescribePolicy returns the PolicyInfo for the given policy. It returns ErrPolicyNotFound if no such policy exists.

func (*Enclave) DescribeSelf added in v0.19.0

func (e *Enclave) DescribeSelf(ctx context.Context) (*IdentityInfo, *Policy, error)

DescribeSelf returns an IdentityInfo describing the identity making the API request. It also returns the assigned policy, if any.

DescribeSelf allows an application to obtain identity and policy information about itself.

func (*Enclave) Encrypt added in v0.18.0

func (e *Enclave) Encrypt(ctx context.Context, name string, plaintext, context []byte) ([]byte, error)

Encrypt encrypts the given plaintext with the named key at the KES server. The optional context is cryptographically bound to the returned ciphertext. The exact same context must be provided when decrypting the ciphertext again.

Encrypt returns ErrKeyNotFound if no such key exists at the KES server.

func (*Enclave) GenerateKey added in v0.18.0

func (e *Enclave) GenerateKey(ctx context.Context, name string, context []byte) (DEK, error)

GenerateKey returns a new generated data encryption key (DEK). A DEK has a plaintext and ciphertext representation.

The former should be used for cryptographic operations, like encrypting some data.

The later is the result of encrypting the plaintext with the named key at the KES server. It should be stored at a durable location but does not need to stay secret. The ciphertext can only be decrypted with the named key at the KES server.

The context is cryptographically bound to the ciphertext and the same context value must be provided when decrypting the ciphertext via Decrypt. Therefore, an application must either remember the context or must be able to re-generate it.

GenerateKey returns ErrKeyNotFound if no key with the given name exists.

func (*Enclave) GetPolicy added in v0.18.0

func (e *Enclave) GetPolicy(ctx context.Context, name string) (*Policy, error)

GetPolicy returns the policy with the given name. It returns ErrPolicyNotFound if no such policy exists.

func (*Enclave) ImportKey added in v0.18.0

func (e *Enclave) ImportKey(ctx context.Context, name string, key []byte) error

ImportKey imports the given key into a KES server. It returns ErrKeyExists if a key with the same key already exists.

func (*Enclave) ListIdentities added in v0.18.0

func (e *Enclave) ListIdentities(ctx context.Context, pattern string) (*IdentityIterator, error)

ListIdentities lists all identites that match the given pattern.

The pattern matching happens on the server side. If pattern is empty ListIdentities returns all identities.

func (*Enclave) ListKeys added in v0.18.0

func (e *Enclave) ListKeys(ctx context.Context, pattern string) (*KeyIterator, error)

ListKeys lists all names of cryptographic keys that match the given pattern. It returns a KeyIterator that iterates over all matched key names.

The pattern matching happens on the server side. If pattern is empty the KeyIterator iterates over all key names.

func (*Enclave) ListPolicies added in v0.18.0

func (e *Enclave) ListPolicies(ctx context.Context, pattern string) (*PolicyIterator, error)

ListPolicies lists all policy names that match the given pattern.

The pattern matching happens on the server side. If pattern is empty ListPolicies returns all policy names.

func (*Enclave) SetPolicy added in v0.18.0

func (e *Enclave) SetPolicy(ctx context.Context, name string, policy *Policy) error

SetPolicy creates the given policy. If a policy with the same name already exists, SetPolicy overwrites the existing policy with the given one. Any existing identites will be assigned to the given policy.

type Error added in v0.6.0

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

Error is a KES server API error.

func NewError

func NewError(code int, msg string) Error

NewError returns a new Error with the given HTTP status code and error message.

func (Error) Error added in v0.6.0

func (e Error) Error() string

func (Error) Status added in v0.6.0

func (e Error) Status() int

Status returns the HTTP status code of the error.

type ErrorEvent added in v0.7.0

type ErrorEvent struct {
	Message string // The logged error message
}

ErrorEvent is the event a KES server generates when it encounters and logs an error.

type ErrorStream added in v0.7.0

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

ErrorStream iterates over a stream of ErrorEvents. Close the ErrorStream to release associated resources.

func NewErrorStream added in v0.7.0

func NewErrorStream(r io.Reader) *ErrorStream

NewErrorStream returns a new ErrorStream that reads from r.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/minio/kes"
)

const ErrorStream = `{"message":"2020/03/24 14:46:10 aws: secret was not encrypted with '4f9147d9-a676-47cd-ad3f-3485abf9123d'"}
{"message":"2020/03/24 14:46:17 aws: the CMK 'ff8e2c25-b259-4f74-a001-c7b62d17e0a4' does not exist"}
{"message":"2020/03/24 14:46:25 aws: the CMK '8fc17745-9647-4797-b170-afd8b52ed7c0' cannot be used for decryption"}`

func main() {
	reader := strings.NewReader(ErrorStream)

	stream := kes.NewErrorStream(reader)
	defer stream.Close()

	for stream.Next() {
		event := stream.Event()
		fmt.Println(event.Message)
	}
	if err := stream.Close(); err != nil {
		panic(err) // TODO: error handling
	}
}
Output:

2020/03/24 14:46:10 aws: secret was not encrypted with '4f9147d9-a676-47cd-ad3f-3485abf9123d'
2020/03/24 14:46:17 aws: the CMK 'ff8e2c25-b259-4f74-a001-c7b62d17e0a4' does not exist
2020/03/24 14:46:25 aws: the CMK '8fc17745-9647-4797-b170-afd8b52ed7c0' cannot be used for decryption

func (*ErrorStream) Close added in v0.7.0

func (s *ErrorStream) Close() error

Close closes the ErrorStream and releases any associated resources.

func (*ErrorStream) Event added in v0.7.0

func (s *ErrorStream) Event() ErrorEvent

Event returns the most recent ErrorEvent, generated by Next.

func (*ErrorStream) Message added in v0.18.0

func (s *ErrorStream) Message() string

Message returns the current error message or the ErrorEvent. It is a short-hand for Event().Message.

func (*ErrorStream) Next added in v0.7.0

func (s *ErrorStream) Next() bool

Next advances the stream to the next ErrorEvent and returns true if there is another one. It returns false if there are no more ErrorEvents or when the ErrorStream encountered an error.

func (*ErrorStream) WriteTo added in v0.18.0

func (s *ErrorStream) WriteTo(w io.Writer) (int64, error)

WriteTo writes the entire ErrorEvent stream to w. It returns the number of bytes written to w and the first error encounterred, if any.

type Identity

type Identity string

An Identity should uniquely identify a client and is computed from the X.509 certificate presented by the client during the TLS handshake using an IdentityFunc.

const IdentityUnknown Identity = ""

IdentityUnknown is the identity returned by an IdentityFunc if it cannot map a particular X.509 certificate to an actual identity.

func (Identity) IsUnknown

func (id Identity) IsUnknown() bool

IsUnknown returns true if and only if the identity is IdentityUnknown.

func (Identity) String

func (id Identity) String() string

String returns the string representation of the identity.

type IdentityInfo added in v0.18.0

type IdentityInfo struct {
	Identity  Identity
	IsAdmin   bool      // Indicates whether the identity has admin privileges
	Policy    string    // Name of the associated policy
	CreatedAt time.Time // Point in time when the identity was created
	CreatedBy Identity  // Identity that created the identity
}

IdentityInfo describes a KES identity.

type IdentityIterator added in v0.15.0

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

IdentityIterator iterates over a stream of IdentityInfo objects. Close the IdentityIterator to release associated resources.

func (*IdentityIterator) Close added in v0.15.0

func (i *IdentityIterator) Close() error

Close closes the IdentityIterator and releases any associated resources

func (*IdentityIterator) CreatedAt added in v0.18.0

func (i *IdentityIterator) CreatedAt() time.Time

CreatedAt returns the created-at timestamp of the current identity. It is a short-hand for Value().CreatedAt.

func (*IdentityIterator) CreatedBy added in v0.18.0

func (i *IdentityIterator) CreatedBy() Identity

CreatedBy returns the identiy that created the current identity. It is a short-hand for Value().CreatedBy.

func (*IdentityIterator) Identity added in v0.18.0

func (i *IdentityIterator) Identity() Identity

Identity returns the current identity. It is a short-hand for Value().Identity.

func (*IdentityIterator) Next added in v0.15.0

func (i *IdentityIterator) Next() bool

Next returns true if there is another IdentityInfo. It returns false if there are no more IdentityInfo objects or when the IdentityIterator encounters an error.

func (*IdentityIterator) Policy added in v0.18.0

func (i *IdentityIterator) Policy() string

Policy returns the policy assigned to the current identity. It is a short-hand for Value().Policy.

func (*IdentityIterator) Value added in v0.15.0

func (i *IdentityIterator) Value() IdentityInfo

Value returns the current IdentityInfo. It remains valid until Next is called again.

func (*IdentityIterator) Values added in v0.20.0

func (i *IdentityIterator) Values(n int) ([]IdentityInfo, error)

Values returns up to the next n IdentityInfo values. Subsequent calls will yield further IdentityInfos if there are any.

If n > 0, Values returns at most n IdentityInfo structs. In this case, if Values returns an empty slice, it will return an error explaining why. At the end of the listing, the error is io.EOF.

If n <= 0, Values returns all remaining IdentityInfo records. In this case, Values always closes the IdentityIterator. When it succeeds, it returns a nil error, not io.EOF.

func (*IdentityIterator) WriteTo added in v0.19.0

func (i *IdentityIterator) WriteTo(w io.Writer) (int64, error)

WriteTo encodes and writes all remaining IdentityInfos from its current iterator position to w. It returns the number of bytes written to w and the first error encounterred, if any.

type KeyInfo added in v0.18.0

type KeyInfo struct {
	Name      string    // Name of the cryptographic key
	CreatedAt time.Time // Point in time when the key was created
	CreatedBy Identity  // Identity that created the key
}

KeyInfo describes a cryptographic key at a KES server.

type KeyIterator added in v0.13.0

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

KeyIterator iterates over a stream of KeyInfo objects. Close the KeyIterator to release associated resources.

func (*KeyIterator) Close added in v0.13.0

func (i *KeyIterator) Close() error

Close closes the IdentityIterator and releases any associated resources.

func (*KeyIterator) CreatedAt added in v0.18.0

func (i *KeyIterator) CreatedAt() time.Time

CreatedAt returns the created-at timestamp of the current key. It is a short-hand for Value().CreatedAt.

func (*KeyIterator) CreatedBy added in v0.18.0

func (i *KeyIterator) CreatedBy() Identity

CreatedBy returns the identiy that created the current key. It is a short-hand for Value().CreatedBy.

func (*KeyIterator) Name added in v0.18.0

func (i *KeyIterator) Name() string

Name returns the name of the current key. It is a short-hand for Value().Name.

func (*KeyIterator) Next added in v0.13.0

func (i *KeyIterator) Next() bool

Next returns true if there is another KeyInfo. It returns false if there are no more KeyInfo objects or when the KeyIterator encounters an error.

func (*KeyIterator) Value added in v0.13.0

func (i *KeyIterator) Value() KeyInfo

Value returns the current KeyInfo. It returns the same KeyInfo until Next is called again.

If KeyIterator has been closed or if Next has not been called once resp. once Next returns false then the behavior of Value is undefined.

func (*KeyIterator) Values added in v0.20.0

func (i *KeyIterator) Values(n int) ([]KeyInfo, error)

Values returns up to the next n KeyInfo values. Subsequent calls will yield further PolicyInfos if there are any.

If n > 0, Values returns at most n KeyInfo structs. In this case, if Values returns an empty slice, it will return an error explaining why. At the end of the listing, the error is io.EOF.

If n <= 0, Values returns all remaining KeyInfo records. In this case, Values always closes the KeyIterator. When it succeeds, it returns a nil error, not io.EOF.

func (*KeyIterator) WriteTo added in v0.19.0

func (i *KeyIterator) WriteTo(w io.Writer) (int64, error)

WriteTo encodes and writes all remaining KeyInfos from its current iterator position to w. It returns the number of bytes written to w and the first error encounterred, if any.

type Metric added in v0.13.2

type Metric struct {
	RequestOK     uint64 `json:"kes_http_request_success"` // Requests that succeeded
	RequestErr    uint64 `json:"kes_http_request_error"`   // Requests that failed with a well-defined error
	RequestFail   uint64 `json:"kes_http_request_failure"` // Requests that failed unexpectedly due to an internal error
	RequestActive uint64 `json:"kes_http_request_active"`  // Requests that are currently active and haven't completed yet

	AuditEvents uint64 `json:"kes_log_audit_events"` // Number of generated audit events
	ErrorEvents uint64 `json:"kes_log_error_events"` // Number of generated error events

	// Histogram of the KES server response latency.
	// It shows how fast the server can handle requests.
	//
	// The KES server response latency is the time
	// it takes to reply with a response once a request
	// has been received.
	//
	// The histogram consists of n time buckets. Each
	// time bucket contains the number of responses
	// that took the time T or less. For example:
	//
	//   10ms │ 50ms │ 100ms │ 250ms │ 500ms │ ...
	//   ─────┼──────┼───────┼───────┼───────┼────
	//    100 │  115 │  121  │  126  │  130  │
	//
	//   Here, there were 100 responses that took
	//   10ms or less to generate. There were also
	//   115 responses that took 50ms or less.
	//
	//   So, there were 15 responses in the window
	//   >10ms and <=50ms.
	//
	LatencyHistogram map[time.Duration]uint64 `json:"kes_http_response_time"`

	UpTime time.Duration `json:"kes_system_up_time"` // The time the KES server has been up and running

	// The number of logical CPU cores available on the system.
	//
	// The number of available CPU cores may be larger than
	// the number of cores usable by the server.
	//
	// If CPUs == UsableCPUs then the server can use the entire
	// computing power available on the system.
	CPUs int `json:"kes_system_num_cpu"`

	// The number of logical CPU cores usable by the server.
	//
	// The number of usable CPU cores may be smaller than
	// the number of available CPUs on the system. For
	// instance, a set of CPU cores may be reserved for
	// other tasks.
	UsableCPUs int `json:"kes_system_num_cpu_used"`

	// The number of concurrent co-routines/threads that currently exists.
	//
	// It may not correspond to the number of OS threads.
	Threads int `json:"kes_system_num_threads"`

	// HeapAlloc is the number of bytes currently allocated on the heap memory.
	//
	// It increases as the server allocates objects living on the heap and
	// decreases as allocated objects get freed.
	HeapAlloc uint64 `json:"kes_system_mem_heap_used"`

	// HeapObjects is the number of currently allocated objects on th heap memory.
	//
	// Similar to HeapAlloc, it increases as objects are allocated and decreases
	// as they get freed.
	HeapObjects uint64 `json:"kes_system_mem_heap_objects"`

	// StackAlloc is the number of bytes currently used on the OS stack memory.
	//
	// It increases as the server starts more co-routines / threads, invokes
	// functions, etc. and decreases as spawned co-routines / threads terminate.
	StackAlloc uint64 `json:"kes_system_mem_stack_used"`
}

Metric is a KES server metric snapshot.

func (*Metric) RequestN added in v0.13.2

func (m *Metric) RequestN() uint64

RequestN returns the total number of received requests.

type PCP added in v0.19.0

type PCP struct {
	Plaintext []byte
	Context   []byte
}

PCP is a structure wrapping a plaintext / encryption context pair.

Its main purpose is to group a plaintext and encryption context to improve API ergonomics.

type Policy

type Policy struct {
	Allow []string // Set of allow patterns
	Deny  []string // Set of deny patterns

	Info PolicyInfo // Info contains metadata for the Policy.
}

Policy contains a set of rules that explicitly allow or deny HTTP requests.

These rules are specified as glob patterns. The rule applies if the pattern matches the request URL path. For more details on the glob syntax in general see 1 and for the specific pattern syntax see 2.

A policy contains two different rule sets:

  • Allow rules
  • Deny rules

A policy determines whether a request should be allowed or denied in two steps. First, it iterates over all deny rules. If any deny rules matches the given request then the request is rejected. Then it iterates over all allow rules. If any allow rule matches the given request then the request is accepted. Otherwise, the request is rejected by default. Hence, a request is only accepted if at least one allow rules and no deny rule matches the request. Also, a deny rule takes precedence over an allow rule.

type PolicyInfo added in v0.18.0

type PolicyInfo struct {
	Name      string    `json:"name"`                 // Name of the policy
	CreatedAt time.Time `json:"created_at,omitempty"` // Point in time when the policy was created
	CreatedBy Identity  `json:"created_by,omitempty"` // Identity that created the policy
}

PolicyInfo describes a KES policy.

type PolicyIterator added in v0.18.0

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

PolicyIterator iterates over a stream of PolicyInfo objects. Close the PolicyIterator to release associated resources.

func (*PolicyIterator) Close added in v0.18.0

func (i *PolicyIterator) Close() error

Close closes the PolicyIterator and releases any associated resources.

func (*PolicyIterator) CreatedAt added in v0.18.0

func (i *PolicyIterator) CreatedAt() time.Time

CreatedAt returns the created at timestamp of the current policy. It is a short-hand for Value().CreatedAt.

func (*PolicyIterator) CreatedBy added in v0.18.0

func (i *PolicyIterator) CreatedBy() Identity

CreatedBy returns the identiy that created the current policy. It is a short-hand for Value().CreatedBy.

func (*PolicyIterator) Name added in v0.18.0

func (i *PolicyIterator) Name() string

Name returns the name of the current policy. It is a short-hand for Value().Name.

func (*PolicyIterator) Next added in v0.18.0

func (i *PolicyIterator) Next() bool

Next returns true if there is another PolicyInfo. It returns false if there are no more PolicyInfo objects or when the PolicyIterator encounters an error.

func (*PolicyIterator) Value added in v0.18.0

func (i *PolicyIterator) Value() PolicyInfo

Value returns the current PolicyInfo. It remains valid until Next is called again.

func (*PolicyIterator) Values added in v0.20.0

func (i *PolicyIterator) Values(n int) ([]PolicyInfo, error)

Values returns up to the next n PolicyInfo values. Subsequent calls will yield further PolicyInfos if there are any.

If n > 0, Values returns at most n PolicyInfo structs. In this case, if Values returns an empty slice, it will return an error explaining why. At the end of the listing, the error is io.EOF.

If n <= 0, Values returns all remaining PolicyInfo records. In this case, Values always closes the PolicyIterator. When it succeeds, it returns a nil error, not io.EOF.

func (*PolicyIterator) WriteTo added in v0.19.0

func (i *PolicyIterator) WriteTo(w io.Writer) (int64, error)

WriteTo encodes and writes all remaining PolicyInfos from its current iterator position to w. It returns the number of bytes written to w and the first error encounterred, if any.

type State added in v0.18.0

type State struct {
	Version    string        `json:"version"`        // KES server version
	OS         string        `json:"os"`             // OS running the KES server
	Arch       string        `json:"arch"`           // CPU architecture the KES server is running on
	UpTime     time.Duration `json:"uptime"`         // Time the KES server has been up and running
	CPUs       int           `json:"num_cpu"`        // Number of available logical CPU cores
	UsableCPUs int           `json:"num_cpu_used"`   // Number of usbale logical CPU cores
	HeapAlloc  uint64        `json:"num_heap_used"`  // Number of bytes currently allocated on the heap
	StackAlloc uint64        `json:"num_stack_used"` // Number of bytes currently allocated on the stack
}

State is a KES server status snapshot.

Directories

Path Synopsis
cmd
kes
internal
aws
cli
cpu
fs
Package fs implements a key-value store that stores keys as file names and values as file content.
Package fs implements a key-value store that stores keys as file names and values as file content.
gcp
gemalto
Package gemalto implements a key store that fetches/stores cryptographic keys on a Gemalto KeySecure instance.
Package gemalto implements a key store that fetches/stores cryptographic keys on a Gemalto KeySecure instance.
key
log
mem
Package mem implements an in-memory key-value store.
Package mem implements an in-memory key-value store.
sys
vault
Package vault implements a secret key store that stores secret keys as key-value entries on the Hashicorp Vault K/V secret backend.
Package vault implements a secret key store that stores secret keys as key-value entries on the Hashicorp Vault K/V secret backend.
yml
Package kestest provides utilities for end-to-end KES testing.
Package kestest provides utilities for end-to-end KES testing.

Jump to

Keyboard shortcuts

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