From ba93d124973ecfdc7f9cd068c05fc9d2246eef1c Mon Sep 17 00:00:00 2001 From: Martin Besozzi Date: Tue, 7 Nov 2023 19:23:14 -0300 Subject: [PATCH] feat: Automatically import all the required configurations into the Keycloak and OpenFGA platforms. The new docker compose file, called 'docker-compose-import.yaml, uses the 'openfga/cli' image to import the OpenFga authorization schema --- README.md | 51 ++++-------- docker-compose-import.yml | 38 +++++++++ docker-compose-openfga.yml | 7 +- keycloak/initialize-poc.sh | 13 +-- openfga/import.sh | 23 ------ openfga/keycloak-authorization-model.json | 98 ----------------------- openfga/model.dsl | 11 +++ store-oidc-app/vue.config.js | 3 +- 8 files changed, 81 insertions(+), 163 deletions(-) create mode 100644 docker-compose-import.yml mode change 100644 => 100755 keycloak/initialize-poc.sh delete mode 100755 openfga/import.sh delete mode 100644 openfga/keycloak-authorization-model.json create mode 100644 openfga/model.dsl diff --git a/README.md b/README.md index 0443b87..f95a76e 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Another cool feature of custom extension is its capability to discover the OpenF 2. Execute following Docker Compose command to start the deployment ```sh - docker-compose -f docker-compose.yml -f docker-compose-apps.yml -f docker-compose-openfga.yml up + docker-compose -f docker-compose.yml -f docker-compose-apps.yml -f docker-compose-openfga.yml -f docker-compose-import.yml up ``` 3. To be able to use this environment, you need to add this line to your local HOSTS file: @@ -62,43 +62,31 @@ Another cool feature of custom extension is its capability to discover the OpenF | Store API | http://store-api:9091 | | Custom image | -## Post configuration steps -### OpenFGA -1. Import the [OpenFGA authorization schema for Keycloak](openfga/keycloak-authorization-model.json): - ```bash - cd openfga - ./import.sh - ``` -2. As the result you will see the following OpenFGA Authorization Model in the [OpenFGA Playground Console](http://localhost:8080/playground) : +## Review configuration (optional) - ![openfga-keycloak-authorization-model](doc/images/openfga-authz-model.png) +> +> In this new version of the workshop, we automatically import all the required configurations into the Keycloak and OpenFGA platforms 😄 🪄 +> +### Keycloak Platform +- You will find that the OpenFGA Event Listener 'openfga-events-publisher' extension in Keycloak is enabled. -### Keycloak -1. Enable the Keycloak OpenFGA Event Listener extension in Keycloak: - - * Open [administration console](http://keycloak:8081) - * Choose realm - * Realm settings - * Select `Events` tab and add `openfga-events-publisher` to Event Listeners. + * [Administration console](http://keycloak:8081) > Realm settings > `openfga-events-publisher` -2. Proceed to initialize the PoC: - - Execute the following [script](keycloak/initialize-poc.sh) to initialize the PoC: - - ```bash - docker exec keycloak /bin/bash /opt/keycloak/initialize-poc.sh - ``` - - This script will create the OAuth Clients and the following Users and Role Model: +- The following roles and demo users have already been created in Keycloak. ![users](doc/images/users.png) The password for all the users is `demo1234!` - Once these steps are finished, the Keycloak OpenFGA Event Publisher extension has proceed to send these events over HTTP to the OpenFGA solution. Here, are all tuples stored. +### OpenFGA Platform +- You will see the following OpenFGA Authorization Model in the [OpenFGA Playground Console](http://localhost:3000/playground) and the Tuples tab: + + + +- Once the workshop is deployed, the Keycloak OpenFGA Event Publisher extension proceeds to send these events over HTTP to the OpenFGA solution. Here, all tuples are stored. | User | Relation | Object | | ------------------------- |:-----------------------------:|:---------------------:| @@ -109,16 +97,11 @@ Another cool feature of custom extension is its capability to discover the OpenF | user:richard | assignee | role:admin-catalog | - The users are identified by the value of the claim sub in the [OpenFGA Playground](http://localhost:3000/playground), see the Tuples tab: - - - - -3. Restart the apps (containers: `store` and `store-api`) + The users are identified by the value of the claim sub. ## Test cases As an example, we will implement an Product Catalog web application that has the following requirements: -* Only authenticated user with MFA can access to the application +* Only authenticated user can access to the application * Product can be viewed by their Analyst * Product can be edited by their Admin * Global Admin users can view or edit any Product diff --git a/docker-compose-import.yml b/docker-compose-import.yml new file mode 100644 index 0000000..8c94fd0 --- /dev/null +++ b/docker-compose-import.yml @@ -0,0 +1,38 @@ +version: '3.8' + +services: + openfga-import: + depends_on: + openfga: + condition: service_healthy + image: openfga/cli:v0.2.0 + container_name: openfga-import + restart: "no" + command: "store create --name keycloak --api-url http://openfga:8080 --model /tmp/model.dsl" + networks: + - default + volumes: + - $PWD/openfga:/tmp + keycloak-import: + depends_on: + openfga: + condition: service_healthy + keycloak: + condition: service_healthy + openfga-import: + condition: service_completed_successfully + image: quay.io/keycloak/keycloak:21.1 + container_name: keycloak-import + restart: "no" + entrypoint: [ + "sh", + "-c", + "echo 'Waiting 10 secs for importing Keycloak configuration...';sleep 10;/opt/keycloak/import.sh" + ] + environment: + KEYCLOAK_URL: http://keycloak:8081 + KEYCLOAK_USER: admin + KEYCLOAK_PASSWORD: password + volumes: + - $PWD/keycloak/initialize-poc.sh:/opt/keycloak/import.sh + \ No newline at end of file diff --git a/docker-compose-openfga.yml b/docker-compose-openfga.yml index d945f07..8e638fe 100644 --- a/docker-compose-openfga.yml +++ b/docker-compose-openfga.yml @@ -46,4 +46,9 @@ services: - default ports: - "8080:8080" #http - - "3000:3000" #playground \ No newline at end of file + - "3000:3000" #playground + healthcheck: + test: ["CMD", "/usr/local/bin/grpc_health_probe", "-addr=openfga:8081"] + interval: 3s + timeout: 30s + retries: 3 \ No newline at end of file diff --git a/keycloak/initialize-poc.sh b/keycloak/initialize-poc.sh old mode 100644 new mode 100755 index 94ea84a..15085a0 --- a/keycloak/initialize-poc.sh +++ b/keycloak/initialize-poc.sh @@ -2,7 +2,13 @@ echo "Creating PoC Users, Role Model, User Role Assigments and Clients" -/opt/keycloak/bin/kcadm.sh config credentials --server http://localhost:8081 --realm master --user $KEYCLOAK_USER --password $KEYCLOAK_PASSWORD +/opt/keycloak/bin/kcadm.sh config credentials --server $KEYCLOAK_URL --realm master --user $KEYCLOAK_USER --password $KEYCLOAK_PASSWORD + +# Enable openfga-events +/opt/keycloak/bin/kcadm.sh update events/config -s 'eventsListeners=["openfga-events-publisher","jboss-logging"]' + +# Clients +/opt/keycloak/bin/kcadm.sh create clients -r master -s clientId=portal -s publicClient=true -s 'redirectUris=["http://store:9090/callback"]' -s 'webOrigins=["http://store:9090"]' -s 'attributes={ "post.logout.redirect.uris": "http://store:9090/home?action=logout", "access.token.lifespan": 3600}' -o # Users /opt/keycloak/bin/kcadm.sh create users -r master -s username=paula -s firstName=Paula -s lastName=Von -s enabled=true -s email=paula@demo.com @@ -25,8 +31,3 @@ echo "Creating PoC Users, Role Model, User Role Assigments and Clients" /opt/keycloak/bin/kcadm.sh add-roles -r master --uusername paula --rolename analyst-catalog /opt/keycloak/bin/kcadm.sh add-roles -r master --uusername richard --rolename admin-catalog - -# Clients -/opt/keycloak/bin/kcadm.sh create clients -r master -s clientId=portal -s publicClient=true -s 'redirectUris=["http://store:9090/callback"]' -s 'webOrigins=["http://store:9090"]' -s 'attributes={ "post.logout.redirect.uris": "http://store:9090/home?action=logout", "access.token.lifespan": 3600}' -o - - diff --git a/openfga/import.sh b/openfga/import.sh deleted file mode 100755 index b5d79cf..0000000 --- a/openfga/import.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -# Create store and authorization model in OpenFGA -# Version: 1.0.0 - -OPENFGA_API_URI=${OPENFGA_API_URI:-http://localhost:8080} -OPENFGA_STORE_ID="" -OPENFGA_AUTHORIZATION_MODEL_ID="" - -create_store() { - OPENFGA_STORE_ID=$(curl -X POST $OPENFGA_API_URI/stores -d @store.json | jq -r '.id') -} - -create_authorization_model() { - OPENFGA_AUTHORIZATION_MODEL_ID=$(curl -X POST $OPENFGA_API_URI/stores/$OPENFGA_STORE_ID/authorization-models -d @keycloak-authorization-model.json | jq -r '.authorization_model_id') -} - - -create_store -echo "OpenFGA store id: " + $OPENFGA_STORE_ID - -create_authorization_model -echo "OpenFGA authorization model id: " + $OPENFGA_AUTHORIZATION_MODEL_ID \ No newline at end of file diff --git a/openfga/keycloak-authorization-model.json b/openfga/keycloak-authorization-model.json deleted file mode 100644 index 7548ef0..0000000 --- a/openfga/keycloak-authorization-model.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "type_definitions": [ - { - "type": "group", - "relations": { - "assignee": { - "this": {} - } - }, - "metadata": { - "relations": { - "assignee": { - "directly_related_user_types": [ - { - "type": "user" - } - ] - } - } - } - }, - { - "type": "role", - "relations": { - "assignee": { - "union": { - "child": [ - { - "this": {} - }, - { - "tupleToUserset": { - "tupleset": { - "object": "", - "relation": "parent" - }, - "computedUserset": { - "object": "", - "relation": "assignee" - } - } - }, - { - "tupleToUserset": { - "tupleset": { - "object": "", - "relation": "parent_group" - }, - "computedUserset": { - "object": "", - "relation": "assignee" - } - } - } - ] - } - }, - "parent": { - "this": {} - }, - "parent_group": { - "this": {} - } - }, - "metadata": { - "relations": { - "assignee": { - "directly_related_user_types": [ - { - "type": "user" - } - ] - }, - "parent": { - "directly_related_user_types": [ - { - "type": "role" - } - ] - }, - "parent_group": { - "directly_related_user_types": [ - { - "type": "group" - } - ] - } - } - } - }, - { - "type": "user", - "relations": {}, - "metadata": null - } - ], - "schema_version": "1.1" -} \ No newline at end of file diff --git a/openfga/model.dsl b/openfga/model.dsl new file mode 100644 index 0000000..a8f2a92 --- /dev/null +++ b/openfga/model.dsl @@ -0,0 +1,11 @@ +model + schema 1.1 +type group + relations + define assignee: [user] +type role + relations + define assignee: [user] or assignee from parent or assignee from parent_group + define parent: [role] + define parent_group: [group] +type user \ No newline at end of file diff --git a/store-oidc-app/vue.config.js b/store-oidc-app/vue.config.js index c1850f5..79fa048 100644 --- a/store-oidc-app/vue.config.js +++ b/store-oidc-app/vue.config.js @@ -1,5 +1,6 @@ module.exports = { devServer: { - disableHostCheck: true + disableHostCheck: true, + progress: false } } \ No newline at end of file