Skip to content

Configuration ​

For developers and operators tuning a deployment. This page is the single reference for the cosec.* properties the starter binds, and for the cocache.* properties that change how CoSec behaves; other pages name a property and link here for its type and default.

Every property is optional unless marked required. A property only acts when the module it configures is on the classpath: each integration is a module the application adds next to the starter (Modules). Durations take Spring's format (500ms, 10s, 7d), data sizes 16MB; sets and lists take a comma-separated value or a YAML list; enum values are case-insensitive. Properties that 7.x had and 8.0 does not are listed in Upgrading.

Unknown properties ​

Startup fails on a cosec.* key CoSec does not read, whatever else is configured (cosec.enabled=false included): a misspelled, renamed or removed key would otherwise do nothing. A key is known when the configuration metadata on the classpath (META-INF/spring-configuration-metadata.json) declares it, or when it lies under a map- or list-valued property. The message lists every unknown key and links the table of removed and renamed keys. No property turns this check off: a key prefix a release replaced, had it been ignored, would leave token revocations where nothing reads them.

Keys are compared as Spring's binder compares them, so every spelling it documents for a known key is known: local-max-age, localMaxAge or local_max_age in a properties file, and COSEC_AUTHORIZATION_SNAPSHOT_LOCALMAXAGE as an environment variable (upper case, dots as underscores, dashes dropped). A variable that is not that spelling of a key CoSec reads stays unknown, a typo (COSEC_PIPELINE_TIMEUOT) and the legacy COSEC_AUTHORIZATION_SNAPSHOT_LOCAL_MAX_AGE alike: the message names it as cosec.authorization.snapshot.local.max.age.

One thing is never an unknown key: the variables Kubernetes injects for a Service named cosec or cosec-* (service links), which Spring reads as cosec.* keys (COSEC_GATEWAY_SERVICE_HOST as cosec.gateway.service.host). The check skips exactly their shapes, matched on the variable names and only in the process environment, where <SVC> is COSEC or COSEC_<NAME>:

  • <SVC>_SERVICE_HOST, <SVC>_SERVICE_PORT and <SVC>_SERVICE_PORT_<PORT NAME>;
  • <SVC>_PORT, when the value is a tcp://, udp:// or sctp:// URL;
  • <SVC>_PORT_<port>_<TCP|UDP|SCTP> and the same with _PROTO, _PORT or _ADDR.

Every other COSEC_* variable is checked (COSEC_JWT_SECRT fails startup), and so is the same key in application.yaml, a system property or any other source. No CoSec property has one of these names, and a known key is never unknown whatever its source, so the exemption cannot hide a property CoSec reads. Setting enableServiceLinks: false on the pod keeps the variables out of the environment altogether (Troubleshooting).

Feature switches ​

