Class AnkaSecureKeyManagementSdk
The Key Management SDK automates the key management of one tenant as an administrative
workload: keys and their versions, rotation, destruction requests, the workload's own quorum
requests, exchange contexts, exchanges, capability grants, constraint policies and internal
cryptographic use cases, with read-only lookups of applications, actors and counterparty types. It
authenticates workloads only: authenticateWorkload(WorkloadCredential) uses the OAuth 2.0
client_credentials grant (RFC 6749 section 4.4) with a signed or federated
client_assertion and a DPoP proof (RFC 9449), and returns an immutable
AutoCloseable AuthenticatedKeyManagementSdk. People sign in on the Admin Console;
approving or rejecting a quorum request, tenant policies and key backends are console operations and
are not part of this SDK.
The tenant is the one the workload's token names in its tenantId claim: a tenant workload
acts only in its own tenant, so no method of the SDK takes a tenant.
Secret handling
A workload never sends a shared secret: it proves its identity with a key or an external token
(WorkloadCredential). Access tokens are held only in memory as char[] and are never
persisted. No credential, assertion, proof or token ever appears in a log line, exception message, or
toString().
Transport security
TLS certificate verification is on by default (standard OkHttp validation). A
trust-all toggle is available only via the kmsdk.tls.insecure=true configuration property;
enabling it emits a WARN log naming the property and is intended solely for development against
self-signed endpoints.
Every request goes to the configured origin (kmsdk.scheme, kmsdk.host,
kmsdk.port) under that one TLS trust: the authorization server metadata, the token request with
its client assertion, and every Key Management request. The metadata's token_endpoint must be
the platform token endpoint on that same origin, or the workload is refused before any credential is
sent; the client assertion's audience is the configured origin followed by /api, and every DPoP
proof's htu names the configured origin. No request of the SDK follows a redirect: a
3xx answer is an error naming the status (KeyManagementSdkException), so neither the
client assertion nor the access token is ever sent anywhere the SDK was not configured to reach.
Basic usage
Properties props = new Properties();
props.setProperty("kmsdk.scheme", "https");
props.setProperty("kmsdk.host", "api.example.com");
props.setProperty("kmsdk.port", "443");
AnkaSecureKeyManagementSdk factory = new AnkaSecureKeyManagementSdk(props);
WorkloadCredential credential = WorkloadCredential.privateKeyJwt(
UUID.fromString("9b2f6c1e-3d4a-4c8b-a1e7-5f0d2c9b8a71"), Path.of("/etc/acme/workload-key.jwk"));
try (AuthenticatedKeyManagementSdk sdk = factory.authenticateWorkload(credential)) {
PageAdminKeyResponse keys = sdk.keys().list(KeyListQuery.firstPage());
}
-
Constructor Summary
ConstructorsConstructorDescriptionAnkaSecureKeyManagementSdk(Properties config) Constructs the factory from configuration properties. -
Method Summary
Modifier and TypeMethodDescriptionauthenticateWorkload(WorkloadCredential credential) Authenticates an administrative workload and returns an immutable SDK instance whose every request is DPoP-bound (RFC 9449).withCorrelationIdSupplier(Supplier<String> supplier) Registers an optional correlation-id supplier for cross-service request tracing.
-
Constructor Details
-
AnkaSecureKeyManagementSdk
Constructs the factory from configuration properties.Recognized keys:
kmsdk.scheme— required:httpsorhttp. This constructor accepts either;authenticateWorkload(WorkloadCredential)then refuses plainhttp, before any request, unless the host is a loopback host orkmsdk.tls.insecureistrue(development)kmsdk.host— required: the host of the platform's public edgekmsdk.port(default: the scheme's own port,443for https,80for http)kmsdk.connectTimeoutMs(default10000)kmsdk.readTimeoutMs(default30000)kmsdk.writeTimeoutMs(default30000)kmsdk.tls.insecure(defaultfalse) — trust-all toggle; emits a WARNkmsdk.auth.issuer(defaulthttps://auth.ankatech.co) — the platform issuer identifier the Auth API's metadata must name before a workload authenticates
No origin is ever assumed: a configuration without a scheme or a host is refused, naming each missing key. A port or a timeout that is not a number in its range is refused naming its key, never replaced by its default. A refusal names keys, never their values.
- Parameters:
config- configuration properties; must not benull- Throws:
NullPointerException- ifconfigisnullKeyManagementSdkException- ifkmsdk.schemeorkmsdk.hostis missing, the scheme is neitherhttpsnorhttp, or a port or timeout is malformed or out of range
-
-
Method Details
-
withCorrelationIdSupplier
Registers an optional correlation-id supplier for cross-service request tracing. When set, every SDK instance subsequently produced by this factory attaches an OkHttp interceptor to both its auth and key management HTTP clients that stamps theX-Request-IDheader on each outbound request, using the value returned bysupplier.get()at request time.The supplier is invoked per request, so it may return a fresh correlation id for each call. If it returns
nullor a blank value, no header is added. Passingnullclears any previously registered supplier. The correlation id is a tracing token, not a secret; the SDK never logs it.- Parameters:
supplier- the correlation-id source, ornullto disable correlation stamping- Returns:
- this factory, for fluent chaining
-
authenticateWorkload
Authenticates an administrative workload and returns an immutable SDK instance whose every request is DPoP-bound (RFC 9449).The SDK first reads the Auth API's authorization server metadata (RFC 8414) and checks that it names the configured platform issuer (
kmsdk.auth.issuer), lists ES256 DPoP proofs and publishes the platform token endpoint of the configured origin; a deployment that does not issue DPoP-bound workload tokens, or a document naming another origin, is reported here, before any credential is sent. Every DPoP proof names the configured origin, and theprivate_key_jwtaudience is that origin followed by/api. The SDK then generates an EC P-256 key in memory for this instance (never written anywhere) and requests a token withgrant_type=client_credentials,client_id= the workload id, the credential'sclient_assertionand a DPoP proof for that token endpoint. Noclient_secretor password is ever sent.Every later request carries
Authorization: DPoP <token>and a new proof bound to the request's method, path and token. The token (five minutes) is renewed when it is within 60 seconds of its expiry, once for all threads waiting on it. The instance acts in the tenant the token names.A refused token request raises a
KeyManagementSdkExceptioncarrying the HTTP status,the OAuth error(invalid_clientfor a refused credential,invalid_dpop_prooffor a refused proof,invalid_requestfor a deployment that does not issue workload tokens) and, on a503, the server'sRetry-After. No other credential is tried.UUID workloadId = UUID.fromString("9b2f6c1e-3d4a-4c8b-a1e7-5f0d2c9b8a71"); try (AuthenticatedKeyManagementSdk sdk = factory.authenticateWorkload( WorkloadCredential.federatedTokenFile(workloadId, Path.of("/var/run/secrets/tokens/ankasecure")))) { sdk.keys().get("payments-signing-key"); } catch (KeyManagementSdkException e) { if ("invalid_client".equals(e.getOAuthError())) { // the workload, its credential or its federation binding was refused } }- Parameters:
credential- how the workload proves its identity; must not benull- Returns:
- an authenticated SDK instance bound to the workload's tenant; never
null - Throws:
KeyManagementSdkException- if the private key file is readable by others (POSIX) or holds no usable key, the metadata cannot be read or does not admit DPoP-bound workload tokens, the token request is refused, or the server is unreachableNullPointerException- ifcredentialisnull
-