Skip to content

Commit

Permalink
feat: credential injector impl (envoyproxy#30850)
Browse files Browse the repository at this point in the history
* credential injector impl

Signed-off-by: huabing zhao <zhaohuabing@gmail.com>

---------

Signed-off-by: huabing zhao <zhaohuabing@gmail.com>
Signed-off-by: Huabing Zhao <zhaohuabing@gmail.com>
Co-authored-by: phlax <phlax@users.noreply.github.com>
Co-authored-by: Adi (Suissa) Peleg <adip@google.com>
  • Loading branch information
3 people authored and alyssawilk committed Apr 29, 2024
1 parent aedebb0 commit c6b4239
Show file tree
Hide file tree
Showing 40 changed files with 1,300 additions and 64 deletions.
5 changes: 5 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,11 @@ extensions/filters/http/oauth2 @derekargueta @mattklein123

/*/extensions/health_checkers/common @zuercher @botengyao

# HTTP credential injector
/*/extensions/filters/http/credential_injector @zhaohuabing @kyessenov
/*/extensions/http/injected_credentials/common @zhaohuabing @kyessenov
/*/extensions/http/injected_credentials/generic @zhaohuabing @kyessenov

# Lua cluster specifier
/*/extensions/router/cluster_specifiers/lua @StarryVae @wbpcode

Expand Down
4 changes: 2 additions & 2 deletions api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -265,12 +265,12 @@ proto_library(
"//envoy/extensions/http/early_header_mutation/header_mutation/v3:pkg",
"//envoy/extensions/http/header_formatters/preserve_case/v3:pkg",
"//envoy/extensions/http/header_validators/envoy_default/v3:pkg",
"//envoy/extensions/http/injected_credentials/generic/v3:pkg",
"//envoy/extensions/http/injected_credentials/oauth2/v3:pkg",
"//envoy/extensions/http/original_ip_detection/custom_header/v3:pkg",
"//envoy/extensions/http/original_ip_detection/xff/v3:pkg",
"//envoy/extensions/http/stateful_session/cookie/v3:pkg",
"//envoy/extensions/http/stateful_session/header/v3:pkg",
"//envoy/extensions/injected_credentials/generic/v3:pkg",
"//envoy/extensions/injected_credentials/oauth2/v3:pkg",
"//envoy/extensions/internal_redirect/allow_listed_routes/v3:pkg",
"//envoy/extensions/internal_redirect/previous_routes/v3:pkg",
"//envoy/extensions/internal_redirect/safe_cross_scheme/v3:pkg",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,29 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
option (xds.annotations.v3.file_status).work_in_progress = true;

// [#protodoc-title: Credential Injector]
// [#not-implemented-hide:]
// Credential Injector :ref:`configuration overview <config_http_filters_credential_injector>`.
// [#extension: envoy.filters.http.credential_injector]

// Credential Injector injects credentials into outgoing HTTP requests. The filter configuration is used to retrieve the credentials, or
// they can be requested through the OAuth2 client credential grant. The credentials obtained are then injected into the Authorization header
// of the proxied HTTP requests, utilizing either the Basic or Bearer scheme.
//
// If the credential is not present, the request will fail with 401 Unauthorized if fail_if_not_present is set to true.
// If the credential is not present or there was a failure injecting the credential, the request will fail with ``401 Unauthorized`` unless
// ``allow_request_without_credential`` is set to ``true``.
//
// Notice: This filter is intended to be used for workload authentication, which means that the identity associated with the inserted credential
// is considered as the identity of the workload behind the envoy proxy(in this case, envoy is typically deployed as a sidecar alongside that
// workload). Please note that this filter does not handle end user authentication. Its purpose is solely to authenticate the workload itself.
//
// Here is an example of CredentialInjector configuration with Generic credential, which injects an HTTP Basic Auth credential into the proxied requests.
//
// .. code-block:: yaml
// .. code-block:: yaml
//
// overwrite: true
// fail_if_not_present: true
// credential:
// name: generic_credential
// typed_config:
// "@type": type.googleapis.com/envoy.extensions.injected_credentials.generic.v3.Generic
// "@type": type.googleapis.com/envoy.extensions.http.injected_credentials.generic.v3.Generic
// credential:
// name: credential
// sds_config:
Expand All @@ -49,7 +48,8 @@ option (xds.annotations.v3.file_status).work_in_progress = true;
// header: Authorization
//
// credential.yaml for Basic Auth:
// .. code-block:: yaml
//
// .. code-block:: yaml
//
// resources:
// - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret"
Expand All @@ -59,8 +59,10 @@ option (xds.annotations.v3.file_status).work_in_progress = true;
// inline_string: "Basic base64EncodedUsernamePassword"
//
// It can also be configured to inject a Bearer token into the proxied requests.
//
// credential.yaml for Bearer Token:
// .. code-block:: yaml
//
// .. code-block:: yaml
//
// resources:
// - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret"
Expand All @@ -74,12 +76,15 @@ message CredentialInjector {
// Value defaults to false.
bool overwrite = 1;

// Whether to fail the request if the credential is not present.
// Value defaults to false.
// If set to true, the request will fail with 401 Unauthorized if the credential is not present.
bool fail_if_not_present = 2;
// Whether to send the request to upstream if the credential is not present or if the credential injection
// to the request fails.
//
// By default, a request will fail with ``401 Unauthorized`` if the
// credential is not present or the injection of the credential to the request fails.
// If set to true, the request will be sent to upstream without the credential.
bool allow_request_without_credential = 2;

// The credential to inject into the proxied requests
// TODO add extension-category
// [#extension-category: envoy.http.injected_credentials]
config.core.v3.TypedExtensionConfig credential = 3 [(validate.rules).message = {required: true}];
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
syntax = "proto3";

package envoy.extensions.injected_credentials.generic.v3;
package envoy.extensions.http.injected_credentials.generic.v3;

import "envoy/extensions/transport_sockets/tls/v3/secret.proto";

Expand All @@ -9,58 +9,19 @@ import "xds/annotations/v3/status.proto";
import "udpa/annotations/status.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.extensions.injected_credentials.generic.v3";
option java_package = "io.envoyproxy.envoy.extensions.http.injected_credentials.generic.v3";
option java_outer_classname = "GenericProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/injected_credentials/generic/v3;genericv3";
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/http/injected_credentials/generic/v3;genericv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;
option (xds.annotations.v3.file_status).work_in_progress = true;

// [#protodoc-title: Generic Credential]
// [#not-implemented-hide:]
// [#extension: envoy.injected_credentials.generic]
// [#extension: envoy.http.injected_credentials.generic]

// Generic extension can be used to inject HTTP Basic Auth, Bearer Token, or any arbitrary credential
// into the proxied requests.
// The credential will be injected into the specified HTTP request header.
// Example:
//
// .. code-block:: yaml
//
// credential:
// name: generic_credential
// typed_config:
// "@type": type.googleapis.com/envoy.extensions.injected_credentials.generic.v3.Generic
// credential:
// name: credential
// sds_config:
// path_config_source:
// path: credential.yaml
// header: Authorization
//
// credential.yaml for Basic Auth:
//
// .. code-block:: yaml
//
// resources:
// - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret"
// name: credential
// generic_secret:
// secret:
// inline_string: "Basic base64EncodedUsernamePassword"
//
// Refer to [RFC 7617: The 'Basic' HTTP Authentication Scheme](https://www.rfc-editor.org/rfc/rfc7617) for details.
//
// credential.yaml for Bearer Token:
//
// .. code-block:: yaml
// resources:
// - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret"
// name: credential
// generic_secret:
// secret:
// inline_string: "Bearer myToken"
//
// Refer to [RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://www.rfc-editor.org/rfc/rfc6750) for details.
//
message Generic {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
syntax = "proto3";

package envoy.extensions.injected_credentials.oauth2.v3;
package envoy.extensions.http.injected_credentials.oauth2.v3;

import "envoy/config/core/v3/http_uri.proto";
import "envoy/extensions/transport_sockets/tls/v3/secret.proto";
Expand All @@ -10,16 +10,16 @@ import "xds/annotations/v3/status.proto";
import "udpa/annotations/status.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.extensions.injected_credentials.oauth2.v3";
option java_package = "io.envoyproxy.envoy.extensions.http.injected_credentials.oauth2.v3";
option java_outer_classname = "Oauth2Proto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/injected_credentials/oauth2/v3;oauth2v3";
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/http/injected_credentials/oauth2/v3;oauth2v3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;
option (xds.annotations.v3.file_status).work_in_progress = true;

// [#protodoc-title: OAuth2 Credential]
// [#not-implemented-hide:]
// [#extension: envoy.injected_credentials.oauth2]
// [#extension: envoy.http.injected_credentials.oauth2]

// OAuth2 extension can be used to retrieve an OAuth2 access token from an authorization server and inject it into the
// proxied requests.
Expand Down
4 changes: 2 additions & 2 deletions api/versioning/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -203,12 +203,12 @@ proto_library(
"//envoy/extensions/http/early_header_mutation/header_mutation/v3:pkg",
"//envoy/extensions/http/header_formatters/preserve_case/v3:pkg",
"//envoy/extensions/http/header_validators/envoy_default/v3:pkg",
"//envoy/extensions/http/injected_credentials/generic/v3:pkg",
"//envoy/extensions/http/injected_credentials/oauth2/v3:pkg",
"//envoy/extensions/http/original_ip_detection/custom_header/v3:pkg",
"//envoy/extensions/http/original_ip_detection/xff/v3:pkg",
"//envoy/extensions/http/stateful_session/cookie/v3:pkg",
"//envoy/extensions/http/stateful_session/header/v3:pkg",
"//envoy/extensions/injected_credentials/generic/v3:pkg",
"//envoy/extensions/injected_credentials/oauth2/v3:pkg",
"//envoy/extensions/internal_redirect/allow_listed_routes/v3:pkg",
"//envoy/extensions/internal_redirect/previous_routes/v3:pkg",
"//envoy/extensions/internal_redirect/safe_cross_scheme/v3:pkg",
Expand Down
4 changes: 4 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,10 @@ removed_config_or_runtime:
removed ``envoy_reloadable_features_initialize_upstream_filters`` and legacy code paths.
new_features:
- area: filters
change: |
Added the :ref:`credential injector filter <envoy_v3_api_msg_extensions.filters.http.credential_injector.v3.CredentialInjector>`,
which can be used to inject credentials into the HTTP headers.
- area: basic_auth
change: |
Added :ref:`forward_username_header <envoy_v3_api_field_extensions.filters.http.basic_auth.v3.BasicAuth.forward_username_header>`
Expand Down
1 change: 1 addition & 0 deletions docs/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ filegroup(
"root/configuration/http/http_filters/_include/checksum_filter.yaml",
# TODO(phlax/windows-dev): figure out how to get this working on windows
# "Error: unable to read file: /etc/ssl/certs/ca-certificates.crt"
"root/configuration/http/http_filters/_include/credential-injector-filter.yaml",
"root/configuration/http/http_filters/_include/dns-cache-circuit-breaker.yaml",
"root/configuration/other_features/_include/dlb.yaml",
"root/configuration/other_features/_include/hyperscan_matcher.yaml",
Expand Down
1 change: 1 addition & 0 deletions docs/root/api-v3/config/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Extensions
http/header_validators
http/original_ip_detection
http/stateful_session
injected_credentials/injected_credentials
geoip_provider/geoip_provider
trace/trace
internal_redirect/internal_redirect
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Injected credentials
====================

.. toctree::
:glob:
:maxdepth: 2

../../extensions/http/injected_credentials/*/v3/*
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
static_resources:
listeners:
- name: listener_0
address:
socket_address:
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
access_log:
- name: envoy.access_loggers.stdout
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: service1
http_filters:
- name: envoy.filters.http.credential_injector
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.credential_injector.v3.CredentialInjector
allow_request_without_credential: true
overwrite: true
credential:
name: envoy.http.injected_credentials.generic
typed_config:
"@type": type.googleapis.com/envoy.extensions.http.injected_credentials.generic.v3.Generic
credential:
name: credential
sds_config:
path_config_source:
path: /home/ubuntu/credential.yaml
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

clusters:
- name: service1
load_assignment:
cluster_name: service1
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 8080
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
.. _config_http_filters_credential_injector:

Credential Injector
===================

The credential injector HTTP filter serves the purpose of injecting credentials into outgoing HTTP requests.

The filter configuration is used to retrieve the credentials, or they can be fetched from a remote source
such as an OAuth2 authorization server. The credentials obtained are then injected into the ``Authorization``
header of the proxied HTTP requests, utilizing either the ``Basic`` or ``Bearer`` scheme.

Notice: This filter is intended to be used for workload authentication, which means that the identity associated
with the inserted credential is considered as the identity of the workload behind the Envoy proxy (in this case,
Envoy is typically deployed as a sidecar alongside that workload).

.. note::
This filter does not handle end user authentication.

The purpose of the filter is solely to authenticate the workload itself.

Configuration
-------------

* This filter should be configured with the type URL ``type.googleapis.com/envoy.extensions.filters.http.credential_injector.v3.CredentialInjector``.
* :ref:`v3 API reference <envoy_v3_api_msg_extensions.filters.http.credential_injector.v3.CredentialInjector>`

Currently the filter supports :ref:`generic <envoy_v3_api_msg_extensions.http.injected_credentials.generic.v3.Generic>` only.
Other credential types can be supported as extensions.

Here is an example configuration with Generic credential, which injects an HTTP Basic Auth credential into the proxied requests.

.. literalinclude:: _include/credential-injector-filter.yaml
:language: yaml
:lines: 28-41
:caption: :download:`credential-injector-filter.yaml <_include/credential-injector-filter.yaml>`


credential.yaml for Basic Auth:

.. code-block:: yaml
resources:
- "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret"
name: credential
generic_secret:
secret:
inline_string: "Basic base64EncodedUsernamePassword"
It can also be configured to inject a Bearer token into the proxied requests.

credential.yaml for Bearer Token:

.. code-block:: yaml
resources:
- "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret"
name: credential
generic_secret:
secret:
inline_string: "Bearer myToken"
Statistics
----------

The HTTP credential injector filter outputs statistics in the ``http.<stat_prefix>.credential_injector.`` namespace.

.. csv-table::
:header: Name, Type, Description
:widths: 1, 1, 2

``injected``, Counter, Total number of requests with injected credentials
``failed``, Counter, Total number of requests that failed to inject credentials
``already_exists``, Counter, Total number of requests that already had credentials and overwrite is false
1 change: 1 addition & 0 deletions docs/root/configuration/http/http_filters/http_filters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ HTTP filters
composite_filter
connect_grpc_bridge_filter
cors_filter
credential_injector_filter
csrf_filter
custom_response_filter
decompressor_filter
Expand Down
Loading

0 comments on commit c6b4239

Please sign in to comment.