pomerium/docs/docs/topics/original-request-context.md
Alex Fornuto 1a5cfda940
Docs: Batch Updates (#2628)
* define IdP acronym

* remove 'enable user imporsonation', which was removed

* copy edit recovery token

* integrate SA docs into reference

* rename Prometheus as Metrics
2021-09-29 09:49:42 -05:00

6.5 KiB

title description sidebarDepth
Original User Context This article describes how the original user context is passed secondary requests. 0

Original User Context

::: tip This article describes a use case available to Pomerium Enterprise customers. :::

In enterprise environments where multiple services protected by Pomerium communicate with each other using a service account, there are scenarios where the original user context must be preserved. This article describes how this is accomplished with the X-Pomerium-Jwt-Assertion-For header.

Abstract

When a User communicates with a service downstream of Pomerium, the service can identify that user by the X-Pomerium-JWT-Assertion header, added by Pomerium, which provides as a value a Java Web Token (JWT) identifying the user.

Should that service need to communicate with another Pomerium-protected service to construct the response, that connection should be authorized through Pomerium with a Service Account. Service accounts should be provided to Pomerium from the first service as a bearer token header, i.e. Authorization: Bearer Pomerium-${service_acount_jwt}. This header is how the secondary service authenticates the machine-to-machine interaction.

Should that second service need to know the original user context to return the proper response, it would have no way of knowing, as the first service authenticated as the service account and not the original user.

The solution is to have the first service forward the headers, including X-Pomerium-JWT-Assertion, in its request to the second service. When Pomerium receives a request that already includes this header, it passes the value to the second service in the X-Pomerium-JWT-Assertion-For header. This header can be read by the secondary service to identify the user context.

Should the second service need to communicate with a tertiary service (or more), it can also pass along the original headers it received. When Pomerium receives a request with the X-Pomerium-JWT-Assertion-For header, it preserves the value as provided to all additional upstream services.

Example

Let's look at two example routes, App and API:

routes:
  - name: App
    from: https://app.localhost.pomerium.io
    to: https://appserver.local
    pass_identity_headers: true
    policy:
      - allow:
          or:
            - domain:
                is: companydomain.com
  - name: API
    from: https://api.localhost.pomerium.io
    to: https://apiserver.local
    pass_identity_headers: true
    policy:
      - allow:
          or:
            - user:
                is: api-access
  • App is a user-facing application. Users connect to it through Pomerium.
  • API is also accessed through it's Pomerium Route, but is only accessible by the App, using a service account to authenticate.
  • The API service needs to know the user making the request to App in order to formulate the correct response.

Both Routes include pass_identity_headers, which provides (at minimum) the X-Pomerium-Jwt-Assertion header to the downstream application.

When a user makes a request that requires data from the API service, the following happens:

sequenceDiagram
    autonumber
    participant Browser
    participant Pomerium
    participant App
    participant API
    participant API2
    Browser->>Pomerium: Authenticated Request
    rect rgba(197, 183, 221)
        Pomerium-->>App: X-Pomerium-JWT-Assertion (User JWT)
        %%rect rgba(0, 255, 255)
            Note over App: "App" copies X-Pomerium-JWT-Assertion <br/>from the original request
            App-->>Pomerium: X-Pomerium-JWT-Assertion (User JWT)<br/> Service Account Bearer Token
            Note over Pomerium, App: "App" calls "API" through Pomerium.
            Pomerium-->>API: X-Pomerium-JWT-Assertion (Service Account) <br/>X-Pomerium-JWT-Assertion-For (User JWT)
            Note over Pomerium, API: Pomerium copies X-Pomerium-JWT-Assertion as X-Pomerium-JWT-Assertion-For
       %% end
        Note over API: The "API" service uses <br/>X-Pomerium-JWT-Assertion-For <br/>To identify context
        API-->>Pomerium: Response
        Pomerium-->>App: Response
        App-->>Pomerium: Result Page
    end
    Pomerium->>Browser: Result Page
  1. The user first authenticates with Pomerium.

  2. As the traffic is passed to App, Pomerium adds the X-Pomerium-Jwt-Assertion header with the JWT for the user as a value.

  3. The App software has been configured by the software developer to send a request to API, using a bearer token to authenticate as the service account, with the original X-Pomerium-Jwt-Assertion header forwarded as well.

  4. Pomerium, seeing that the incoming request already includes X-Pomerium-JTW-Assertion copies the value to X-Pomerium-Jwt-Assertion-For and includes it in the request to API. X-Pomerium-Jwt-Assertion now contains the service account bearer token

  5. Now the API can service can read X-Pomerium-Jwt-Assertion-For as needed to determine the proper response to send to App (through Pomerium), which can then construct the results page for the user.

Secondary Requests

Suppose the API service needed to connect to another machine interface (which we'll call API2) for additional information, and this call also needs the original user context.

If API is configured to pass along the X-Pomerium-JWT-Assertion-For header, Pomerium will recognize and preserve this. All subsequent connections with this header forwarded will perpetuate the original user context.

sequenceDiagram
    autonumber
    participant Browser
    participant Pomerium
    participant App
    participant API
    participant API2
    rect rgba(197, 183, 221)
        opt Secondary Request
            Note over API, Pomerium: "API" is configured to pass all headers from the original request.
            API-->>Pomerium: X-Pomerium-JWT-Assertion (Service Account Bearer Token) <br/>X-Pomerium-JWT-Assertion-For (User JWT)
            Note over Pomerium, API2: Pomerium preserves X-Pomerium-JWT-Assertion-For as provided by "API"
            Pomerium-->> API2: X-Pomerium-JWT-Assertion (Service Account) <br/>X-Pomerium-JWT-Assertion-For (User JWT)
            Note over API2: "API2" reads X-Pomerium-JWT-Assertion-For <br/>for user context
            API2-->>Pomerium: Response
            Pomerium-->>API: Response
        end
    end