blob: 49ae3077d80b73bdf01a2a91192b397bf13a417c [file] [view]
---
sidebar_label: Secrets in Configuration
title: Secrets in Configuration
sidebar_position: 4
---
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
# Secrets in Configuration
Configuration values such as credentials for lake catalogs or object storage do not need to be
written into `server.yaml` (or client configuration) as literals. Instead, a value can be an
**indirection marker** that points at an external source, and Fluss resolves it at load time:
```yaml title="conf/server.yaml"
config.providers: directory,env
config.providers.directory.param.allowed.paths: /etc/fluss/secrets
# read from the file /etc/fluss/secrets/s3-secret-key
datalake.paimon.s3.secret-key: ${directory:/etc/fluss/secrets:s3-secret-key}
# read from an environment variable
datalake.paimon.s3.access-key: ${env:PAIMON_S3_ACCESS_KEY}
```
This keeps the configuration file free of secret material, so it can be checked into version
control or shipped as a plain Kubernetes ConfigMap while the secrets live in a mounted
`Secret` volume or injected environment variables.
## Markers
A marker has the form `${provider:[path:]key}` and must be the **entire** configuration value;
markers embedded inside larger values are not resolved. To use a literal value that starts with
`${`, escape it by doubling the dollar sign: `$${literal}` becomes `${literal}`. The escape, like
marker resolution, only applies when `config.providers` is set.
Resolution happens once, when the configuration is loaded: on server startup, when a client
connection is created via `ConnectionFactory`, and when the lake tiering service parses its
arguments. Rotating a secret requires a restart of the affected process. Markers are rejected in
dynamically altered cluster configuration. If a value looks like a marker but `config.providers`
is not set, it is kept as a literal and a warning is logged.
## Providers
Providers are enabled explicitly with `config.providers`; a marker referencing a provider that is
not declared fails the startup. Provider parameters are passed as
`config.providers.<identifier>.param.<parameter>`.
| Provider | Marker | Description |
| --- | --- | --- |
| `directory` | `${directory:/dir:file}` | Reads the content of `/dir/file` verbatim (UTF-8). Matches a Kubernetes `Secret` mounted as a volume, where each secret key becomes a file. |
| `env` | `${env:VAR}` | Reads an environment variable, e.g. one injected via `secretKeyRef`. |
| `file` | `${file:/path/creds.properties:key}` | Reads a single property from a Java properties file. |
The filesystem-reading providers (`directory`, `file`) require the `allowed.paths` parameter a
comma-separated list of roots they may read from. A marker resolving to a file outside every root
is rejected, so a stray marker cannot read arbitrary files. The `env` provider optionally accepts
`allowlist.pattern`, a regular expression the variable name must match.
Custom providers can be added by implementing
`org.apache.fluss.config.provider.ConfigProvider` and registering the implementation for
Java `ServiceLoader` discovery. The provider must be visible to the classloader that loads Fluss
itself: place the jar on the server classpath (`lib/`), or bundle it with the Fluss connector for
Flink jobs. Plugin directories are not scanned.
## Kubernetes example
When deploying with the Helm chart, the `secrets.mounts` / `secrets.env` values generate all of
the below see
[Deploying with Helm](../install-deploy/deploying-with-helm.md#secrets-in-configuration-overrides).
```yaml
# server.yaml shipped as a plain ConfigMap — contains no secrets
config.providers: directory
config.providers.directory.param.allowed.paths: /etc/fluss/secrets
datalake.paimon.s3.secret-key: ${directory:/etc/fluss/secrets:s3-secret-key}
```
```yaml
# pod spec: the secret is a normal Secret volume, never part of the ConfigMap
volumes:
- name: fluss-secrets
secret:
secretName: fluss-paimon-creds
containers:
- name: tablet-server
volumeMounts:
- name: fluss-secrets
mountPath: /etc/fluss/secrets
readOnly: true
```
Values resolved through a provider are treated as sensitive and are hidden when the configuration
is logged, regardless of the key name.