Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Kafka Configuration Providers

Configuration providers enable Kafka to retrieve sensitive configuration values from external systems. This separates secrets from configuration files, improving security and enabling centralized secret management.


Configuration providers resolve variable references in Kafka configuration files at runtime.

Configuration provider resolving a variable from an external secret storeConfiguration provider resolving a variable from an external secret storeKafka ProcessExternal Secret StoreConfiguration LoaderConfig ProviderKafka ComponentVault / KMS / Fileserver.propertiesread configresolve ${provider:path}resolved valuefetch secretreturn valueconfigured

Providers implement org.apache.kafka.common.config.provider.ConfigProvider:

public interface ConfigProvider extends Configurable, Closeable {
ConfigData get(String path);
ConfigData get(String path, Set<String> keys);
}

Configuration values use the syntax:

${provider-name:path:key}
ComponentDescriptionExample
provider-nameConfigured provider aliasvault, file, env
pathPath to secret in provider/secret/kafka/broker
keySpecific key within secretssl.keystore.password

Example:

ssl.keystore.password=${vault:/secret/kafka:keystore-password}

Reads configuration from files on disk.

# Register the file provider
config.providers=file
config.providers.file.class=org.apache.kafka.common.config.provider.FileConfigProvider
# Reference file-based secrets
ssl.keystore.password=${file:/etc/kafka/secrets/keystore-password:password}
ssl.key.password=${file:/etc/kafka/secrets/key-password:password}

Secret file format:

/etc/kafka/secrets/keystore-password
password=my-secret-password

Reads configuration from environment variables. Available in Kafka 3.5+.

# Register the env provider
config.providers=env
config.providers.env.class=org.apache.kafka.common.config.provider.EnvVarConfigProvider
# Reference environment variables
ssl.keystore.password=${env:KAFKA_SSL_KEYSTORE_PASSWORD}
sasl.jaas.config=${env:KAFKA_JAAS_CONFIG}

Reads secrets from individual files in a directory (Kubernetes secrets pattern).

# Register the directory provider
config.providers=dir
config.providers.dir.class=org.apache.kafka.common.config.provider.DirectoryConfigProvider
config.providers.dir.param.directory=/etc/kafka/secrets
# Reference secrets (filename = key)
ssl.keystore.password=${dir:ssl.keystore.password}
ssl.key.password=${dir:ssl.key.password}

Directory structure:

/etc/kafka/secrets/
├── ssl.keystore.password # Contains: my-keystore-password
├── ssl.key.password # Contains: my-key-password
└── sasl.jaas.config # Contains: JAAS config string

Integrates with HashiCorp Vault for enterprise secret management.

# Register Vault provider
config.providers=vault
config.providers.vault.class=io.confluent.kafka.security.vault.VaultConfigProvider
# Vault connection
config.providers.vault.param.vault.url=https://vault.example.com:8200
config.providers.vault.param.vault.token=${env:VAULT_TOKEN}
# Or use AppRole authentication
config.providers.vault.param.vault.auth.method=approle
config.providers.vault.param.vault.approle.role.id=${env:VAULT_ROLE_ID}
config.providers.vault.param.vault.approle.secret.id=${env:VAULT_SECRET_ID}
# Secret engine configuration
config.providers.vault.param.vault.secrets.engine=kv-v2
config.providers.vault.param.vault.secrets.mount=secret
# Reference Vault secrets
ssl.keystore.password=${vault:secret/data/kafka/broker:keystore-password}
Terminal window
# Store secrets in Vault
vault kv put secret/kafka/broker \
keystore-password="my-keystore-password" \
key-password="my-key-password" \
truststore-password="my-truststore-password"
MethodConfiguration
Tokenvault.token
AppRolevault.approle.role.id, vault.approle.secret.id
Kubernetesvault.kubernetes.role
AWS IAMvault.aws.role

Integrates with AWS Secrets Manager.

# Register AWS provider
config.providers=aws
config.providers.aws.class=io.confluent.kafka.security.aws.AwsSecretsManagerConfigProvider
# AWS configuration
config.providers.aws.param.aws.region=us-east-1
# Authentication (use IAM roles when possible)
# Falls back to default credential chain
# Reference AWS secrets
ssl.keystore.password=${aws:kafka/broker/ssl:keystore-password}
sasl.jaas.config=${aws:kafka/broker/sasl:jaas-config}
Terminal window
# Create secret in AWS Secrets Manager
aws secretsmanager create-secret \
--name kafka/broker/ssl \
--secret-string '{
"keystore-password": "my-keystore-password",
"key-password": "my-key-password",
"truststore-password": "my-truststore-password"
}'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": [
"arn:aws:secretsmanager:us-east-1:123456789012:secret:kafka/*"
]
}
]
}

Integrates with Azure Key Vault.

# Register Azure provider
config.providers=azure
config.providers.azure.class=io.confluent.kafka.security.azure.AzureKeyVaultConfigProvider
# Azure Key Vault configuration
config.providers.azure.param.azure.keyvault.url=https://my-keyvault.vault.azure.net/
config.providers.azure.param.azure.tenant.id=${env:AZURE_TENANT_ID}
config.providers.azure.param.azure.client.id=${env:AZURE_CLIENT_ID}
config.providers.azure.param.azure.client.secret=${env:AZURE_CLIENT_SECRET}
# Or use managed identity
config.providers.azure.param.azure.use.managed.identity=true
# Reference Azure secrets
ssl.keystore.password=${azure:kafka-keystore-password}

