Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ See [Build and Features](docs/deployment/build-and-features.md).

## Security references

**Security assurance:** 356 automated functional scenarios, including 90
**Security assurance:** 364 automated functional scenarios, including 90
protocol and corruption failure-injection scenarios plus one 3-of-5 share-recovery scenario, run
for every pull request and commit to `main`. See
[Security Assurance](docs/security-model/security-assurance.md) for tested attack
Expand All @@ -205,7 +205,7 @@ vectors and executable evidence.

The HTTP contract is described by [openapi.yaml](openapi.yaml).

Java integrations can use [`org.exploit:tkeeper-sdk:2.4.0`](sdk/README.md).
Java integrations can use [`org.exploit:tkeeper-sdk:2.4.1`](sdk/README.md).

## Verification

Expand Down
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {
def mainClassName = 'org.exploit.keeper.TKeeperKt'

group = 'org.exploit'
version = '2.4.0'
version = '2.4.1'

repositories {
mavenCentral()
Expand Down Expand Up @@ -39,6 +39,7 @@ def featureModules = [

def explicitFeatureModules = [
'features:auth-dev' : 'keeper.feature.auth.dev',
'features:dry-run' : 'keeper.feature.dry-run',
'features:recovery' : 'keeper.feature.recovery',
]

Expand Down Expand Up @@ -375,6 +376,7 @@ tasks.register('shadowJarProductionTest', com.github.jengelman.gradle.plugins.sh
doLast {
def forbidden = [
'auth-dev' : 'org/exploit/keeper/auth/dev/provider/DevAuthProvider.class',
'dry-run' : 'org/exploit/keeper/emulator/controller/DryRunController.class',
'failure-injection': 'org/exploit/keeper/module/failure/FailureInjectionController.class',
'recovery' : 'org/exploit/keeper/controller/external/RecoveryController.class',
'recovery-ecc' : 'org/exploit/keeper/module/recovery/ecc/service/ECCRecoveryService.class',
Expand Down Expand Up @@ -403,6 +405,7 @@ tasks.register('artifactIsolationTest') {
doLast {
def markers = [
'auth-dev' : 'org/exploit/keeper/auth/dev/provider/DevAuthProvider.class',
'dry-run' : 'org/exploit/keeper/emulator/controller/DryRunController.class',
'failure-injection': 'org/exploit/keeper/module/failure/FailureInjectionController.class',
'recovery' : 'org/exploit/keeper/controller/external/RecoveryController.class',
'recovery-ecc' : 'org/exploit/keeper/module/recovery/ecc/service/ECCRecoveryService.class',
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ TKeeper gives machines, agents, services, and workflows a cryptographic identity
| Choose mono or threshold | [Quorum Modes](security-model/quorum-modes.md) |
| Create and govern identities | [Create, Rotate, and Refresh](key-management/key-lifecycle.md) |
| Govern signing | [Authorities](signing-and-authorities/authorities.md) |
| Preview an authority-policy decision | [Dry Run Policy Evaluation](signing-and-authorities/dry-run.md) |
| Select cryptographic platforms | [Platforms](crypto-platforms/platforms.md) |
| Use the HTTP API | [OpenAPI](api-reference/openapi.md) |
| Run integration tests | [Integration Tests](operations/integration-tests.md) |
Expand Down
1 change: 1 addition & 0 deletions docs/api-reference/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Read:

- [OpenAPI](openapi.md)
- [Java SDK](sdk.md)
- [Dry Run Policy Evaluation](../signing-and-authorities/dry-run.md)
- [Errors](errors.md)
- [Permissions](permissions.md)

Expand Down
2 changes: 2 additions & 0 deletions docs/api-reference/permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ tkeeper.key.*.sign
| `tkeeper.compliance.inventory` | read asset inventory |
| `tkeeper.integrity.rotate` | rotate audit integrity key |
| `tkeeper.audit.log.verify` | verify signed audit log lines |
| `tkeeper.emulate` | evaluate an authority policy without executing its command |
| `tkeeper.control.system` | read control-plane system state |
| `tkeeper.control.sinks` | read control-plane audit sink state |

Expand All @@ -55,6 +56,7 @@ tkeeper.key.*.sign
- Keep import permissions highly restricted.
- Restrict consistency repair, share recovery, and quorum promotion to recovery operators.
- Treat control-plane read permissions as sensitive operational metadata.
- Treat dry-run access as sensitive policy metadata; `tkeeper.emulate` is not scoped to a key id.
- Keep destroy permissions separate from rotate and refresh.
- Use negative permissions to carve high-risk identities out of broad grants.
- Review wildcard grants before production.
Expand Down
5 changes: 3 additions & 2 deletions docs/api-reference/sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
The Java SDK provides typed modules for the public TKeeper API:

- [SDK README](../../sdk/README.md)
- Maven coordinate: `org.exploit:tkeeper-sdk:2.4.0`
- Maven coordinate: `org.exploit:tkeeper-sdk:2.4.1`
- Java toolchain: 17 or newer

The SDK follows the same module boundaries as the API: system, DKG, signing, storage/import, quorum promotion, ECIES, compliance, expiration, audit, integrity, consistency, destroy, and control-plane reads.
The SDK follows the same module boundaries as the API: system, DKG, signing, storage/import, quorum promotion, ECIES, dry run, compliance, expiration, audit, integrity, consistency, destroy, and control-plane reads.

The wire contract remains [`../../openapi.yaml`](../../openapi.yaml). Treat generated or handwritten SDK helpers as convenience code, not a competing source of truth.

Expand All @@ -16,5 +16,6 @@ The wire contract remains [`../../openapi.yaml`](../../openapi.yaml). Treat gene
- Close `TKeeperClient` to release its HTTP resources.
- Pass `KeySetAuthorities` explicitly when creating governed identities; convenience constructors without authorities select `arbitrary` raw signing.
- Build signing requests with `AuthorityCommand`. Verify converts it to a `VerificationCommand`, which retains only the material `type` and `artifact`. Verification may use any supported material type, including typed or arbitrary material, without requiring that type or payload to belong to the key's current authority manifest.
- Use `dryRun().emulate(...)` to preview an authority-policy decision; see [Dry Run Policy Evaluation](../signing-and-authorities/dry-run.md).
- Catch `TKeeperException` and branch on `ErrorType`, not diagnostic detail text.
- Do not retry authorization or policy denials as availability failures.
2 changes: 1 addition & 1 deletion docs/deployment/backup-and-recovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ Legacy unversioned generation zero is outside the recovery boundary.
3. Restart each participant with recovery mode enabled:

```bash
java -Dkeeper.recovery=true -jar build/libs/tkeeper-2.4.0.jar
java -Dkeeper.recovery=true -jar build/libs/tkeeper-2.4.1.jar
```

4. Unseal the keepers if required and confirm health and status.
Expand Down
21 changes: 14 additions & 7 deletions docs/deployment/build-and-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Equivalent:
The jar lands under:

```text
build/libs/tkeeper-2.4.0.jar
build/libs/tkeeper-2.4.1.jar
```

TKeeper requires Java 25.
Expand Down Expand Up @@ -60,6 +60,7 @@ Feature names match child project names. The module `:features:authority-evm` is
| AWS KMS seal provider | `seal-aws` | any required crypto platform |
| Google Cloud KMS seal provider | `seal-gcloud` | any required crypto platform |
| Developer token authentication | `auth-dev` (explicit opt-in, excluded from `all`) | any required crypto platform |
| Authority policy dry run | `dry-run` (explicit opt-in, excluded from `all`) | any required crypto platform |
| ML-DSA identities | none | `pqc` |
| Default production set | `all` | `all` |

Expand All @@ -76,7 +77,7 @@ recovery module for each selected platform:

The first command includes `:features:recovery` and `:features:recovery:ecc`; the second includes
`:features:recovery` and `:features:recovery:pqc`; the third includes all three. The platform modules
are not selected separately. Recovery and `auth-dev` are excluded from `keeper.features=all` and
are not selected separately. Recovery, `auth-dev`, and `dry-run` are excluded from `keeper.features=all` and
must be requested explicitly.

Treat this as a maintenance artifact. After recovery, rebuild and redeploy the normal production
Expand All @@ -89,6 +90,12 @@ code and routes in the artifact.
./gradlew :build -Pkeeper.features=auth-dev -Pkeeper.platforms=ecc
```

Build the dry-run endpoint explicitly in the same way:

```bash
./gradlew :build -Pkeeper.features=dry-run -Pkeeper.platforms=ecc
```

## Selection properties

| Scope | Features | Platforms |
Expand All @@ -98,7 +105,7 @@ code and routes in the artifact.
| Select all | `keeper.features.all=true` | `keeper.platforms.all=true` |

Comma-separated selectors accept short names such as `ecies`, `ecc`, and `pqc`. `all` selects every
default production module in that category. Explicit features such as `recovery` and `auth-dev` are
default production module in that category. Explicit features such as `recovery`, `auth-dev`, and `dry-run` are
not included.

## Docker
Expand All @@ -120,7 +127,7 @@ Build a recovery image with both platform implementations:
Production image tags:

```text
exploit/tkeeper:2.4.0
exploit/tkeeper:2.4.1
exploit/tkeeper:latest
```

Expand All @@ -139,7 +146,7 @@ docker run --rm \
-v "$PWD/config:/etc/tkeeper:ro" \
-v "$PWD/data:/var/lib/tkeeper" \
-e KEEPER_CONFIG_LOCATION=/etc/tkeeper \
exploit/tkeeper:2.4.0
exploit/tkeeper:2.4.1
```

## Integration image
Expand All @@ -161,8 +168,8 @@ Build both images used by functional integration tests with:
The test task reuses these images. Re-run the build after changing application code, dependencies, or Dockerfiles.

Do not pass `keeper.features` or `keeper.platforms` to this task. The development integration image
uses a dedicated classpath containing every default production feature, the explicit `auth-dev` and
`recovery` features, both recovery platform modules, every platform, and the test-only
uses a dedicated classpath containing every default production feature, the explicit `auth-dev`,
`dry-run`, and `recovery` features, both recovery platform modules, every platform, and the test-only
failure-injection module.

Never deploy either test image as production runtime.
Expand Down
2 changes: 1 addition & 1 deletion docs/deployment/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Example:
java \
-Dkeeper.config.location=/etc/tkeeper \
-Dkeeper.dev.config.location=/etc/tkeeper \
-jar build/libs/tkeeper-2.4.0.jar
-jar build/libs/tkeeper-2.4.1.jar
```

Minimal node config:
Expand Down
2 changes: 1 addition & 1 deletion docs/deployment/control-plane-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Disable the UI at startup:
```bash
java \
-Dkeeper.ui.enabled=false \
-jar build/libs/tkeeper-2.4.0.jar
-jar build/libs/tkeeper-2.4.1.jar
```

## Authentication
Expand Down
4 changes: 2 additions & 2 deletions docs/getting-started/local-single-node.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Build the jar with the explicit developer-auth feature:
The jar is:

```text
build/libs/tkeeper-2.4.0.jar
build/libs/tkeeper-2.4.1.jar
```

## Create local config
Expand Down Expand Up @@ -102,7 +102,7 @@ java \
-Dkeeper.dev.enabled=true \
-Dkeeper.dev.config.location=/tmp/tkeeper \
-Dkeeper.coordinator.enabled=true \
-jar build/libs/tkeeper-2.4.0.jar
-jar build/libs/tkeeper-2.4.1.jar
```

## Initialize the node
Expand Down
2 changes: 1 addition & 1 deletion docs/operations/error-tracking.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ sentry {
enabled = true
dsn = "https://public@example.sentry.io/1"
environment = "prod"
release = "2.4.0"
release = "2.4.1"
}
```

Expand Down
5 changes: 3 additions & 2 deletions docs/operations/integration-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,13 @@ Do not pass `keeper.features` or `keeper.platforms` to `buildTestContainers`. Th
- every default production feature
- the explicit recovery feature and both recovery platform modules
- development authentication
- dry-run policy evaluation
- every platform
- the test-only failure-injection module

The production transport test image uses the production UBI Dockerfile and excludes development
authentication, recovery, and failure injection. Regular `shadowJar` and `dockerBuild` exclude
failure injection; recovery is included only when selected.
authentication, dry run, recovery, and failure injection. Regular `shadowJar` and `dockerBuild`
exclude failure injection; dry run and recovery are included only when selected.

See [`../../integration-tests/README.md`](../../integration-tests/README.md) for local requirements and Testcontainers setup.

Expand Down
8 changes: 5 additions & 3 deletions docs/security-model/security-assurance.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Security Assurance

TKeeper security assurance currently comprises **356 automated functional scenarios across 17 test
TKeeper security assurance currently comprises **364 automated functional scenarios across 18 test
classes**, including **90 protocol and corruption failure-injection scenarios** and one 3-of-5
share-recovery scenario, executed against multi-node Keeper deployments.

Expand All @@ -10,7 +10,7 @@ transport cluster and a 3-of-5 recovery cluster with per-run PKI, TLS, mTLS, pee
and SPKI pinning. The transport cluster also exercises JWT and JWKS behavior.

Every pull request targeting `main` and every commit pushed to `main` runs the Release Gate. A
passing revision completes the module test tasks, all 356 functional scenarios, artifact isolation,
passing revision completes the module test tasks, all 364 functional scenarios, artifact isolation,
and both container builds.

> **In short:** TKeeper tests cover production identity and transport,
Expand Down Expand Up @@ -233,6 +233,7 @@ paths are covered in [SignatureTests].
| --- | --- | --- |
| Authority downgrade or type confusion (T-3, partial T-4) | Raw `arbitrary` authority cannot be mixed with OCI authorities. Empty, duplicate, malformed, missing-reference, reference/id-mismatched, unsupported, command-unattached, and artifact-type-mismatched authorities fail closed. | [AuthorityPolicyTests]: `rejectsAuthorityThatIsNotAllowedForKey`, `rejectsArtifactTypeThatDoesNotMatchAuthorityType`, `rejectsGenerateWithArbitraryMixedWithOciAuthority`, `rejectsDuplicateAuthorityIdsOnGenerate`, `rejectsGenerateWithEmptyAuthorities`, `rejectsGenerateWithInvalidAuthorityId`, `rejectsOciAuthorityWithoutReference`, `rejectsOciReferenceWhoseAuthorityIdDoesNotMatch`, `rejectsUnsupportedAuthorityTypeBeforeCreatingKey`, `verifyRejectsMalformedEvmMaterialWithoutResolvingAuthority` |
| Typed intent or effect-policy bypass (T-5) | Allowed commands sign while policy violations are denied for custom payments, EVM native/ERC-20 transfer, approval, `transferFrom`, vault operations, Bitcoin spend, and X.509 issuance. Unknown fields, wrong types, wrong principals, and over-limit amounts are exercised. | [AuthorityPolicyTests]: `deniesTypedCommandRejectedByAuthorityPolicy`, `rejectsTypedCommandWithUnknownField`, `rejectsTypedCommandWithWrongFieldType`, `deniesEvmErc20ApprovalWhenAmountExceedsPolicy`, `deniesEvmErc20TransferFromWhenOwnerDoesNotMatchPolicy`, `deniesEvmVaultWithdrawWhenRecipientDoesNotMatchPolicy`, `deniesBitcoinSpendRejectedByAuthorityPolicy`, `deniesX509TbsCertificateRejectedByAuthorityPolicy` |
| Dry-run policy bypass (T-1, T-3, T-5) | The optional endpoint reports allow, deny, and four-eye-control decisions with approval requirements; it requires authentication, validates key identifiers and existence, and rejects authorities not assigned to the key. | [DryRunTests]: `returnsAllowForAcceptedCommand`, `returnsDenyAsEvaluationResult`, `returnsAllowWithRequirementsForFourEyeControl`, `requiresAuthentication`, `rejectsInvalidKeyId`, `rejectsMissingKey`, `rejectsAuthorityNotAssignedToKey` |
| Four-eye bypass or incomplete approval group (T-6) | Sign, decrypt, refresh, rotate, and destroy fail without required proofs. Replaced approver sets invalidate old proofs; every matching authority group is required; key and authority requirements are cumulative. | [FourEyeControlTests]: `ensureDecryptRequiresProofs`, `ensureSignRequiresProofs`, `ensureRefreshRequiresProofs`, `ensureOldKeySetNoLongerWorks`, `ensureRotateRequiresProofs`, `authorityPolicyRequiresEveryMatchingApprovalGroup`, `keyAndAuthorityPoliciesShareOneApprovalNonce`, `lenientFourEyeControlAppliesToDestroy` |
| Approval substitution, replay, or race (T-6) | Changing an approved command invalidates its proof. A consumed approval cannot replay; concurrent submissions yield only one success; consumption survives coordinator restart. | [FourEyeControlTests]: `authorityPolicyBindsProofsAndRejectsReplay`, `approvalNonceIsConsumedAtomically`, `approvalNonceRemainsConsumedAfterCoordinatorRestart` |
| Single-peer policy tampering (T-3, T-5, T-6) | Mutating the coordinator's authority or deleting its four-eye or expiry policy does not reach threshold. A healthy quorum still accepts a valid command when one non-coordinator peer has missing or swapped authority metadata. | [FailureInjectionTests]: `arbitraryAuthorityInjectedOnOneCoordinatorPeerDoesNotReachThreshold`, `authoritySwappedOnCoordinatorCannotAuthorizeDifferentCommand`, `fourEyePolicyDeletedOnCoordinatorStillRequiresPeerApprovals`, `expiredApplyPolicyClearedOnCoordinatorStillBlocksAtPeers`, `validCommandStillSignsWhenOnePeerRemovedAuthorities`, `validCommandStillSignsWhenOnePeerSwappedAuthorities` |
Expand Down Expand Up @@ -264,7 +265,7 @@ paths are covered in [SignatureTests].
| --- | --- | --- |
| Invalid TLS identity rotation | A mismatched PEM key/certificate update retains the last known good identity. | [ProductionTransportSecurityTests]: `publicPemRotationRetainsLastKnownGoodIdentityWhileFilesMismatch` |
| JWKS rotation or refresh failure | Rotation accepts the new key and removes the retired key; failed refresh retains the last known good set. | [ProductionTransportSecurityTests]: `jwksRotationAcceptsNewSigningKeyWithoutRestart`, `failedJwksRefreshKeepsLastKnownGoodKeys` |
| Optional-module isolation | Development authentication, failure injection, and recovery modules are present in the integration artifact and absent from the production test artifact. | `./gradlew artifactIsolationTest` |
| Optional-module isolation | Development authentication, dry run, failure injection, and recovery modules are present in the integration artifact and absent from the production test artifact. | `./gradlew artifactIsolationTest` |
| Release evidence | Module tests, artifact isolation, container builds, functional suites, and production transport tests execute as one release gate. | `./gradlew releaseGate` |

### Exact protocol vector catalog
Expand Down Expand Up @@ -332,6 +333,7 @@ produces and verifies a normal distributed signature with the same stored key.
[NIST ACVP ML-DSA specification]: https://pages.nist.gov/ACVP/draft-celi-acvp-ml-dsa.html
[AuthorityPolicyTests]: https://github.com/tkeeper-org/tkeeper/blob/main/integration-tests/functional/src/test/kotlin/org/exploit/test/functional/AuthorityPolicyTests.kt
[CoordinatorDisabledTest]: https://github.com/tkeeper-org/tkeeper/blob/main/integration-tests/functional/src/test/kotlin/org/exploit/test/functional/CoordinatorDisabledTest.kt
[DryRunTests]: https://github.com/tkeeper-org/tkeeper/blob/main/integration-tests/functional/src/test/kotlin/org/exploit/test/functional/DryRunTests.kt
[ECIESTests]: https://github.com/tkeeper-org/tkeeper/blob/main/integration-tests/functional/src/test/kotlin/org/exploit/test/functional/ECIESTests.kt
[FailureInjectionTests]: https://github.com/tkeeper-org/tkeeper/blob/main/integration-tests/functional/src/test/kotlin/org/exploit/test/functional/FailureInjectionTests.kt
[RecoveryFailureInjectionTests]: https://github.com/tkeeper-org/tkeeper/blob/main/integration-tests/functional/src/test/kotlin/org/exploit/test/functional/RecoveryFailureInjectionTests.kt
Expand Down
1 change: 1 addition & 0 deletions docs/signing-and-authorities/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Read:

- [Signing](signing.md)
- [Authorities](authorities.md)
- [Dry Run Policy Evaluation](dry-run.md)
- [CEL Functions](cel-functions.md)
- [Arbitrary and Typed Authorities](arbitrary-and-typed.md)
- [EVM Authorities](evm.md)
Expand Down
6 changes: 3 additions & 3 deletions docs/signing-and-authorities/authorities.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ policy:
allowedEnvironments: [production]
requiredRoles: [release-manager, production]
allowedCidrs: ["10.20.0.0/16", "fd00:20::/48"]
minimumReleaseVersion: "2.4.0"
minimumReleaseVersion: "2.4.1"
maximumRiskScore: "0.25"
minimumSequence: "10000000000000000000"
maximumWindowSeconds: 300
Expand Down Expand Up @@ -181,7 +181,7 @@ For a concrete authority, the sign command must reference an authority attached
"action": "deploy",
"service": "billing-api",
"environment": "production",
"releaseVersion": "2.4.0",
"releaseVersion": "2.4.1",
"sequence": 10000000000000000001,
"riskScore": 0.20,
"roles": ["release-manager", "production"],
Expand Down Expand Up @@ -239,7 +239,7 @@ Example effect:
"action": "deploy",
"service": "billing-api",
"environment": "production",
"version": "2.4.0",
"version": "2.4.1",
"sequence": 10000000000000000001
}
```
Expand Down
Loading