Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: add a filter for injecting credentials into outgoing HTTP requests #21851

Open
yskopets opened this issue Jun 23, 2022 · 16 comments
Open
Labels
area/http_filter enhancement Feature requests. Not bugs or questions. help wanted Needs help!

Comments

@yskopets
Copy link
Member

Title: Add a filter for injecting credentials into outgoing HTTP requests

Description:

It would be conventient to have a standard filter that can inject credentials into outgoing HTTP requests (as a value of Authorization header).

The most common use cases:

  1. OAuth2 access token credential
  2. basic auth credential
  3. opaque bearer token credential

The primary focus of this proposal is on injecting OAuth2 access token credential.

Proposal:

Add an HTTP filter with the following configuration model:

- name: envoy.filters.network.http_connection_manager
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
    http_filters:
    - name: envoy.filters.http.credentials
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.http.credentials.v3alpha.Injector
        config:
          rules:
          - match:
              ... # HTTP requests to match
            inject:
              credential: { ... } # credential to inject

If the list of rules is empty, the filter will have no effect.

With regards to OAuth2 support:

  • the filter will allow a user to specify client_id and client_password
  • and let filter to acquire OAuth2 access token through Client Credentials Grant flow
  • the filter will also take care of refreshing access token

Usage examples:

Injecting OAuth2 access token

- name: envoy.filters.network.http_connection_manager
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
    http_filters:
    - name: envoy.filters.http.credentials
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.http.credentials.v3alpha.Injector
        config:
          rules:
          - match:
              prefix: /
            inject:
              credential:
                oauth2:
                  token_endpoint:
                    cluster: oauth
                    uri: oauth.com/token
                    timeout: 3s
                  client_credentials:
                    client_id:
                      secret:
                        name: client-id
                        sds_config:
                          path: "/var/run/secret/credentials/oauth2/client-id.yaml"
                    client_password:
                      secret:
                        name: client-password
                        sds_config:
                          path: "/var/run/secret/credentials/oauth2/client-password.yaml"
                  # (Optional)
                  scopes:
                  - "example"

Injecting basic auth credentials

- name: envoy.filters.network.http_connection_manager
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
    http_filters:
    - name: envoy.filters.http.credentials
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.http.credentials.v3alpha.Injector
        config:
          rules:
          - match:
              prefix: /
            inject:
              credential:
                basic:
                  username:
                    secret:
                      name: username
                      sds_config:
                        path: "/var/run/secret/credentials/basic/username.yaml"
                  password:
                    secret:
                      name: password
                      sds_config:
                        path: "/var/run/secret/credentials/basic/password.yaml"

Injecting opaque bearer token credential

- name: envoy.filters.network.http_connection_manager
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
    http_filters:
    - name: envoy.filters.http.credentials
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.http.credentials.v3alpha.Injector
        config:
          rules:
          - match:
              prefix: /
            inject:
              credential:
                generic:
                  prefix: "Bearer "
                  value:
                    secret:
                      name: bearer-token
                      sds_config:
                        path: "/var/run/secret/credentials/generic/bearer-token.yaml"
@yskopets yskopets added the triage Issue requires triage label Jun 23, 2022
@wbpcode wbpcode added enhancement Feature requests. Not bugs or questions. area/http_filter and removed triage Issue requires triage labels Jun 29, 2022
@wbpcode
Copy link
Member

wbpcode commented Jun 29, 2022

Could you give some more descriptions about the specific scenes?

IMO, this may be useful in the mesh where the mTLS is disabled and authentication is necessary.

@mbana
Copy link
Contributor

mbana commented Jul 18, 2022

We are also interested in this.

We want/need client_credentials: https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-credentials-flow because Envoy supports only authorization_code: https://github.com/envoyproxy/envoy/blob/main/source/extensions/filters/http/oauth2/oauth_client.cc#L25.

Do you have a branch or image I could use for testing, if you're already implemented it, that is.

@tedli
Copy link
Contributor

tedli commented Jul 20, 2022

Seriously, I need this feature, and I believe I'm not alone.

There was an out of maintenance service (A) which runs robustly for years. But the service (B) this old service depends on, got updated, that introduced auth for existing apis. (A calls B)
So a proxy is needed to inject credentials into request from A to consume B, because not willing to touch the code of A.

@wbpcode
Copy link
Member

wbpcode commented Jul 20, 2022

Seriously, I need this feature, and I believe I'm not alone.

There was an out of maintenance service (A) which runs robustly for years. But the service (B) this old service depends on, got updated, that introduced auth for existing apis. (A calls B) So a proxy is needed to inject credentials into request from A to consume B, because not willing to touch the code of A.

Sounds reasonable scene.

@wbpcode wbpcode added the help wanted Needs help! label Jul 20, 2022
@wbpcode
Copy link
Member

wbpcode commented Jul 20, 2022

I tagged this issue to help wanted. But based on our contributing policy, we need a maintainer (@envoyproxy/envoy-maintainers) to sponsor this feature. Because we will add a new extension.

