Skip to content

Make TPM dirstore cache size configurable - #1070

Merged
hslatman merged 5 commits into
masterfrom
diego/eff-89-dirstore-cache-option
Jul 14, 2026
Merged

hslatman merged 5 commits into
masterfrom
diego/eff-89-dirstore-cache-option

Conversation

@darkfronza

Copy link
Copy Markdown
Contributor

Summary

NewDirstore hardcoded the diskv in-memory read cache at 1 MiB. Because a store handle serves a key/AK blob from that cache after its first read, a handle keeps returning a blob even after a separate handle deletes it from the backing directory. Callers that mutate the directory out of band therefore have to rebuild their store handle to observe the change.

This adds a way to disable (or size) that cache.

Changes

  • tpm/storage: NewDirstore(directory string, opts ...DirstoreOption) is now variadic (backward compatible; existing callers keep the 1 MiB default). New WithCacheSize(bytes uint64) option; 0 disables caching so every read reflects current on-disk state.
  • kms/tpmkms: thread the setting through the storage-cache-size URI parameter, parsed in both ParseTPMOptions and New. New now parses the URI before constructing the default store, so the setting is honored regardless of whether the storage directory comes from the URI or apiv1.Options.StorageDirectory.

Motivation

The smallstep agent hit this on Windows: it recovers from an "orphaned AK" (blob present, backing PCP/CNG key deleted) by deleting the stale blob and letting the KMS recreate the AK. Its probe TPM handle had already cached the dead blob, forcing a handle rebuild after deletion. With storage-cache-size=0 the probe handle reflects the deletion directly and the rebuild goes away. (Loading a key into the TPM dwarfs a blob read from disk, so caching that read buys little here.)

Testing

  • TestNewDirstore_cacheSize — default / custom / disabled map to the right CacheSizeMax.
  • TestDirstore_noCacheReflectsOutOfBandDelete — a cached store serves a stale blob after an out-of-band delete; an uncached store reflects the delete.
  • TestParseDirstoreOptions — URIs (nil, absent, =0, =4096, negative) thread through to the expected cache behavior via the public store API.

🤖 Generated with Claude Code

NewDirstore hardcoded the diskv in-memory read cache at 1 MiB, so a store
handle would keep serving a key/AK blob it had already read even after a
separate handle deleted that blob out from under it. This forces callers
that mutate the backing directory out of band to rebuild their store
handle to observe the change.

Add a WithCacheSize functional option to NewDirstore (the constructor is
now variadic and backward compatible; the default stays 1 MiB). Setting
it to 0 disables caching entirely so every read reflects the current
on-disk state.

Thread it through tpmkms via the storage-cache-size URI parameter, parsed
in both ParseTPMOptions and New so the default and URI-provided stores
both honor it. New now parses the URI before constructing the default
store so the setting applies regardless of where the storage directory
comes from.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@darkfronza
darkfronza force-pushed the diego/eff-89-dirstore-cache-option branch from 4cab1ed to d017c2b Compare July 7, 2026 17:06
Comment thread kms/tpmkms/tpmkms_test.go Resolved
Per review: a negative storage-cache-size now clamps to 0 (cache
disabled) rather than being ignored and silently falling back to the
default cache, which is less surprising for the caller.

Change-Type: patch
Release-Note: no
Audience: developer
Impact: none
Breaking: false
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread kms/tpmkms/tpmkms.go Resolved
darkfronza and others added 2 commits July 7, 2026 19:19
Per review: verify New resolves the correct storage directory and cache
size. Extract the directory-precedence and dirstore-options logic New uses
into resolveStorageDirectory (URI storage-directory > opts.StorageDirectory
> default "tpm"), which also removes the previous "two WithStore, last
wins" construction. Add TestResolveStorageDirectory covering the directory
precedence and cache-size threading, and factor the shared test helpers
(parseTestURI, assertCacheDisabled).

Change-Type: patch
Release-Note: no
Audience: developer
Impact: none
Breaking: false
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
TestResolveStorageDirectory only covered the helper. Add
TestNew_storeConstruction, which drives New and asserts the storage
directory and exact cache size the backing dirstore is built with, via a
newDirstore test seam. Add storage.Dirstore.CacheSize() so the cache
budget is observable.

Change-Type: patch
Release-Note: no
Audience: developer
Impact: none
Breaking: false
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread kms/tpmkms/tpmkms.go Resolved
Comment thread kms/tpmkms/tpmkms.go Resolved
New previously replicated ParseTPMOptions' device + store-from-URI logic
(via resolveStorageDirectory plus inline device handling). Consolidate
both into a single tpmOptionsForURI(u, defaultStorageDirectory) builder:
ParseTPMOptions delegates with an empty default, New with its resolved
storage directory (opts.StorageDirectory, else "tpm"; a URI
storage-directory still wins). The store is built through the newDirstore
seam, and storage-cache-size threads through parseDirstoreOptions in that
one place.

Drop TestResolveStorageDirectory (the helper is gone) and fold its
default-directory case into TestNew_storeConstruction, which already
drives New end to end.

Change-Type: patch
Release-Note: no
Audience: developer
Impact: none
Breaking: false
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hslatman hslatman changed the title tpm/storage: make dirstore cache size configurable Make TPM dirstore cache size configurable Jul 14, 2026
@hslatman
hslatman merged commit b9dd702 into master Jul 14, 2026
12 checks passed
@hslatman
hslatman deleted the diego/eff-89-dirstore-cache-option branch July 14, 2026 13:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants