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

External auth background and goals. #2459

Closed
jpeach opened this issue Apr 23, 2020 · 6 comments
Closed

External auth background and goals. #2459

jpeach opened this issue Apr 23, 2020 · 6 comments
Assignees

Comments

@jpeach
Copy link
Contributor

jpeach commented Apr 23, 2020

This issue captures background context and research for adding Contour support for service authentication. It's not the final design, though preliminary design directions are included. The goal of this issue is to capture feedback about the direction.

Goals

  1. Support multiple external authentication servers.

Since Contour targets soft multi-tenancy for proxies, we should expect
that different services have different authentication needs. This means
that Contour must support multiple authentication servers.

  1. Support multiple external authentication types.

The Contour external authentication mechanism should be general enough to
support multiple kinds of authentication. At minimum, we should support
HTTP basic auth and OAuth2 (via OIDC).

  1. Support externalName authentication servers.

For some kinds of authentication, the authentication server can run in
the same cluster. However, running an auth server has a certain amount
of overhead cost and may have specific security operational requirements,
so Contour should support using an out-of-cluster service as an external
authentication server.

  1. Interoperate with existing authentication servers.

Writing a external authentication server can be non-trivial. Contour
should facilitate users who wish to use existing authentication
servers. Contour should not invent a bespoke protocol to attach
authentication servers.

  1. Support GRPC and HTTP authentication servers.

Since Contour will not invent its own server attachment protocol,
exposing the Envoy protocol makes the most sense. Both the GRPC and
HTTP attachment protocols should be exposed since (1) other Envoy-based
Ingress controllers expose both and (2) there are authentication servers
that depend on both protocols.

  1. Support TLS sessions with authentication servers.

Contour should always use TLS to send request to authentication
servers. Mutual TLS is not required, though it seems reasonable
for sites to want that capability.

  1. Re-use existing HTTPProxy configuration as much as possible.

In API that describes how to bind an external authentication service,
Contour should leverage the existing configuration stanzas and concepts
in HTTPProxy as much as possible (e.g. Service, HeadersPolicy).

  1. Disable authentication on specific paths.

Many applications have internal HTTP paths that don't require
authentication (e.g. static assets). There needs to be a way to disable
the authentication requirement for specific paths within a virtual host.

Non-Goals

  1. Internal or plugin authentication mechanisms.

We should not support any non-external authentication in Contour since
this would divert resources (development, testing and documentation)
from the external server path, which is the primary use case. This means
that the Contour service itself should not satisfy authentication requests
or load plugins that do.

  1. Insecure authentication server attachment.

Contour does not need to support attaching authentication servers over
HTTP. It can assume HTTPS.

  1. Support Ingress and IngressRoute documents.

Since the IngressRoute API is deprecated, there is no need to ever
implement external authentication there. The situation for Ingress is
less clear. Ingress is a supported API, but is also less expressive in
some ways than HTTPProxy. For now, Ingress won't be supported for
external auth, but we should be open to revisiting the isssue.

Authorization request flow

Authorizing requests with an external server involves a number of
collaborating parties, so it can be helpful so understand how requests
flow through the various services.

  • Client: A HTTP client
  • Proxy: An Envoy proxy server
  • ExtAuth: A external auth server that implements the Envoy ext_authz protocol
  • AuthProvider: A server that can authenticate requests. This could be
    an OIDC server, a server that can do LDAP authentication, or HTTP Basic
    auth. It could be implemented in the same process as the ExtAuth service.
  • Origin: A HTTP origin server that responds to authenticated requests.

Verifying an authorized request

This flow describes what happens if the client already has already
authenticated and obtained some sort of authorization token.

+---------+                  +-------+                    +---------+             +---------------+ +---------+
| Client  |                  | Proxy |                    | ExtAuth |             | AuthProvider  | | Origin  |
+---------+                  +-------+                    +---------+             +---------------+ +---------+
     |                           |                             |                          |              |
     | Send HTTP request         |                             |                          |              |
     |-------------------------->|                             |                          |              |
     |                           |                             |                          |              |
     |                           | Authorize HTTP request      |                          |              |
     |                           |---------------------------->|                          |              |
     |                           |                             | -----------------\       |              |
     |                           |                             |-| Verify request |       |              |
     |                           |                             | |----------------|       |              |
     |                           |                             |                          |              |
     |                           |                      200 OK |                          |              |
     |                           |<----------------------------|                          |              |
     |         ----------------\ |                             |                          |              |
     |         | Inject        |-|                             |                          |              |
     |         | authorization | |                             |                          |              |
     |         | metadata      | |                             |                          |              |
     |         |---------------| | Forward HTTP request        |                          |              |
     |                           |---------------------------------------------------------------------->|
     |                           |                             |                          |              |
     |                           |                             |                 Respond to HTTP request |
     |                           |<----------------------------------------------------------------------|
     |                           |                             |                          |              |
     |     Forward HTTP response |                             |                          |              |
     |<--------------------------|                             |                          |              |
     |                           |                             |                          |              |