Check this https://github.com/envoyproxy/envoy/blob/main/CONTRIBUTING.md#adding-new-extensions for more info.

cc @yskopets

@tedli
Copy link
Contributor

tedli commented Jul 20, 2022

It would be convenient if this can affect at route level. So in an istio mesh, we can create EnvoyFilter cr to patch virtual_host, to tell which route need this, also the workload selector could be used to tell which pod need this.

@irab
Copy link

irab commented Nov 7, 2022

I'm keen to have this feature as well. There's a great use case for an outbound edge proxy, adding some protection against malicious code.

Say for example an internal service A needs to access an external service like GitHub. Current practice is to inject a PAT into the container, which can be retrieved by either code execution on the container or privileged access at a node or cluster level. If we move the PAT token out of the container and/or cluster then we can protect against malicious actors with code execution.

Authorisation could be managed with service account + outbound domain allowlists, with JWT validation?

@deva26
Copy link

deva26 commented Nov 24, 2022

We would be very much interested in this feature getting implemented. +100

@kyessenov
Copy link
Contributor

Can this be used to implement STS? E.g. exchange k8s service account for a Google service account when connecting to Google services?

@zhaohuabing
Copy link
Member

It seems that STS works like oauth Client Credentials Grant, so I think it would be possible to also include it in this new filter. However, the initial implementation will focus on oauth Client Credentials Grant flow.

@pre
Copy link

pre commented Nov 3, 2023

Our use case: Expose Kubernetes API server's OIDC metadata.

  • Kubernetes API server's OIDC metadata is not publicly available
  • OIDC metadata can be retrieved with a ServiceAccount's token

It'd be great to expose the OIDC metadata with Istio/envoy, without having to deploy an extra component to request the OIDC metadata from Kubernetes API using the ServiceAccount's token.

Why? The OIDC metadata needs to be available for AWS IAM for AWS IAM Roles as Service Accounts (IRSA). This comes out-of-the-box in EKS, but in a private Kubernetes installation one needs to jump through hoops.

@zhaohuabing
Copy link
Member

zhaohuabing commented Nov 4, 2023

Our use case: Expose Kubernetes API server's OIDC metadata.

  • Kubernetes API server's OIDC metadata is not publicly available
  • OIDC metadata can be retrieved with a ServiceAccount's token

It'd be great to expose the OIDC metadata with Istio/envoy, without having to deploy an extra component to request the OIDC metadata from Kubernetes API using the ServiceAccount's token.

Why? The OIDC metadata needs to be available for AWS IAM for AWS IAM Roles as Service Accounts (IRSA). This comes out-of-the-box in EKS, but in a private Kubernetes installation one needs to jump through hoops.

When you talk about 'OIDC metadata', Do you mean ID token?

Sounds this could be implemented as an extension tpye of the credentials injector, or use the existing 'Generic' credential extentension. #27769

@pre
Copy link

pre commented Nov 29, 2023

When you talk about 'OIDC metadata', Do you mean ID token?

No, I mean the OIDC metadata of the Kubernetes API Server.

With AWS IRSA, one needs to create a new Identity Provider in AWS IAM, and its authentication can be OIDC. Then AWS IAM will retrieve the OIDC metadata of this Identity Provider, which in this case is the Kubernetes API server.

Nowdays Kubernetes API server provides the OIDC metadata out-of-the-box. The problem is, in some case like ours, the metadata endpoint requires authentication. Because AWS IAM requires the OIDC metadata be publicly available, one needs to configure a proxy which provides AWS IAM with the OIDC metadata. In this case this proxy will authenticate to the Kubernetes API server OIDC endpoint using the ServiceAccount's credentials (Bearer token).

It looks like this:

❯ curl https://public-proxy-hostname.example.com/.well-known/openid-configuration
{"issuer":"https://public-proxy-hostname.example.com","jwks_uri":"https://public-proxy-hostname.example.com/jwks","response_types_supported":["id_token"],"subject_types_supported":["public"],"id_token_signing_alg_values_supported":["RS256"]}

And here the issuer matches with the hostname of the metadata endpoint which is required for by AWS IAM Identity Provider configuration.

Now were are deploying our own simple proxy web server implementation for https://public-proxy-hostname.example.com/ but it would be neat if the istio envoy sidecar could be configured to authenticate to the private Kubernetes API server OIDC metadata endpoint. Then we wouldn't need to deploy an extra service only for this purpose.

@loewenstein
Copy link

I'd be interested in this as well. Is there already a rough idea for when the work in #30850 might get released?

@phlax
Copy link
Member

phlax commented Jan 26, 2024

i should imagine it will be included in the next release

@juanmolle
Copy link
Contributor

It would be convenient if this can affect at route level. So in an istio mesh, we can create EnvoyFilter cr to patch virtual_host, to tell which route need this, also the workload selector could be used to tell which pod need this.

we are interesting in using it as upstream filter. For those apis that could be weight routing.

#35194

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/http_filter enhancement Feature requests. Not bugs or questions. help wanted Needs help!
Projects
None yet
Development

No branches or pull requests