Using Credential Stores With Encrypted Expressions With WildFly
WildFly allows the use of credential stores to keep alias for sensitive information, such as, passwords for external services. Credential stores can be used to store different credentials under aliases and use credential-reference to specify them in server configuration. As a result, the sensitive information is no longer visible in clear text.
Prerequisites
To complete this guide, you need:
-
Roughly 10 minutes
-
JDK 11+ installed with
JAVA_HOME
configured appropriately -
Apache Maven 3.9+
Prerequisite
To follow along with this guide you will need:
-
about 10 minutes
-
WildFly with credential-store support
About Encrypted Expressions
A previous guide demonstrates how to use credential stores to avoid using clear-text passwords. However, as you may have noticed, the password for the credential store was specified in clear-text. And while having access to the credential-store password does not allow a human to read the contents of a credential-store, it is still not secure. Additionally, there are other types of sensitive information we may use when configuring a server which we would not want to appear in the standalone.xml file.
This is where encrypted expressions are useful. Support for encrypted expressions allow us to specify sensitive information, like the password for a credential-store without using plain-text values. Encrypted expressions can also be used for system properties, where a value expression is specified. And lastly, credential-store can only be used for credential-reference attributes. But there are other attributes where we can enter sensitive information, but it does not include a credential reference. This guide will explain the these three use cases for encrypted expressions and how to configure them.
Configuring Encrypted Expressions
Let’s first create a secret-key-credential-store
that we can use to store secret keys that will be used to encrypt expressions. Just like a regular credential-store file, this will also create a .cs file inside the directory you specify. However, this will be human readable.
/subsystem=elytron/secret-key-credential-store=newCredStore:add(path=newSecretKeyCred.cs, relative-to=jboss.server.config.dir)
If you already had a .cs file that you would like to use, then you can specify the path here and set the create
and populate
attributes to false
. These attributes are true
by default as seen here:
{
"outcome" => "success",
"result" => {
"path" => "newSecretKeyCred.cs",
"relative-to" => "jboss.server.config.dir",
"create" => true,
"default-alias" => "key",
"key-size" => 256,
"populate" => true
}
}
Here is an example of the contents of the newSecretKeyCred.cs file:
# Properties Credential Store (Do Not Modify)
key=RUxZAUsOhzQhCv7KbD9f2SGBgWkmTC9l0lgu28FWM4UfRBY7QQ==
As you can see there has been a key created for you already using the default alias key
. You can create a new key with a new alias of your own using the following command:
/subsystem=elytron/secret-key-credential-store=newCredStore:generate-secret-key(alias=newSecretKey, key-size=128)
Now let’s use these keys for the use cases mentioned above.
Encrypted Expression for Credential Reference
Now that we have a generated secret key in a credential store we can activate the resource responsible for handling encrypted expressions. And we can use that to convert a clear-text password phrase into an encrypted expression.
/subsystem=elytron/expression=encryption:add(resolvers=[{name=initial-resolver, credential-store=newCredStore, secret-key=key}])
/subsystem=elytron/expression=encryption:create-expression(resolver=initial-resolver, clear-text=MyPassword)
the second command will give you an output like this which we will use to specify the password instead of the clear-text phrase:
{
"outcome" => "success",
"result" => {"expression" => \
"${ENC::initial-resolver:RUxZAUMQEH6CP3xXyAqYzqsC3oNayyeGH32wsdAZ8VLkkxaEmWc=}"}
}
Now if we wanted to create another credential-store, then we can use this encrypted expression to create it as follows:
/subsystem=elytron/credential-store=main:add(path=mySecondCredStore.cs, relative-to=jboss.server.config.dir, credential-reference= {clear-text="${ENC::initial-resolver:RUxZAUMQEH6CP3xXyAqYzqsC3oNayyeGH32wsdAZ8VLkkxaEmWc=}"}, create=true)
This does not just apply to credential stores, we can also do this with any other resource that uses credential-reference, such as a key-store
or a key-manager
.
Encrypted Expression for System Property
System properties can be used to customize the behaviour of the server. These are key-value pairs that can be specified using the cli commands. System properties can be specified as follows:
/system-property=foo:add(value=bar)
However, sometimes the value may be something you do not want to specify in plaintext. If we configure it as shown above, the value can easily be discovered using the read-resource function. So, we need a way to specify it without using clear-text. However, since this does not use credential-reference we cannot use a credential-store directly. Instead, we can use encrypted expressions.
We can encrypt the value for a system property using encrypted expressions as follows:
/subsystem=elytron/expression=encryption:create-expression(resolver=initial-resolver, clear-text=bar)
{
"outcome" => "success",
"result" => {"expression" => "${ENC::initial-resolver:RUxZAUMQXSp3dFy+4aUcAzpayRZVeHHNTU/4bE3iUW8LGPplXkA=}"}
}
We can now update our value to this encrypted expression:
/system-property=foo:write-attribute(name=value, value=${ENC::initial-resolver:RUxZAUMQXSp3dFy+4aUcAzpayRZVeHHNTU/4bE3iUW8LGPplXkA=})
If we use the read-resource function on our system property, we can no longer see the value in plaintext.
Encrypted Expressions to Replace Other Passwords
The WildFly has some resources which contain sensitive information, such as passwords, without using credential-reference. One such example is the truststore-password
attribute under the secure-deployment
resource under tne elytron-oidc-client
subsystem. These values can also be specified using encrypted expressions. We can encrypt the value as follows:
/subsystem=elytron/expression=encryption:create-expression(resolver=initial-resolver, clear-text=secret)
{
"outcome" => "success",
"result" => {"expression" => "${ENC::initial-resolver:RUxZAUMQdZ5/RHt5Oj+Whv
K3l+rtR2AnjrtOhBkKW6X58vUtrUw=}"}
}
Once the encrypted expression has been added, it can easily be used to specify sensitive information, like as seen below:
/subsystem=elytron-oidc-client/secure-deployment=simple-webapp.war:write-attribute(name=truststore-password,value="${ENC::initial-resolver:RUxZAUMQA6O7VXU/6cdzA4qlQNU1SM34N5kk53l8DjsljXoEYTc=}")
and for the naming subsystem example, we can use the following commands:
/subsystem=naming/binding=java\:global\/federation\/ldap\/example:write-attribute(name=environment, value={java.naming.security.credentials="${ENC::initial-resolver:RUxZAUMQA6O7VXU6cdzA4qlQNU1SM34N5kk53l8DjsljXoEYTc=}"})
Disabling Cli History
As you may notice some of the commands still include sensitive information. And since the jboss cli caches all executed commands, we need to disable history to hide all inputs using the command below:
history --disable
Caching can be enabled again using the command below:
history --enable
Summary
This guide demonstrates three use cases where we can use encrypted expressions to specify sensitive information.