ory / kratos

The most scalable and customizable identity server on the market. Replace your Homegrown, Auth0, Okta, Firebase with better UX and DX. Has all the tablestakes: Passkeys, Social Sign In, Multi-Factor Auth, SMS, SAML, TOTP, and more. Written in Go, cloud native, headless, API-first. Available as a service on Ory Network and for self-hosters.
https://www.ory.sh/?utm_source=github&utm_medium=banner&utm_campaign=kratos
Apache License 2.0
11.08k stars 956 forks source link

doc about a reverse proxy example #1031

Closed hbrls closed 3 years ago

hbrls commented 3 years ago

Is your feature request related to a problem? Please describe.

Want a copy-able reverse proxy (nginx) example.

Or a list of apis/pages/routes so I can make the nginx config myself.

Describe the solution you'd like

https://www.ory.sh/kratos/docs/debug/csrf#running-on-separate-sub-domains

Make sure that your application (e.g. the SecureApp from the quickstart) and ORY Krato's Public API are available on the same domain - preferably without subdomains. Hosting both systems and routing paths with a Reverse Proxy such as Nginx or Envoy or AWS API Gateway is the best solution. For example, routing https://my-website/kratos/... to ORY Kratos and https://my-website/dashboard to the SecureApp's Dashboard. Alternatively you can use piping in your app as we do in the Quickstart guide.

Expecting something like:

All kratos routes start with: https://my.example.com/kratos/login/browser https://my.example.com/kratos/xxxx

All self-service routes start with: https://my.example.com/self-service/auth/login https://my.example.com/self-service/xxxx

All kratos api routes start with: https://my.example.com/kratos-api/register https://my.example.com/kratos-api/xxxx

All kratos admin api routes start with: https://my.example.com/kratos-admin-api/search https://my.example.com/kratos-admin-api/xxxx

Can I have a list of all the routes? Do they have a pattern so I can config nginx?

vinckr commented 3 years ago

Have a loot at the REST API Documentation. We also have an example of a reverse proxy (Ory Oathkeeper) with Ory Kratos: Zero Trust with IAP Proxy Maybe you can set it up in a similar fashion. Also check out the graphic in this section of the guide.

If would be happy to help you along with an nginx example, let me know when you run into trouble. We could put it into ory/works, our WIP example repo.

ltouro commented 3 years ago

I was able to setup Kratos (with Cookies) on a Swarm Cluster using a reverse proxy (nginx-proxy) and two subdomains on the same DOMAIN.TLD (everything in Docker containers).

I have not dealt with NGINX configs. In my case, simple ENV vars were enough to make the plumbing. I had to mess with kratos.yml a little bit to configure it properly though.

Please let me know if this is useful to you and I will try to share the important bits with you.

hbrls commented 3 years ago

I've tried https://kratos.example.com and https://self-service.example.com. The cookie was set to kratos.example.com and .kratos.example.com. I want to use kratos.example.com as sso/cas and self-service.example.com as a real full function app site. Am I using it right?

I was able to setup Kratos (with Cookies) on a Swarm Cluster using a reverse proxy (nginx-proxy) and two subdomains on the same DOMAIN.TLD (everything in Docker containers).

I have not dealt with NGINX configs. In my case, simple ENV vars were enough to make the plumbing. I had to mess with kratos.yml a little bit to configure it properly though.

Please let me know if this is useful to you and I will try to share the important bits with you.

hbrls commented 3 years ago

The below config works.

As far as I can infer:

  1. Each App should be deployed with its own Kratos under the same Domain. Each App has its own Identities.
  2. App A and App B use different Kratos with different Identities.
  3. Kratos is not SSO
  4. Use Hydra to implement SSO.

Are the above conclusions close to the purpose of ory projects?

kratos-traefik

# docker-compose.yml
services:
  kratos:
    container_name: kratos
    image: oryd/kratos:v0.5.5
    labels:
      - "traefik.http.services.kratos.loadbalancer.server.scheme=http"
      - "traefik.http.services.kratos.loadbalancer.server.port=4433"
      - "traefik.http.services.kratos-svc.loadbalancer.server.scheme=http"
      - "traefik.http.services.kratos-svc.loadbalancer.server.port=4433"
      - "traefik.http.services.kratos-admin.loadbalancer.server.scheme=http"
      - "traefik.http.services.kratos-admin.loadbalancer.server.port=4434"
      - "traefik.http.routers.kratos.service=kratos"
      - "traefik.http.routers.kratos.entrypoints=https"
      - "traefik.http.routers.kratos.tls=true"
      - "traefik.http.routers.kratos.rule=Host(`kratos.example.com`)"
      - "traefik.http.routers.kratos-svc.service=kratos-svc"
      - "traefik.http.routers.kratos-svc.entrypoints=http"
      - "traefik.http.routers.kratos-svc.tls=false"
      - "traefik.http.routers.kratos-svc.rule=Host(`kratos.internal.svc`)"

  kratos-ui:
    container_name: kratos-ui
    image: oryd/kratos-selfservice-ui-node:v0.5.5-alpha.1
    labels:
      - "traefik.http.services.kratos-ui.loadbalancer.server.scheme=http"
      - "traefik.http.services.kratos-ui.loadbalancer.server.port=4455"
      - "traefik.http.routers.kratos-ui-1.entrypoints=https"
      - "traefik.http.routers.kratos-ui-1.tls=true"
      - "traefik.http.routers.kratos-ui-1.service=kratos-ui"
      - "traefik.http.routers.kratos-ui-1.rule=Host(`kratos.example.com`) && Path(`/dashboard`)"
      - "traefik.http.routers.kratos-ui-2.entrypoints=https"
      - "traefik.http.routers.kratos-ui-2.tls=true"
      - "traefik.http.routers.kratos-ui-2.service=kratos-ui"
      - "traefik.http.routers.kratos-ui-2.rule=Host(`kratos.example.com`) && Path(`/{css:.+}.css`)"
      - "traefik.http.routers.kratos-ui-3.entrypoints=https"
      - "traefik.http.routers.kratos-ui-3.tls=true"
      - "traefik.http.routers.kratos-ui-3.service=kratos-ui"
      - "traefik.http.routers.kratos-ui-3.rule=Host(`kratos.example.com`) && PathPrefix(`/auth`)"
    environment:
      - KRATOS_BROWSER_URL=https://kratos.example.com/
      - KRATOS_ADMIN_URL=http://kratos-admin.internal.svc/
      - KRATOS_PUBLIC_URL=http://kratos.internal.svc/
ltouro commented 3 years ago

@hbrls what you described is exactly the setup I'm using. I'm not using Traefik as reverse proxy, so I can't help you with that. But I think the result is the same: Kratos exposes 1 domain/port publicly (kratos.example.com:443) and 2 ports internally (kratos:4433, kratos:4434);

Regarding kratos.yml, here is the tips I think is relevant to you:

serve.public.base_url is the Kratos Public URL (URL: https://kratos.example.com) service.admin.base_url is the Kratos internal URL that your app will use to communicate internally with Kratos (URL: http://kratos:4434/) selfservice.whitelisted_return_urls should contain an entry to your APP URL (https://self-service.example.com) selfservice.default_browser_return_url should point to your APP URL (https://self-service.example.com) serve.public.cors should be configured correctly (see example below)

and the most important one:

session.cookie.domain should be set to the base domain that is shared between your app and kratos (i.e, example.com). That is what allows the cookies to be shared between your subdomains.

Also, remember to change your flow config with the self-service app URL. For example, flows.login.ui_url may point to https://self-service.example.com/login.

ps.: mind the protocols above (HTTP/HTTPS). Do not remove them.

CORS config example:

serve:
  public:
    base_url: https://kratos.example.com
    cors:
      enabled: true
      allowed_origins:
        - https://kratos.example.com
      allowed_methods:
        - POST
        - GET
        - PUT
        - PATCH
        - DELETE
      allowed_headers:
        - Authorization
        - Cookie
      exposed_headers:
        - Content-Type
        - Set-Cookie

Not related to the issue, but in my case the "self-service app" is actually composed by two parts: a front-end react app and a back-end express api. No SSR used. Just for you to know that this setup is also feasible.