envoyproxy / envoyproxy/envoy

Proposal: Cache-enable Envoy External Authentication HTTP Filter

Open
#44,852 30 comments 0 reactions 1 assignee Claimed by @toddmgreer View on GitHub
design proposal enhancement no stalebot
Dominant language
C++
Stars
28.9k
Forks
5.6k
Avg merge
1d 20h
Merged PRs (30d)
428

Description

# Proposal: Pluggable Caching for Envoy External Authentication Filter via TypedExtensionConfig

## **Background**

We want to support caching of authorization responses in the `ext_authz` filter to reduce latency and load on external authorization services. We will enable this by adding a caching extension point to delegate caching to a dedicated caching implementation while remaining agnostic to the underlying cache configuration, policies, and storage (e.g., in-memory, Redis, Memcached).

This design works for both HTTP and gRPC versions of the filter.

## **Configuration Change**

We will add a new field to the `ExtAuthz` configuration message in `api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto`:

```protobuf
import "envoy/config/core/v3/extension.proto";

// ...

message ExtAuthz {
// ...

// Optional configuration for a cache extension. If specified, the filter will
// attempt to lookup and populate the cache for authorization requests.
// The extension must implement the "envoy.filters.http.ext_authz.cache" interface.
envoy.config.core.v3.TypedExtensionConfig cache = 33;
}
```

## **Cache Extension Interface**

We will define a new extension category `envoy.filters.http.ext_authz.cache` and a corresponding C++ interface that caching extensions will implement.

```cpp
namespace Envoy {
namespace Extensions {
namespace HttpFilters {
namespace ExtAuthz {

class AuthCache {
public:
virtual ~AuthCache() = default;

using LookupCallback = std::function;

/**
* Performs an asynchronous lookup in the cache.
* @param request The HTTP request attributes.
* @param cb The callback to invoke when the lookup completes.
* @param parent_span The parent span for tracing.
* @param stream_info The stream info.
*/
virtual void lookup(const envoy::service::auth::v3::CheckRequest& request,
LookupCallback&& cb,
Tracing::Span& parent_span,
const StreamInfo::StreamInfo& stream_info) = 0;

/**
* Inserts a response into the cache. The key is constructed from the request headers previously passed to `lookup`.
* @param response The Response received from the authz service.
* @param parent_span The parent span for tracing.
* @param stream_info The stream info.
*/
virtual void insert(const Filters::Common::ExtAuthz::Response& response,
Tracing::Span& parent_span,
const StreamInfo::StreamInfo& stream_info) = 0;

/**
* Called when the filter is being destroyed. The cache implementation should
* abort any in-progress asynchronous operations before returning.
*/
virtual void onDestroy() = 0;
};

} // namespace ExtAuthz
} // namespace HttpFilters
} // namespace Extensions
} // namespace Envoy
```

## **Filter Behavioral Changes**

When `cache` is configured, the `ext_authz` filter behavior changes as follows:

1. **Request Path (`Filter::initiateCall`):**
* Before creating and using an `ExtAuthz::Client`, the filter calls `AuthCache::lookup`, then stops decoding (returns `StopIteration` or `StopAllIterationAndWatermark`) while waiting for the cache lookup callback.

2. **Cache Lookup Callback (`onCacheLookupComplete`):**
* If ResponsePtr is null, it's a **Cache Miss**:
* The filter continues with the existing flow.
* If ResponsePtr is not null, it's a **Cache Hit**:
* The filter uses the returned response as if it came directly from the authz service, and does not call the authz service.

3. **External Call Completion (`Filter::onComplete`):**
* When the external call completes successfully, the filter calls `AuthCache::insert`, then processes the response and continues/stops the filter chain as usual.

## **Alternatives Considered**

### **Dynamic Metadata (Previous Proposal)**
Previous versions of this proposal suggested using dynamic metadata to decouple `ext_authz` from a caching filter (e.g. an `ext_proc` based cache). However, this has the drawback that gRPC does not support dynamic metadata, and `ext_authz` is intended to be potable across xDS implementations.

Cache implementations can still use this mechanism (if they don't require portability to gRPC data plane xDS implementations), but that is beyond the scope of this proposal.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.