redis_proxy: add support for external authentication (#35643)

resolves #35673

## PR overview

Redis proxy users may want to create advanced authentication methods.
For example, the official [Azure SDK extension for
Redis](https://github.com/Azure/Microsoft.Azure.StackExchangeRedis)
allows to authenticate to a Redis server using Microsoft Entra ID
token-based authentication, by passing a token in the password argument
of the `AUTH` command periodically, based on token expiration.
This PR introduces a way to support external authentication via a gRPC
service with additional support for expiry of such authentication (e.g.
for token-based authentication).
This way we keep it extensible for **any** advanced authentication
methods users might want to develop.

### The reviewer may ask: Why not use the _ext_authz_ filter?
The cost/latency impact by using the _ext_authz_ filter is much bigger
than the proposed design. That's because instead of being called on
every request, the current design only calls the external dependency on
**AUTH** commands. Not only that, but also we would have to decode the
Redis protocol twice, if we used a separate filter.

---

Risk Level: Medium (small optional feature added to existing filter)

Testing:  
- Unit Tests
- Integration Tests
- Manual Testing

![image](https://github.com/user-attachments/assets/3caab358-7c37-446d-8e12-bff9c1442948)
- Also, we are already using the signed _-dev_ build on a test AKS
cluster

Docs Changes: 

- Proto docs

![image](https://github.com/user-attachments/assets/1432114f-ff93-431a-90ad-1c1262989e8c)

- Updated authentication-related information on the Redis protocol page.

Release Notes: 

---------

Signed-off-by: Diogo Barbosa <diogobarbosa@microsoft.com>
Signed-off-by: Diogo Barbosa <pessoal.dbarbosa@gmail.com>

Mirrored from https://github.com/envoyproxy/envoy @ 67b69c9038402b88953a2ab171ae38cab5cb23ab
main
update-envoy[bot] 3 months ago
parent 21ad0c113a
commit 1de17b0b24
  1. 1
      BUILD
  2. 31
      envoy/extensions/filters/network/redis_proxy/v3/redis_proxy.proto
  3. 10
      envoy/service/redis_auth/v3/BUILD
  4. 47
      envoy/service/redis_auth/v3/redis_external_auth.proto
  5. 1
      versioning/BUILD

@ -360,6 +360,7 @@ proto_library(
"//envoy/service/metrics/v3:pkg",
"//envoy/service/rate_limit_quota/v3:pkg",
"//envoy/service/ratelimit/v3:pkg",
"//envoy/service/redis_auth/v3:pkg",
"//envoy/service/route/v3:pkg",
"//envoy/service/runtime/v3:pkg",
"//envoy/service/secret/v3:pkg",

@ -3,6 +3,7 @@ syntax = "proto3";
package envoy.extensions.filters.network.redis_proxy.v3;
import "envoy/config/core/v3/base.proto";
import "envoy/config/core/v3/grpc_service.proto";
import "envoy/extensions/common/dynamic_forward_proxy/v3/dns_cache.proto";
import "google/protobuf/duration.proto";
@ -25,7 +26,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// Redis Proxy :ref:`configuration overview <config_network_filters_redis_proxy>`.
// [#extension: envoy.filters.network.redis_proxy]
// [#next-free-field: 10]
// [#next-free-field: 11]
message RedisProxy {
option (udpa.annotations.versioning).previous_message_type =
"envoy.config.filter.network.redis_proxy.v2.RedisProxy";
@ -353,6 +354,15 @@ message RedisProxy {
// client. If an AUTH command is received when the password is not set, then an "ERR Client sent
// AUTH, but no ACL is set" error will be returned.
config.core.v3.DataSource downstream_auth_username = 7 [(udpa.annotations.sensitive) = true];
// External authentication configuration. If set, instead of validating username and password against ``downstream_auth_username`` and ``downstream_auth_password``,
// the filter will call an external gRPC service to authenticate the client.
// A typical usage of this feature is for situations where the password is a one-time token that needs to be validated against a remote service, like a sidecar.
// Expiration is also supported, which will disable any further commands from the client after the expiration time, unless a new AUTH command is received and the external auth service returns a new expiration time.
// If the external auth service returns an error, authentication is considered failed.
// If this setting is set together with ``downstream_auth_username`` and ``downstream_auth_password``, the external auth service will be source of truth, but those fields will still be used for downstream authentication to the cluster.
// The API is defined by :ref:`RedisProxyExternalAuthRequest <envoy_v3_api_msg_service.redis_auth.v3.RedisProxyExternalAuthRequest>`.
RedisExternalAuthProvider external_auth_provider = 10;
}
// RedisProtocolOptions specifies Redis upstream protocol options. This object is used in
@ -370,3 +380,22 @@ message RedisProtocolOptions {
// `<https://redis.io/topics/acl>`_ in the server's configuration file.
config.core.v3.DataSource auth_username = 2 [(udpa.annotations.sensitive) = true];
}
// RedisExternalAuthProvider specifies a gRPC service that can be used to authenticate Redis clients.
// This service will be called every time an AUTH command is received from a client.
// If the service returns an error, authentication is considered failed.
// If the service returns a success, the client is considered authenticated.
// The service can also return an expiration timestamp, which will be used to disable any further
// commands from the client after it passes, unless a new AUTH command is received and the
// external auth service returns a new expiration timestamp.
message RedisExternalAuthProvider {
// External auth gRPC service configuration.
// It will be called every time an AUTH command is received from a client.
config.core.v3.GrpcService grpc_service = 1;
// If set to true, the filter will expect an expiration timestamp in the response from the external
// auth service. This timestamp will be used to disable any further commands from the client after
// the expiration time, unless a new AUTH command is received and the external auth service returns
// a new expiration timestamp.
bool enable_auth_expiration = 2;
}

@ -0,0 +1,10 @@
# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py.
load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")
licenses(["notice"]) # Apache 2
api_proto_package(
has_services = True,
deps = ["@com_github_cncf_xds//udpa/annotations:pkg"],
)

@ -0,0 +1,47 @@
syntax = "proto3";
package envoy.service.redis_auth.v3;
import "google/protobuf/timestamp.proto";
import "google/rpc/status.proto";
import "udpa/annotations/status.proto";
option java_package = "io.envoyproxy.envoy.service.redis_auth.v3";
option java_outer_classname = "RedisExternalAuthProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/service/redis_auth/v3;redis_authv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;
// [#protodoc-title: Redis external authentication service]
// The messages used by the redis_proxy filter when performing external authentication.
// A generic interface for performing external password authentication on incoming AUTH commands.
service RedisProxyExternalAuth {
// Performs authentication check based on the data sent with the AUTH request.
// Returns either an OK status or an error status.
rpc Authenticate(RedisProxyExternalAuthRequest) returns (RedisProxyExternalAuthResponse) {
}
}
message RedisProxyExternalAuthRequest {
// Username, if applicable. Otherwise, empty.
string username = 1;
// Password sent with the AUTH command.
string password = 2;
}
message RedisProxyExternalAuthResponse {
// Status of the authentication check.
google.rpc.Status status = 1;
// Optional expiration time for the authentication.
// If set, the authentication will be valid until this time.
// If not set, the authentication will be valid indefinitely.
google.protobuf.Timestamp expiration = 2;
// Optional message to be sent back to the client.
string message = 3;
}

@ -299,6 +299,7 @@ proto_library(
"//envoy/service/metrics/v3:pkg",
"//envoy/service/rate_limit_quota/v3:pkg",
"//envoy/service/ratelimit/v3:pkg",
"//envoy/service/redis_auth/v3:pkg",
"//envoy/service/route/v3:pkg",
"//envoy/service/runtime/v3:pkg",
"//envoy/service/secret/v3:pkg",

Loading…
Cancel
Save