Chapter 6. Securing a proxy
Secure proxies by using TLS and storing sensitive values in external resources.
6.1. Prerequisites Copy linkLink copied to clipboard!
- A running Streams for Apache Kafka Proxy instance
6.2. Securing the client-to-proxy connection Copy linkLink copied to clipboard!
Secure client-to-proxy communications using TLS.
6.2.1. TLS configuration for client-to-proxy connections Copy linkLink copied to clipboard!
This example shows a VirtualKafkaCluster, exposing it to Kafka clients running on the same OpenShift cluster. It uses TLS as the transport protocol so that communication between Kafka clients and the proxy is encrypted.
Example VirtualKafkaCluster configuration
kind: VirtualKafkaCluster
apiVersion: kroxylicious.io/v1alpha1
metadata:
name: my-cluster
namespace: my-proxy
spec:
proxyRef:
name: simple
targetKafkaServiceRef:
name: my-cluster
ingresses:
- ingressRef:
name: cluster-ip
tls:
certificateRef:
name: server-certificate
kind: Secret
- 1
- Identifies the
KafkaProxyresource that this virtual cluster is part of. It must be in the same namespace as theVirtualKafkaCluster. - 2
- The virtual cluster names the
KafkaServiceto be proxied. It must be in the same namespace as theVirtualKafkaCluster. - 3
- The virtual cluster can be exposed by one or more ingresses. Each ingress must reference a
KafkaProxyIngressin the same namespace as theVirtualKafkaCluster. - 4
- If the ingress supports TLS, the
tlsproperty configures the TLS server certificate to use.
Within a VirtualKafkaCluster, an ingress’s tls property configures TLS for that ingress. The tls.certificateRef specifies the Secret resource holding the TLS server certificate that the proxy uses for clients connecting through this ingress. The referenced KafkaProxyIngress also needs to be configured for TLS.
Example KafkaProxyIngress configuration for TLS
kind: KafkaProxyIngress
apiVersion: kroxylicious.io/v1alpha1
metadata:
name: cluster-ip
namespace: my-proxy
spec:
proxyRef:
name: simple
clusterIP:
protocol: TLS
6.2.2. Mutual TLS configuration for client-to-proxy connections Copy linkLink copied to clipboard!
You can configure a virtual cluster ingress to request or require Kafka clients to authenticate to the proxy using TLS. This configuration is known as mutual TLS (mTLS), because both the client and the proxy authenticate each other using TLS.
Example VirtualKafkaCluster configuration requiring clients to present a trusted certificate
kind: VirtualKafkaCluster
metadata:
# ...
spec:
# ...
ingresses:
- ingressRef:
name: cluster-ip
tls:
certificateRef:
# ...
trustAnchorRef:
kind: ConfigMap
name: trusted-cas
key: trusted-cas.pem
tlsClientAuthentication: REQUIRED
- 1
- References a separate OpenShift resource containing the trusted CA certificates.
- 2
- The
kindis optional and defaults toConfigMap. - 3
- Name of the resource of the given
kind, which must exist in the same namespace as theVirtualKafkaCluster. - 4
- Key identifying the entry in the given resource. The corresponding value must be a set of CA certificates. Supported formats for the bundle are:
PEM,PKCS#12, andJKS. - 5
- Specifies whether client authentication is required (
REQUIRED), requested (REQUESTED), or disabled (NONE). If atrustAnchorRefis specified, the default isREQUIRED.
6.2.3. TLS version configuration for client-to-proxy connections Copy linkLink copied to clipboard!
Some older versions of TLS (and SSL before it) are now considered insecure. These versions remain enabled by default in order to maximize interoperability between TLS clients and servers that only support older versions.
If the Kafka cluster than you want to connect to supports newer TLS versions, you can disable the proxy’s support for older, insecure versions. For example, if the Kafka cluster supports TLSv1.1, TLSv1.2 and TLSv1.3 you might choose to enable only TLSv1.3 support. This would reduce the susceptibility to a TLS downgrade attack.
It is good practice to disable insecure protocol versions.
You can restrict which TLS protocol versions the proxy supports for client-to-proxy connections by configuring the protocols property.
Example VirtualKafkaCluster with restricted TLS protocol versions
kind: VirtualKafkaCluster
metadata:
# ...
spec:
# ...
ingresses:
- ingressRef:
name: cluster-ip
tls:
certificateRef:
# ...
protocols:
allow:
- TLSv1.3
Alternatively, you can use deny to specify protocol versions to exclude.
The names of the TLS protocol versions supported depend on the JVM in the proxy container image. For more information, see SSLContext names.
6.2.4. TLS cipher suite configuration for client-to-proxy connections Copy linkLink copied to clipboard!
A cipher suite is a set of cryptographic algorithms that together provide the security guarantees offered by TLS. During TLS negotiation, a server and client agree on a common cipher suite that they both support.
Some older cipher suites are now considered insecure, but may be enabled on the Kafka cluster to allow older clients to connect.
The cipher suites enabled by default in the proxy depend on the JVM used in the proxy image and the TLS protocol version that is negotiated.
To prevent TLS downgrade attacks, you can disable cipher suites known to be insecure or no longer recommended. However, the proxy and the cluster must support at least one cipher suite in common.
It is good practice to disable insecure cipher suites.
You can restrict which TLS cipher suites the proxy uses when negotiating client-to-proxy connections by configuring the cipherSuites property.
Example VirtualKafkaCluster configuration using cipherSuites to allow specific ciphers
kind: VirtualKafkaCluster
metadata:
# ...
spec:
# ...
ingresses:
- ingressRef:
name: cluster-ip
tls:
certificateRef:
# ...
cipherSuites:
allow:
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
Alternatively, you can use deny to specify cipher suites to exclude.
The names of the cipher suites supported depend on the JVM in the proxy container image. For more information, see JSSE Cipher Suite Names.
6.3. Securing the proxy-to-broker connection Copy linkLink copied to clipboard!
Secure proxy-to-broker communication using TLS.
6.3.1. TLS trust configuration for proxy-to-cluster connections Copy linkLink copied to clipboard!
By default, the proxy uses the platform’s default trust store when connecting to the proxied cluster over TLS. This works if the cluster’s TLS certificates are signed by a well-known public Certificate Authority (CA), but fails if they’re signed by a private CA instead.
It is good practice to configure trust explicitly, even when proxied cluster’s TLS certificates are signed by a public CA.
This example configures a KafkaService to trust TLS certificates signed by any Certificate Authority (CA) listed in the trusted-cas.pem entry of the ConfigMap named trusted-cas.
Example KafkaService configuration for trusting certificates.
kind: KafkaService
metadata:
# ...
spec:
bootstrapServers: kafka.example.com:9092
tls:
trustAnchorRef:
kind: ConfigMap
name: trusted-cas
key: trusted-cas.pem
# ...
- 1
- The
trustAnchorRefproperty references a separate OpenShift resource which contains the CA certificates to be trusted - 2
- The
kindis optional and defaults toConfigMap. - 3
- The
nameof the resource of the givenkind. This resource must exist in the same namespace as theKafkaService - 4
- The
keyidentifies the entry in the given resource. The corresponding value must be a PEM-encoded set of CA certificates.
6.3.2. TLS authentication to proxied Kafka clusters Copy linkLink copied to clipboard!
Some Kafka clusters require mutual TLS (mTLS) authentication. You can configure the proxy to present a TLS client certificate using the KafkaService resource.
The TLS client certificate you provide must have been issued by a Certificate Authority (CA) that’s trusted by the proxied cluster.
This example configures a KafkaService to use a TLS client certificate stored in a Secret named tls-cert-for-kafka.example.com.
Example KafkaService configuration with TLS client authentication.
kind: KafkaService
metadata:
# ...
spec:
bootstrapServers: kafka.example.com:9092
tls:
trustAnchorRef:
kind: ConfigMap
name: trusted-cas
key: trusted-cas.pem
certificateRef:
kind: Secret
name: tls-cert-for-kafka.example.com
# ...
6.3.3. TLS version configuration for proxy-to-cluster connections Copy linkLink copied to clipboard!
Some older versions of TLS (and SSL before it) are now considered insecure. These versions remain enabled by default in order to maximize interoperability between TLS clients and servers that only support older versions.
If the Kafka cluster than you want to connect to supports newer TLS versions, you can disable the proxy’s support for older, insecure versions. For example, if the Kafka cluster supports TLSv1.1, TLSv1.2 and TLSv1.3 you might choose to enable only TLSv1.3 support. This would reduce the susceptibility to a TLS downgrade attack.
It is good practice to disable insecure protocol versions.
This example configures a KafkaService to allow only TLS v1.3 when connecting to kafka.example.com.
Example KafkaService with restricted TLS protocol versions.
kind: KafkaService
metadata:
# ...
spec:
bootstrapServers: kafka.example.com:9092
tls:
# ...
protocols:
allow:
- TLSv1.3
The protocols property also supports deny, if you prefer to list the versions to exclude instead.
The names of the TLS protocol versions supported depend on the JVM in the proxy container image. For more information, see SSLContext names.
6.3.4. TLS cipher suite configuration for proxy-to-cluster connections Copy linkLink copied to clipboard!
A cipher suite is a set of cryptographic algorithms that together provide the security guarantees offered by TLS. During TLS negotiation, a server and client agree on a common cipher suite that they both support.
Some older cipher suites are now considered insecure, but may be enabled on the Kafka cluster to allow older clients to connect.
The cipher suites enabled by default in the proxy depend on the JVM used in the proxy image and the TLS protocol version that is negotiated.
To prevent TLS downgrade attacks, you can disable cipher suites known to be insecure or no longer recommended. However, the proxy and the cluster must support at least one cipher suite in common.
It is good practice to disable insecure cipher suites.
Example KafkaService configured so that the proxy will negotiate TLS connection using only the listed ciphers.
kind: KafkaService
metadata:
# ...
spec:
bootstrapServers: kafka.example.com:9092
tls:
# ...
cipherSuites:
allow:
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
The cipherSuites property also supports deny, if you prefer to list the cipher suites to exclude instead.
The names of the cipher suites supported depend on the JVM in the proxy container image. For more information, see JSSE Cipher Suite Names.
6.4. Securing filters Copy linkLink copied to clipboard!
Secure filters by using the security features provided by each filter and storing sensitive values in external resources such as an OpenShift Secret.
6.4.1. Security-sensitive values in filter resources Copy linkLink copied to clipboard!
6.4.1.1. Template use and value interpolation Copy linkLink copied to clipboard!
Interpolation is supported in spec.configTemplate for the automatic substitution of placeholder values at runtime. This allows security-sensitive values, such as passwords or keys, to be specified in OpenShift Secret resources rather than directly in the KafkaProtocolFilter resource. Likewise, things like trusted CA certificates can be defined in ConfigMap resources.
The operator determines which Secret and ConfigMap resources are referenced by a KafkaProtocolFilter resource and declares them as volumes in the proxy Pod, mounted into the proxy container. This example shows how to configure the RecordEncryptionFilter using a Vault KMS deployed in the same OpenShift cluster.
Example KafkaProtocolFilter configuration
kind: KafkaProtocolFilter
metadata:
# ...
spec:
type: RecordEncryption
configTemplate:
kms: VaultKmsService
kmsConfig:
vaultTransitEngineUrl: http://vault.vault.svc.cluster.local:8200/v1/transit
vaultToken:
password: ${secret:vault:token}
selector: TemplateKekSelector
selectorConfig:
template: "$(topicName)"
- 1
- The
typeis the Java class name of the proxy filter. If the unqualified name is ambiguous, it must be qualified by the filter package name. - 2
- The
KafkaProtocolFilterrequires aconfigTemplate, which supports interpolation references. - 3
- The
passworduses an interpolation reference, enclosed by${and}instead of a literal value. The operator supplies the value at runtime from the specifiedSecret. - 4
- The selector
templateis interpreted by the proxy. It uses different delimiters,$(and), than the interpolation reference.
6.4.1.2. Structure of interpolation references Copy linkLink copied to clipboard!
Let’s look at the example interpolation reference ${secret:vault:token} in more detail.
It starts with ${ and ends with }. Between these, it is broken into three parts, separated by colons (:):
-
secretis a provider. Supported providers aresecretandconfigmap(note the use of lower case). -
vaultis a path. The interpretation of the path depends on the provider. -
tokenis a key. The interpretation of the key also depends on the provider.
For both secret and configmap providers:
-
The path is interpreted as the name of a
SecretorConfigMapresource in the same namespace as theKafkaProtocolFilterresource. -
The key is interpreted as a key in the
dataproperty of theSecretorConfigMapresource.