This page provides information about KES configuration options for a KES Client and a KES Server.

KES Client

As a basic standard configuration, a KES client needs to know the

  • KES server endpoint
  • KES client’s own client certificate
  • Corresponding private key to the client certificate

You can provide these values in different ways, such as through environment variables at the command line or through a Software Development Kit.

Command Line

From the command line, use the following environment variables to define the three basic settings.

  • The KES server endpoint:
    export KES_SERVER=
  • The client X.509 certificate:
    export KES_CLIENT_CERT=$HOME/root.cert
  • The private key that corresponds to the public key embedded in the certificate:
    export KES_CLIENT_KEY=$HOME/root.key


When using an SDK, provide a server endpoint and fetch the client’s private key and certificate:

package main

import (


func main() {
	const (
		endpoint = ""
		certFile = "./root.cert"
		keyFile  = "./root.key"
	certificate, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {

	client := kes.NewClient(endpoint, certificate)

	// now use the client to perform operations...
	_ = client

KES Server

The KES server needs four pieces of information as a base configuration:

  1. TCP address (that is, an IP address and port) to listen for incoming requests
  2. X.509 certificate
  3. A corresponding private key
  4. A root identity.

You can specify these parameters with command line (CLI) flags or by a config file. If you set a parameter in both the command line and in the config file, the command line setting takes precedence.

If you do not specify the TCP address, the KES server listens on all available network interfaces on port 7373.

The following command starts a KES server listening on all network interfaces on port 7373 with the X.509 TLS certificate server.crt, the corresponding private key server.key, and the root identity taken from the environment variable $ROOT_IDENTITY:

kes server --cert server.crt --key private.key --root $ROOT_IDENTITY

Config File

Customize KES server behavior with a YAML config file.

The config file is separated into various sections:

  • A general server configuration section including the server address and root identity.
  • A TLS section to specify the server key/certificate and TLS proxy configuration.
  • An API section to enable or disable authentication for specific endpoints.
  • A policy section to control who can perform various API operations.
  • A cache section to control how long the KES server caches keys in memory.
  • A logging section to control what log messages write to STDOUT and STDERR.
  • A KMS / key store section specifies where to store and fetch keys.

TLS Configuration

Use the TLS configuration section to specify the X.509 certificate of the KES server and the corresponding private key:

  cert: server.crt
  key:  server.key

Optionally, also configure a TLS proxy in this section. See the separate TLS Proxy page for more information.

API Configuration

By default, KES requires a valid TLS certificate for all API calls. You can change this behavior for specific API endpoints to allow requests to the endpoints without a certificate.

The default behavior of the KES API endpoints should be suitable for most situations. Only customize endpoints for a specific need.

When you disable authentication for at least one endpoint, KES no longer requires a certificate for a client to call any API endpoint. However, the request must still include a certificate for KES to successfully process a call to any API endpoint that requires authentication.

This change means that on KES servers with at least one endpoint configured to disable authentication, clients do not receive a TLS error on failure, but an HTTP error instead.

You can disable authentication for the following API endpoints:

  • /v1/ready
  • /v1/status
  • /v1/metrics
  • /v1/api

For example, to skip authentication for the endpoints that allow readiness probes and status checks, add the following to the configuration file:

    skip_auth: true
    timeout:   15s
    skip_auth: false
    timeout:   15s

See link text for information on the KES API.

Cache Configuration

Use the cache configuration section to specify how the KES server should cache keys fetched from the external KMS.

    any:    5m0s
    unused: 20s

Control how often the KES server has to fetch keys from the external KMS by specifying different expiry values for any cached key or unused cache keys.

For example, any: 5m0s means that the KES server clears the in-memory cache every 5 min. unused: 20s means that the KES server removes any key from the cache that has not been used within last 20 seconds.

The choice of cache expiry values is a trade-off between security and performance. By setting a value of any: 1m0s, the KES server has to communicate to the external KMS 5x more often compared to any: 5m0s. However, the any: 1m0s setting reduces the time the KES server can act without any control by the external KMS.

The following values may help you make a decision.

Security Level any unused
liberal 5m0s 30s
moderate 1m0s 20s
conservative 30s 5s

Logging Configuration

Use the log configuration section to specify which log events write to STDOUT or STDERR. The KES server distinguishes error and audit log events. By default, the server writes error events to STDERR but does not log audit events to STDOUT.

Usually, error events indicate that some configuration or operational error occurred. For example, the KES Server logs an error event when fetching a key from the KMS fails for an unexpected reason.

The KES Server produce an audit event whenever it accepts a client request. The audit event describes the request-response pair and contains information about who issued the request.

  error: on  # To disable error logging to STDERR - explicitly set it to off
  audit: off # To enable audit logging to STDOUT - explicitly set it to on

The log section only controls event logging to STDOUT and STDERR. The KES server also provides audit and error log tracing through the API with /v1/log/audit/trace and /v1/log/error/trace.

A client with sufficient permissions can subscribe to the audit or error log at any point in time.

Policy Configuration

In the policy configuration section you define policies and identity-based access control rules. The policy section can contain arbitrary many policy definitions. Each policy must have an unique name - e.g. my-policy. Let’s take a look at an example policy:

    - /v1/key/create/my-key
    - /v1/key/generate/my-key
    - /v1/key/decrypt/my-key
    - /v1/key/*/my-key-internal

A policy explicitly allows API operations with its API allow and deny rules. Each rule is a glob pattern. A client request must match at least one allow and no deny pattern. Otherwise, the server rejects the request.

A KES server evaluates a policy as follows:

  1. Evaluate all deny patterns. If any deny pattern matches, reject the request with a prohibited by policy error.
  2. Evaluate all allow patterns. If at least one allow pattern matches, then KES accepts the request.
  3. If no allow pattern matches, reject the request with a prohibited by policy error.

It is not necessary to deny specific API operations. Instead, only use deny rules for fine-grain access control. The KES Server denies any API operation a policy does not not explicitly allow. Explicit deny rules take precedence over allow rules.

The policy my-policy discussed earlier grants access to the /v1/key API. In particular, the policy allows three operations: create, generate and decrypt. However, only the key my-key can be used. Therefore, the my-policy policy has the following semantics:

Request Response Reason
/v1/key/create/my-key allow Request path matches 1st policy path
/v1/key/generate/my-key allow Request path matches 2nd policy path
/v1/key/create/my-key2 deny my-key2 does not match my-key
/v1/key/delete/my-key deny delete does not match create, generate nor decrypt
/v1/policy/write/my-policy deny policy does not match key
/v0/key/create/my-key deny v0 does not match v1

Specifying the exact request paths is quite inflexible. Therefore, a policy path is a glob pattern. Let’s adjust the my-policy policy as following:

    - /v1/key/create/my-key*
    - /v1/key/generate/my-key*
    - /v1/key/decrypt/my-key*
    - /v1/key/delete/my-key
    - /v1/key/*/my-key-internal

Now, the my-policy policy would have the following semantics:

Request Response Reason
/v1/key/create/my-key allow Request path matches 1st policy path
/v1/key/generate/my-key allow Request path matches 2nd policy path
/v1/key/create/my-key2 allow Request path matches 1st policy path
/v1/key/delete/my-key allow Request path matches 4th policy path
/v1/key/delete/my-key2 deny delete/my-key2 does not match delete/my-key (No *)
/v1/key/decrypt/my-key-internal deny decrypt/my-key-internal is explicitly denied

By using glob patterns the policy is quite flexible but still easy to read for humans.

For example:

  • /v1/key/create/*: Allow creating keys with arbitrary names.
  • /v1/key/*/my-key: Allow all key API operations (create, generate, …) for the key my-key.
  • /v1/key/*/*: Allow all key API operations for any key.

For example, in the updated policy example above, the deny rule /v1/key/*/my-key-internal denies any API operation using the key my-key-internal.

Note that a glob wildcard (* or ?) only applies to the current path segment. /v1/key/* and /v1/key/*/* are not identical. The first rule allows arbitrary key API operations, but only for empty key names. The second rule allows arbitrary key API operations for arbitrary keys.

For more details, see the comprehensive list at the server APIs page.

Policies and Identities

Use the policy section to define which policy applies to which identity. An identity can be computed from the X.509 certificate as follows:

kes identity of <path-to-certificate-file>

You can assign one or multiple identities to a policy in the policy section. You can specify an identity in two ways:

  • insert the identity itself
  • specify an environment variable name

If you use an environment variable, the KES server inserts the value on startup.

    - /v1/key/create/my-key
    - /v1/key/generate/my-key
    - /v1/key/decrypt/my-key
    - 3ecfcdf38fcbe141ae26a1030f81e96b753365a46760ae6b578698a97c59fd22
You must set all expected environment variables before starting the server. The server starts even if an environment variable is not present or does not contain a “valid” identity.

Key Configuration

Use the key configuration section to declare cryptographic keys that should exist before the KES server starts accepting requests.

  - name: "my-key"
  - name: "my-key-2"

At start, the KES server makes sure that the specified keys exist. The KES Server tries to create any non-existing keys before it accepts client requests and exits if it fails to create a key.

KMS Configuration

Use the KMS/key store configuration section to specify where the KES server stores and fetches master keys. This should be a KMS that provides a secure storage element or an encrypted key store. However, for testing and development, you can store master keys in-memory or on the filesystem.

If you do not specify a KMS/key store in the config file, the KES server creates master keys in memory. This is only useful for testing or development setups, as all master keys are lost when you restart the server.

To create a persistent testing or development setup, specify a filesystem key store in the config file:

    path: ./keys # The key store directory. Keys will be created inside ./keys/

For production setups, use a secure key store backed by a KMS such as Hashicorp Vault.

Sample Configuration File

The following yaml file provides an example configuration file with notes for use. For the latest example file, see the GitHub repository.

# The config file version. Currently this field is optional but future
# KES versions will require it. The only valid value is "v1". 
version: v1

# The TCP address (ip:port) for the KES server to listen on.
address: # The pseudo address refers to all network interfaces 

  # The admin identity identifies the public/private key pair
  # that can perform any API operation.
  # The admin account can be disabled by setting a value that
  # cannot match any public key - for example, "foobar" or "disabled".
  identity: c84cc9b91ae2399b043da7eca616048d4b4200edf2ff418d8af3835911db945d

# The TLS configuration for the KES server. A KES server
# accepts HTTP only over TLS (HTTPS). Therefore, a TLS
# private key and public certificate must be specified,
# either here as part of the config file or via CLI arguments.
  key:      ./server.key   # Path to the TLS private key
  cert:     ./server.cert  # Path to the TLS certificate
  password: ""             # An optional password to decrypt the TLS private key

  # Specify how/whether the KES server verifies certificates presented
  # by clients. Valid values are "on" and "off". Defaults to off, which
  # is recommended for most use cases.
  auth:     ""
  # An optional path to a file or directory containing X.509 certificate(s).
  # If set, the certificate(s) get added to the list of CA certificates for
  # verifying the mTLS certificates sent by the KES clients.
  # If empty, the system root CAs will be used.
  ca:       ""        

  # The TLS proxy configuration. A TLS proxy, like nginx, sits in
  # between a KES client and the KES server and usually acts as a
  # load balancer or common endpoint.
  # All connections from the KES client to the TLS proxy as well
  # the connections from the TLS proxy to the KES server must be
  # established over TLS.
    # The identities of all TLS proxies directly connected to the
    # KES server.
    # Note that a TLS proxy can act as any identity (including root)
    # since it can forward arbitrary client certificates. Client certificates
    # aren't secret information and a malicious TLS proxy can fake any
    # identity it has seen before. Therefore, its critical that all TLS proxy
    # identities are secure and trusted servers.
    identities: []
    # The HTTP header sent by the TLS proxy to forward certain data
    # about the client to the KES server.
      # The HTTP header containing the URL-escaped and PEM-encoded
      # certificate of the kes client forwarded by the TLS proxy.
      cert: X-Tls-Client-Cert

# The API configuration. The APIs exposed by the KES server can
# be adjusted here. Each API is identified by its API path.
# In general, the KES server uses reasonable defaults for all APIs.
# Only customize the APIs if there is a real need.
# Disabling authentication for an API must be carefully evaluated.
# One example, when disabling authentication may be justified, would
# be the liveness and readiness probes in a Kubernetes environment.
# When authentication is disabled, the particular API can be
# accessed by any client that can send HTTPS requests to the
# KES server.
# When disabling authentication for any API, the KES server will
# change its TLS handshake behavior. By default, KES requires that
# a client sends a client certificate during the handshake or KES
# aborts the handshake. This means that a client can only send an
# HTTP request to KES when it provides a certificate during the
# handshake. This is no longer the case when authentication is 
# disabled for at least one API. Clients should be able to call
# the API even without a certificate. Hence, KES can no longer
# require a certificate during the TLS handshake but instead has
# to check the certificate when executing the API handler. 
# Now, these two behaviors have slightly different semantics:
# By default, KES does not accept connections from clients without
# a TLS certificate. When disabling authentication for one API, KES
# has to accept connections from any client for all APIs. However,
# the API handlers that still require authentication will reject
# requests from clients without a certificate. Instead of a TLS
# error these clients will receive an HTTP error.
# Currently, authentication can only be disabled for the
# following APIs:
#   - /v1/ready
#   - /v1/status
#   - /v1/metrics
#   - /v1/api
    skip_auth: false
    timeout:   15s
# The (pre-defined) policy definitions.
# A policy must have an unique name (e.g my-app) and specifies which
# server APIs can be accessed. An API path pattern is a glob pattern
# of the following form:
#   <API-version>/<API>/<operation>/[<argument-0>/<argument-1>/...]>
# Each KES server API has an unique path - for example, /v1/key/create/<key-name>.
# A client request is allowed if and only if no deny pattern AND at least one
# allow pattern matches the request URL path.
# A policy has zero (by default) or more assigned identities. However,
# an identity can never be assigned to more than one policy at the same
# time. So, one policy has N assigned identities but one identity is
# assigned to at most one policy.
# In general, each user/application should only have the minimal
# set of policy permissions to accomplish whatever it needs to do.
# Therefore, it is recommended to define policies based on workflows
# and then assign them to the identities.

# The following policy section shows some example policy definitions.
# Please remove/adjust to your needs.
    - /v1/key/create/my-app*
    - /v1/key/generate/my-app*
    - /v1/key/decrypt/my-app*
    - /v1/key/generate/my-app-internal*
    - /v1/key/decrypt/my-app-internal*
    - df7281ca3fed4ef7d06297eb7cb9d590a4edc863b4425f4762bb2afaebfd3258
    - c0ecd5962eaf937422268b80a93dde4786dc9783fb2480ddea0f3e5fe471a731

    - /v1/key/delete/my-app*
    - /v1/policy/show/my-app
    - /v1/identity/assign/my-app/*
    - 7ec8095a5308a535b72b35c7ccd4ce1d7c14af713acd22e2935a9d6e4fe18127

  # Cache expiry specifies when cache entries expire.
    # Period after which any cache entries are discarded.
    # It determines how often the KES server has to fetch
    # a secret key from the KMS.
    # If not set, KES will default to an expiry of 5 minutes.
    any: 5m0s
    # Period after which all unused cache entries are discarded.
    # It determines how often "not frequently" used secret keys
    # must be fetched from the KMS.
    # If not set, KES will default to an expiry of 30 seconds.
    unused: 20s
    # Period after which any cache entries in the offline cache
    # are discarded.
    # It determines how long the KES server can serve stateless
    # requests when the KMS key store has become unavailable -
    # for example, due to a network outage.
    # If not set, KES will disable the offline cache.
    # Offline caching should only be enabled when trying to
    # reduce the impact of the KMS key store being unavailable.
    offline: 0s

# The console logging configuration. In general, the KES server
# distinguishes between (operational) errors and audit events.
# By default, the KES server logs error events to STDERR but
# does not log audit log events to STDOUT.
# The following log configuration only affects logging to console.
  # Enable/Disable logging error events to STDERR. Valid values
  # are "on" or "off". If not set the default is "on". If no error
  # events should be logged to STDERR it has to be set explicitly
  # to: "off".
  error: on

  # Enable/Disable logging audit events to STDOUT. Valid values
  # are "on" and "off". If not set the default is "off".
  # Logging audit events to STDOUT may flood your console since
  # there will be one audit log event per request-response pair.
  # For tracing/monitoring audit logs take a look at the
  # /v1/log/audit/trace API.
  # Each audit event is a JSON object representing a request-response
  # pair that contains the time, client identity, the API path, HTTP
  # response status code etc.
  # {
  #   "time": "2006-01-02T15:04:05Z07:00",
  #   "request": {
  #     "ip":       "",
  #     "path":     "/v1/key/create/my-app-key",
  #     "identity": "4067503933d4a78358f908a2df7ec14e554c612acf8a9d1aa29b7da4aa018ec9",
  #   },
  #   "response": {
  #     "status": 200
  #   }
  # }
  # The server will write such an audit log entry for every HTTP
  # request-response pair - including invalid requests.
  audit: off

# In the keys section, pre-defined keys can be specified. The KES
# server will try to create the listed keys before startup.
  - name: some-key-name 
  - name: another-key-name

# The keystore section specifies which KMS - or in general key store - is
# used to store and fetch encryption keys.
# A KES server can only use one KMS / key store at the same time.
# If no store is explicitly specified the server will use store
# keys in-memory. In this case all keys are lost when the KES server
# restarts.
  # Configuration for storing keys on the filesystem.
  # The path must be path to a directory. If it doesn't
  # exist then the KES server will create the directory.
  # The main purpose of the fs configuration is testing
  # and development. It should not be used for production.
    path: "" # Path to directory. Keys will be stored as files.
  # Hashicorp Vault configuration. The KES server will store/fetch
  # secret keys at/from Vault's key-value backend.
  # For more information take a look at:
    endpoint: ""  # The Vault endpoint - for example,
    engine: ""    # The path of the K/V engine - for example, secrets. If empty, defaults to: kv. (Vault default)
    version: ""   # The K/V engine version - either "v1" or "v2". The "v1" engine is recommended.
    namespace: "" # An optional Vault namespace. See:
    prefix: ""    # An optional K/V prefix. The server will store keys under this prefix.
    transit:      # Optionally encrypt keys stored on the K/V engine with a Vault-managed key.
      engine: ""  # The path of the transit engine - for example, "my-transit". If empty, defaults to: transit (Vault default)
      key: ""     # The key name that should be used to encrypt entries stored on the K/V engine.
    approle:    # AppRole credentials. See:
      namespace: "" # Optional Vault namespace used only for authentication. For the Vault root namespace, use "/".
      engine: ""    # The path to the AppRole engine, for example: authenticate. If empty, defaults to: approle. (Vault default)
      id: ""        # Your AppRole Role ID
      secret: ""    # Your AppRole Secret ID
    kubernetes: # Kubernetes credentials. See:
      namespace: "" # Optional Vault namespace used only for authentication. For the Vault root namespace, use "/".
      engine: ""    # The path to the Kubernetes engine, for example: authenticate. If empty, defaults to: kubernetes. (Vault default)
      role: ""      # The Kubernetes JWT role
      jwt:  ""      # Either the JWT provided by K8S or a path to a K8S secret containing the JWT.
    tls:        # The Vault client TLS configuration for mTLS authentication and certificate verification
      key: ""     # Path to the TLS client private key for mTLS authentication to Vault
      cert: ""    # Path to the TLS client certificate for mTLS authentication to Vault
      ca: ""      # Path to one or more PEM root CA certificates
    status:     # Vault status configuration. The server will periodically reach out to Vault to check its status.
      ping: 10s   # Duration until the server checks Vault's status again.

    # The Fortanix SDKMS key store. The server will store secret keys at the Fortanix SDKMS.
    # See:
      endpoint: ""   # The Fortanix SDKMS endpoint - for example:
      group_id: ""   # An optional group ID newly created keys will be placed at. For example: ce08d547-2a82-411e-ae2d-83655a4b7617 
                     # If empty, the applications default group is used. 
      credentials:   # The Fortanix SDKMS access credentials
        key: ""      # The application's API key - for example: NWMyMWZlNzktZDRmZS00NDFhLWFjMzMtNjZmY2U0Y2ViMThhOnJWQlh0M1lZaDcxZC1NNnh4OGV2MWNQSDVVSEt1eXEyaURqMHRrRU1pZDg=
      tls:           # The KeySecure client TLS configuration
        ca: ""       # Path to one or more PEM-encoded CA certificates for verifying the Fortanix SDKMS TLS certificate. 
    # The AWS SecretsManager key store. The server will store
    # secret keys at the AWS SecretsManager encrypted with
    # AWS-KMS. See:
      endpoint: ""   # The AWS SecretsManager endpoint      - for example,
      region: ""     # The AWS region of the SecretsManager - for example, us-east-2
      kmskey: ""     # The AWS-KMS key ID used to en/decrypt secrets at the SecretsManager. By default (if not set) the default AWS-KMS key will be used.
      credentials:   # The AWS credentials for accessing secrets at the AWS SecretsManager.
        accesskey: ""  # Your AWS Access Key
        secretkey: ""  # Your AWS Secret Key
        token: ""      # Your AWS session token (usually optional)

    # The Gemalto KeySecure key store. The server will store
    # keys as secrets on the KeySecure instance.
      endpoint: ""    # The KeySecure endpoint - for example,
      credentials:    # The authentication to access the KeySecure instance.
        token: ""     # The refresh token to obtain new short-lived authentication tokens.
        domain: ""    # The KeySecure domain for which the refresh token is valid. If empty, defaults to the root domain.
        retry: 15s    # The time the KES server waits before it tries to re-authenticate after connection loss.
      tls:            # The KeySecure client TLS configuration
        ca: ""        # Path to one or more PEM-encoded CA certificates for verifying the KeySecure TLS certificate.

    # The Google Cloud Platform secret manager.
    # For more information take a look at:
      # The project ID is a unique, user-assigned ID that can be used by Google APIs.
      # The project ID must be a unique string of 6 to 30 lowercase letters, digits, or hyphens.
      # It must start with a letter, and cannot have a trailing hyphen.
      # See:
      project_id: ""
      # An optional GCP SecretManager endpoint. If not set, defaults to:
      endpoint: ""
      # An optional list of GCP OAuth2 scopes. For a list of GCP scopes refer to:
      # If not set, the GCP default scopes are used.
      - ""
      # The credentials for your GCP service account. If running inside GCP (app engine) the credentials
      # can be empty and will be fetched from the app engine environment automatically.
        client_email:   "" # The service account email                          - for example, <account>@<project-ID>
        client_id:      "" # The service account client ID                      - for example, 113491952745362495489"
        private_key_id: "" # The service account private key                    - for example, 381514ebd3cf45a64ca8adc561f0ce28fca5ec06
        private_key:    "" # The raw encoded private key of the service account - for example, "-----BEGIN PRIVATE KEY-----\n ... \n-----END PRIVATE KEY-----\n

    # The Azure KeyVault configuration.
    # For more information take a look at:
      endpoint: ""      # The KeyVault endpoint - for example,
      # Azure client credentials used to
      # authenticate to Azure KeyVault.
        tenant_id: ""      # The ID of the tenant the client belongs to - that is, a UUID.
        client_id: ""      # The ID of the client - that is, a UUID.
        client_secret: ""  # The value of the client secret.
      # Azure managed identity used to
      # authenticate to Azure KeyVault
      # with Azure managed credentials.
        client_id: ""      # The Azure managed identity of the client - that is, a UUID.

    # The Entrust KeyControl configuration.
    # For more information take a look at:
      endpoint: ""     # The KeyControl endpoint - for example,
      vault_id: ""     # The Vault ID            - for example, e30497c1-bff7-4e81-beb7-fb35c4b7410c
      box_id:   ""     # The Box name or ID      - for example, tenant-1
      # The KeyControl access credentials
        username: ""   # A username with access to the Vault and Box.
        password: ""   # The user password
      # The KeyControl client TLS configuration
        ca: ""         # Path to one or more PEM-encoded CA certificates for verifying the KeyControl TLS certificate.