Azure Key Vault uses flat secret names (no hierarchy):

Kafka SecretAzure Key Vault Name
SSL keystore passwordkafka-ssl-keystore-password
SSL key passwordkafka-ssl-key-password
SASL passwordkafka-sasl-password

Integrates with Google Cloud Secret Manager.

# Register GCP provider
config.providers=gcp
config.providers.gcp.class=io.confluent.kafka.security.gcp.GcpSecretManagerConfigProvider
# GCP configuration
config.providers.gcp.param.gcp.project.id=my-project
config.providers.gcp.param.gcp.credentials.path=/etc/kafka/gcp-credentials.json
# Or use default credentials (GCE, GKE)
# No explicit credentials needed
# Reference GCP secrets
ssl.keystore.password=${gcp:kafka-keystore-password}
Terminal window
# Create secret
gcloud secrets create kafka-keystore-password \
--replication-policy="automatic"
# Add secret version
echo -n "my-keystore-password" | \
gcloud secrets versions add kafka-keystore-password --data-file=-

Multiple providers can be configured simultaneously:

# Register multiple providers
config.providers=file,vault,env
config.providers.file.class=org.apache.kafka.common.config.provider.FileConfigProvider
config.providers.vault.class=io.confluent.kafka.security.vault.VaultConfigProvider
config.providers.env.class=org.apache.kafka.common.config.provider.EnvVarConfigProvider
# Vault configuration
config.providers.vault.param.vault.url=https://vault.example.com:8200
config.providers.vault.param.vault.token=${env:VAULT_TOKEN}
# Use different providers for different secrets
ssl.keystore.password=${vault:secret/data/kafka:keystore-password}
ssl.truststore.password=${file:/etc/kafka/secrets/truststore-password:password}
log.dirs=${env:KAFKA_LOG_DIRS}

public class CustomConfigProvider implements ConfigProvider {
private String secretPath;
@Override
public void configure(Map<String, ?> configs) {
this.secretPath = (String) configs.get("secret.path");
}
@Override
public ConfigData get(String path) {
Map<String, String> data = fetchSecretsFromPath(path);
return new ConfigData(data);
}
@Override
public ConfigData get(String path, Set<String> keys) {
Map<String, String> allData = fetchSecretsFromPath(path);
Map<String, String> filteredData = new HashMap<>();
for (String key : keys) {
if (allData.containsKey(key)) {
filteredData.put(key, allData.get(key));
}
}
return new ConfigData(filteredData);
}
@Override
public void close() {
// Cleanup resources
}
private Map<String, String> fetchSecretsFromPath(String path) {
// Implementation to fetch secrets
return new HashMap<>();
}
}
config.providers=custom
config.providers.custom.class=com.example.CustomConfigProvider
config.providers.custom.param.secret.path=/custom/secrets

Mount Kubernetes secrets as files and use the DirectoryConfigProvider:

apiVersion: v1
kind: Pod
metadata:
name: kafka-broker
spec:
containers:
- name: kafka
image: kafka:latest
volumeMounts:
- name: kafka-secrets
mountPath: /etc/kafka/secrets
readOnly: true
volumes:
- name: kafka-secrets
secret:
secretName: kafka-broker-secrets
server.properties
config.providers=dir
config.providers.dir.class=org.apache.kafka.common.config.provider.DirectoryConfigProvider
config.providers.dir.param.directory=/etc/kafka/secrets
ssl.keystore.password=${dir:keystore-password}
ssl.key.password=${dir:key-password}

For dynamic secret injection, use External Secrets Operator with Vault or cloud providers:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: kafka-secrets
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: kafka-broker-secrets
data:
- secretKey: keystore-password
remoteRef:
key: secret/data/kafka/broker
property: keystore-password

PracticeDescription
Least privilegeGrant minimum required permissions to access secrets
Secret rotationUse providers that support automatic rotation
Audit loggingEnable audit logs in secret management systems
Network securityRestrict network access to secret management systems
Encryption at restEnsure secrets are encrypted in the external store
Secret rotation sequence between a secret manager and a brokerSecret ManagerKafka BrokerSecret ManagerSecret ManagerKafka BrokerKafka BrokerSecret rotatedPush new secret (webhook)Reload configurationFetch updated secretReturn new valueApply new credentialsZero-downtime rotation
ProviderSecurity Consideration
FileRestrict file permissions (600)
EnvironmentAvoid logging environment variables
VaultUse short-lived tokens, enable audit
AWSUse IAM roles, avoid access keys
AzureUse managed identity
GCPUse Workload Identity

IssueCauseSolution
Provider not foundClass not in classpathAdd provider JAR to classpath
Authentication failedInvalid credentialsVerify credentials and permissions
Secret not foundWrong path or keyCheck path syntax and secret existence
TimeoutNetwork issuesCheck connectivity to secret store
# Enable configuration provider logging
log4j.logger.org.apache.kafka.common.config.provider=DEBUG
log4j.logger.io.confluent.kafka.security=DEBUG
Terminal window
# Test variable resolution (dry run)
kafka-configs.sh --bootstrap-server localhost:9092 \
--describe \
--entity-type brokers \
--entity-name 0