Key Management SDK — Prerequisites
SDK Version: 3.4.0
Audience: A product or pipeline that manages the keys of one AnkaSecure tenant without a person at the keyboard
The Key Management SDK signs in as an administrative workload of a tenant. Before the first call, three things must exist: a reachable deployment, the workload with its public key registered, and the scopes the workload needs. The SDK creates none of them: people prepare the workload once, in the Admin Console.
The SDK itself must be on the classpath first. Coordinates, JAR and checksums are on the Downloads page.
1. A reachable deployment
The SDK dials one origin over https and reaches both the Auth API (the workload token) and the Admin API (key management) through it. It first reads the deployment's authorization server metadata (/api/v3/auth/.well-known/oauth-authorization-server) and refuses to send any credential unless that document names the platform issuer, lists ES256 DPoP proofs and publishes a token endpoint.
The published token endpoint must be on the origin the SDK dials; otherwise the SDK refuses to sign in. Every DPoP proof and the assertion audience name that origin. Configure the deployment's address that serves the authorization server metadata and the workload token endpoint.
2. The administrative workload
An administrative workload is an identity of the tenant: a UUID that proves itself with a key pair your product holds, or with a token an issuer the platform trusts minted for it. It is not a user and has no client secret. Two people prepare it once, in this order:
| Step | Who | Does | Hands over |
|---|---|---|---|
| 1 | Integration developer | Generates the workload's key pair and keeps the private key | The public JWK, to the tenant administrator |
| 2 | Tenant administrator | Creates the workload, registers the public JWK, assigns the scopes | The workload id, to the integration developer |
| 3 | Integration developer | Configures the SDK with the deployment's address, the workload id and the private key file | — |
After step 3 nobody signs in again for the product's automation.
2.1 Step 1 — the integration developer generates the key pair
The private key never leaves the product, and the platform never sees it. Any tool that produces an EC P-256, P-384 or P-521 key, or an RSA key of 2048 to 4096 bits, will do, as long as you end with:
- the private key as an unencrypted PKCS#8 PEM file (it begins
-----BEGIN PRIVATE KEY-----) or as a private JWK. A SEC1 PEM (-----BEGIN EC PRIVATE KEY-----) and an encrypted PEM are not read; - the public key as a JWK:
kty,crv,x,yfor EC;kty,n,efor RSA.kid,alg,use(sig) andkey_ops(withverify) are accepted and nothing else; the platform ignores akidyou set and names the key by its RFC 7638 thumbprint.
The JDK alone does it, with nothing to install:
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.util.Base64;
/** Generates an EC P-256 key pair for an administrative workload. */
public class GenerateWorkloadKey {
public static void main(String[] args) throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
generator.initialize(new ECGenParameterSpec("secp256r1"));
KeyPair pair = generator.generateKeyPair();
// The private key, as an unencrypted PKCS#8 PEM file: it stays with the integration.
String pem = "-----BEGIN PRIVATE KEY-----\n"
+ Base64.getMimeEncoder(64, new byte[] {'\n'}).encodeToString(pair.getPrivate().getEncoded())
+ "\n-----END PRIVATE KEY-----\n";
Files.writeString(Path.of("workload-key.pem"), pem, StandardCharsets.US_ASCII);
// The public JWK: the only part the tenant administrator registers.
ECPublicKey publicKey = (ECPublicKey) pair.getPublic();
Base64.Encoder base64url = Base64.getUrlEncoder().withoutPadding();
System.out.println("{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\""
+ base64url.encodeToString(coordinate(publicKey.getW().getAffineX()))
+ "\",\"y\":\""
+ base64url.encodeToString(coordinate(publicKey.getW().getAffineY())) + "\"}");
}
/** A P-256 coordinate as exactly 32 unsigned big-endian bytes (RFC 7518, section 6.2.1.2). */
private static byte[] coordinate(BigInteger value) {
byte[] raw = value.toByteArray();
byte[] fixed = new byte[32];
int start = Math.max(0, raw.length - 32);
System.arraycopy(raw, start, fixed, 32 - (raw.length - start), raw.length - start);
return fixed;
}
}
java GenerateWorkloadKey.java > workload-public.jwk # prints the public JWK, writes workload-key.pem
chmod 600 workload-key.pem # owner-only: the SDK refuses a group- or world-readable key
Send workload-public.jwk to the tenant administrator; it holds nothing secret. Keep workload-key.pem where the product runs, readable only by the product's account. On Windows, restrict the file's access list to that account: the SDK warns when another principal can read it.
2.2 Step 2 — the tenant administrator prepares the workload
- Create the workload on the console's Administrative Workloads screen, with a name the audit trail will show for everything the product does (for example
acme-key-rotation). A new workload isACTIVEbut can do nothing yet. - Register the public key on the workload's Keys tab: paste the JWK the developer sent. Valid until is optional; left empty, the key is accepted for twelve months, and never for more than twenty-four.
- Assign the scopes on the Scopes tab: exactly the ones the product calls, and no more (§3).
- Send the developer the workload's id, the UUID shown under its name when you open it. It is not secret.
On a SaaS deployment the tenant's own administrator prepares it. On a private cloud or on-premises deployment a platform administrator may as well. A workload of the tenant can never prepare another one for that tenant.
2.3 Step 3 — the integration developer configures the SDK
Three values reach the SDK, and none of them is a secret held by the platform:
- the deployment's address (
kmsdk.scheme,kmsdk.host,kmsdk.port); - the workload id from the tenant administrator;
- the path of the private key file, or the source of the federated token.
The same id and key file also sign the Key Management CLI in:
ankasecure-km init --url https://api.example.com --workload-id <workload id> --private-key-file /etc/acme/workload-key.pem
3. Scopes
A workload's token carries exactly the scopes assigned to it, and the SDK never requests scopes explicitly. A call without its scope is refused with 403 and the SDK raises a KeyManagementSdkException.
| Group | Operation | Scope |
|---|---|---|
| Keys | list, get, export, lifecycle-cause verdicts | admin.keys.read |
| Keys | create | admin.keys.orchestrate |
| Keys | update metadata | admin.keys.patch |
| Keys | import a key | migration.importKey |
| Keys | import or analyse a keystore | migration.importKeystore |
| Keys | supported algorithms | admin.tenant.algorithms.read |
| Keys | suspend, reactivate, revoke, archive | admin.keys.suspend, admin.keys.reactivate, admin.keys.revoke, admin.keys.archive |
| Key versions | list, get | admin.tenant.keys.materials.read |
| Key versions | revoke | admin.tenant.keys.materials.revoke |
| Rotation | rotate | admin.keys.rotate |
| Rotation | admissibility | admin.keys.read |
| Rotation | schedule, executions | admin.keys.rotation-schedule.read |
| Rotation | replace schedule | admin.keys.rotation-schedule.write |
| Destruction | request / cancel for a key | admin.keys.mark-for-destruction / admin.keys.cancel-destruction |
| Destruction | request / cancel for a version | admin.tenant.keys.materials.mark-for-destruction / admin.tenant.keys.materials.cancel-destruction |
| Destruction | orders | admin.keys.read |
| Own quorum requests | list, get / cancel | admin.tenant.quorum.read / admin.tenant.quorum.cancel |
| Exchange contexts | read / create, update, delete, suspend, resume, close | admin.tenant.exchange-context.list, .read / .create, .update, .delete, .suspend, .resume, .close |
| Exchanges | list, get | admin.tenant.exchange.read |
| Exchanges | create, clone | admin.tenant.exchange.create |
| Exchanges | update, validate | admin.tenant.exchange.update |
| Exchanges | preview activation, activate, resume | admin.tenant.exchange.activate |
| Exchanges | suspend / revoke / discard a draft | admin.tenant.exchange.suspend / .revoke / .delete |
| Capability grants | list, get / create, preview / delete | admin.tenant.capability-grant.list, .read / .create / .revoke |
| Constraint policies | list, get / create / update / delete | admin.tenant.constraint-policy.list, .read / .create / .update / .delete |
| Internal cryptographic use cases | list, get / create / suspend / resume / delete | admin.tenant.internal-use-case.read / .create / .suspend / .resume / .revoke |
| Directory | applications / actors / counterparty types | admin.tenant.application.list, .read / admin.tenant.actor.list, .read / admin.tenant.counterparty-type.list, .read |
A workload is never admitted to the scopes of tenant general policies, key backends, BYOK, key custody or the tenant override switch: those stay with people in the Admin Console. The version-level destruction request that would leave the key with no version outside a destruction is the key's own destruction request and needs admin.keys.mark-for-destruction as well (Key Destruction).
4. Configuration
The SDK reads its endpoint from a Properties object. The credential is a method argument, not configuration. kmsdk.scheme and kmsdk.host are required: the constructor refuses a configuration that lacks either with a KeyManagementSdkException naming each missing key (kmsdk.host is required), and never assumes an address. A port or timeout that is not a number, or is out of range, is refused the same way, naming the key.
| Property | Default | Purpose |
|---|---|---|
kmsdk.scheme | None — required | Protocol: https, or http for development |
kmsdk.host | None — required | The host the SDK dials |
kmsdk.port | The scheme's own port: 443 for https, 80 for http | The port the SDK dials, from 1 to 65535 |
kmsdk.connectTimeoutMs | 10000 | Connection timeout (milliseconds) |
kmsdk.readTimeoutMs | 30000 | Read timeout (milliseconds) |
kmsdk.writeTimeoutMs | 30000 | Write timeout (milliseconds) |
kmsdk.tls.insecure | false | Trust-all TLS toggle — development only; emits a WARN when enabled |
kmsdk.auth.issuer | https://auth.ankatech.co | The platform issuer the authorization server metadata must name before a workload authenticates |
5. Next steps
- Quick Start — sign in and list the tenant's keys.
- Usage Guide — every group, with examples.
- Security Best Practices — custody of the workload key.
Version: 3.4.0
Last updated: 2026-10-26