You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Problem Result caching is currently forced off when OBO (user-delegated-auth) or MSSQL set-session-context is enabled: - OBO: config validation requires runtime.cache.enabled = false - Session-context: CanUseCache() returns false so the cache is never used That is safe but overly conservative. The database identity is already isolated per request, yet operators must choose between per-user authorization and caching (or run dual instances). Database policies (@claims.*) also cause many read paths to skip the cache even when caching is otherwise enabled. ## Proposal Partition result-cache keys by an authorization-context fingerprint so cached results cannot cross security boundaries: text ResultCacheKey = QueryFingerprint + auth:{Fingerprint} + v:{EntityVersion} - Fingerprint inputs: client role (X-MS-API-ROLE), subject (oid / sub), tenant (tid), and either policy-referenced claims (when static analysis is complete) or the full non-volatile principal (session-context / incomplete analysis). - Fail-closed: if the fingerprint cannot be computed, that request skips cache get and set. - Mutations: bump a per-entity version token so all auth partitions miss after a write (same process). - Non-isolated entities: keep the existing key shape (no auth: segment). ## Security invariant Share a cache entry only when every result-affecting security input matches. The previous ΓÇ£disable cache under OBO/session-contextΓÇ¥ rule is replaced by explicit isolation, not by weakening isolation. ## Scope (v1) - SQL query path (REST + GraphQL via SqlQueryEngine) - OBO and set-session-context are MSSQL features; other engines keep current semantics aside from the shared entity-version segment when an entity name is supplied - Opt-in via existing runtime.cache.enabled / entity cache settings (defaults unchanged) ## Proposed v1 decisions (for maintainer alignment) | Open question | Proposed v1 answer | | :--- | :--- | | Multi-instance / L2 Redis invalidation | Process-local entity version + TTL. Document that cross-replica staleness is bounded by cache TTL. Shared Redis version key is a follow-up when L2 is configured. | | @claims.* static analysis | Regex extractor at config load for @claims.<name> in database policy strings. Richer policy AST analyzer only if review finds gaps. | | Observability | Logging only in v1 (e.g. fail-closed at Warning). Metrics for isolated hit/miss / fail-closed as a follow-up. | ### Multi-instance wording (proposed for the design contract) > Multi-instance invalidation: Entity version counters are process-local in the initial design. Cross-replica staleness is bounded by cache TTL. A follow-up can move the version token into L2 (Redis) when distributed cache is enabled (INCR on mutation, include value in the key on read), preserving the same key shape and fail-closed behavior without requiring per-partition eviction. ## Validation status (prototype) - Unit coverage for fingerprint isolation, fail-closed, claim analysis, and config validation - Live Entra OBO + cache smoke on MSSQL - Full multi-engine CI and a dedicated TestServer JWT suite remain follow-ups Feedback on the isolation model and the multi-instance invalidation approach would be especially useful before an implementation PR.
Problem Result caching is currently forced off when OBO (
user-delegated-auth) or MSSQLset-session-contextis enabled: - OBO: config validation requiresruntime.cache.enabled = false- Session-context:CanUseCache()returns false so the cache is never used That is safe but overly conservative. The database identity is already isolated per request, yet operators must choose between per-user authorization and caching (or run dual instances). Database policies (@claims.*) also cause many read paths to skip the cache even when caching is otherwise enabled. ## Proposal Partition result-cache keys by an authorization-context fingerprint so cached results cannot cross security boundaries:text ResultCacheKey = QueryFingerprint + auth:{Fingerprint} + v:{EntityVersion}- Fingerprint inputs: client role (X-MS-API-ROLE), subject (oid/sub), tenant (tid), and either policy-referenced claims (when static analysis is complete) or the full non-volatile principal (session-context / incomplete analysis). - Fail-closed: if the fingerprint cannot be computed, that request skips cache get and set. - Mutations: bump a per-entity version token so all auth partitions miss after a write (same process). - Non-isolated entities: keep the existing key shape (noauth:segment). ## Security invariant Share a cache entry only when every result-affecting security input matches. The previous ΓÇ£disable cache under OBO/session-contextΓÇ¥ rule is replaced by explicit isolation, not by weakening isolation. ## Scope (v1) - SQL query path (REST + GraphQL viaSqlQueryEngine) - OBO andset-session-contextare MSSQL features; other engines keep current semantics aside from the shared entity-version segment when an entity name is supplied - Opt-in via existingruntime.cache.enabled/ entity cache settings (defaults unchanged) ## Proposed v1 decisions (for maintainer alignment) | Open question | Proposed v1 answer | | :--- | :--- | | Multi-instance / L2 Redis invalidation | Process-local entity version + TTL. Document that cross-replica staleness is bounded by cache TTL. Shared Redis version key is a follow-up when L2 is configured. | |@claims.*static analysis | Regex extractor at config load for@claims.<name>in database policy strings. Richer policy AST analyzer only if review finds gaps. | | Observability | Logging only in v1 (e.g. fail-closed at Warning). Metrics for isolated hit/miss / fail-closed as a follow-up. | ### Multi-instance wording (proposed for the design contract) > Multi-instance invalidation: Entity version counters are process-local in the initial design. Cross-replica staleness is bounded by cache TTL. A follow-up can move the version token into L2 (Redis) when distributed cache is enabled (INCRon mutation, include value in the key on read), preserving the same key shape and fail-closed behavior without requiring per-partition eviction. ## Validation status (prototype) - Unit coverage for fingerprint isolation, fail-closed, claim analysis, and config validation - Live Entra OBO + cache smoke on MSSQL - Full multi-engine CI and a dedicated TestServer JWT suite remain follow-ups Feedback on the isolation model and the multi-instance invalidation approach would be especially useful before an implementation PR.