The CommandK SDK enables users to fetch secrets programmatically, either directly from within the apps to use or as part of a build pipeline to inject them into the app's artifact.
repositories {
maven {
url = uri("https://mvn.cmdk.sh")
}
mavenCentral()
}
dependencies {
implementation 'dev.commandk:java-sdk:0.0.5:all'
}
In your project's pom.xml
file add the repository and dependency:
<project>
<repositories>
<repository>
<id>commandk</id>
<url>https://mvn.cmdk.sh</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>dev.commandk</groupId>
<artifactId>java-sdk</artifactId>
<version>0.0.5</version>
<classifier>all</classifier>
</dependency>
</dependencies>
</project>
Let's look at a very basic example that configures the client and retrieves secrets.
package dev.commandk.example;
import dev.commandk.javasdk.CommandKClient;
import dev.commandk.javasdk.models.RenderedAppSecret;
import java.util.List;
public class Main {
public static void main(String[] args) {
// The host and access token need to be provided to the client somehow.
// One of the ways the client tries to access it is by looking them up in the
// system properties with the `commandk.host` and `commandk.apiToken` properties.
System.setProperty("commandk.host", "https://api.commandk.dev");
System.setProperty("commandk.apiToken", "<api_token>");
// With the default configuration, the client will pick up the credentials from
// the system properties we set.
CommandKClient commandKClient = CommandKClient.withDefaults();
// To fetch secrets of an app we need to specify the app id and the environment id
List<RenderedAppSecret> renderedAppSecrets = commandKClient.getRenderedAppSecrets(
"<app_id>",
"<environment>", // staging, production, sandbox, development,
List.of()
);
// And it's ready to be consumed
renderedAppSecrets.forEach(renderedAppSecret -> {
System.out.printf("%s: %s\n", renderedAppSecret.getKey(), renderedAppSecret.getSerializedValue());
});
}
}
This uses the default configuration for the client and should be enough to start consuming secrets from CommandK. Depending on how you want to configure the client you will have to either setup some system variables or implement some classes.
The CommandK client needs two values to communicate with the CommandK system. The domain/host where CommandK is installed and the API token to authenticate the requests to it. There are two ways this can be configured:
- Using the default configuration with
CommandKClient.withDefaults();
- Providing a custom configuration with
CommandKClient(kvStoreFactory, credentialsProvider)
CommandKClient commandKClient = CommandKClient.withDefaults();
The default configuration is what the example above uses. It will look up the host and access token for your CommandK installation in this order and use up the first one it finds.
- Environment variables:
COMMANDK_HOST
andCOMMANDK_API_TOKEN
- Java system properties:
commandk.host
andcommandk.apiToken
- Configuration file:
3.1 At the location provided in the environment variable
COMMANDK_CONFIG_FILE
3.2 At the location provided in the java system propertycommandk.configFile
In our example the client finds the credentials we set in the java system properties.
NOTE If you are using an on-prem installation of commandk, your host value would look like this
https://api.<installation-name>.commandk.dev
For the value ofhost
, refer to the Customer Information Sheet that would have been shared by the CommandK team for your installation. Usually, if you access your dashboard atapp.<name>.commandk.dev
, then the host for your commandk installation would behttps://api.<name>.commandk.dev
Instead of setting the credentials directly in the system properties you could also load them up from a file.
- Create a file at
~/commandk.config
host: https://api.commandk.dev
apiToken: <api_token>
- Set the environment variable
export COMMANDK_CONFIG_FILE=~/commandk.config
or the system property through the application.yml
file
# application.yml
commandk.configFile=~/commandk.config
or like in the example set the system property in the application
// Replace these line in the example
// The host and access token need to be provided to the client somehow.
// One of the ways the client tries to access it is by looking them up in the
// system properties with the `commandk.host` and `commandk.apiToken` properties.
System.setProperty("commandk.host", "https://api.commandk.dev");
System.setProperty("commandk.apiToken", "<api_token>");
// with this
System.setProperty("commandk.configFile", "~/commandk.config");
If you want to override the way the credentials are provided then you construct the client by providing a CommandKCredentialProvider. A very simple one would look like this:
class CustomCredentialsProvider implements CommandKCredentialsProvider {
@Override
public CommandKCredentials resolveCredentials() {
return new CommandKCredentials("https://api.commandk.dev", "<api_token>");
}
}
Construct the client like this:
CommandKClient commandKClient = CommandKClient(new GlobalKVStoreFactory(), new CustomCredentialsProvider())
The client when constructed manually requires two things:
- A
KVStoreFactory
, a factory class that will create a key value store for the client to use cache for fetched secrets. For this we will use the default one,GlobalKVStoreFactory
, that ships with the client. - A
CommandKCredentialsProvider
, in this case it is an instance of ourCustomCredentialProvider
.
Below is a full example:
package dev.commandk.example;
import dev.commandk.javasdk.CommandKClient;
import dev.commandk.javasdk.credential.CommandKCredentials;
import dev.commandk.javasdk.credential.CommandKCredentialsProvider;
import dev.commandk.javasdk.kvstore.GlobalKVStoreFactory;
import dev.commandk.javasdk.models.RenderedAppSecret;
import java.util.List;
public class Main {
public static void main(String[] args) {
CommandKClient commandKClient = new CommandKClient(new GlobalKVStoreFactory(), new CredentialProviderExample());
// To fetch secrets of an app we need to specify the app id and the environment id
List<RenderedAppSecret> renderedAppSecrets = commandKClient.getRenderedAppSecrets(
"<app_id>",
"<environment>",
List.of()
);
// And it's ready to be consumed
renderedAppSecrets.forEach(renderedAppSecret -> {
System.out.printf("%s: %s\n", renderedAppSecret.getKey(), renderedAppSecret.getSerializedValue());
});
}
}
class CredentialProviderExample implements CommandKCredentialsProvider {
@Override
public CommandKCredentials resolveCredentials() {
return new CommandKCredentials("https://api.commandk.dev", "<api_token>");
}
}
Note: The default KVStoreFactory
, GlobalKvStoreFactory
, used by the CommandKClient uses a thread safe static object as the underlying store. So all instances of it will use the same store. Hence, all default instantiations of the CommandKClient will also share the same KVStore. If your application/pipeline is multithreaded then please make sure that any custom implementations of KvStore
and KvStoreFactory
are also thread safe.