From 17363b312deff8b92fc1b0d158dc70670d5938e5 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Sun, 12 Apr 2020 13:17:22 +0200 Subject: [PATCH] fix: decouple quickstart scenarios (#336) Creates several docker compose examples which include various scenarios of the quickstart. The regular quickstart guide now works without ORY Oathkeeper and uses the standalone mode of the example app instead. Additionally, the Makefile was improved and now automatically pulls required dependencies in the appropriate version. Closes #262 --- .bin/.gitignore | 2 + .dockerignore | 2 + Makefile | 67 ++-- contrib/quickstart/oathkeeper/.oathkeeper.yml | 1 + .../quickstart/oathkeeper/access-rules.yml | 6 +- docs/config.js | 5 +- ...o-trust-iap-proxy-identity-access-proxy.md | 347 ++++++++++++++++++ docs/docs/quickstart.mdx | 118 +++--- docs/sidebar.js | 47 ++- quickstart-crdb.yml | 16 + quickstart-mysql.yml | 17 + quickstart-oathkeeper.yml | 31 ++ quickstart-postgres.yml | 19 + quickstart-standalone.yml | 9 + quickstart.yml | 30 -- 15 files changed, 587 insertions(+), 130 deletions(-) create mode 100644 .bin/.gitignore create mode 100644 docs/docs/guides/zero-trust-iap-proxy-identity-access-proxy.md create mode 100644 quickstart-crdb.yml create mode 100644 quickstart-mysql.yml create mode 100644 quickstart-oathkeeper.yml create mode 100644 quickstart-postgres.yml create mode 100644 quickstart-standalone.yml diff --git a/.bin/.gitignore b/.bin/.gitignore new file mode 100644 index 000000000000..bb2bac7751ec --- /dev/null +++ b/.bin/.gitignore @@ -0,0 +1,2 @@ +* +.lock diff --git a/.dockerignore b/.dockerignore index 24b46de8bf6a..9eaefbc84509 100644 --- a/.dockerignore +++ b/.dockerignore @@ -10,3 +10,5 @@ database.yaml contrib/quickstart contrib/swagutil node_modules/ +./quickstart.yml +./quickstart-*.yml diff --git a/Makefile b/Makefile index 8fdbdc1c9912..2eb98c4e2abd 100644 --- a/Makefile +++ b/Makefile @@ -1,31 +1,33 @@ SHELL=/bin/bash -o pipefail -all: -ifeq (, $(shell which golangci-lint)) - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.23.2 +EXECUTABLES = docker-compose docker node npm go +K := $(foreach exec,$(EXECUTABLES),\ + $(if $(shell which $(exec)),some string,$(error "No $(exec) in PATH"))) + +export GO111MODULE := on +export PATH := .bin:${PATH} + +deps: +ifneq ("v0",$(shell cat .bin/.lock)) + curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b .bin/ v1.24.0 + go build -o .bin/go-acc github.com/ory/go-acc + go build -o .bin/goreturns github.com/sqs/goreturns + go build -o .bin/listx github.com/ory/x/tools/listx + go build -o .bin/mockgen github.com/golang/mock/mockgen + go build -o .bin/swagger github.com/go-swagger/go-swagger/cmd/swagger + go build -o .bin/goimports golang.org/x/tools/cmd/goimports + go build -o .bin/swagutil github.com/ory/sdk/swagutil + go build -o .bin/packr2 github.com/gobuffalo/packr/v2/packr2 + echo "v0" > .bin/.lock endif -.PHONY: tools -tools: - go install github.com/ory/go-acc github.com/ory/x/tools/listx github.com/go-swagger/go-swagger/cmd/swagger github.com/go-bindata/go-bindata/go-bindata github.com/sqs/goreturns github.com/ory/sdk/swagutil - -.PHONY: build -build: - make sqlbin - CGO_ENABLED=0 GO111MODULE=on GOOS=linux GOARCH=amd64 go build -o kratos . - -.PHONY: init -init: - go install \ - github.com/sqs/goreturns \ - github.com/ory/x/tools/listx \ - github.com/ory/go-acc \ - github.com/golang/mock/mockgen \ - github.com/go-swagger/go-swagger/cmd/swagger \ - golang.org/x/tools/cmd/goimports +.PHONY: docs +docs: + cd docs; npm i; npm run build .PHONY: lint -lint: +lint: deps + which golangci-lint GO111MODULE=on golangci-lint run -v ./... .PHONY: cover @@ -34,20 +36,15 @@ cover: go tool cover -func=cover.out .PHONE: mocks -mocks: +mocks: deps mockgen -mock_names Manager=MockLoginExecutorDependencies -package internal -destination internal/hook_login_executor_dependencies.go github.com/ory/kratos/selfservice loginExecutorDependencies .PHONY: install -install: - packr2 || (GO111MODULE=on go install github.com/gobuffalo/packr/v2/packr2 && packr2) +install: deps + packr2 GO111MODULE=on go install . packr2 clean -# Adds sql files to the binary using go-bindata -.PHONY: sqlbin -sqlbin: - cd driver; go-bindata -o sql_migration_files.go -pkg driver ../contrib/sql/... - .PHONY: test-resetdb test-resetdb: docker kill kratos_test_database_mysql || true @@ -66,7 +63,7 @@ test: test-resetdb # Generates the SDKs .PHONY: sdk -sdk: +sdk: deps $$(go env GOPATH)/bin/swagger generate spec -m -o .schema/api.swagger.json -x internal/httpclient $$(go env GOPATH)/bin/swagutil sanitize ./.schema/api.swagger.json $$(go env GOPATH)/bin/swagger validate ./.schema/api.swagger.json @@ -77,18 +74,20 @@ sdk: $$(go env GOPATH)/bin/swagger generate client -f ./.schema/api.swagger.json -t internal/httpclient -A Ory_Kratos make format +.PHONY: quickstart quickstart: docker pull oryd/kratos:latest-sqlite docker pull oryd/kratos-selfservice-ui-node:latest - docker-compose -f quickstart.yml up --build --force-recreate + docker-compose -f quickstart.yml -f quickstart-standalone.yml up --build --force-recreate +.PHONY: quickstart-dev quickstart-dev: docker build -f .docker/Dockerfile-build -t oryd/kratos:latest-sqlite . - docker-compose -f quickstart.yml up --build --force-recreate + docker-compose -f quickstart.yml -f quickstart-standalone.yml up --build --force-recreate # Formats the code .PHONY: format -format: +format: deps $$(go env GOPATH)/bin/goreturns -w -local github.com/ory $$($$(go env GOPATH)/bin/listx .) # Runs tests in short mode, without database adapters diff --git a/contrib/quickstart/oathkeeper/.oathkeeper.yml b/contrib/quickstart/oathkeeper/.oathkeeper.yml index f84665318da5..51cd7ad58e74 100644 --- a/contrib/quickstart/oathkeeper/.oathkeeper.yml +++ b/contrib/quickstart/oathkeeper/.oathkeeper.yml @@ -46,6 +46,7 @@ errors: verbose: true access_rules: + matching_strategy: glob repositories: - file:///etc/config/oathkeeper/access-rules.yml diff --git a/contrib/quickstart/oathkeeper/access-rules.yml b/contrib/quickstart/oathkeeper/access-rules.yml index 0fd0411ff64d..1cb3ebc55b38 100644 --- a/contrib/quickstart/oathkeeper/access-rules.yml +++ b/contrib/quickstart/oathkeeper/access-rules.yml @@ -5,7 +5,7 @@ url: "http://kratos:4433" strip_path: /.ory/kratos/public match: - url: "http://127.0.0.1:4455/.ory/kratos/public/<.*>" + url: "http://127.0.0.1:4455/.ory/kratos/public/<**>" methods: - GET - POST @@ -26,7 +26,7 @@ preserve_host: true url: "http://kratos-selfservice-ui-node:4435" match: - url: "http://127.0.0.1:4455/<(error|verify|auth/login|auth/registration|(.+\\.css))(|/)>" + url: "http://127.0.0.1:4455/<{error,verify,auth/*,**.css,**.js}{/,}>" methods: - GET authenticators: @@ -44,7 +44,7 @@ preserve_host: true url: "http://kratos-selfservice-ui-node:4435" match: - url: "http://127.0.0.1:4455<(/debug|/|/dashboard|/settings|)(|/)>" + url: "http://127.0.0.1:4455/<{,debug,dashboard,settings}{/,}>" methods: - GET authenticators: diff --git a/docs/config.js b/docs/config.js index 1341edad8a5b..c44aa8e20b8b 100644 --- a/docs/config.js +++ b/docs/config.js @@ -9,7 +9,10 @@ module.exports = { }, { replacer: ({content, next}) => content.replace(/git checkout (v[0-9a-zA-Z\\.\\-]+)/gi, `git checkout ${next}`), - files: ['docs/docs/quickstart.mdx'] + files: [ + 'docs/docs/guides/zero-trust-iap-proxy-identity-access-proxy.md', + 'docs/docs/quickstart.mdx', + ] } ], updateConfig: { diff --git a/docs/docs/guides/zero-trust-iap-proxy-identity-access-proxy.md b/docs/docs/guides/zero-trust-iap-proxy-identity-access-proxy.md new file mode 100644 index 000000000000..ea4ad71d9f8b --- /dev/null +++ b/docs/docs/guides/zero-trust-iap-proxy-identity-access-proxy.md @@ -0,0 +1,347 @@ +--- +id: zero-trust-iap-proxy-identity-access-proxy +title: Zero Trust with IAP Proxy +--- + +import useBaseUrl from '@docusaurus/useBaseUrl' + +The [Quickstart](../quickstart.mdx) covers a basic set up that uses a pipe +in SecureApp to forward requests to ORY Kratos. + +Systems that have more than a few components often use Reverse Proxies such as +Nginx, Envoy, Kong to route and authorize traffic to applications. ORY Kratos +works very well in such a environment and the purpose of this guide +is clarifying how one can use a reverse proxy with IAP (Identity and Access Proxy) +capabilities to authorize incoming requests. In this tutorial, we will +use ORY Oathkeeper to achieve this. + +This guide expects that you have familiarized yourself with ORY Kratos' concepts +and that builds on the components and flows established in the [Quickstart](../quickstart.mdx). + +To ensure that no one can access the dashboard without prior authentication +(login), we will use a reverse proxy +([ORY Oathkeeper](https://github.com/ory/oathkeeper)) to deny all +unauthenticated traffic to `http://secure-app/dashboard` and redirect the user +to the login page at `http://secure-app/auth/login`. Further, we will configure +access to `http://secure-app/auth/login` in such a way that access only works if +one is not yet authenticated. + +## Running ORY Kratos and the ORY Oathkeeper Identity and Access Proxy + +Clone the ORY Kratos repository and fetch the latest images: + +```shell script +git clone https://github.com/ory/kratos.git +# or if you have git+ssh set up: +# git clone git@github.com:ory/kratos.git +cd kratos +git checkout v0.1.1-alpha.1 + +docker pull oryd/kratos:latest-sqlite +docker pull oryd/kratos-selfservice-ui-node:latest +``` + +Next, run the quickstart and add the ORY Oathkeeper config: + +```shell script +docker-compose \ + -f quickstart.yml \ + -f quickstart-oathkeeper.yml \ + up --build --force-recreate +``` + +This might take a minute or two. Once the output slows down and logs indicate a +healthy system you're ready to roll! A healthy system will show something along +the lines of (the order of messages might be reversed): + +``` +kratos_1 | time="2020-01-20T14:52:13Z" level=info msg="Starting the admin httpd on: 0.0.0.0:4434" +kratos_1 | time="2020-01-20T14:52:13Z" level=info msg="Starting the public httpd on: 0.0.0.0:4433" + +oathkeeper_1 | {"level":"info","msg":"TLS has not been configured for api, skipping","time":"2020-01-20T09:22:09Z"} +oathkeeper_1 | {"level":"info","msg":"Listening on http://:4456","time":"2020-01-20T09:22:09Z"} +oathkeeper_1 | {"level":"info","msg":"TLS has not been configured for proxy, skipping","time":"2020-01-20T09:22:09Z"} +oathkeeper_1 | {"level":"info","msg":"Listening on http://:4455","time":"2020-01-20T09:22:09Z"} +``` + +:::note +There are two important factors to get a fully functional system: + +- You need to make sure that ports `4435`, `4455`, `4456`, `4433`, `4434`, + `4436` > + [are free](https://serverfault.com/questions/309052/check-if-port-is-open-or-closed-on-a-linux-server). +- Make sure to always use `127.0.0.1` as the hostname, never use `localhost`! + This is important because browsers treat these two as separate domains and + will therefore have issues with setting and using the right cookies. +::: + +### Network Architecture + +This demo makes use of several services / Docker Images: + +1. [ORY Kratos](https://github.com/ory/kratos) +2. The **SecureApp** - an + [example application written in NodeJS](http://github.com/ory/kratos-selfservice-ui-node) + that implements the login, registration, logout, ..., and dashboard screen. +3. A reverse proxy ([ORY Oathkeeper](https://github.com/ory/oathkeeper)) to + protect the **SecureApp**. +4. An SMTP server with which ORY Kratos can send E-Mails with. We will use + [MailHog](https://github.com/mailhog/MailHog), a minimalistic SMTP throaway + server with an easy UI. + +To better understand how everything is wired, let's take a look at the network +configuration. This assumes that you have at least some understanding of how +Docker (Compose) Networks work: + +[![User Login and Registration Network Topology](https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGggaG5bSG9zdCBOZXR3b3JrXVxuICAgIEJbQnJvd3Nlcl1cbiAgICBCLS0-fENhbiBhY2Nlc3MgVVJMcyB2aWEgMTI3LjAuMC4xOjQ0NTV8T0tQSE5cbiAgICBCLS0-fENhbiBhY2Nlc3MgVUkgdmlhIDEyNy4wLjAuMTo0NDM2fFNNVFBVSVxuICAgIE9LUEhOKFtSZXZlcnNlIFByb3h5IGV4cG9zZWQgYXQgOjQ0NTVdKVxuICAgIFNNVFBVSShbTWFpbFNsdXJwZXIgVUkgZXhwb3NlZCBhdCA6NDQzNl0pXG5lbmRcblxuc3ViZ3JhcGggZG5bXCJJbnRlcm5hbCBEb2NrZXIgTmV0d29yayAoaW50cmFuZXQpXCJdXG4gICAgT0tQSE4tLT5PT1xuICAgIFNNVFBVSS0tPlNNVFBcbiAgICBPTy0tPnxQcm94aWVzIFVSTHNzIC8ub3J5L2tyYXRvcy9wdWJsaWMvKiB0b3xPS1xuICAgIE9PLS0-fFwiUHJveGllcyAvYXV0aC9sb2dpbiwgL2F1dGgvcmVnaXN0cmF0aW9uLCAvZGFzaGJvYXJkLCAuLi4gdG9cInxTQVxuICAgIFNBLS0-fFRhbGtzIHRvfE9LXG4gICAgT0stLT58U2VuZHMgbWFpbCB2aWF8U01UUFxuICAgIE9PLS0-fFZhbGlkYXRlcyBhdXRoIHNlc3Npb25zIHVzaW5nfE9LXG5cbiAgICBPS1tPUlkgS3JhdG9zXVxuICAgIE9PW1wiUmV2ZXJzZSBQcm94eSAoT1JZIE9hdGhrZWVwZXIpXCJdXG4gICAgU0FbXCJTZWN1cmVBcHAgKE9SWSBLcmF0b3MgU2VsZlNlcnZpY2UgVUkgTm9kZSBFeGFtcGxlKVwiXVxuICAgIFNNVFBbXCJTTVRQIFNlcnZlciAoTWFpbFNsdXJwZXIpXCJdXG5lbmRcbiIsIm1lcm1haWQiOnsidGhlbWUiOiJuZXV0cmFsIiwiZmxvd2NoYXJ0Ijp7InJhbmtTcGFjaW5nIjo2NSwibm9kZVNwYWNpbmciOjMwLCJjdXJ2ZSI6ImJhc2lzIn19fQ)](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGggaG5bSG9zdCBOZXR3b3JrXVxuICAgIEJbQnJvd3Nlcl1cbiAgICBCLS0-fENhbiBhY2Nlc3MgVVJMcyB2aWEgMTI3LjAuMC4xOjQ0NTV8T0tQSE5cbiAgICBCLS0-fENhbiBhY2Nlc3MgVUkgdmlhIDEyNy4wLjAuMTo0NDM2fFNNVFBVSVxuICAgIE9LUEhOKFtSZXZlcnNlIFByb3h5IGV4cG9zZWQgYXQgOjQ0NTVdKVxuICAgIFNNVFBVSShbTWFpbFNsdXJwZXIgVUkgZXhwb3NlZCBhdCA6NDQzNl0pXG5lbmRcblxuc3ViZ3JhcGggZG5bXCJJbnRlcm5hbCBEb2NrZXIgTmV0d29yayAoaW50cmFuZXQpXCJdXG4gICAgT0tQSE4tLT5PT1xuICAgIFNNVFBVSS0tPlNNVFBcbiAgICBPTy0tPnxQcm94aWVzIFVSTHNzIC8ub3J5L2tyYXRvcy9wdWJsaWMvKiB0b3xPS1xuICAgIE9PLS0-fFwiUHJveGllcyAvYXV0aC9sb2dpbiwgL2F1dGgvcmVnaXN0cmF0aW9uLCAvZGFzaGJvYXJkLCAuLi4gdG9cInxTQVxuICAgIFNBLS0-fFRhbGtzIHRvfE9LXG4gICAgT0stLT58U2VuZHMgbWFpbCB2aWF8U01UUFxuICAgIE9PLS0-fFZhbGlkYXRlcyBhdXRoIHNlc3Npb25zIHVzaW5nfE9LXG5cbiAgICBPS1tPUlkgS3JhdG9zXVxuICAgIE9PW1wiUmV2ZXJzZSBQcm94eSAoT1JZIE9hdGhrZWVwZXIpXCJdXG4gICAgU0FbXCJTZWN1cmVBcHAgKE9SWSBLcmF0b3MgU2VsZlNlcnZpY2UgVUkgTm9kZSBFeGFtcGxlKVwiXVxuICAgIFNNVFBbXCJTTVRQIFNlcnZlciAoTWFpbFNsdXJwZXIpXCJdXG5lbmRcbiIsIm1lcm1haWQiOnsidGhlbWUiOiJuZXV0cmFsIiwiZmxvd2NoYXJ0Ijp7InJhbmtTcGFjaW5nIjo2NSwibm9kZVNwYWNpbmciOjMwLCJjdXJ2ZSI6ImJhc2lzIn19fQ) + +As you can see, most requests are proxied through the Reverse Proxy +([ORY Oathkeeper](https://github.com/ory/oathkeeper)). The `quickstart.yml` file +also defines additional ports such as `4434`, `4456`, and others. These ports +are only there for debugging and playing around with and are not actually +required for the demo to work. + +The next diagram shows how we've configured the routes in our Reverse Proxy +([ORY Oathkeeper](https://github.com/ory/oathkeeper)): + +[![User Login and Registration Routes](https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGggcGlbUHVibGljIEludGVybmV0XVxuICAgIEJbQnJvd3Nlcl1cbmVuZFxuXG5zdWJncmFwaCB2cGNbVlBDIC8gQ2xvdWQgLyBEb2NrZXIgTmV0d29ya11cbnN1YmdyYXBoIFwiRGVtaWxpdGFyaXplZCBab25lIC8gRE1aXCJcbiAgICBPS1tPUlkgT2F0aGtlZXBlciA6NDQ1NV1cbiAgICBCIC0tPiBPS1xuZW5kXG5cbiAgICBPSyAtLT58XCJGb3J3YXJkcyB7LywvZGFzaGJvYXJkfSB0b1wifCBTQURcbiAgICBPSyAtLT58XCJGb3J3YXJkcyAvYXV0aC9sb2dvdXQgdG9cInwgU0FMVVxuICAgIE9LIC0tPnxcIkZvcndhcmRzIC9hdXRoL2xvZ2luIHRvXCJ8IFNBTElcbiAgICBPSyAtLT58XCJGb3J3YXJkcyAvYXV0aC9yZWdpc3RyYXRpb24gdG9cInwgU0FSXG4gICAgT0sgLS0-fFwiRm9yd2FyZHMgL2F1dGgvKiB0b1wifCBTQUFcbiAgICBPSyAtLT58XCJGb3J3YXJkcyAvLm9yeS9rcmF0b3MvcHVibGljLyogdG9cInwgS1BcblxuICAgIHN1YmdyYXBoIFwiUHJpdmF0ZSBTdWJuZXQgLyBJbnRyYW5ldFwiXG4gICAgS1sgT1JZIEtyYXRvcyBdXG5cbiAgICBLUChbIE9SWSBLcmF0b3MgUHVibGljIEFQSSBdKVxuICAgIEtBKFsgT1JZIEtyYXRvcyBBZG1pbiBBUEkgXSlcbiAgICBTQSAtLT4gS0FcbiAgICBLQSAtLmJlbG9uZ3MgdG8uLT4gS1xuICAgIEtQIC0uYmVsb25ncyB0by4tPiBLXG5cbiAgICBzdWJncmFwaCBzYVtcIlNlY3VyZUFwcCAvIGtyYXRvcy1zZXJsZnNlcnZpY2UtdWktbm9kZSBFeGFtcGxlXCJdXG5cbiAgICAgICAgU0FbU2VjdXJlQXBwXVxuICAgICAgICBTQUQgLS5iZWxvbmdzIHRvLi0-IFNBXG4gICAgICAgIFNBTFUgLS5iZWxvbmdzIHRvLi0-IFNBXG4gICAgICAgIFNBTEkgLS5iZWxvbmdzIHRvLi0-IFNBXG4gICAgICAgIFNBUiAtLmJlbG9uZ3MgdG8uLT4gU0FcbiAgICAgICAgU0FBIC0uYmVsb25ncyB0by4tPiBTQVxuXG4gICAgICAgIHN1YmdyYXBoIFwiSGFzIGFjdGl2ZSBsb2dpbiBzZXNzaW9uXCJcbiAgICAgICAgICAgIFNBRChbUm91dGUgL2Rhc2hib2FyZF0pXG4gICAgICAgICAgICBTQUxVKFtSb3V0ZSAvYXV0aC9sb2dvdXRdKVxuICAgICAgICBlbmRcblxuICAgICAgICBzdWJncmFwaCBcIk5vIGFjdGl2ZSBsb2dpbiBzZXNzaW9uXCJcbiAgICAgICAgICAgIFNBTEkoW1JvdXRlIC9hdXRoL2xvZ2luXSkgXG4gICAgICAgICAgICBTQVIoW1JvdXRlIC9hdXRoL3JlZ2lzdHJhdGlvbl0pIFxuICAgICAgICAgICAgU0FBKFtSb3V0ZSAvYXV0aC8uLi5dKVxuICAgICAgICBlbmRcbiAgICBlbmRcbiAgICBlbmRcblxuZW5kXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoibmV1dHJhbCIsImZsb3djaGFydCI6eyJyYW5rU3BhY2luZyI6NzAsIm5vZGVTcGFjaW5nIjozMCwiY3VydmUiOiJiYXNpcyJ9fX0)](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGggcGlbUHVibGljIEludGVybmV0XVxuICAgIEJbQnJvd3Nlcl1cbmVuZFxuXG5zdWJncmFwaCB2cGNbVlBDIC8gQ2xvdWQgLyBEb2NrZXIgTmV0d29ya11cbnN1YmdyYXBoIFwiRGVtaWxpdGFyaXplZCBab25lIC8gRE1aXCJcbiAgICBPS1tPUlkgT2F0aGtlZXBlciA6NDQ1NV1cbiAgICBCIC0tPiBPS1xuZW5kXG5cbiAgICBPSyAtLT58XCJGb3J3YXJkcyB7LywvZGFzaGJvYXJkfSB0b1wifCBTQURcbiAgICBPSyAtLT58XCJGb3J3YXJkcyAvYXV0aC9sb2dvdXQgdG9cInwgU0FMVVxuICAgIE9LIC0tPnxcIkZvcndhcmRzIC9hdXRoL2xvZ2luIHRvXCJ8IFNBTElcbiAgICBPSyAtLT58XCJGb3J3YXJkcyAvYXV0aC9yZWdpc3RyYXRpb24gdG9cInwgU0FSXG4gICAgT0sgLS0-fFwiRm9yd2FyZHMgL2F1dGgvKiB0b1wifCBTQUFcbiAgICBPSyAtLT58XCJGb3J3YXJkcyAvLm9yeS9rcmF0b3MvcHVibGljLyogdG9cInwgS1BcblxuICAgIHN1YmdyYXBoIFwiUHJpdmF0ZSBTdWJuZXQgLyBJbnRyYW5ldFwiXG4gICAgS1sgT1JZIEtyYXRvcyBdXG5cbiAgICBLUChbIE9SWSBLcmF0b3MgUHVibGljIEFQSSBdKVxuICAgIEtBKFsgT1JZIEtyYXRvcyBBZG1pbiBBUEkgXSlcbiAgICBTQSAtLT4gS0FcbiAgICBLQSAtLmJlbG9uZ3MgdG8uLT4gS1xuICAgIEtQIC0uYmVsb25ncyB0by4tPiBLXG5cbiAgICBzdWJncmFwaCBzYVtcIlNlY3VyZUFwcCAvIGtyYXRvcy1zZXJsZnNlcnZpY2UtdWktbm9kZSBFeGFtcGxlXCJdXG5cbiAgICAgICAgU0FbU2VjdXJlQXBwXVxuICAgICAgICBTQUQgLS5iZWxvbmdzIHRvLi0-IFNBXG4gICAgICAgIFNBTFUgLS5iZWxvbmdzIHRvLi0-IFNBXG4gICAgICAgIFNBTEkgLS5iZWxvbmdzIHRvLi0-IFNBXG4gICAgICAgIFNBUiAtLmJlbG9uZ3MgdG8uLT4gU0FcbiAgICAgICAgU0FBIC0uYmVsb25ncyB0by4tPiBTQVxuXG4gICAgICAgIHN1YmdyYXBoIFwiSGFzIGFjdGl2ZSBsb2dpbiBzZXNzaW9uXCJcbiAgICAgICAgICAgIFNBRChbUm91dGUgL2Rhc2hib2FyZF0pXG4gICAgICAgICAgICBTQUxVKFtSb3V0ZSAvYXV0aC9sb2dvdXRdKVxuICAgICAgICBlbmRcblxuICAgICAgICBzdWJncmFwaCBcIk5vIGFjdGl2ZSBsb2dpbiBzZXNzaW9uXCJcbiAgICAgICAgICAgIFNBTEkoW1JvdXRlIC9hdXRoL2xvZ2luXSkgXG4gICAgICAgICAgICBTQVIoW1JvdXRlIC9hdXRoL3JlZ2lzdHJhdGlvbl0pIFxuICAgICAgICAgICAgU0FBKFtSb3V0ZSAvYXV0aC8uLi5dKVxuICAgICAgICBlbmRcbiAgICBlbmRcbiAgICBlbmRcblxuZW5kXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoibmV1dHJhbCIsImZsb3djaGFydCI6eyJyYW5rU3BhY2luZyI6NzAsIm5vZGVTcGFjaW5nIjozMCwiY3VydmUiOiJiYXNpcyJ9fX0) + +You might notice that we're also proxying requests to ORY Kratos' Public API. We +are doing this because that way all requests are going to and coming from the +same hostname. This avoids common cross-domain issues with cookies. + +## Perform registration, logout, login + +Enough theory, it's time to get this thing going! Let's start by trying to open +the dashboard - **go to +[127.0.0.1:4455/dashboard](http://127.0.0.1:4455/dashboard)**. + +Check the [Quickstart](../quickstart.mdx) for the other flows! + +## Configuration + +You can find all configuration files for this quickstart guide in +`./contrib/quickstart`, `./quickstart.yml`, `./quickstart-oathkeeper.yml`. + +### ORY Oathkeeper: Identity and Access Proxy + +All configuration for [ORY Oathkeeper](https://www.ory.sh/oathkeeper/) resides in `./contrib/quickstart/oathkeeper`. + +#### Configuration + +We define several configuration options for ORY Oathkeeper, such as the port where the proxy should run +or where to load the access rules from. + +##### Cookie Session Authenticator + +The [Cookie Session Authenticator](https://www.ory.sh/docs/oathkeeper/pipeline/authn#cookie_session) +is enabled and points to [ORY Kratos' `/sessions/whoami` API](../reference/api.md). It +uses the `ory_kratos_session` cookie to identify if a request contains a session or not: + +```yaml title="contrib/quickstart/oathkeeper/.oathkeeper.yml" +# ... +authenticators + cookie_session: + enabled: true + config: + check_session_url: http://kratos:4433/sessions/whoami + preserve_path: true + extra_from: "@this" + subject_from: "identity.id" + only: + - ory_kratos_session +# ... +``` + +It's more or less doing what the `needsLogin` function does in the [Quickstart](../quickstart.mdx). + +#### Anonymous Authenticator + +The [Anonymous Authenticator](https://www.ory.sh/docs/oathkeeper/pipeline/authn#anonymous) is useful +for endpoints that do not need login, such as the registration screen: + +```yaml title="contrib/quickstart/oathkeeper/.oathkeeper.yml" +# ... +authenticators + anonymous: + enabled: true + config: + subject: guest +# ... +``` + +#### Allowed Authorizer + +The [Allowed Authenticator](https://www.ory.sh/docs/oathkeeper/pipeline/authz#allowed) simply allows +all users to access the URL. Since we don't have RBAC or ACL in place for this example, this will +be enough. + +```yaml title="contrib/quickstart/oathkeeper/.oathkeeper.yml" +# ... +authorizers + allowed: + enabled: true +# ... +``` + +### ID Token Mutator + +The [ID Token Mutator](https://www.ory.sh/docs/oathkeeper/pipeline/mutator#id_token) takes +all the available session information and puts it into a JSON Web Token (JWT). The protected +SecureApp will now receive `Authorization: bearer ` in the HTTP Header instead of +`Cookie: ory_kratos_session=...`. The JWT is signed using a RS256 key. To verify the JWT +we can use the public key provided by ORY Oathkeeper's JWKS API +`http://127.0.0.1:4456/.well-known/jwks.json`. You can generate the RS256 key yourself by running: +`oathkeeper credentials generate --alg RS256 > id_token.jwks.json`. + +We also enabled the [NoOp Mutator](https://www.ory.sh/docs/oathkeeper/pipeline/mutator#) for +the login, registration, ... endpoints: + +```yaml title="contrib/quickstart/oathkeeper/.oathkeeper.yml" +mutators: + noop: + enabled: true + + id_token: + enabled: true + config: + issuer_url: http://127.0.0.1:4455/ + jwks_url: file:///etc/config/oathkeeper/id_token.jwks.json + claims: | + { + "session": {{ .Extra | toJson }} + } +``` + +You could obviously also use other mutators such as the +[Header Mutator](https://www.ory.sh/docs/oathkeeper/pipeline/mutator#header) and +use headers such as `X-User-ID` instead of the JWT. + +### Error Handling + +We configure the error handling in such a way that a missing or invalid login session +(when accessed from a browser) leads to a redirect to `/auth/login`: + +```yaml title="contrib/quickstart/oathkeeper/.oathkeeper.yml" +errors: + fallback: + - json + + handlers: + redirect: + enabled: true + config: + to: http://127.0.0.1:4455/auth/login + when: + - + error: + - unauthorized + - forbidden + request: + header: + accept: + # We don't want this for application/json requests, only browser requests! + - text/html + json: + enabled: true + config: + verbose: true +``` + +### Access Rules + +We use [glob matching](https://github.com/gobwas/glob) to match the HTTP requests for our access rules: + +```yaml title="contrib/quickstart/oathkeeper/.oathkeeper.yml" +access_rules: + matching_strategy: glob + repositories: + - file:///etc/config/oathkeeper/`access-rules.yml` +``` + +In `access-rules.yml` we define three rules. The first rule forwards all traffic matching `http://127.0.0.1:4455/.ory/kratos/public/` to ORY Kratos' Public API: + + +```yaml title="contrib/quickstart/oathkeeper/access-rules.yml" +- + id: "ory:kratos:public" + upstream: + preserve_host: true + url: "http://kratos:4433" + strip_path: /.ory/kratos/public + match: + url: "http://127.0.0.1:4455/.ory/kratos/public/<**>" + methods: + - GET + - POST + - PUT + - DELETE + - PATCH + authenticators: + - + handler: noop + authorizer: + handler: allow + mutators: + - handler: noop +``` + +The second rule allows anonymous requests to login, registration, re-send verification email, and the error page plus any +assets: + +```yaml title="contrib/quickstart/oathkeeper/access-rules.yml" +# ... +- + id: "ory:kratos-selfservice-ui-node:anonymous" + upstream: + preserve_host: true + url: "http://kratos-selfservice-ui-node:4435" + match: + url: "http://127.0.0.1:4455/<{error,verify,auth/*,**.css,**.js}{/,}>" + methods: + - GET + authenticators: + - + handler: anonymous + authorizer: + handler: allow + mutators: + - + handler: noop +``` + +And the final rule requires a valid session before allowing requests to the dashboard and user settings: + +```yaml title="contrib/quickstart/oathkeeper/access-rules.yml" +# ... +- + id: "ory:kratos-selfservice-ui-node:protected" + upstream: + preserve_host: true + url: "http://kratos-selfservice-ui-node:4435" + match: + url: "http://127.0.0.1:4455/<{,debug,dashboard,settings}{/,}>" + methods: + - GET + authenticators: + - + handler: cookie_session + authorizer: + handler: allow + mutators: + - handler: id_token + errors: + - handler: redirect + config: + to: http://127.0.0.1:4455/auth/login +``` + +## Cleaning up Docker + +To clean everything up, you need to bring down the Docker Compose environment +and remove all mounted volumes. + +```shell script +docker-compose -f quickstart.yml -f quickstart-oathkeeper.yml down -v +docker-compose -f quickstart.yml -f quickstart-oathkeeper.yml rm -f -s -v +``` diff --git a/docs/docs/quickstart.mdx b/docs/docs/quickstart.mdx index 04a4a361374d..4b5f882b45a6 100644 --- a/docs/docs/quickstart.mdx +++ b/docs/docs/quickstart.mdx @@ -56,12 +56,59 @@ Templating Engine. We will implement all the user-facing UIs (dashboard, login, registration, ...) in our NodeJS SecureApp! To ensure that no one can access the dashboard without prior authentication -(login), we will use a reverse proxy -([ORY Oathkeeper](https://github.com/ory/oathkeeper)) to deny all -unauthenticated traffic to `http://secure-app/dashboard` and redirect the user -to the login page at `http://secure-app/auth/login`. Further, we will configure -access to `http://secure-app/auth/login` in such a way that access only works if -one is not yet authenticated. +(login), we can use a small piece of code (here ExpressJS) +to do that: + +```js +// Import the ORY Kratos SDK. SDKs are available for all popular programming +// languages! +// +// We will add examples for other programming languages here soon! +import { KratosPublicSDK } from '@oryd/kratos-client' + +// You can use protect as a middleware for expressJS: +// +// import express from 'express' +// const app = express() +// app.get("/dashboard", needsLogin, dashboard) +// +const needsLogin = (req, res, next) => { + new KratosPublicSDK("https://public.ory-kratos") + .whoami(req).then(({ body }) => { + req.user = { session: body } + next() + }).catch(() => { res.redirect('/login') }) +} +``` + +:::info +ORY Kratos is not just an API, it uses cookies, HTTP redirects, Anti-CSRF Tokens +and more so you don't have to! +::: + +Because our SecureApp and ORY Kratos need to share cookies, in order for Anti-CSRF Tokens +and Login Session to work, we will set up path with forwards requests to ORY Krato's Public API. +If a HTTP Request to `https://my-secureap/.ory/kratos/public/self-service/browser/flows/login` +is made, we forward (like a proxy) the request to `https://public.ory-kratos/self-service/browser/flows/login` +and pipe the response back to the initial HTTP Request: + +```js +import express from 'express' +import request from 'request' +const app = express() + +const pathPrefix = '/.ory/kratos/public' +app.use(pathPrefix + '/', (req, res) => { + const url = 'https://public.ory-kratos' + req.url.replace(pathPrefix, '') + + // Uses the request library to forward the request to ORY Kratos + req.pipe(request(url, { followRedirect: false })).pipe(res) +}) + +// ... +// app.get("/dashboard", needsLogin, dashboard) +// ... +``` ORY Kratos does not ship with an administrative user interface. You must implement that yourself or choose the ORY Cloud offering (to be announced). In @@ -103,7 +150,7 @@ make quickstart # or if you don't have make installed: docker pull oryd/kratos:latest-sqlite docker pull oryd/kratos-selfservice-ui-node:latest -docker-compose -f quickstart.yml up --build --force-recreate +docker-compose -f quickstart.yml -f quickstart-standalone.yml up --build --force-recreate ``` This might take a minute or two. Once the output slows down and logs indicate a @@ -113,18 +160,12 @@ the lines of (the order of messages might be reversed): ``` kratos_1 | time="2020-01-20T14:52:13Z" level=info msg="Starting the admin httpd on: 0.0.0.0:4434" kratos_1 | time="2020-01-20T14:52:13Z" level=info msg="Starting the public httpd on: 0.0.0.0:4433" - -oathkeeper_1 | {"level":"info","msg":"TLS has not been configured for api, skipping","time":"2020-01-20T09:22:09Z"} -oathkeeper_1 | {"level":"info","msg":"Listening on http://:4456","time":"2020-01-20T09:22:09Z"} -oathkeeper_1 | {"level":"info","msg":"TLS has not been configured for proxy, skipping","time":"2020-01-20T09:22:09Z"} -oathkeeper_1 | {"level":"info","msg":"Listening on http://:4455","time":"2020-01-20T09:22:09Z"} ``` :::note There are two important factors to get a fully functional system: -- You need to make sure that ports `4435`, `4455`, `4456`, `4433`, `4434`, - `4436` > +- You need to make sure that ports `4455`, `4433`, `4434`, `4436` > [are free](https://serverfault.com/questions/309052/check-if-port-is-open-or-closed-on-a-linux-server). - Make sure to always use `127.0.0.1` as the hostname, never use `localhost`! This is important because browsers treat these two as separate domains and @@ -144,9 +185,7 @@ This demo makes use of several services / Docker Images: 2. The **SecureApp** - an [example application written in NodeJS](http://github.com/ory/kratos-selfservice-ui-node) that implements the login, registration, logout, ..., and dashboard screen. -3. A reverse proxy ([ORY Oathkeeper](https://github.com/ory/oathkeeper)) to - protect the **SecureApp**. -4. An SMTP server with which ORY Kratos can send E-Mails with. We will use +3. An SMTP server with which ORY Kratos can send E-Mails with. We will use [MailHog](https://github.com/mailhog/MailHog), a minimalistic SMTP throaway server with an easy UI. @@ -154,20 +193,9 @@ To better understand how everything is wired, let's take a look at the network configuration. This assumes that you have at least some understanding of how Docker (Compose) Networks work: -[![User Login and Registration Network Topology](https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGggaG5bSG9zdCBOZXR3b3JrXVxuICAgIEJbQnJvd3Nlcl1cbiAgICBCLS0-fENhbiBhY2Nlc3MgVVJMcyB2aWEgMTI3LjAuMC4xOjQ0NTV8T0tQSE5cbiAgICBCLS0-fENhbiBhY2Nlc3MgVUkgdmlhIDEyNy4wLjAuMTo0NDM2fFNNVFBVSVxuICAgIE9LUEhOKFtSZXZlcnNlIFByb3h5IGV4cG9zZWQgYXQgOjQ0NTVdKVxuICAgIFNNVFBVSShbTWFpbFNsdXJwZXIgVUkgZXhwb3NlZCBhdCA6NDQzNl0pXG5lbmRcblxuc3ViZ3JhcGggZG5bXCJJbnRlcm5hbCBEb2NrZXIgTmV0d29yayAoaW50cmFuZXQpXCJdXG4gICAgT0tQSE4tLT5PT1xuICAgIFNNVFBVSS0tPlNNVFBcbiAgICBPTy0tPnxQcm94aWVzIFVSTHNzIC8ub3J5L2tyYXRvcy9wdWJsaWMvKiB0b3xPS1xuICAgIE9PLS0-fFwiUHJveGllcyAvYXV0aC9sb2dpbiwgL2F1dGgvcmVnaXN0cmF0aW9uLCAvZGFzaGJvYXJkLCAuLi4gdG9cInxTQVxuICAgIFNBLS0-fFRhbGtzIHRvfE9LXG4gICAgT0stLT58U2VuZHMgbWFpbCB2aWF8U01UUFxuICAgIE9PLS0-fFZhbGlkYXRlcyBhdXRoIHNlc3Npb25zIHVzaW5nfE9LXG5cbiAgICBPS1tPUlkgS3JhdG9zXVxuICAgIE9PW1wiUmV2ZXJzZSBQcm94eSAoT1JZIE9hdGhrZWVwZXIpXCJdXG4gICAgU0FbXCJTZWN1cmVBcHAgKE9SWSBLcmF0b3MgU2VsZlNlcnZpY2UgVUkgTm9kZSBFeGFtcGxlKVwiXVxuICAgIFNNVFBbXCJTTVRQIFNlcnZlciAoTWFpbFNsdXJwZXIpXCJdXG5lbmRcbiIsIm1lcm1haWQiOnsidGhlbWUiOiJuZXV0cmFsIiwiZmxvd2NoYXJ0Ijp7InJhbmtTcGFjaW5nIjo2NSwibm9kZVNwYWNpbmciOjMwLCJjdXJ2ZSI6ImJhc2lzIn19fQ)](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGggaG5bSG9zdCBOZXR3b3JrXVxuICAgIEJbQnJvd3Nlcl1cbiAgICBCLS0-fENhbiBhY2Nlc3MgVVJMcyB2aWEgMTI3LjAuMC4xOjQ0NTV8T0tQSE5cbiAgICBCLS0-fENhbiBhY2Nlc3MgVUkgdmlhIDEyNy4wLjAuMTo0NDM2fFNNVFBVSVxuICAgIE9LUEhOKFtSZXZlcnNlIFByb3h5IGV4cG9zZWQgYXQgOjQ0NTVdKVxuICAgIFNNVFBVSShbTWFpbFNsdXJwZXIgVUkgZXhwb3NlZCBhdCA6NDQzNl0pXG5lbmRcblxuc3ViZ3JhcGggZG5bXCJJbnRlcm5hbCBEb2NrZXIgTmV0d29yayAoaW50cmFuZXQpXCJdXG4gICAgT0tQSE4tLT5PT1xuICAgIFNNVFBVSS0tPlNNVFBcbiAgICBPTy0tPnxQcm94aWVzIFVSTHNzIC8ub3J5L2tyYXRvcy9wdWJsaWMvKiB0b3xPS1xuICAgIE9PLS0-fFwiUHJveGllcyAvYXV0aC9sb2dpbiwgL2F1dGgvcmVnaXN0cmF0aW9uLCAvZGFzaGJvYXJkLCAuLi4gdG9cInxTQVxuICAgIFNBLS0-fFRhbGtzIHRvfE9LXG4gICAgT0stLT58U2VuZHMgbWFpbCB2aWF8U01UUFxuICAgIE9PLS0-fFZhbGlkYXRlcyBhdXRoIHNlc3Npb25zIHVzaW5nfE9LXG5cbiAgICBPS1tPUlkgS3JhdG9zXVxuICAgIE9PW1wiUmV2ZXJzZSBQcm94eSAoT1JZIE9hdGhrZWVwZXIpXCJdXG4gICAgU0FbXCJTZWN1cmVBcHAgKE9SWSBLcmF0b3MgU2VsZlNlcnZpY2UgVUkgTm9kZSBFeGFtcGxlKVwiXVxuICAgIFNNVFBbXCJTTVRQIFNlcnZlciAoTWFpbFNsdXJwZXIpXCJdXG5lbmRcbiIsIm1lcm1haWQiOnsidGhlbWUiOiJuZXV0cmFsIiwiZmxvd2NoYXJ0Ijp7InJhbmtTcGFjaW5nIjo2NSwibm9kZVNwYWNpbmciOjMwLCJjdXJ2ZSI6ImJhc2lzIn19fQ) - -As you can see, most requests are proxied through the Reverse Proxy -([ORY Oathkeeper](https://github.com/ory/oathkeeper)). The `quickstart.yml` file -also defines additional ports such as `4434`, `4456`, and others. These ports -are only there for debugging and playing around with and are not actually -required for the demo to work. - -The next diagram shows how we've configured the routes in our Reverse Proxy -([ORY Oathkeeper](https://github.com/ory/oathkeeper)): - -[![User Login and Registration Routes](https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGggcGlbUHVibGljIEludGVybmV0XVxuICAgIEJbQnJvd3Nlcl1cbmVuZFxuXG5zdWJncmFwaCB2cGNbVlBDIC8gQ2xvdWQgLyBEb2NrZXIgTmV0d29ya11cbnN1YmdyYXBoIFwiRGVtaWxpdGFyaXplZCBab25lIC8gRE1aXCJcbiAgICBPS1tPUlkgT2F0aGtlZXBlciA6NDQ1NV1cbiAgICBCIC0tPiBPS1xuZW5kXG5cbiAgICBPSyAtLT58XCJGb3J3YXJkcyB7LywvZGFzaGJvYXJkfSB0b1wifCBTQURcbiAgICBPSyAtLT58XCJGb3J3YXJkcyAvYXV0aC9sb2dvdXQgdG9cInwgU0FMVVxuICAgIE9LIC0tPnxcIkZvcndhcmRzIC9hdXRoL2xvZ2luIHRvXCJ8IFNBTElcbiAgICBPSyAtLT58XCJGb3J3YXJkcyAvYXV0aC9yZWdpc3RyYXRpb24gdG9cInwgU0FSXG4gICAgT0sgLS0-fFwiRm9yd2FyZHMgL2F1dGgvKiB0b1wifCBTQUFcbiAgICBPSyAtLT58XCJGb3J3YXJkcyAvLm9yeS9rcmF0b3MvcHVibGljLyogdG9cInwgS1BcblxuICAgIHN1YmdyYXBoIFwiUHJpdmF0ZSBTdWJuZXQgLyBJbnRyYW5ldFwiXG4gICAgS1sgT1JZIEtyYXRvcyBdXG5cbiAgICBLUChbIE9SWSBLcmF0b3MgUHVibGljIEFQSSBdKVxuICAgIEtBKFsgT1JZIEtyYXRvcyBBZG1pbiBBUEkgXSlcbiAgICBTQSAtLT4gS0FcbiAgICBLQSAtLmJlbG9uZ3MgdG8uLT4gS1xuICAgIEtQIC0uYmVsb25ncyB0by4tPiBLXG5cbiAgICBzdWJncmFwaCBzYVtcIlNlY3VyZUFwcCAvIGtyYXRvcy1zZXJsZnNlcnZpY2UtdWktbm9kZSBFeGFtcGxlXCJdXG5cbiAgICAgICAgU0FbU2VjdXJlQXBwXVxuICAgICAgICBTQUQgLS5iZWxvbmdzIHRvLi0-IFNBXG4gICAgICAgIFNBTFUgLS5iZWxvbmdzIHRvLi0-IFNBXG4gICAgICAgIFNBTEkgLS5iZWxvbmdzIHRvLi0-IFNBXG4gICAgICAgIFNBUiAtLmJlbG9uZ3MgdG8uLT4gU0FcbiAgICAgICAgU0FBIC0uYmVsb25ncyB0by4tPiBTQVxuXG4gICAgICAgIHN1YmdyYXBoIFwiSGFzIGFjdGl2ZSBsb2dpbiBzZXNzaW9uXCJcbiAgICAgICAgICAgIFNBRChbUm91dGUgL2Rhc2hib2FyZF0pXG4gICAgICAgICAgICBTQUxVKFtSb3V0ZSAvYXV0aC9sb2dvdXRdKVxuICAgICAgICBlbmRcblxuICAgICAgICBzdWJncmFwaCBcIk5vIGFjdGl2ZSBsb2dpbiBzZXNzaW9uXCJcbiAgICAgICAgICAgIFNBTEkoW1JvdXRlIC9hdXRoL2xvZ2luXSkgXG4gICAgICAgICAgICBTQVIoW1JvdXRlIC9hdXRoL3JlZ2lzdHJhdGlvbl0pIFxuICAgICAgICAgICAgU0FBKFtSb3V0ZSAvYXV0aC8uLi5dKVxuICAgICAgICBlbmRcbiAgICBlbmRcbiAgICBlbmRcblxuZW5kXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoibmV1dHJhbCIsImZsb3djaGFydCI6eyJyYW5rU3BhY2luZyI6NzAsIm5vZGVTcGFjaW5nIjozMCwiY3VydmUiOiJiYXNpcyJ9fX0)](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGggcGlbUHVibGljIEludGVybmV0XVxuICAgIEJbQnJvd3Nlcl1cbmVuZFxuXG5zdWJncmFwaCB2cGNbVlBDIC8gQ2xvdWQgLyBEb2NrZXIgTmV0d29ya11cbnN1YmdyYXBoIFwiRGVtaWxpdGFyaXplZCBab25lIC8gRE1aXCJcbiAgICBPS1tPUlkgT2F0aGtlZXBlciA6NDQ1NV1cbiAgICBCIC0tPiBPS1xuZW5kXG5cbiAgICBPSyAtLT58XCJGb3J3YXJkcyB7LywvZGFzaGJvYXJkfSB0b1wifCBTQURcbiAgICBPSyAtLT58XCJGb3J3YXJkcyAvYXV0aC9sb2dvdXQgdG9cInwgU0FMVVxuICAgIE9LIC0tPnxcIkZvcndhcmRzIC9hdXRoL2xvZ2luIHRvXCJ8IFNBTElcbiAgICBPSyAtLT58XCJGb3J3YXJkcyAvYXV0aC9yZWdpc3RyYXRpb24gdG9cInwgU0FSXG4gICAgT0sgLS0-fFwiRm9yd2FyZHMgL2F1dGgvKiB0b1wifCBTQUFcbiAgICBPSyAtLT58XCJGb3J3YXJkcyAvLm9yeS9rcmF0b3MvcHVibGljLyogdG9cInwgS1BcblxuICAgIHN1YmdyYXBoIFwiUHJpdmF0ZSBTdWJuZXQgLyBJbnRyYW5ldFwiXG4gICAgS1sgT1JZIEtyYXRvcyBdXG5cbiAgICBLUChbIE9SWSBLcmF0b3MgUHVibGljIEFQSSBdKVxuICAgIEtBKFsgT1JZIEtyYXRvcyBBZG1pbiBBUEkgXSlcbiAgICBTQSAtLT4gS0FcbiAgICBLQSAtLmJlbG9uZ3MgdG8uLT4gS1xuICAgIEtQIC0uYmVsb25ncyB0by4tPiBLXG5cbiAgICBzdWJncmFwaCBzYVtcIlNlY3VyZUFwcCAvIGtyYXRvcy1zZXJsZnNlcnZpY2UtdWktbm9kZSBFeGFtcGxlXCJdXG5cbiAgICAgICAgU0FbU2VjdXJlQXBwXVxuICAgICAgICBTQUQgLS5iZWxvbmdzIHRvLi0-IFNBXG4gICAgICAgIFNBTFUgLS5iZWxvbmdzIHRvLi0-IFNBXG4gICAgICAgIFNBTEkgLS5iZWxvbmdzIHRvLi0-IFNBXG4gICAgICAgIFNBUiAtLmJlbG9uZ3MgdG8uLT4gU0FcbiAgICAgICAgU0FBIC0uYmVsb25ncyB0by4tPiBTQVxuXG4gICAgICAgIHN1YmdyYXBoIFwiSGFzIGFjdGl2ZSBsb2dpbiBzZXNzaW9uXCJcbiAgICAgICAgICAgIFNBRChbUm91dGUgL2Rhc2hib2FyZF0pXG4gICAgICAgICAgICBTQUxVKFtSb3V0ZSAvYXV0aC9sb2dvdXRdKVxuICAgICAgICBlbmRcblxuICAgICAgICBzdWJncmFwaCBcIk5vIGFjdGl2ZSBsb2dpbiBzZXNzaW9uXCJcbiAgICAgICAgICAgIFNBTEkoW1JvdXRlIC9hdXRoL2xvZ2luXSkgXG4gICAgICAgICAgICBTQVIoW1JvdXRlIC9hdXRoL3JlZ2lzdHJhdGlvbl0pIFxuICAgICAgICAgICAgU0FBKFtSb3V0ZSAvYXV0aC8uLi5dKVxuICAgICAgICBlbmRcbiAgICBlbmRcbiAgICBlbmRcblxuZW5kXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoibmV1dHJhbCIsImZsb3djaGFydCI6eyJyYW5rU3BhY2luZyI6NzAsIm5vZGVTcGFjaW5nIjozMCwiY3VydmUiOiJiYXNpcyJ9fX0) +[![User Login and Registration Network Topology](https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGggaG5bSG9zdCBOZXR3b3JrXVxuICAgIEJbQnJvd3Nlcl1cbiAgICBCLS0-fENhbiBhY2Nlc3MgVVJMcyB2aWEgMTI3LjAuMC4xOjQ0NTV8T0tQSE5cbiAgICBCLS0-fENhbiBhY2Nlc3MgVUkgdmlhIDEyNy4wLjAuMTo0NDM2fFNNVFBVSVxuICAgIE9LUEhOKFtTZWN1cmVBcHAgZXhwb3NlZCBhdCA6NDQ1NV0pXG4gICAgU01UUFVJKFtNYWlsU2x1cnBlciBVSSBleHBvc2VkIGF0IDo0NDM2XSlcbmVuZFxuXG5zdWJncmFwaCBkbltcIkludGVybmFsIERvY2tlciBOZXR3b3JrIChpbnRyYW5ldClcIl1cbiAgICBPS1BITi0uLT5TQVxuICAgIFNNVFBVSS0uLT5TTVRQXG4gICAgU0EtLT58UHJveGllcyBVUkxzIC8ub3J5L2tyYXRvcy9wdWJsaWMvKiB0b3xPS1xuICAgIFNBLS0-fFRhbGtzIHRvIGFuZCB2YWxpZGF0ZXMgbG9naW4gc2Vzc2lvbnMgdXNpbmd8T0tcbiAgICBPSy0tPnxTZW5kcyBtYWlsIHZpYXxTTVRQXG5cbiAgICBPS1tPUlkgS3JhdG9zXVxuICAgIFNBW1wiU2VjdXJlQXBwIChPUlkgS3JhdG9zIFNlbGZTZXJ2aWNlIFVJIE5vZGUgRXhhbXBsZSlcIl1cbiAgICBTTVRQW1wiU01UUCBTZXJ2ZXIgKE1haWxTbHVycGVyKVwiXVxuZW5kXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoibmV1dHJhbCIsImZsb3djaGFydCI6eyJyYW5rU3BhY2luZyI6NjUsIm5vZGVTcGFjaW5nIjozMCwiY3VydmUiOiJiYXNpcyJ9fSwidXBkYXRlRWRpdG9yIjpmYWxzZX0)](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGggaG5bSG9zdCBOZXR3b3JrXVxuICAgIEJbQnJvd3Nlcl1cbiAgICBCLS0-fENhbiBhY2Nlc3MgVVJMcyB2aWEgMTI3LjAuMC4xOjQ0NTV8T0tQSE5cbiAgICBCLS0-fENhbiBhY2Nlc3MgVUkgdmlhIDEyNy4wLjAuMTo0NDM2fFNNVFBVSVxuICAgIE9LUEhOKFtTZWN1cmVBcHAgZXhwb3NlZCBhdCA6NDQ1NV0pXG4gICAgU01UUFVJKFtNYWlsU2x1cnBlciBVSSBleHBvc2VkIGF0IDo0NDM2XSlcbmVuZFxuXG5zdWJncmFwaCBkbltcIkludGVybmFsIERvY2tlciBOZXR3b3JrIChpbnRyYW5ldClcIl1cbiAgICBPS1BITi0uLT5TQVxuICAgIFNNVFBVSS0uLT5TTVRQXG4gICAgU0EtLT58UHJveGllcyBVUkxzIC8ub3J5L2tyYXRvcy9wdWJsaWMvKiB0b3xPS1xuICAgIFNBLS0-fFRhbGtzIHRvIGFuZCB2YWxpZGF0ZXMgbG9naW4gc2Vzc2lvbnMgdXNpbmd8T0tcbiAgICBPSy0tPnxTZW5kcyBtYWlsIHZpYXxTTVRQXG5cbiAgICBPS1tPUlkgS3JhdG9zXVxuICAgIFNBW1wiU2VjdXJlQXBwIChPUlkgS3JhdG9zIFNlbGZTZXJ2aWNlIFVJIE5vZGUgRXhhbXBsZSlcIl1cbiAgICBTTVRQW1wiU01UUCBTZXJ2ZXIgKE1haWxTbHVycGVyKVwiXVxuZW5kXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoibmV1dHJhbCIsImZsb3djaGFydCI6eyJyYW5rU3BhY2luZyI6NjUsIm5vZGVTcGFjaW5nIjozMCwiY3VydmUiOiJiYXNpcyJ9fSwidXBkYXRlRWRpdG9yIjpmYWxzZX0) -You might notice that we're also proxying requests to ORY Kratos' Public API. We +As already explained, we're proxying requests to ORY Kratos' Public API. We are doing this because that way all requests are going to and coming from the same hostname. This avoids common cross-domain issues with cookies. @@ -178,16 +206,15 @@ the dashboard - **go to [127.0.0.1:4455/dashboard](http://127.0.0.1:4455/dashboard)**. You will probably notice that you're ending up at the login endpoint: -Login screen of your secured app; +Login screen of your secured app Looking at the network stack, you can see two redirects happening: -Network trace of your secured app; +Network trace of your secured app The first redirect from `http://127.0.0.1:4445/dashboard` to -`http://127.0.0.1:4455/.ory/kratos/public/auth/browser/login` is initiated by -the Reverse Proxy ([ORY Oathkeeper](https://github.com/ory/oathkeeper)) because -the browser does not have a valid authentication (login) session yet. The +`http://127.0.0.1:4455/.ory/kratos/public/self-service/browser/flows/login` is initiated +because the browser does not have a valid authentication (login) session yet. The redirect points to one of ORY Krato's APIs used for logging in browser-based applications. ORY Kratos does some security checks and prepares form data and redirects the browser to `http://127.0.0.1:4445/auth/login`, appending a @@ -201,7 +228,7 @@ $ curl http://127.0.0.1:4434/self-service/browser/flows/requests/login?request=< "id": "27aa98bc-a074-418f-96fa-8b8146050209", "expires_at": "2020-01-20T21:10:12.7365393Z", "issued_at": "2020-01-20T21:00:12.7365532Z", - "request_url": "http://127.0.0.1:4455/auth/browser/login", + "request_url": "http://127.0.0.1:4455/self-service/browser/flows/login", "methods": { "password": { "method": "password", @@ -235,21 +262,21 @@ $ curl http://127.0.0.1:4434/self-service/browser/flows/requests/login?request=< This data is then rendered as an HTML form. This flow also works with Single Page Apps (SPA) and Frameworks like Angular or ReactJS. For more details about the specific flows (login, registration, logout, ...), head over to the -[concept](./concepts/index.md) chapter. +[concept](concepts/index.md) chapter. Let's move on to the next flow - registration! Click on "Create an account", which initiates a flow similar to the one we just used: -Registration screen of your secured app; +Registration screen of your secured app The network trace looks familiar by now: -Registration with network trace screen of your secured app; +Registration with network trace screen of your secured app If we try to sign up using a password like `123456`, ORY Krato's password policy will complain: -Registration with network trace screen of your secured app; +Registration with network trace screen of your secured app The error message is coming directly from ORY Krato's API: @@ -259,7 +286,7 @@ $ curl http://127.0.0.1:4434/self-service/browser/flows/requests/registration?re "id": "79349cbd-c785-476a-8db8-d0d71c5b003c", "expires_at": "2020-01-20T21:17:00.5077381Z", "issued_at": "2020-01-20T21:07:00.5077527Z", - "request_url": "http://127.0.0.1:4455/auth/browser/registration", + "request_url": "http://127.0.0.1:4455/self-service/browser/flows/registration", "methods": { "password": { "method": "password", @@ -297,14 +324,14 @@ $ curl http://127.0.0.1:4434/self-service/browser/flows/requests/registration?re Setting a password that doesn't violate these policies, we will be immediately redirected to the Dashboard: -SecureApp Dashboard; +SecureApp Dashboard By using "logout" you will be redirected to the log in screen again an will be able to use the credentials just set up to log in! ### Understanding how Login and Registration works -Head over to the [Self-Service Flows Chapter](./self-service/flows/index.md) for +Head over to the [Self-Service Flows Chapter](self-service/flows/index.md) for a in-depth explanation of how the individual flows work. ### Email Verification @@ -316,7 +343,7 @@ You can retrieve the email however by opening the MailSlurper UI at You should see something like this: -User Email Verification; +User Email Verification If not, hard refresh the tab or click on the home icon in the menu bar. @@ -324,7 +351,7 @@ Next, click the verification link. You will end up at the dashboard, with a verified E-Mail Address (check the `verified` and `verified_at` field in the JSON Payload): -SecureApp Dashboard; +SecureApp Dashboard To re-request the verification email, fill out the form at [127.0.0.1:4455/verify](http://127.0.0.1:4455/verify). @@ -339,7 +366,6 @@ this documentation. In the future, this guide will support more use cases such as: - Use GitHub to login in and sign up -- Use PostgreSQL / MySQL instead of SQLite ## Cleaning up Docker diff --git a/docs/sidebar.js b/docs/sidebar.js index b54b55e8811c..1437b87790f9 100644 --- a/docs/sidebar.js +++ b/docs/sidebar.js @@ -11,23 +11,38 @@ module.exports = { "concepts/federation", "concepts/security" ], - "Self Service Flows": [ - "self-service/flows/index", - "self-service/flows/user-login-user-registration", - "self-service/flows/user-logout", - "self-service/flows/user-settings-profile-management", - "self-service/flows/password-reset-account-recovery", - "self-service/flows/user-facing-errors", - "self-service/flows/verify-email-account-activation" + "Self Service": [ + { + type: "category", + label: "Flows", items: [ + "self-service/flows/index", + "self-service/flows/user-login-user-registration", + "self-service/flows/user-logout", + "self-service/flows/user-settings-profile-management", + "self-service/flows/password-reset-account-recovery", + "self-service/flows/user-facing-errors", + "self-service/flows/verify-email-account-activation" + + ] + }, + { + type: "category", + label: "Strategies", items: [ + "self-service/strategies/index", + "self-service/strategies/username-email-password", + "self-service/strategies/openid-connect-social-sign-in-oauth2" + ] + }, + { + type: "category", + label: "Hooks / Jobs", items: [ + "self-service/workflows/jobs/before", + "self-service/workflows/jobs/after" + ] + } ], - "Self Service Strategies": [ - "self-service/strategies/index", - "self-service/strategies/username-email-password", - "self-service/strategies/openid-connect-social-sign-in-oauth2" - ], - "Self Service Jobs and Workflows": [ - "self-service/workflows/jobs/before", - "self-service/workflows/jobs/after" + Guides: [ + "guides/zero-trust-iap-proxy-identity-access-proxy" ], "Reference": [ "reference/configuration", diff --git a/quickstart-crdb.yml b/quickstart-crdb.yml new file mode 100644 index 000000000000..f0a3ce9366d4 --- /dev/null +++ b/quickstart-crdb.yml @@ -0,0 +1,16 @@ +version: '3.7' + +services: + kratos-migrate: + environment: + - DSN=cockroach://root@cockroachd:26257/defaultdb?sslmode=disable&max_conns=20&max_idle_conns=4 + + kratos: + environment: + - DSN=cockroach://root@cockroachd:26257/defaultdb?sslmode=disable&max_conns=20&max_idle_conns=4 + + cockroachd: + image: cockroachdb/cockroach:v2.1.6 + ports: + - "26257:26257" + command: start --insecure diff --git a/quickstart-mysql.yml b/quickstart-mysql.yml new file mode 100644 index 000000000000..b76bb86f9fe0 --- /dev/null +++ b/quickstart-mysql.yml @@ -0,0 +1,17 @@ +version: '3.7' + +services: + kratos-migrate: + environment: + - DSN=mysql://root:secret@tcp(mysqld:3306)/mysql?max_conns=20&max_idle_conns=4 + + kratos: + environment: + - DSN=mysql://root:secret@tcp(mysqld:3306)/mysql?max_conns=20&max_idle_conns=4 + + mysqld: + image: mysql:5.7 + ports: + - "3306:3306" + environment: + - MYSQL_ROOT_PASSWORD=secret diff --git a/quickstart-oathkeeper.yml b/quickstart-oathkeeper.yml new file mode 100644 index 000000000000..68030cd30c5f --- /dev/null +++ b/quickstart-oathkeeper.yml @@ -0,0 +1,31 @@ +version: '3.7' + +services: + kratos-selfservice-ui-node: + ports: + - "4435:4435" + environment: + - PORT=4435 + - KRATOS_BROWSER_URL=http://127.0.0.1:4455/.ory/kratos/public + - JWKS_URL=http://oathkeeper:4456/.well-known/jwks.json + - SECURITY_MODE=jwks + + oathkeeper: + image: oryd/oathkeeper:v0.37 + depends_on: + - kratos + ports: + - "4455:4455" + - "4456:4456" + command: + serve proxy -c "/etc/config/oathkeeper/.oathkeeper.yml" + environment: + - LOG_LEVEL=debug + restart: on-failure + networks: + - intranet + volumes: + - + type: bind + source: ./contrib/quickstart/oathkeeper + target: /etc/config/oathkeeper diff --git a/quickstart-postgres.yml b/quickstart-postgres.yml new file mode 100644 index 000000000000..0562df01a9ec --- /dev/null +++ b/quickstart-postgres.yml @@ -0,0 +1,19 @@ +version: '3.7' + +services: + kratos-migrate: + environment: + - DSN=postgres://kratos:secret@postgresd:5432/kratos?sslmode=disable&max_conns=20&max_idle_conns=4 + + kratos: + environment: + - DSN=postgres://kratos:secret@postgresd:5432/kratos?sslmode=disable&max_conns=20&max_idle_conns=4 + + postgresd: + image: postgres:9.6 + ports: + - "5432:5432" + environment: + - POSTGRES_USER=kratos + - POSTGRES_PASSWORD=secret + - POSTGRES_DB=kratos diff --git a/quickstart-standalone.yml b/quickstart-standalone.yml new file mode 100644 index 000000000000..16d1ff9e8d5f --- /dev/null +++ b/quickstart-standalone.yml @@ -0,0 +1,9 @@ +version: '3.7' + +services: + kratos-selfservice-ui-node: + ports: + - "4455:4455" + environment: + - PORT=4455 + - SECURITY_MODE=cookie \ No newline at end of file diff --git a/quickstart.yml b/quickstart.yml index a027f7b278a9..21fe28f7d8ab 100644 --- a/quickstart.yml +++ b/quickstart.yml @@ -1,11 +1,6 @@ -########################################################################### -####### FOR DEMONSTRATION PURPOSES ONLY ####### -########################################################################### - version: '3.7' services: - kratos-migrate: image: oryd/kratos:latest-sqlite environment: @@ -28,38 +23,13 @@ services: kratos-selfservice-ui-node: image: oryd/kratos-selfservice-ui-node:latest - ports: - - "4435:4435" environment: - - PORT=4435 - KRATOS_PUBLIC_URL=http://kratos:4433/ - KRATOS_ADMIN_URL=http://kratos:4434/ - - KRATOS_BROWSER_URL=http://127.0.0.1:4455/.ory/kratos/public - - JWKS_URL=http://oathkeeper:4456/.well-known/jwks.json networks: - intranet restart: on-failure - oathkeeper: - image: oryd/oathkeeper:v0.35.5-beta.1 - depends_on: - - kratos - ports: - - "4455:4455" - - "4456:4456" - command: - serve proxy -c "/etc/config/oathkeeper/.oathkeeper.yml" - environment: - - LOG_LEVEL=debug - restart: on-failure - networks: - - intranet - volumes: - - - type: bind - source: ./contrib/quickstart/oathkeeper - target: /etc/config/oathkeeper - kratos: depends_on: - kratos-migrate