smallrye-config icon indicating copy to clipboard operation
smallrye-config copied to clipboard

Secret type to represent secrets and integrate with the secrets handling

Open radcortez opened this issue 1 year ago • 3 comments

  • Fixes #1199

Adds a new wrapper type, Secret<T>, to represent a secret. When a Secret is part of a mapping, the path is added to the Secrets interceptor, to not include the secret in property names or access the secret without calling SecretKeys.doUnlocked.

This is initial work to support more advanced scenarios around secrets, that we should discuss.

radcortez avatar Oct 02 '24 12:10 radcortez

The type is Secret but it's really a text password. Credentials however can be a variety of things - Key and its subclasses for example. Also we have a Password type and hierarchy in wildfly-elytron, which we use for security functions in Quarkus. This type extends Key, which is really the canonical supertype for secrets AFAICT.

What about supporting the existing types as secrets? Or at most maybe adding a wrapper e.g. Secret<PrivateKey> where we have a nested conversion process?

Also please look into how Elytron does password encoding because it could be relevant.

dmlloyd avatar Oct 02 '24 13:10 dmlloyd

The type is Secret but it's really a text password. Credentials however can be a variety of things - Key and its subclasses for example. Also we have a Password type and hierarchy in wildfly-elytron, which we use for security functions in Quarkus.

Yes, I was not too certain about the name, but the rationale was to keep it consistent with what we already have, SecretKeys, SecretKeysHandler.

This type extends Key, which is really the canonical supertype for secrets AFAICT.

What do you mean? This only extends Destroyable, which, yes, I agree, is mainly for Key. The goal was to have a way to remove values from the mapping, because values are cached. Still, was only an idea.

What about supporting the existing types as secrets? Or at most maybe adding a wrapper e.g. Secret<PrivateKey> where we have a nested conversion process?

We need the mapping generator to identify which elements are considered secrets. Either we provide a list of types for that case, or maybe we can make it work generically with a wrapper type. Let me see what I can do.

radcortez avatar Oct 02 '24 17:10 radcortez

I've moved Secret to a wrapper type Secret<T>, so this will allow using whatever type you want for the actual secret. The wrapper type only marks the property as a secret, which can be hidden from the list of names or forbid it to retrieve it directly with the API.

We need to figure out how to handle the nested converters piece. I'm wondering if we should support nested converter creation automatically.

radcortez avatar Oct 04 '24 12:10 radcortez

//cc @sberyozkin @gsmet @yrodiere

radcortez avatar Dec 13 '24 10:12 radcortez

@dmlloyd I'm resuming the work here. Are you ok with the current design?

radcortez avatar Jul 21 '25 16:07 radcortez

At a high level, yes; but why does the config mapper need special support for it? Will it not work just using converters?

dmlloyd avatar Jul 21 '25 16:07 dmlloyd

Will it not work just using converters?

Yes. The support in config mapper is just to record the configuration paths that reference Secret types, allowing us to add these to the SecretKeysConfigSourceInterceptor and throw an exception if the name is accessed directly and exclude it from the list of property names.

radcortez avatar Jul 22 '25 10:07 radcortez

Looks nice, just a question:

to not include the secret in property names

I wonder how that will play out with Map<String, SomeConfigGroup> properties? If someone only sets a secret in SomeConfigGroup, the entry disappears from the map?

yrodiere avatar Jul 22 '25 11:07 yrodiere

I wonder how that will play out with Map<String, SomeConfigGroup> properties? If someone only sets a secret in SomeConfigGroup, the entry disappears from the map?

The mapping process will keep access to all names (even if they are secrets). This will only affect the programmatic API. If required, users can use SecretKeys.doUnlocked to access all names and do lookups.

radcortez avatar Jul 22 '25 13:07 radcortez

I had a few questions here: how do you make a propery a secret...

And also how do you make sure it's not logged when validated to avoid things like:

java.lang.IllegalArgumentException: SRCFG00039: The config property quarkus.github-app.private-key with the config value "-----BEGIN RSA PRIVATE KEY

gsmet avatar Jul 28 '25 14:07 gsmet

I had a few questions here: how do you make a propery a secret...

There are two ways:

You can call withSecretKeys in the builder and pass in the configuration names that are secrets. This has been available and supported for some time. Obviously, this is not very friendly.

To complement the previous way, the PR proposes a wrapper type Secret<T> to be used in @ConfigMapping, so you can express that a specific member is a secret. This will automatically list that the corresponding configuration name to the config mapping member is a secret.

java.lang.IllegalArgumentException: SRCFG00039: The config property quarkus.github-app.private-key with the config value "-----BEGIN RSA PRIVATE KEY

We already have an interceptor that throws an exception when we try to access a configuration that is listed in the secret keys.

Also check: https://smallrye.io/smallrye-config/Latest/config/secret-keys/#secret-keys-names

radcortez avatar Aug 18 '25 11:08 radcortez