Signing in to an service

This flow describes what happens if the client doesn't already already
have any authentication information and needs to sign in to some
authentication service.

Note that in the sign in flow, the ExtAuth server may need to generate
a 302 redirection to send the client back to the authentication provider
to obtain the proper authorization tokens. Once this happens, the client
has to resend the original request and enters the verification flow above.

+---------+                   +-------+                    +---------+      +---------------+ +---------+
| Client  |                   | Proxy |                    | ExtAuth |      | AuthProvider  | | Origin  |
+---------+                   +-------+                    +---------+      +---------------+ +---------+
     |                            |                             |                   |              |
     | Send HTTP request          |                             |                   |              |
     |--------------------------->|                             |                   |              |
     |                            |                             |                   |              |
     |                            | Authorize HTTP request      |                   |              |
     |                            |---------------------------->|                   |              |
     |                            |                             |                   |              |
     |                            |                             | Authorize         |              |
     |                            |                             |------------------>|              |
     |                            |                             |                   |              |
     |                            |                             |         Challenge |              |
     |                            |                             |<------------------|              |
     |                            |                             |                   |              |
     |                            |                302 Redirect |                   |              |
     |                            |<----------------------------|                   |              |
     |                            | ----------------\           |                   |              |
     |                            |-| Generate      |           |                   |              |
     |                            | | authorization |           |                   |              |
     |                            | | redirection   |           |                   |              |
     |     Authorization redirect | |---------------|           |                   |              |
     |<---------------------------|                             |                   |              |
     |                            |                             |                   |              |
     | Sign in                    |                             |                   |              |
     |----------------------------------------------------------------------------->|              |
     |                            |                             |                   |              |
     |                            |                          Authorization response |              |
     |<-----------------------------------------------------------------------------|              |
     |                            |                             |                   |              |
     | Resend HTTP request        |                             |                   |              |
     |--------------------------->|                             |                   |              |
     |                            |                             |                   |              |

Envoy ext_authz semantics

The Envoy ext_authz filter is a HTTP filter that is specified as a
field on the HTTP Connection Manager. This forces some limitations on
how authentication can be configured. Notably, there can be exactly 1
external auth server for a HTTP ConnectionManager.

For the HTTP (cleartext on port 80) listener, Contour configures a single
HTTP Connection Manager which contains a VirtualHost field for each
domain. Since HTTP filters are attached to the Connection Manager, there
can only be one ext_authz server filter configured. This means that all
the domains exposed on this listener must have the same ext_authz server.

For the HTTPS (TLS on port 443) listener, Contour constructs a
configuration tree with an extra FilterChainMatch level to match on the
TLS SNI server name. The filters associated with this match include a
HTTP Connection Manager which references a unique route configuration
for the matching hostname. This implements a strong binding between the
SNI server name and available routes, but as a side-effect, the unique
Connection Manager allows a separate ext_authz filter to be naturally
specified for each SNI server name.

These behaviours allow us to enumerate the following
configuration possibilities:

  1. All HTTP virtual hosts must have the same ext_authz server.
  2. Each HTTPS virtual host can have a separate ext_authz server.
  3. All HTTPS virtual hosts that don't match on a SNI server name
    must have the same ext_authz server.

It is possible to raise the limitations of the Envoy ext_authz
filter. One way to do this is to write an extauth server that ships
with Contour. This extauth server would be configured with a policy for
how to choose a next-hop external auth server that can be a lot more
flexible than the Envoy configuration (e.g. an arbitrary virtual host,
an HTTP path or header). From our goals, we wish to be able to support
existing authentication server integrations, so this extauth server
would then proxy to the selected external auth server using the same
wire protocols that the Envoy ext_authz filter uses.

In this model, it is necessary for Contour to implement and ship the
extauth proxy, because its semantics will be exposed as part of the
Contour API. That is, it is not possible for a third party to implement
this approach. Obviously, an alternative to this approach would be to
directly address the configuration limitation in Envoy.

Design Proposal

At a high level, this design proposes a new CRD to represent an external
authentication server. This CRD can be referenced by HTTP services.

