KO
|
EN
gitlite — search
Search
#javascript
#python
#hacktoberfest
#react
#ai
#typescript
#llm
#go
#golang
#android
#machine-learning
#rust
#deep-learning
#linux
ory-stack
★ 8
Open GitHub ↗
Ory hydra oathkeeper and keto
Download README (.md)
Explore Similar Repositories
docker-nginx-uwsgi-flask-py3
:
用docker来构建nginx+uwsgi+flask(py3)服务
porolith-pc98
:
Tetris-like game I made in the 1990s for MS-DOS.
WowInterfaces
:
No description available.
vue-cli-plugin-publicpath
:
rewrite assets public path
torrent-clean
:
Deletes files that are not listed in the selected torrent file
// repository documentation
Was this content helpful?
★ 0
(0 ratings)
Select Rating:
★
★
★
★
★
Submit Feedback
Recent Feedback
×
Download README
Do you want to download the
README.md
file for
ory-stack
?
Download (.md)
# ory-stack > A working OAuth2/OIDC and permissions stack: Ory Hydra, Ory Oathkeeper and Ory Keto, wired together and proven by an end-to-end test suite.  Hydra issues tokens, Oathkeeper sits in front of your services and decides who gets through, and Keto answers "may this subject do this thing to this object". Individually they are three servers with three config schemas; the point of this repo is the wiring between them. Everything is Docker Compose plus configuration — there is no Helm chart and nothing here builds a container image. ## Quick start ```sh make up-d # start the stack, wait for every healthcheck make ps make test # bring up an isolated copy, run the e2e suite, tear it down make down # stop everything and drop the volumes ``` `make up-d` needs nothing but Docker. The rest of the toolchain (bats, shfmt, jq) is pinned in `.tool-versions` and installed by `make prepare`. ## What is running | Service | Image | Ports | Role | | ------------ | --------------------------- | ------------------------- | ---- | | `postgres` | `postgres:18-alpine` | internal | Separate `hydra` and `keto` databases | | `hydra` | `oryd/hydra:v26.2.0` | 4444 public, 4445 admin | OAuth2 / OIDC provider | | `keto` | `oryd/keto:v26.2.0` | 4466 read, 4467 write | Zanzibar-style permission server | | `oathkeeper` | `oryd/oathkeeper:v26.2.0` | 4455 proxy, 4456 api | Identity-aware reverse proxy | | `whoami` | `traefik/whoami:v1.12.0` | internal | The protected upstream, echoes what it received | | `consent` | `oryd/hydra-login-consent-node:v26.2.0` | 3000 | Login/consent UI — `dev` profile only | Hydra, Keto and Oathkeeper share a single version number because Ory now releases all three together on a calendar scheme. `v26.2.0` is the March 2026 release; before that the three drifted independently (Hydra 2.3.0, Keto 0.14.0, Oathkeeper 0.40.9). Migrations run as one-shot containers (`hydra-migrate`, `keto-migrate`) that must exit successfully before their server starts. Re-running them is a no-op. ## The request path ``` ┌──────────┐ introspect token ┌───────┐ │ │ ──────────────────► │ hydra │ client ───► │oathkeeper│ └───────┘ │ :4455 │ may sub view obj? ┌───────┐ │ │ ──────────────────► │ keto │ └────┬─────┘ └───────┘ │ + X-Subject, signed ID token ▼ upstream ``` Four access rules ship in `docker/oathkeeper/access-rules.yaml`: | Path | Authentication | Authorization | | ----------------- | ---------------------- | -------------------- | | `/anonymous` | none | allow | | `/forbidden` | none | deny | | `/protected` | Hydra token | allow | | `/documents/<id>` | Hydra token | Keto relation tuple | `/documents/<id>` is the interesting one. Oathkeeper introspects the caller's access token against Hydra, then asks Keto whether that subject has the `view` relation on that document. Grant the tuple and the next request succeeds — no redeploy, no new token, no config reload. ### Try it ```sh make up-d # register a client and get a token client=$(docker compose -f docker/compose.yaml exec -T hydra \ hydra create client --endpoint http://127.0.0.1:4445 --format json \ --grant-type client_credentials --scope documents.read) id=$(echo "$client" | jq -r .client_id) secret=$(echo "$client" | jq -r .client_secret) token=$(curl -s -u "$id:$secret" -d grant_type=client_credentials \ -d scope=documents.read http://127.0.0.1:4444/oauth2/token | jq -r .access_token) # denied: keto knows nothing about this client curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $token" \ http://127.0.0.1:4455/documents/report # 403 # grant the relation curl -s -X PUT http://127.0.0.1:4467/admin/relation-tuples \ -H 'Content-Type: application/json' \ -d "{\"namespace\":\"documents\",\"object\":\"report\",\"relation\":\"view\",\"subject_id\":\"$id\"}" # allowed curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $token" \ http://127.0.0.1:4455/documents/report # 200 ``` ## Configuration `.env.example` documents every knob and is copied to `.env` on first `make`. Each value also has a default baked into `docker/compose.yaml`, so a bare `docker compose -f docker/compose.yaml up` works with no `.env` at all. Service config lives next to the service it configures: ``` docker/ ├── compose.yaml ├── hydra/hydra.yaml ├── keto/keto.yaml ├── oathkeeper/oathkeeper.yaml ├── oathkeeper/access-rules.yaml └── postgres/initdb/10-create-databases.sh ``` Deployment-specific values (DSNs, the issuer URL, secrets) come from the environment rather than the config files, because Ory merges environment variables over file config — `URLS_SELF_ISSUER` overrides `urls.self.issuer`. ## Make targets | Target | Does | | ----------- | ---- | | `prepare` | Installs the toolchain (asdf, cloc, then everything in `.tool-versions`) | | `configure` | Checks that toolchain is on PATH | | `up` / `up-d` | Start the stack, foreground or detached-and-waited | | `down` | Stop everything, including every profile, and drop volumes | | `logs` / `ps` | The obvious | | `test` | Runs `test/e2e` — see below | | `test/e2e` | Brings up an isolated stack, runs bats, tears it down | | `lint` / `format` | `shfmt` over shell sources, plus a compose config check | | `count` | `cloc` over tracked files | | `clean` / `purge` | Tear down and remove generated state / everything untracked | Compose targets accept a profile: `make docker/up-d/dev` starts the login and consent UI alongside the core services. There is no `build` target because nothing here compiles. ## Tests `make test` starts a second, isolated copy of the whole stack under the `ory-stack-test` project name on a `14xxx` port block, so it does not disturb a stack you already have running. It then runs 37 bats tests and tears it down. `KEEP_STACK=1 make test` leaves it up afterwards. The suite covers OIDC discovery and the JWKS endpoint, client registration, the client-credentials grant, introspection and revocation, Keto tuple writes, checks, subject-set indirection, expand and delete, and every Oathkeeper rule including the Hydra-to-Keto authorization path and the ID token handed to the upstream. ## Upgrading from the 2019 version of this repo The original `docker-compose.yaml` targeted Hydra `v1.0.0-beta.9` and configured all three services entirely through environment variables. Almost none of that carries forward: **Hydra.** `DATABASE_URL` became `DSN`. `OAUTH2_ISSUER_URL`, `OAUTH2_LOGIN_URL` and `OAUTH2_CONSENT_URL` became `urls.self.issuer`, `urls.login` and `urls.consent`. Every administrative endpoint moved behind `/admin`, so the old `http://hydra:4445/oauth2/introspect` is now `http://hydra:4445/admin/oauth2/introspect`. Schema migrations became an explicit `hydra migrate sql` step instead of something the server did on boot. `--dangerous-force-http` became `--dev`. **Keto.** This is a rewrite, not an upgrade. The old Keto evaluated ACP policy documents ("warden"); current Keto is a Zanzibar implementation that stores relation tuples and answers reachability queries over them. Policies do not convert — the model has to be re-expressed as namespaces, relations and tuples. Reads and writes are also split across two ports now (4466 and 4467), which means you can expose the read API widely and keep the write API private. **Oathkeeper.** The old setup ran two containers, `serve proxy` and `serve api`, pointed at each other through `OATHKEEPER_API_URL`. That split is gone; one `oathkeeper serve` process handles both. The per-handler environment variables (`AUTHENTICATOR_*`, `AUTHORIZER_*`, `CREDENTIALS_ISSUER_*`) became the `authenticators`, `authorizers` and `mutators` blocks of a config file. **The Keto authorizer specifically.** Oathkeeper still ships a `keto_engine_acp_ory` authorizer, and it still looks like the obvious choice. It is not: it calls the pre-1.0 ACP endpoint that current Keto does not serve. The working integration is the `remote_json` authorizer pointed at Keto's `/relation-tuples/check`, which returns 403 on a failed check — exactly the contract `remote_json` expects. That is what this repo does. **Removed.** The `identity_api`, `dockerhost` and `bastion` services are gone. They were scaffolding for reaching a login/consent app running on the host; the `consent` service under the `dev` profile does that job now. ## Known gaps - **Not production-ready as shipped.** Hydra runs with `--dev` so it will accept a plain-HTTP issuer URL. Put TLS in front of it and drop the flag before this goes anywhere real. The secrets in `.env.example` are placeholders. - **Keto uses an inline namespace list**, not the Ory Permission Language. That is enough for direct relations and subject sets, which is what the rules here need. Computed permissions (`permits`) require an OPL file; `docker/keto/keto.yaml` shows the one-line change. - **The login/consent UI is published for `linux/amd64` only.** On arm64 it runs under emulation and takes a while to boot. It is behind the `dev` profile and nothing in the core stack or the test suite depends on it. - **Access tokens are opaque**, so every proxied request costs Hydra an introspection call. Switch `strategies.access_token` to `jwt` if you would rather have stateless validation and can accept that revocation stops being immediate. ## License [MIT License](LICENSE) [Jam Risser](https://codejamninja.com) © 2019