Secret type to represent secrets and integrate with the secrets handling
- 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.
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.
The type is
Secretbut it's really a text password. Credentials however can be a variety of things -Keyand its subclasses for example. Also we have aPasswordtype and hierarchy inwildfly-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.
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.
//cc @sberyozkin @gsmet @yrodiere
@dmlloyd I'm resuming the work here. Are you ok with the current design?
At a high level, yes; but why does the config mapper need special support for it? Will it not work just using converters?
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.
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?
I wonder how that will play out with
Map<String, SomeConfigGroup>properties? If someone only sets a secret inSomeConfigGroup, 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.
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
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