This design proposes that

  1. Contour configures the Envoy ext_authz filter directly
  2. Contour only supports external auth on HTTPS virtual hosts
    that are bound to a SNI server name

The rationale for this is that practically all HTTP authentication
mechanisms require TLS since they often carry private informations (bearer
tokens, API keys, etc). Extending external auth to other cases leads to
confusing and inexplicable limitations, and removing those limitations
requires a lot more engineering work. Starting with a HTTPS-only would
not preclude extending support later if necessary.

ExternalAuth CRD

TBD

The ExternalAuth CRD need to contain enough information to configure and
Envoy cluster for the auth server, as well as relevant fields from the
ExtAuthz protobuf. We should try to re-use concepts or structures from
HTTPProxy (maybe the Service struct).

Using a separate CRD allows Contour to update status on it, which can
facilitate #2352.

HTTPProxy Changes

TBD

On the root HTTPProxy, specify which ext_authz service to attach to
with a reference to a ExternalAuth document. Allow ExtAuthzPerRoute
context extension key/value pairs here.

On the HTTPProxy route (probably?), add a boolean field to toggle
disabling authentication.

Think through whether it makes sense to default authentication to being
disabled on the root HTTPProxy. Could be more convenient for some cases,
but adds a lot of complexity.

Ingress Changes

TBD

Supporting authentication for Ingress is similar to supporting it
in HTTPProxy. The ExternalAuth CRD still represents an external
authentication service, but rather than referencing it with document
fields as HTTPProxy does, Ingress references it with annotations.

Implementation Survey

Traefik

https://docs.traefik.io/middlewares/forwardauth/
https://docs.traefik.io/v1.7/configuration/backends/kubernetes/#authentication

  • Forwards whole request to auth server. If auth responds 200,
    releases request, otherwise returns auth server response.

  • Specific TLS config for auth server.

  • Auth server config is represented in a custom "middleware" CRD.

  • Ingress implementation lets you target different auth servers per
    ingress.

Auth servers:

- https://github.com/thomseddon/traefik-forward-auth
    (Google, OpenID)

Ambassador

https://www.getambassador.io/docs/latest/topics/running/services/auth-service/
https://www.getambassador.io/docs/latest/topics/running/services/ext_authz/
https://www.getambassador.io/docs/latest/topics/using/filters/

  • Supports both HTTP and GRPC auth servers.
  • AuthService CRD describes how to bind an auth server into the
    Envoy filter.
  • Filter CRD does the same, with slightly different semantics.

For HTTP auth servers, the inbound request is a combination of
the upstream client request and the auth request

- Host header is for the auth server
- HTTP method and URI are from the client request
- Pre-configured headers from the client request are added.
- Body is normally empty, but can be configured to be the
  client request body (up to a limit)

For HTTP auth servers, the response is

- 200 OK response allows the client request
- 5xx is an explicit deny
- Other codes indicate auth intercept and the client is
  served the auth response

For GRPC, auth servers must implement Envoy ext_authz protocol directly.

Ambassador has a semi-generic way to express filters using the Filter
and FilterPolicy CRDs.

The AuthService CRD is meant to configure a single global auth service,
but Filter is supposed to be per host or even per path. I was not able
to get Filters to make any changes to the Envoy config. Ambassador
seems to always configure a single built-in authz cluster pointing to
itself. That might indicate that it has an intermediate auth service,
but I wasn't able to prove that or find the code in open source.

OAuth2 Filter is a OIDC client. Substantial configuration
surface. Lots of work to support web applications.

JWT Filter validates JWT tokens. More substantial configuration
surface. Does request header and error response body templating.

Kong

https://docs.konghq.com/hub/#authentication

  • All packaged authentication support is in plugins.
  • Plugins for OAuth, OIDC, Basic, LDAP, Vault, &c, &c.
  • Plugins are in Lua (in process?)
  • No standard mechanism for external auth

Gloo

https://docs.solo.io/gloo/latest/guides/security/auth/
https://docs.solo.io/gloo/latest/guides/security/auth/custom_auth/

  • Custom external auth server is defined globally in Settings
    CRD, then vhosts opt in with their own CRDs.

  • There can only be one custom external auth server, but multiple
    instances of the builtin auth types.

  • Direct support for envoy GRPC.

  • Auth servers can co-locate in same pod and auth over unix
    domain sockets. Not clear whether this includes custom auth
    servers (possibly not).

  • HTTP custom auth server protocol is lightly described, but
    probably the same as Ambassador (i.e. envoy HTTP mechanism).

NGINX

http://nginx.org/en/docs/http/ngx_http_auth_request_module.html

  • Sends a new subrequest to the auth server. Auth server may
    respond 2xx to allow the original request, or 401/403 only
    to deny.
  • 401 response copies the WWW-Authenticate header from the
    subrequest to the main response.

Auth servers:

- https://oauth2-proxy.github.io/oauth2-proxy/

Configuration is pretty complex, see
    https://oauth2-proxy.github.io/oauth2-proxy/configuration#configuring-for-use-with-the-nginx-auth_request-directive

HAProxy

Authentication types

Auth servers to Support

Related Contour Issues

#68 Ingress auth labels
#432 Main auth issue
#433 TLS client auth
#1922 Forward auth (traefik style)

#748 JWT auth (closed)
#986 Single sign on (closed)

#1014 design proposal

#2325 Contour checking for infrastructure clusters

@jpeach
Copy link
Contributor Author

jpeach commented Apr 23, 2020

/cc @stevesloka @youngnick @michmike

@ryanelian
Copy link

ryanelian commented Apr 24, 2020

Basic Authentication API Proposal

An administrator should be able to define users for authentication using common htpasswd format, which is also used in other reverse proxies such as NGINX.

apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: name-example-foo
  namespace: default
spec:
  virtualhost:
    fqdn: foo1.bar.com
  routes:
    - services:
      - name: s1
        port: 80
  auth:
    basic:
      - htpasswd: admin:$2y$10$0GIc9.rhJd8U7UjG9yq4VObl.QxfhmcN1Z7ZI7Hn4T2mioa.2lkhi
      - htpasswd: alice:$2y$10$6Xnm2tVXLKDbh2iK4LmaMu9XmI8EyN9F8D1hRFU5guAGxIyVZj5M2
      - htpasswd: bob:$2y$10$Trw2zst7Vb8RW2.pjvkSk.8VHBrX/K9tTzntV7ZaYS4euX0E2BBfS

In that particular example, the passsword is BCrypt-hashed, which is quite secure and makes it fine for it to be visible in plain view.

If I'm not mistaken, htpasswd format can be also be:

  • SHA1 (insecure)
  • MD5 (insecure)
  • Argon2 (secure but uncommon because newer. See libsodium)

ConfigMap / Secret Reference

But because Contour is Cloud Native, we should also support Kubernetes-style configmap / secret reference (for the extra paranoid):

apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: name-example-foo
  namespace: default
spec:
  virtualhost:
    fqdn: foo1.bar.com
  routes:
    - services:
      - name: s1
        port: 80
  auth:
    basic:
      - secretKeyRef:
          name: myhtpasswd-secret
          key: htpasswd
      - configMapKeyRef:
          name: myhtpasswd-configmap
          key: htpasswd

This API is similar to the API used by Kubernetes for defining environment variable using Secret or ConfigMap value:

The value inside the ConfigMap or Secret should be a newline-delimited value of htpasswd file:

admin:$2y$10$0GIc9.rhJd8U7UjG9yq4VObl.QxfhmcN1Z7ZI7Hn4T2mioa.2lkhi
alice:$2y$10$6Xnm2tVXLKDbh2iK4LmaMu9XmI8EyN9F8D1hRFU5guAGxIyVZj5M2
bob:$2y$10$Trw2zst7Vb8RW2.pjvkSk.8VHBrX/K9tTzntV7ZaYS4euX0E2BBfS

All these techniques should be similar to the technique used by Apache / NGINX for creating Basic authentication users...

image

... while maintaining familiarity for general Kubernetes users and should be good enough for 99% use cases.

@ryanelian
Copy link

ryanelian commented Apr 24, 2020

As for the OpenID Connect external authentication feature, I would like to request a feature where the administrator can define what roles can access a particular service.

Roles and Groups claims are quite common in OpenID Connect products such as:


For example:

An HTTPProxy is configured to only allow "Manager" role to access the page.

Bob has these roles: "IT", "Manager"

When the user has not logged in, the HTTPProxy will redirect the user to the login page of the Identity Provider.

When Bob logged in, he will receive "roles" claims (if the scope is requested)

After Bob has logged in, Contour will check Bob roles against roles allowed, which is the "Manager" role. Since Bob has that role, he is allowed to access the page.

On the other hand, Alice has no roles at all. When Alice has logged in and redirected back to the application, she will be kicked to a 403 Forbidden page.