PropertyTypeDefaultTurns on
cosec.enabledbooleantrueevery CoSec auto-configuration
cosec.authentication.login.enabledbooleantruethe login beans, which turn credentials into a token: CompositeAuthentication over your Authentication beans, TokenCompositeAuthentication with JWT, and social login. Authenticating requests in the pipeline does not depend on it
cosec.authentication.login.social.enabledbooleantruesocial login (cosec-social; needs cosec.authentication.login.enabled)
cosec.jwt.enabledbooleantrue; false with cosec.pipeline.mode=gatewayissuing, verifying and revoking JWTs. Off, the pipeline rejects every token (token-invalid) and treats a request without one as anonymous
cosec.api-key.enabledbooleanfalseAPI keys for machine clients. true or false only: any other value fails startup.
cosec.audit.enabledbooleantruethe audit log listener, and the Kafka audit listener with cosec.audit.kafka.enabled
cosec.audit.kafka.enabledbooleantruethe Kafka audit listener (cosec-kafka and a KafkaOperations bean)
cosec.metrics.enabledbooleantruethe metrics listener (cosec-micrometer and a MeterRegistry bean, Spring Boot's own auto-configured one included)
cosec.ip2region.enabledbooleantruethe ext.ip2region.* attribute provider (cosec-ip2region)
cosec.openapi.enabledbooleantruethe bearer-auth customizer of the OpenAPI document (cosec-openapi)
cosec.authorization.shadow.enabledbooleantruethis instance's part in shadow windows (cosec-cocache); see Shadow windows
cosec.gateway.identity.enabledbooleantrueon a Spring Cloud Gateway host, forwarding the verified identity to the services behind it; see Gateway identity

These have no switch:

  • Tracing is on whenever cosec-opentelemetry is on the classpath (Tracing).
  • The control plane is on whenever cosec-control and cosec-cocache are on the classpath; its routes need a WebFlux or WebMvc application (Control plane).
  • The rate limiter is always there: on Redis when a ReactiveStringRedisTemplate bean exists (cosec-cocache), otherwise counted per instance (Rate limiting).
  • Token revocation is always on with JWT (Startup).
  • The cosecServiceGenerator actuator endpoint is there whenever cosec-openapi, springdoc and Spring Boot Actuator are; expose it like any actuator endpoint.

Key prefix ​

Every key a deployment writes to Redis lives under one prefix (SNP-9): snapshot documents, control-plane records, shadow reports, revocations, memberships, API keys, rate limit counters and OAuth states (Redis keys). Two deployments on one Redis that use different prefixes share nothing. Within one application, CoCache refuses to create a cache whose storage keys would overlap another's, so a prefix that puts a CoSec cache under one of the application's own caches fails startup (Troubleshooting). It replaced cosec.authorization.snapshot.key-prefix, cosec.authorization.cache.key-prefix and cosec.api-key.key-prefix: an environment that sets one of them fails startup, as any key CoSec does not read does (Troubleshooting).

PropertyTypeDefaultEffect
cosec.key-prefixstringcosecThe prefix of every Redis key, with a trailing : removed. Every service of one deployment, its control plane and cosec-migrate --key-prefix use the same value. With the Redis rate limiter, a prefix whose first { is immediately followed by } (an empty hash tag) fails startup, and one with a hash tag of its own, such as {cosec}, puts every rate limit counter on one Redis Cluster slot (Rate limiting).

Pipeline ​

cosec.pipeline.*: how one request is read and bounded.

PropertyTypeDefaultEffect
cosec.pipeline.timeoutduration5sThe whole evaluation of one request. Past it the request is answered 503 unavailable.
cosec.pipeline.authentication-timeoutduration1sOne call of the Authenticator. Past it, 503.
cosec.pipeline.allow-query-tokenbooleanfalseAlso read the access token from the authorization query parameter. Off because URLs end up in access logs, browser history and Referer headers.
cosec.pipeline.allow-cookie-tokenbooleanfalseAlso read the access token from the authorization cookie. Off because a browser sends a cookie on its own, on a cross-site request too: turn it on only with your own CSRF defense (Authentication).
cosec.pipeline.api-key-headerstringX-API-KeyThe request header an API key comes in. No document may read it: every compiler of the host refuses a reference to it, as to the other credential headers (Headers).
cosec.pipeline.trace-leveloff, full, exhaustiveoffHow much of each evaluation the engine traces. Decision events carry the trace as evaluationTrace (null at off, and when the request did not reach the engine); a higher level costs time on every request.
cosec.pipeline.modeenforce, gatewayenforceenforce: the host decides with policies. gateway: a service behind a CoSec gateway reads the caller from the CoSec-Identity header the gateway forwards, and wires no authenticator, API keys, snapshot, policies, control plane or Redis of its own (Services behind the gateway). Any other value fails startup, and so does gateway on a Spring Cloud Gateway host. In gateway mode only the gateway may be able to reach the service: startup logs a WARN saying so. In gateway mode cosec.jwt.enabled defaults to false: a service that also issues tokens sets it to true.
cosec.pipeline.identity.max-ageduration60sIn gateway mode, an identity issued longer ago than this, plus cosec.authentication.revocation.skew, is refused: 401 token-expired.
cosec.pipeline.identity.max-sizedata size8KBIn gateway mode, a larger CoSec-Identity header is refused: 400 invalid-request.

Authorization ​

cosec.authorization.*: the host's scope and the per-stage timeouts.

PropertyTypeDefaultEffect
cosec.authorization.scope.app-idstringnoneThe app this host serves. A credential that declares another app, or none, is rejected (403 scope-rejected). Unset, the credential's app applies (Apps). On a gateway, a route's metadata cosec-app-id takes precedence for that route's requests (Gateway).
cosec.authorization.remote-ip.max-trusted-indexint1How many proxy hops of X-Forwarded-For to trust when resolving the client IP. 0 ignores the header (the host is exposed directly); N takes the entry the N-th closest proxy appended.
cosec.authorization.membership.timeoutduration500msOne call of the MembershipProvider. Past it, or when it fails, 503.
cosec.authorization.attributes.timeoutduration300msOne call of an AttributeProvider that sets no timeout of its own. Past it, its attributes are unavailable, and a statement that needs them makes the decision Indeterminate.
cosec.authorization.routes.locationcomma-separated resource locationsunsetThe route maps a WebFlux or WebMvc host loads at startup, each logged with its service and route count. A location that does not exist, a map that does not parse, or a map with no routes fails startup. Unset, no route map is loaded and every request is authorized in the http namespace, unless classpath:cosec-routes.json exists: startup then fails until the property names it or is set empty. Empty runs without a route map on purpose. A Spring Cloud Gateway host ignores it and loads no route map.

Gateway ​

cosec.gateway.*, on a Spring Cloud Gateway host (cosec-gateway) that decides with policies.

PropertyTypeDefaultEffect
cosec.gateway.unprotected-endpointsset of endpoint idsemptyActuator endpoints that may be exposed over HTTP on the gateway's application port, where CoSec does not authorize them, because something else protects them. Any other one but health fails startup there (STA-2); gateway, which changes routes, is never accepted. On a separate management.server.port any endpoint may be exposed (Actuator on a gateway).

Gateway identity ​

cosec.gateway.identity.*, on a Spring Cloud Gateway host (cosec-gateway): what the gateway forwards to the services behind it. On a permit with a principal it sets CoSec-Identity to the identity it verified (format: schema/cosec-identity.schema.json), on a route that receives it: a route to a registered service (lb://), or one with the metadata cosec-identity: true. A route with cosec-identity: false, or to any other URI without the metadata, receives no identity (Forwarding the identity). The gateway always removes a CoSec-Identity the client sent, whatever these properties, the mode or cosec.enabled say.

PropertyTypeDefaultEffect
cosec.gateway.identity.enabledbooleantrueForward the verified identity to the routes that receive it. Off, the gateway still strips the client's.
cosec.gateway.identity.claimsset of attribute namesemptyPrincipal attributes forwarded with the identity as claims, such as name and email (for a JWT, keys of its attributes claim, not top-level claims): strings of at most 1024 characters, numbers and booleans. Any other value fails the request (500).
cosec.gateway.identity.max-sizedata size8KBA larger encoded identity fails the request closed (500) rather than being cut.
cosec.gateway.identity.forward-authorizationbooleanfalseWhether the client's credentials still go downstream: the Authorization header, the API key header (cosec.pipeline.api-key-header), the authorization query parameter and the authorization cookie. Off, the gateway removes them from every request it forwards (the cookie from each Cookie header, other cookies kept): a service behind it needs none. On, they go only to the routes that would receive the identity (lb://, or cosec-identity: true), whether or not cosec.gateway.identity.enabled is on. Turn it on only for services that verify the token again or call other APIs on the user's behalf.

A credential that never expires (an API key without expires-at) cannot be forwarded: its permits are answered 500.

Rate limiting ​

PropertyTypeDefaultEffect
cosec.authorization.rate-limit.timeoutduration500msOne call of the RateLimiter. Past it, the rule's strictFailure decides: 503, or the rule is skipped.

Rate limit rules are part of the documents (Rate limiting). The limiter is ReactiveRedisRateLimiter when a ReactiveStringRedisTemplate bean exists, otherwise LocalRateLimiter, which counts per instance. The Redis counters have a fixed key prefix (Redis keys). A RateLimiter bean of your own replaces both.

Snapshot ​

cosec.authorization.snapshot.*: how an instance reads and holds the platform, app and tenant documents (How instances read documents).

PropertyTypeDefaultEffect
cosec.authorization.snapshot.local-max-ageduration30sHow long CoCache's local copy of a document may serve a cold load before Redis is asked again. It applies whatever a cache customizer or cocache.* property sets.
cosec.authorization.snapshot.revalidate-intervalduration10sHow often a pass starts that confirms every installed document against Redis with a conditional read; while a pass is still in flight, the next starts as soon as it ends, never overlapped. A change whose invalidation message was lost is installed by the first pass that reaches its document after the change is readable (SNP-6). At least 1s, at most 5m, less than lag-warn and, with fail-closed.tenants, less than fail-closed.max-lag; anything else fails startup. Each pass costs Redis a few microseconds per document, whatever its size (Storage).
cosec.authorization.snapshot.lag-warnduration60sA document not confirmed for longer is logged at WARN. Must not exceed lag-escalate.
cosec.authorization.snapshot.lag-escalateduration5mA document not confirmed for longer is logged at ERROR as stale.
cosec.authorization.snapshot.fail-closed.tenantsset of tenant idsemptyTenants that must not be decided on old documents: when the oldest document a request of such a tenant reads was confirmed longer ago than max-lag, the request is 503 (SourceUnavailable) unless a DENY matches. Other tenants keep deciding on what is installed.
cosec.authorization.snapshot.fail-closed.max-lagduration30mThe lag beyond which the tenants above fail closed.
cosec.authorization.snapshot.cold-load-timeoutduration2sHow long a request waits for a document that is not installed. Past it the document counts as failed for that request.
cosec.authorization.snapshot.max-appsint1024The most app documents held in memory; the least recently used one is dropped beyond it, and loaded again when needed.
cosec.authorization.snapshot.max-tenantsint1024The same for tenant documents. The platform document is never dropped.
cosec.authorization.snapshot.prewarm-appslist of app idsemptyApp documents loaded at startup, after the platform document, which is always loaded. Readiness refuses traffic until the platform document and every listed document are installed; liveness is not affected.
cosec.authorization.snapshot.prewarm-tenantslist of tenant idsemptyTenant documents loaded at startup, as above.
cosec.authorization.snapshot.compile-threadsint2Threads that compile documents.
cosec.authorization.snapshot.eviction-checkfail, warnfailWhat startup does when Redis' maxmemory-policy is not noeviction on every node, or cannot be read (a failed or denied INFO memory, a wrapped or custom CoCache backend). fail stops startup. warn starts and logs a WARN that begins with !!! (Redis requirements). The in-memory CoCache backend always passes. Either way the instance reads the policy again every revalidate-interval, and the cosecSnapshotEviction health indicator is DOWN while Redis may evict; a policy it cannot read is DOWN under fail and UP with eviction: unknown under warn (Troubleshooting).

Shadow windows ​

cosec.authorization.shadow.*: the data plane's part in the control plane's shadow windows. It needs cosec-cocache. How windows work: Testing changes.

PropertyTypeDefaultEffect
cosec.authorization.shadow.enabledbooleantrueEvaluate sampled requests again on the staged candidates, and write this instance's reports and status to Redis. Off, this instance's traffic counts for nothing in a window, a candidate it cannot compile does not block one, and it writes no status for the propagation view.
cosec.authorization.shadow.sample-ratedouble, 0 to 10.1Share of requests evaluated again on the candidates, off the request path.
cosec.authorization.shadow.report-intervalduration10sHow often the instance writes its reports and its status.
cosec.authorization.shadow.instance-idstringa random UUIDThis instance's id in reports and statuses. Unique per running instance; only letters, digits, ., _ and -, since it ends a Redis key. Any other id fails startup.

Authentication ​

PropertyTypeDefaultEffect
cosec.authentication.revocation.skewduration5sHow much later than a subject revocation a token may have been issued and still be revoked by it: room for an issuer whose clock runs ahead.

JWT ​

PropertyTypeDefaultEffect
cosec.jwt.secretstringnoneRequired while JWT is enabled; startup fails when it is blank or shorter than the algorithm needs: 32 bytes (UTF-8) for hmac256, 48 for hmac384, 64 for hmac512 (RFC 7518 §3.2). Use a long random value from a secret store.
cosec.jwt.algorithmhmac256, hmac384, hmac512hmac256Signing algorithm. Issuers and verifiers must agree.
cosec.jwt.token-validity.accessduration10mAccess token lifetime.
cosec.jwt.token-validity.refreshduration7dRefresh token lifetime; a revocation is kept in Redis this long, plus one second.

With JWT enabled, startup fails unless revocations can be recorded and read: cosec-cocache, or a TokenStore and a RevocationReader bean of your own.

API keys ​

PropertyTypeDefaultEffect
cosec.api-key.storememory, redismemorymemory: the keys configured below. redis: keys shared by every instance, under <cosec.key-prefix>:api-key; needs cosec-cocache, a StringRedisTemplate and a ReactiveStringRedisTemplate.
cosec.api-key.keys[n].*listemptyKeys of the memory store; ignored with redis.

The header is cosec.pipeline.api-key-header. API keys need a MembershipProvider bean, or the application does not start (IDN-6, API keys). Each entry of cosec.api-key.keys, where any other field fails startup:

FieldTypeDefaultMeaning
idstringnoneRequired. The key's id; ids must be unique.
hashstringnoneRequired. SHA-256 of the key, 64 lowercase hex characters. Never configure the key itself.
principal-idstringnoneRequired. The principal the key authenticates as.
tenant-idstringnoneRequired. Tenant of the principal.
appstringnoneThe app the key belongs to (Apps). Left out, it declares none, and a host with an app refuses it.
rolessetnoneThe cap: the key holds only these of its principal's roles (role, role@space), and no attached policy or principal binding; [] leaves only what Anyone bindings give. Set this or uncapped.
uncappedbooleanfalsetrue for a key that holds everything its principal holds. Exactly one of roles and uncapped: true is set, or the application does not start.
expires-atinstantnoneAfter this instant the key is rejected.
enabledbooleantrueA disabled key is rejected.

Cache ​

cosec.authentication.revocation.cache.*: the revoked token and revoked subject caches, created with JWT and cosec-cocache. Snapshot documents have their own properties (Snapshot).

PropertyTypeDefaultEffect
cosec.authentication.revocation.cache.*local cache settingslocal-max-age: 30s, maximum-size: 100000Local copy of revocation lookups (RevokedTokenCache and RevokedSubjectCache).

Local cache settings ​

PropertyTypeDefaultEffect
maximum-sizelong100000Maximum entries in the local copy.
initial-capacityintCoCache'sInitial capacity of the local copy.
local-max-ageduration (a bare number is seconds)30sHow long a local copy lives at most: the bound on staleness when an invalidation message is lost.
expire-after-accessduration (a bare number is seconds)noneDrop a local copy not read for this long.

These size and age the local copy only. A revocation's lifetime in Redis is set when it is written.

Audit ​

PropertyTypeDefaultEffect
cosec.audit.kafka.topicstringcosec-auditKafka topic of the audit events.
cosec.audit.kafka.deliverybest-effort, requiredbest-effortHow the Kafka audit listener is delivered. required waits for the broker's acknowledgement, so a permit that cannot be audited is a 503; configure the producer with acks=all. Startup fails when it is required without cosec-kafka (STA-1).

Decision listeners ​

cosec.observability.listener.*: the time a REQUIRED decision listener has, and the queues of the BEST_EFFORT ones (Decision listeners).

PropertyTypeDefaultEffect
cosec.observability.listener.required-timeoutduration1sHow long one REQUIRED decision listener may take. A failure or timeout turns a permit into 503.
cosec.observability.listener.queue-capacityint1024Events one BEST_EFFORT listener may have waiting. A full queue drops the next event and counts it (cosec.listener.dropped).
cosec.observability.listener.drain-timeoutduration5sOn shutdown, how long queued events still go out; the rest is then dropped. The Kafka audit listener gets as long again for the sends it still holds.

Control plane ​

cosec.control.*, with cosec-control and cosec-cocache (Publishing documents).

The control plane checks every approver for revocation as the pipeline reads it: startup fails without a RevocationReader bean or CoSec's tokens with cosec-cocache. Declare RevocationReader.NONE only when no approver's credential is ever revoked.

PropertyTypeDefaultEffect
cosec.control.app-idstringcosec-controlThe app control-plane actions are authorized in.
cosec.control.http.base-pathstring/cosec/controlWhere the control API is served. Its routes are under {base-path}/v1, so moving the API keeps the version.
cosec.control.http.max-body-sizedata size16MBThe largest request body the control API reads on a WebMvc host. A larger body is a 400 invalid-request, unread. On WebFlux, spring.codec.max-in-memory-size (256 KB by default) bounds the body instead. On either stack, a request without a permitted principal has no body read at all (401).
cosec.control.revisions.max-countint50Revisions always kept per document; older ones are reclaimed once also older than min-age. Revisions an open change rests on are kept.
cosec.control.revisions.min-ageduration7dRevisions younger than this are always kept.
cosec.control.revisions.orphan-ageduration1hRecords of conflicted publishes are removed once this old.
cosec.control.revisions.reclaim-intervalduration1hHow often each control-plane instance reclaims revisions; a lease lets one instance at a time do each document. Must be positive.
cosec.control.changes.expire-afterduration7dAn open change request expires this long after it was proposed, and leaves the list of open changes.
cosec.control.approval.expire-afterduration72hHow long an approval stays valid. Startup fails when it is longer than cosec.jwt.token-validity.refresh, how long a token revocation is kept: an approval would outlive the revocation of its token.
cosec.control.approval.four-eyesbooleanfalseWhether the changes of a platform principal holding cosec:approve on the document (the trust root) are analyzed too: what the analysis cannot prove contained then needs another platform principal's approval. A change that escalates needs one either way.
cosec.control.break-glass.max-durationduration4hThe longest a break-glass binding may last. More than 24h fails startup.
cosec.control.shadow.min-durationduration15mA shadow window closes no earlier than this, once it also has min-samples.
cosec.control.shadow.min-sampleslong1000Compared samples a window needs to close before max-duration.
cosec.control.shadow.max-durationduration24hA window closes at this age with fewer samples, as insufficient evidence the publisher must acknowledge. Must not be less than min-duration.
cosec.control.shadow.check-intervalduration1mHow often shadowing changes are looked at, by one instance at a time; a window closes up to this late. Must be positive.
cosec.control.audit.required-timeoutduration5sHow long every REQUIRED change listener together may take to record a gated step (publish, break-glass) before the step fails with 503.
cosec.control.audit.kafka.enabledbooleantrueThe Kafka change listener (cosec-kafka and a KafkaOperations bean).
cosec.control.audit.kafka.topicstringcosec-control-auditKafka topic of the change events.
cosec.control.audit.kafka.deliverybest-effort, requiredbest-effortrequired makes publishing and break-glass wait for the broker. Startup fails when it is required and no Kafka change listener could be created.

Ids ​

cosec.cosid.*, with cosec-cosid and an application on CosId 5 (Ids).

PropertyTypeDefaultEffect
cosec.cosid.generatorstringdefaultThe CosId generator whose ids CoSec takes, with its codec: request, decision event, token and change ids. A generator whose ids are not 1 to 64 characters of A-Z a-z 0-9 . _ - fails startup. Set without cosec-cosid, startup fails and names it (Troubleshooting).

Social login ​

cosec.authentication.login.social.registration.<name>.* configures one OAuth provider per <name>:

yaml
cosec:
  authentication:
    login:
      social:
        registration:
          github:
            type: github           # a JustAuth AuthDefaultSource
            client-id: ${GITHUB_CLIENT_ID}
            client-secret: ${GITHUB_CLIENT_SECRET}
            redirect-uri: https://app.example.com/oauth/github/callback

type (a JustAuth AuthDefaultSource) and client-id are required. The other fields map one-to-one to JustAuth's AuthConfig: client-secret, redirect-uri, alipay-public-key, union-id, stack-overflow-key, agent-id, usertype, domain-prefix, http-config, ignore-check-state, scopes, device-id, client-os-type, pack-id, pkce, auth-server-id, ignore-check-redirect-uri, tenant-id, kid, team-id, login-type (default CorpApp), lang (default zh), ding-talk-org-type, ding-talk-corp-id, ding-talk-exclusive-login and ding-talk-exclusive-corp-id. Booleans default to false, the others to none. Social login keeps its OAuth state in Redis through a StringRedisTemplate.

CoCache properties that affect CoSec ​

With cosec-cocache, CoSec creates its caches through CoCache 8's CoCacheFactory, so CoCache's configuration layers reach them like any other cache. The full list of CoCache properties is in CoCache's documentation. Every CoCache duration needs a unit (2s, 10m); a bare number fails startup.

PropertyEffect on CoSec
cocache.backendredis (default) or memory. With memory nothing is shared between instances, the eviction checks pass, and every instance starts with no documents: local development and tests only.
cocache.defaults.cache.*, cocache.defaults.store.*Fill only what a cache's declaration leaves unwritten. CoSec's caches declare what they depend on, so these change little: MembershipCache is a cache, every other CoSec cache a store (Precedence).
cocache.overrides.cache.*, cocache.overrides.store.*Tighten staleness bounds (local-max-age, absent-ttl) and read-failure over every cache, except for the fields CoSec locks.
cocache.caches.[<CacheName>].*The policy of one cache, by the names above. Setting a field CoSec locks fails startup (Precedence). So does a key CoCache does not know or that does not apply to that cache, usually a typo, unless cocache.caches-validation: warn (Troubleshooting). CoSec publishes the name of every cache it may create, so an entry for one this instance does not create (a control-plane cache on a service without the control plane, MembershipCache without a MembershipLoader, a revocation table with JWT off) starts.
cocache.key-prefixNone: CoSec locks its own prefix, cosec.key-prefix.
cocache.redis.command-timeoutHow long one Redis command may take (2s by default). A snapshot read that times out is a failed read (When Redis is unavailable).
cocache.redis.channel-modepubsub or sharded invalidation. Every instance, and the control plane, must agree.
cocache.redis.assume-maxmemory-policyThe policy CoCache's own eviction check assumes when INFO memory cannot be read. CoCache refuses to start with allkeys-*, or with an unreadable policy and this unset, because CoSec's documents and records are Stores; cosec.authorization.snapshot.eviction-check=warn does not change that (Redis requirements).
cocache.redis.store-eviction-checkWhat CoCache does with a volatile-* policy and a Store whose policy has a finite ttl (the shadow caches): warn (default), fail or off. It counts the revocation tables too, whose entries carry a lifetime of their own, but only once the instance has written or read one, so not at startup; CoSec's own check refuses every policy but noeviction from the start (Redis requirements).
cocache.redis.store-eviction-check-intervalHow often CoCache reads the policy again, for its log and its storeEviction health detail. CoSec reads it again every revalidate-interval on its own, for cosecSnapshotEviction.
spring.data.redis.*The Redis CoCache connects to, and the one the rate limiter and the Redis API key store use.

The control plane's caches and the shadow caches are created with the same locks as the snapshot store, so the same configuration rules apply to them.

Precedence ​

Every CoSec cache is assembled by CoCache's layers, field by field; a later step wins over an earlier one:

  1. CoCache's type default (store: no ttl, local-max-age 30 s; cache: ttl 1 h);
  2. cocache.defaults.cache.* or cocache.defaults.store.*, for the fields CoSec's declaration leaves unwritten;
  3. CoSec's declaration: cosec.authorization.snapshot.local-max-age for the snapshot store, cosec.authentication.revocation.cache.* and unknown-read: absent for the revocation tables (a failed read answers "not revoked"; unknown-read: throw in step 6 makes the revocation check fail closed with 503 instead);
  4. the application's CoCache CacheSpecCustomizer beans;
  5. cocache.overrides.*, which only tighten;
  6. cocache.caches.[<CacheName>].*;
  7. CoSec's constraints, applied last, after unlock too.

A value CoSec declares wins over cocache.defaults.* whatever it is, one equal to CoCache's own default (a maximum-size of 10000) included. So a cocache.caches.[<CacheName>].* property wins over the matching cosec.authentication.revocation.cache.* one. CoSec locks some fields (CoCache's lock): the global layers skip them, a cocache.caches entry that sets one fails startup (unless the entry lists it in unlock, CoCache's break glass), and a customizer that changes one throws. Some are also constrained (step 7), so even unlock cannot change them:

CacheLockedConstrainedWhy
PolicySnapshotCache and the control plane's and shadow window's stores of record (RevisionRecordCache, RevisionIndexCache, ReferenceIndexCache, ControlLeaseCache, ControlListCache, ControlAppListCache, ChangeRequestCache, StageCache, CandidateCache)ttl, unknown-read; the snapshot store also local-max-agettl never expires, unknown-read: throwRedis is the store of record (Storage): an expiry or a failed read taken for "absent" would silently drop a document, and with it its DENY statements. As CoCache Stores, they never reclaim content they cannot read, and a failed delete throws instead of being retried later, when it could delete a newer write.
ShadowReportCache, ShadowReporterCache, InstanceStatusCache, InstanceIndexCacheunknown-read, ttlunknown-read: throw; ttl the declared 8 days (reports, reporters) or 2 minutes (statuses; the list of instances keeps the 8 days)An outage must not read as "no samples" or "no instance", and an instance's samples must not expire from a window it reported in.
MembershipCacheread-failure, unknown-readttl finite (one minute when forever), ttl-jitter: 0s, read-failure and unknown-read: throwA failed read must never become "no memberships", and a lost invalidation must expire.
RevokedTokenCache, RevokedSubjectCacheread-timeoutread-timeout: the store's command timeoutAs Stores they never reclaim an unreadable revocation, which would make its tokens valid again. A read that times out reads "not revoked" (unknown-read: absent), so no layer, cocache.defaults.store.read-timeout included, may time it out sooner.
every CoSec cachekey prefix, namespace, key encoder, codec, key filter, ttl function, data source—The storage layout is CoSec's, where every instance and the control plane look for it.

Next: where the documents live and how instances read them, in Storage and caching.

Licensed under the Apache License, Version 2.0.