Could you give some more information regarding your use case:
- How is the key pair managed? Is this a config secret that a user with config write permission will manage from the gateway config page? Is this a key pair managed by the user somewhere else in the product? Is this a key pair that is not managed by a user, but instead managed by the system?
- How do you want to store your key pair?
You could make the key pair itself the secret. In that case, you'll need to serialize the key pair as a String or byte array in whatever format you want, then wrap that in a Plaintext
instance.
Or you might store the key pair in a Keystore file outside of the secrets system. You might make the password used to protect the Keystore the secret. Again, wrap that password in a Plaintext
instance.
There are two ways to store a secret using the new 8.3 APIs:
- Embedded
- You use the
SystemEncryptionService
provided by the GatewayContext
to encrypt your plaintext into a ciphertext using the platform-managed encryption keys.
- You embed the ciphertext in your config
- Referenced
- The secret is stored in a
SecretProvider
.
- You include a reference to the secret in the secret provider within your config.
- The reference is the pair of (1) the name of the Secret Provider and (2) the name of the Secret stored in the Secret Provider
We have a SecretConfig
class which offers structures for these two types of secrets.
SecretConfig#embedded
static factory method:
/**
* Factory method for creating a new instance of an {@link Embedded} secret config given the ciphertext secret
* retrieved from a call to {@link SystemEncryptionService#encryptToJson(Plaintext)}.
*
* @param ciphertext the ciphertext secret. cannot be null.
* @return a new instance of an {@link Embedded} secret config with the given ciphertext secret
* @throws NullPointerException if the given ciphertext argument is null
*/
public static Embedded embedded(JsonElement ciphertext) {
return new Embedded(ciphertext);
}
SecretConfig#referenced
static factory method:
/**
* Factory method for creating a new instance of a {@link Referenced} secret config given the name of the
* secret provider and the name of the secret stored in the provider.
*
* @param providerName the name of the secret provider where the secret is stored. cannot be null.
* @param secretName the name of the secret stored in the secret provider. cannot be null.
* @return a new instance of a {@link Referenced} secret config pointing to the target secret provider and secret
* @throws NullPointerException if either the providerName or secretNames arguments are null
*/
public static Referenced referenced(String providerName, String secretName) {
return new Referenced(providerName, secretName);
}
As far as getting access to the plaintext value of the secret, we have a Secret
class which abstracts away the implementation details for dealing with embedded vs referenced secrets.
You first grab the SecretConfig
from wherever you are storing your configuration settings. Then create an instance of Secret
given the GatewayContext
and your SecretConfig
using the Secret#create
static factory method:
/**
* Factory method to create a new instance of a Secret
*
* @param context the current {@link GatewayContext}. cannot be null.
* @param config the {@link SecretConfig} of the secret. cannot be null.
* @return a new instance of Secret
* @throws IllegalArgumentException if the provided config is not an embedded or referenced secret
* @throws NullPointerException if either context or config arguments are null
*/
public static Secret<?> create(GatewayContext context, SecretConfig config) {
if (config.isEmbedded()) {
SecretConfig.Embedded embedded = config.getAsEmbedded();
return new Embedded(context, embedded);
} else if (config.isReferenced()) {
SecretConfig.Referenced referenced = config.getAsReferenced();
return new Referenced(context, referenced);
} else {
throw new IllegalArgumentException("unsupported secret config '%s'".formatted(config));
}
}
Then call Secret#getPlaintext
from your instance of Secret
every time you wish to grab the plaintext secret value:
/**
* <p>Get the current {@link Plaintext} value of the configured secret.</p>
* <p>If the configured secret is embedded, the Plaintext value is retrieved by passing the embedded ciphertext
* to the {@link SystemEncryptionService} retrieved from the {@link GatewayContext}.</p>
* <p>If the configured secret is referenced, the Plaintext value is retrieved by getting the
* {@link SecretProviderManager} from the {@link GatewayContext}, then getting the {@link SecretProvider} with the
* configured name from the SecretProviderManager, and finally {@link SecretProvider#read(String) reading} the
* Plaintext value of the secret with the configured name from the SecretProvider.</p>
*
* @return the current {@link Plaintext} value of the configured secret. never null.
* @throws SecretException if there is a problem getting the current Plaintext value of the configured secret
*/
public abstract Plaintext getPlaintext() throws SecretException;
Your code should expect a SecretException
and deal with being unable to grab the plaintext value of the secret. For example: if the secret is encrypted with keys which no longer exist or if it is referencing a provider or secret in the provider which no longer exists, or perhaps the secret provider is remote and a network connection is failing.
If possible, your code should also be written to grab the plaintext from the Secret
instance each time it is needed, instead of grabbing it once at startup and holding onto that value for the lifetime of the object. This allows for dynamically rotating secrets in a secret provider, otherwise you would have to have a way to manually reload the plaintext from the Secret
instance every time the value of the secret in the provider changes.
Hope that helps start you in the right direction at least. But please let me know if you have any further questions or if something isn't adding up right for you. I believe you are the first adopter outside of our own devs for these APIs 