This feature is similar to feature offered by authentication reverse proxies such as Keycloak Gatekeeper: https://www.keycloak.org/docs/latest/securing_apps/#group-claims

Example OpenID Connect in HTTPProxy

apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: name-example-foo
  namespace: default
spec:
  virtualhost:
    fqdn: foo1.bar.com
  routes:
    - services:
      - name: s1
        port: 80
  auth:
    openid:
      - authority: https://oidc.company.com
      - client_id: myapp
      - response_type: code # Contour should get claims from UserInfo endpoint!
      - pkce: 'true' # when using PKCE, no client secret is required
      - scopes:
        - openid
        - profile
        - email
        - roles
      - required:
        - roles: # can be other custom claims which needs to be checked such as "groups"
          - Manager

This example YAML is not comprehensive (only catering to this particular use case). There might be other requirements (like requiring complex roles such as "Manager && IT" || "Director").

@jpeach
Copy link
Contributor Author

jpeach commented Apr 24, 2020

@ryanelian Thanks for your detailed comments! I think that there's enough substance in each of those to generate their own discussions, so I think that it is best to file new issues for basic auth and OIDC configuration (including the information in the comments above). I want to be sure that we don't lose the focus on those features in this discussion.

Thanks :)

@jpeach jpeach changed the title External auth background and goals External auth background and goals. Jun 30, 2020
jpeach added a commit to jpeach/contour that referenced this issue Jun 30, 2020
This updates projectcontour#432.
This updates projectcontour#2459.

Signed-off-by: James Peach <jpeach@vmware.com>
jpeach added a commit to jpeach/contour that referenced this issue Jul 1, 2020
This updates projectcontour#432.
This updates projectcontour#2459.

Signed-off-by: James Peach <jpeach@vmware.com>
jpeach added a commit to jpeach/contour that referenced this issue Jul 1, 2020
This updates projectcontour#432.
This updates projectcontour#2459.

Signed-off-by: James Peach <jpeach@vmware.com>
jpeach added a commit to jpeach/contour that referenced this issue Jul 6, 2020
This updates projectcontour#432.
This updates projectcontour#2459.

Signed-off-by: James Peach <jpeach@vmware.com>
jpeach added a commit to jpeach/contour that referenced this issue Jul 7, 2020
This updates projectcontour#432.
This updates projectcontour#2459.
This updates projectcontour#2325.

Signed-off-by: James Peach <jpeach@vmware.com>
@jpeach
Copy link
Contributor Author

jpeach commented Jul 13, 2020

Basic Authentication API Proposal

An administrator should be able to define users for authentication using common htpasswd format, which is also used in other reverse proxies such as NGINX.

See https://github.com/projectcontour/contour-authserver

jpeach added a commit to jpeach/contour that referenced this issue Jul 14, 2020
This updates projectcontour#432.
This updates projectcontour#2459.
This updates projectcontour#2325.

Signed-off-by: James Peach <jpeach@vmware.com>
jpeach added a commit to jpeach/contour that referenced this issue Jul 16, 2020
This updates projectcontour#432.
This updates projectcontour#2459.
This updates projectcontour#2325.

Signed-off-by: James Peach <jpeach@vmware.com>
jpeach added a commit to jpeach/contour that referenced this issue Jul 17, 2020
This updates projectcontour#432.
This updates projectcontour#2459.
This updates projectcontour#2325.

Signed-off-by: James Peach <jpeach@vmware.com>
jpeach added a commit to jpeach/contour that referenced this issue Jul 20, 2020
This updates projectcontour#432.
This updates projectcontour#2459.
This updates projectcontour#2325.

Signed-off-by: James Peach <jpeach@vmware.com>
jpeach added a commit to jpeach/contour that referenced this issue Jul 21, 2020
This updates projectcontour#432.
This updates projectcontour#2459.
This updates projectcontour#2325.

Signed-off-by: James Peach <jpeach@vmware.com>
jpeach added a commit to jpeach/contour that referenced this issue Jul 22, 2020
This updates projectcontour#432.
This updates projectcontour#2459.
This updates projectcontour#2325.

Signed-off-by: James Peach <jpeach@vmware.com>
jpeach added a commit that referenced this issue Jul 22, 2020
This updates #432.
This updates #2459.
This updates #2325.

Signed-off-by: James Peach <jpeach@vmware.com>
@jpeach jpeach self-assigned this Jul 22, 2020
@jpeach
Copy link
Contributor Author

jpeach commented Jul 22, 2020

This issue has served its purpose. Thanks for all the feedback.

@jpeach jpeach closed this as completed Jul 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants