Secrets (via Quarkus CredentialsProvider)
Quarkus Flow integrates the CNCF Workflow Secrets concept with Quarkus’ CredentialsProvider SPI.
Workflows reference secrets by handle in the DSL (no cleartext), while Quarkus supplies the actual credentials
from Vault/File Vault/custom providers at runtime. When no provider is present, Quarkus Flow defers to the SDK’s
MicroProfile Config–backed manager so you can define secrets directly in application.properties during dev/test.
1. TL;DR
-
Declare and reference secrets in the Java DSL (e.g.,
use(u → u.secrets("mySecret"))and${ $secret.mySecret.key }). -
Primary: Provide a Quarkus
CredentialsProviderbean (Vault, File Vault, or your own) and select it globally or per secret. -
Fallback: If no provider beans exist, define dotted keys in
application.properties:mySecret.username=alice,mySecret.password=s3cr3t!. -
Choose the provider globally or per secret using
@Namedbean names. -
If multiple providers exist with no selection, Quarkus Flow fails fast and lists available names.
2. How resolution works
At runtime, Quarkus Flow provides a SecretManager that prefers Quarkus CredentialsProvider:
-
Per-secret override:
quarkus.flow.secrets.credentials-provider-names.<secret>=<beanName> -
Global default:
quarkus.flow.secrets.credentials-provider-name=<beanName> -
Single provider present: If exactly one
CredentialsProviderbean exists, it is used. -
Zero providers present → SDK fallback: Quarkus Flow does not bind its bridge
SecretManager; the SDK resolves via MicroProfile Config (see below). -
Else (multiple providers, no selection) → fail fast: Clear error listing available
@Namedbeans.
|
Typical keys expected from providers (see the specification types): Basic auth: Bearer token: Your HTTP executor maps these keys to the correct |
3. Configuration (CredentialsProvider path)
# Global provider (by @Named bean)
quarkus.flow.secrets.credentials-provider-name=vault
# Per-secret provider overrides
quarkus.flow.secrets.credentials-provider-names.mySecret=file
quarkus.flow.secrets.credentials-provider-names.dbCreds=vault
| Key | Example | Description |
|---|---|---|
quarkus.flow.secrets.credentials-provider-name |
vault |
Global @Named bean used for all secrets when not overridden. |
quarkus.flow.secrets.credentials-provider-names.<secret> |
mySecret=file |
Per-secret override: provider @Named used for the given secret handle. |
4. Secrets via MicroProfile Config (fallback)
When no CredentialsProvider beans are present in the app, the SDK’s ConfigManager resolves secret keys from
dotted properties in application.properties:
# Dotted keys: <secretHandle>.<key>=<value>
mySecret.username=alice
mySecret.password=s3cr3t!
This matches the SDK’s expectations; your workflow can keep using:
${ $secret.mySecret.username }, ${ $secret.mySecret.password }, etc.
|
5. Java DSL examples
Declare the secret and consume it via the $secret expression:
@ApplicationScoped
public class SecretEchoFlow extends Flow {
@Override
public Workflow descriptor() {
return workflow()
.use(u -> u.secrets("mySecret")) // declare the handle
.tasks(t -> t.set("${ $secret.mySecret.password }")) // -> "s3cr3t!"
.build();
}
}
6. Unit test examples
6.1. Using a CredentialsProvider
@RegisterExtension
static final QuarkusUnitTest unit = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClass(SecretEchoFlow.class)
.addClass(DumbCredentialsProvider.class))
// select our @Named("dumb") provider globally
.overrideConfigKey("quarkus.flow.secrets.credentials-provider-name", "dumb");
@Test
void resolves_secret_from_provider() {
var handle = Arc.container().instance(WorkflowDefinition.class, Identifier.Literal.of(SecretEchoFlow.class.getName()));
assertTrue(handle.isAvailable());
var model = handle.get().instance().start().join();
assertEquals("s3cr3t!", model.as(String.class).orElseThrow());
}
6.2. Using MicroProfile Config fallback (no provider beans)
@RegisterExtension
static final QuarkusUnitTest unit = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClass(SecretEchoFlow.class)
// no CredentialsProvider classes added → fallback kicks in
.addAsResource(new StringAsset(
"mySecret.username=alice\n" +
"mySecret.password=s3cr3t!\n"),
"application.properties"));
@Test
void resolves_secret_from_application_properties() {
var handle = Arc.container().instance(WorkflowDefinition.class, Identifier.Literal.of(SecretEchoFlow.class.getName()));
assertTrue(handle.isAvailable());
var model = handle.get().instance().start().join();
assertEquals("s3cr3t!", model.as(String.class).orElseThrow());
}
7. Behavior & fallback
-
Referenced secret unresolved / no credentials found → Authorization error (per spec). The engine treats missing secrets as an authorization failure. Your HTTP/task executor should surface this as an authorization error (commonly HTTP
401 Unauthorizedor403 Forbidden, depending on the target and policy). -
Multiple providers, no selection → error prompts to set global/per-secret selection and lists available names.
-
Zero providers → SDK fallback (MicroProfile Config dotted keys) is used:
mySecret.username=…,mySecret.password=…. -
Empty credential map from a provider → clear error naming the provider and secret (provider path).
8. Security notes
-
Keep credentials out of the DSL—use handles only (e.g.,
"usernamePasswordSecret"). -
Prefer real secret stores (Vault) in production; File Vault/custom providers or MicroProfile Config are fine for dev/test.
-
Quarkus Flow never logs secret values; errors include only provider/secret names.
8.1. Spec compliance
Per the CNCF Workflow Specification (Secret) the absence of required secret material MUST be treated as an authorization problem. See: https://github.com/serverlessworkflow/specification/blob/main/dsl.md#secret
9. Troubleshooting
-
“CredentialsProvider @Named='X' not found”: Ensure a bean exists with
@Named("X")or remove the selection to use fallback. -
Ambiguous providers: Set
quarkus.flow.secrets.credentials-provider-nameor a per-secret override. -
No credentials found for secret (provider path): Verify your provider returns the expected keys for that secret handle.
-
Fallback not triggering: Check the classpath—any
CredentialsProviderbean presence disables the fallback. -
Authorization error when task executes: Verify the referenced secret handle exists and resolves to the required keys (e.g.,
username,password,token). Missing secrets are treated as authorization failures per spec.
10. References
-
Quarkus guide: Using a Credentials Provider
-
CNCF Workflow Specification — Secrets: dsl.md#secret
-
CNCF Workflow Specification — Authentication: dsl-reference.md#authentication
-
Basic authentication reference: basic-authentication