diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5932a697..866e2b83 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,3 +18,4 @@ repos: rev: "v3.1.0" hooks: - id: prettier +exclude: "(example|hasura|docs)/.*" diff --git a/README.md b/README.md index a47051d1..9d312f89 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Sitrep + ![Lage](docs/images/Lage1.png?raw=true "Lage") ![Lage2](docs/images/Lage2.png?raw=true "Lage2") ![Overview](docs/images/IncidentOverview.png?raw=true "Overview") @@ -22,14 +23,13 @@ A simple local development environment can be created using docker compose and t Oauth2_PROXY clients can be created using Auth0.... ``` -OAUTH2_PROXY_CLIENT_ID=... -OAUTH2_PROXY_CLIENT_SECRET=... -OAUTH2_PROXY_OIDC_ISSUER_URL=https://${TENANT}.eu.auth0.com/ -HASURA_GRAPHQL_JWT_SECRET='{"type":"RS256","key":"-----BEGIN CERTIFICATE-----\n -... -}\n-----END CERTIFICATE-----\n","header":{"type":"Authorization"},"claims_map":{"x-hasura-user-id":{"path":"$.sub"},"x-hasura-email":{"path":"$.email"},"x-hasura-allowed-roles":["user","editor"],"x-hasura-default-role":"user"}}' +OAUTH2_PROXY_CLIENT_ID=sitrep +OAUTH2_PROXY_CLIENT_SECRET=ds8LCRW4jhB58nWdMgZHeVISqx3O3e1o3g0LEr9H8tM= # generate with: openssl rand -base64 32 | tr -- '+/' '-_' +OAUTH2_PROXY_COOKIE_SECRET=kvicWov5Y_w10r2vmnxJTUTugMUtBp6_R4loxuANMtg= # generate with: openssl rand -base64 32 | tr -- '+/' '-_' +HASURA_GRAPHQL_ADMIN_SECRET=388HMfQ00gEyg636O63S1jxRODTSoAiu_XHa0fXhtRo= # generate with: openssl rand -base64 32 | tr -- '+/' '-_' POSTGRES_PASSWORD=postgrespassword -HASURA_GRAPHQL_ADMIN_SECRET=myadminsecretkey + +OAUTH2_PROXY_REDIRECT_URL=http://localhost:3000/oauth2/callback # port for yarn dev server% ``` 3. Run docker compose environment: @@ -41,13 +41,12 @@ docker compose --env-file .env.local up -d 4. Run yarn ``` -yarn start +cd ui && yarn start ``` -5. Open [localhost:3000](http://localhost:3000/). This will automatically proxy to the OAUTH2 proxy which will then proxy requests towards the graphql-engine with its /v1/graphql - +5. Open [localhost:3000](http://localhost:3000/). This will automatically proxy to the OAUTH2 proxy which will then proxy requests towards the graphql-engine with its /v1/graphql. Authentication will be handled by the local dex IDP with it's mock provider. Just click on **Log in with Example**. ### Translations -* To correct or add **translations** we invite you to help us out [on Weblate](https://hosted.weblate.org/projects/sitrep).
-[![Translation status](https://hosted.weblate.org/widgets/sitrep/-/287x66-grey.png)](https://hosted.weblate.org/engage/sitrep/) \ No newline at end of file +- To correct or add **translations** we invite you to help us out [on Weblate](https://hosted.weblate.org/projects/sitrep).
+ [![Translation status](https://hosted.weblate.org/widgets/sitrep/-/287x66-grey.png)](https://hosted.weblate.org/engage/sitrep/) diff --git a/docker-compose.yml b/docker-compose.yml index 72aa11b7..4e4e6802 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,12 +4,14 @@ services: depends_on: postgres: condition: service_started + dex: + condition: service_started environment: HASURA_GRAPHQL_ADMIN_SECRET: ${HASURA_GRAPHQL_ADMIN_SECRET} HASURA_GRAPHQL_DEV_MODE: "true" HASURA_GRAPHQL_ENABLE_CONSOLE: "false" HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log - HASURA_GRAPHQL_JWT_SECRET: ${HASURA_GRAPHQL_JWT_SECRET} + HASURA_GRAPHQL_JWT_SECRET: '{"type":"RS256","jwk_url": "http://dex:5556/dex/keys" ,"header":{"type":"Authorization"},"claims_map":{"x-hasura-user-id":{"path":"$.sub"},"x-hasura-email":{"path":"$.email"},"x-hasura-allowed-roles":["viewer","editor"],"x-hasura-default-role":"editor"}}' HASURA_GRAPHQL_METADATA_DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres HASURA_GRAPHQL_UNAUTHORIZED_ROLE: anonymous HASURA_GRAPHQL_EXPERIMENTAL_FEATURES: naming_convention @@ -29,24 +31,34 @@ services: depends_on: graphql-engine: condition: service_started + dex: + condition: service_started environment: OAUTH2_PROXY_CLIENT_ID: ${OAUTH2_PROXY_CLIENT_ID} OAUTH2_PROXY_CLIENT_SECRET: ${OAUTH2_PROXY_CLIENT_SECRET} OAUTH2_PROXY_CODE_CHALLENGE_METHOD: S256 OAUTH2_PROXY_COOKIE_SECRET: ${OAUTH2_PROXY_COOKIE_SECRET} - OAUTH2_PROXY_DISPLAY_NAME: Auth0 + OAUTH2_PROXY_COOKIE_CSRF_PER_REQUEST: true + OAUTH2_PROXY_COOKIE_CSRF_EXPIRE: 5m OAUTH2_PROXY_EMAIL_DOMAINS: "*" OAUTH2_PROXY_HTTP_ADDRESS: :4180 - OAUTH2_PROXY_OIDC_ISSUER_URL: ${OAUTH2_PROXY_OIDC_ISSUER_URL} + OAUTH2_PROXY_OIDC_ISSUER_URL: http://dex:5556/dex + OAUTH2_PROXY_INSECURE_OIDC_SKIP_ISSUER_VERIFICATION: true OAUTH2_PROXY_PASS_ACCESS_TOKEN: "true" OAUTH2_PROXY_PASS_AUTHORIZATION_HEADER: "true" OAUTH2_PROXY_PROVIDER: oidc OAUTH2_PROXY_PROXY_WEBSOCKETS: "true" - OAUTH2_PROXY_REDIRECT_URL: http://localhost:3000/oauth2/callback OAUTH2_PROXY_UPSTREAMS: http://graphql-engine:8080/v1/graphql OAUTH2_PROXY_SKIP_PROVIDER_BUTTON: true + OAUTH2_PROXY_REDIRECT_URL: ${OAUTH2_PROXY_REDIRECT_URL} + # disable autodiscovery due to token endpoint not properly accessible on localhost for oauth2proxy + OAUTH2_PROXY_SKIP_OIDC_DISCOVERY: "true" + OAUTH2_PROXY_OIDC_JWKS_URL: http://dex:5556/dex/keys + OAUTH2_PROXY_LOGIN_URL: http://localhost:5556/dex/auth + OAUTH2_PROXY_REDEEM_URL: http://dex:5556/dex/token OAUTH2_PROXY_SKIP_AUTH_ROUTES: ^\/(manifest\.json|favicon\.ico|asset-manifest\.json|service-worker\.js\.map|service-worker\.js|robots\.txt|logo\d+\.png) image: quay.io/oauth2-proxy/oauth2-proxy:v7.5.1 + restart: always networks: default: null ports: @@ -54,7 +66,6 @@ services: target: 4180 published: "4180" protocol: tcp - restart: always postgres: environment: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} @@ -72,9 +83,41 @@ services: target: 5432 published: "5432" protocol: tcp + dex: + image: docker.io/dexidp/dex:v2.38.0 + restart: always + environment: + OAUTH2_PROXY_CLIENT_ID: ${OAUTH2_PROXY_CLIENT_ID} + OAUTH2_PROXY_CLIENT_SECRET: ${OAUTH2_PROXY_CLIENT_SECRET} + DEX_CONNECTORS_ENABLE_MOCK: "true" + DEX_CONNECTORS_ENABLE_DEMO_USER: "true" + DEX_ISSUER: http://localhost:5556/dex + networks: + default: null + command: dex serve /etc/dex/config-demo.yaml + volumes: + - type: bind + source: ./example/dexidp/config-demo.yaml + target: /etc/dex/config-demo.yaml + read_only: true + - type: volume + source: dex_data + target: /var/sqlite/dex + volume: {} + ports: + - mode: ingress + target: 5556 + published: "5556" + protocol: tcp + - mode: ingress + target: 5557 + published: "5557" + protocol: tcp networks: default: name: sitrep_default volumes: db_data: name: sitrep_db_data + dex_data: + name: sitrep_dex_data diff --git a/example/.env b/example/.env new file mode 100644 index 00000000..16d3f653 --- /dev/null +++ b/example/.env @@ -0,0 +1,9 @@ +OAUTH2_PROXY_CLIENT_ID=sitrep +OAUTH2_PROXY_CLIENT_SECRET=ds8LCRW4jhB58nWdMgZHeVISqx3O3e1o3g0LEr9H8tM= # generate with: openssl rand -base64 32 | tr -- '+/' '-_' +OAUTH2_PROXY_COOKIE_SECRET=kvicWov5Y_w10r2vmnxJTUTugMUtBp6_R4loxuANMtg= # generate with: openssl rand -base64 32 | tr -- '+/' '-_' +HASURA_GRAPHQL_ADMIN_SECRET=388HMfQ00gEyg636O63S1jxRODTSoAiu_XHa0fXhtRo= # generate with: openssl rand -base64 32 | tr -- '+/' '-_' +POSTGRES_PASSWORD=postgrespassword # set to something secure or generate with: openssl rand -base64 32 | tr -- '+/' '-_' + +# the hostname you want to serve sitrep on, should match your caddy config file +# locally resolvable dns names like sitrep.local work as well if your server is setup accrodingly +SITREP_HOSTNAME=192.168.1.2 diff --git a/example/Caddyfile b/example/Caddyfile new file mode 100644 index 00000000..5af4b4d9 --- /dev/null +++ b/example/Caddyfile @@ -0,0 +1,19 @@ +# add your IP / domain here +sitrep.local, 10.40.1.125 { + log + reverse_proxy /dex* localhost:5556 { + header_up Host {host} # redundant + header_up X-Real-IP {remote} + header_up X-Forwarded-For {remote} # redundant + header_up X-Forwarded-Port {server_port} # redundant + header_up X-Forwarded-Proto {scheme} + } + + reverse_proxy localhost:4180 { + header_up Host {host} # redundant + header_up X-Real-IP {remote} + header_up X-Forwarded-For {remote} # redundant + header_up X-Forwarded-Port {server_port} # redundant + header_up X-Forwarded-Proto {scheme} + } +} diff --git a/example/Readme.md b/example/Readme.md new file mode 100644 index 00000000..f4636fb6 --- /dev/null +++ b/example/Readme.md @@ -0,0 +1,37 @@ +# Example Setup Sitrep + +This shows how to start sitrep with a local DEX IDP. + +Prerequisites: + +- docker / docker compose +- caddy webserver (every other reverse proxy would work as well, nginx, apache, etc.) + +## Configuration + +All configuration can be done in the .env and the Caddyfile file: + +### Caddyfile + +set the hostname in the caddyfile server block: + +```diff +- sitrep.local, 192.168.9.2 { ++ myserver.example.com { + +``` + +### .env file + +- Make sure to set the SITREP_HOSTNAME to the same thing you set in the Caddyfile. +- regenerate all secrets as mentioned in the file + +## Run Sitrep + +1. Start Caddy webserver (from this directory): + +``` +$ caddy run +``` + +2. diff --git a/example/dexidp/config-demo.yaml b/example/dexidp/config-demo.yaml new file mode 100644 index 00000000..5aa4b6c6 --- /dev/null +++ b/example/dexidp/config-demo.yaml @@ -0,0 +1,41 @@ +issuer: {{ getenv "DEX_ISSUER" "http://127.0.0.1:5556/dex" }} + +storage: + type: sqlite3 + config: + file: var/sqlite/dex/dex.db + +web: + http: {{ getenv "DEX_WEB_HTTP" "0.0.0.0:5556" }} + +telemetry: + http: 127.0.0.1:5558 + +logger: + level: {{ getenv "DEX_LOG_LEVEL" "debug" }} + format: {{ getenv "DEX_LOG_FORMAT" "text" }} + +staticClients: + - id: {{ getenv "OAUTH2_PROXY_CLIENT_ID" "sitrep" }} + redirectURIs: + - "http://localhost:4180/oauth2/callback" + - "http://localhost:3000/oauth2/callback" + - {{ getenv "OAUTH2_PROXY_REDIRECT_URL" "https://localhost/oauth2/callback" }} + name: "Sitrep" + secret: {{ getenv "OAUTH2_PROXY_CLIENT_SECRET" "ZXhhbXBsZS1hcHAtc2VjcmV0" }} + +connectors: +{{- if getenv "DEX_CONNECTORS_ENABLE_MOCK" }} + - type: mockCallback + id: mock + name: Example +{{- end }} + +{{- if getenv "DEX_CONNECTORS_ENABLE_DEMO_USER" }} +enablePasswordDB: true +staticPasswords: + - email: "demo@sitrep.ch" + hash: "$2y$10$Og387KAsKCaYF.rZXElhluHR/13BYdtQQfERy.Wf3WVzTYT8j9BiW" # pw: sitrep-demo + username: "demo" + userID: "325d59a7-5240-4616-88d7-c2eb57fff7a6" +{{- end }} diff --git a/example/docker-compose.yml b/example/docker-compose.yml new file mode 100644 index 00000000..da4c5a02 --- /dev/null +++ b/example/docker-compose.yml @@ -0,0 +1,113 @@ +name: sitrep +services: + graphql-engine: + depends_on: + postgres: + condition: service_started + environment: + HASURA_GRAPHQL_ADMIN_SECRET: ${HASURA_GRAPHQL_ADMIN_SECRET} + HASURA_GRAPHQL_DEV_MODE: "true" + HASURA_GRAPHQL_ENABLE_CONSOLE: "false" + HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log + HASURA_GRAPHQL_JWT_SECRET: '{"type":"RS256","jwk_url": "http://dex:5556/dex/keys" ,"header":{"type":"Authorization"},"claims_map":{"x-hasura-user-id":{"path":"$.sub"},"x-hasura-email":{"path":"$.email"},"x-hasura-allowed-roles":["viewer","editor"],"x-hasura-default-role":"editor"}}' + HASURA_GRAPHQL_METADATA_DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres + HASURA_GRAPHQL_UNAUTHORIZED_ROLE: anonymous + HASURA_GRAPHQL_EXPERIMENTAL_FEATURES: naming_convention + HASURA_GRAPHQL_DEFAULT_NAMING_CONVENTION: graphql-default + PG_DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres + image: ghcr.io/f-eld-ch/sitrep-hasura:edge + networks: + default: null + restart: always + sitrep: + depends_on: + graphql-engine: + condition: service_started + environment: + OAUTH2_PROXY_CLIENT_ID: ${OAUTH2_PROXY_CLIENT_ID} + OAUTH2_PROXY_CLIENT_SECRET: ${OAUTH2_PROXY_CLIENT_SECRET} + OAUTH2_PROXY_CODE_CHALLENGE_METHOD: S256 + OAUTH2_PROXY_COOKIE_SECRET: ${OAUTH2_PROXY_COOKIE_SECRET} + OAUTH2_PROXY_COOKIE_CSRF_PER_REQUEST: true + OAUTH2_PROXY_COOKIE_CSRF_EXPIRE: 5m + OAUTH2_PROXY_EMAIL_DOMAINS: "*" + OAUTH2_PROXY_HTTP_ADDRESS: :4180 + OAUTH2_PROXY_PASS_ACCESS_TOKEN: "true" + OAUTH2_PROXY_PASS_AUTHORIZATION_HEADER: "true" + OAUTH2_PROXY_PROVIDER: oidc + OAUTH2_PROXY_PROXY_WEBSOCKETS: "true" + OAUTH2_PROXY_UPSTREAMS: "http://graphql-engine:8080/v1/graphql,file:///static/#/" + OAUTH2_PROXY_SKIP_PROVIDER_BUTTON: true + OAUTH2_PROXY_INSECURE_OIDC_SKIP_ISSUER_VERIFICATION: true + OAUTH2_PROXY_REDIRECT_URL: https://${SITREP_HOSTNAME}/oauth2/callback + OAUTH2_PROXY_SSL_INSECURE_SKIP_VERIFY: true + OAUTH2_PROXY_OIDC_ISSUER_URL: http://dex:5556/dex + image: ghcr.io/f-eld-ch/sitrep:edge + extra_hosts: + - "${SITREP_HOSTNAME}:host-gateway" + networks: + default: null + ports: + - mode: ingress + target: 4180 + published: "4180" + protocol: tcp + restart: always + postgres: + environment: + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + image: postgis/postgis:14-3.2 + networks: + default: null + restart: always + volumes: + - type: volume + source: db_data + target: /var/lib/postgresql/data + volume: {} + ports: + - mode: ingress + target: 5432 + published: "5432" + protocol: tcp + dex: + image: docker.io/dexidp/dex:v2.38.0 + environment: + OAUTH2_PROXY_CLIENT_ID: ${OAUTH2_PROXY_CLIENT_ID} + OAUTH2_PROXY_CLIENT_SECRET: ${OAUTH2_PROXY_CLIENT_SECRET} + DEX_CONNECTORS_ENABLE_MOCK: "true" + DEX_CONNECTORS_ENABLE_DEMO_USER: "true" + DEX_ISSUER: https://${SITREP_HOSTNAME}/dex + OAUTH2_PROXY_REDIRECT_URL: https://${SITREP_HOSTNAME}/oauth2/callback + networks: + default: null + restart: always + extra_hosts: + - "${SITREP_HOSTNAME}:host-gateway" + command: dex serve /etc/dex/config-demo.yaml + volumes: + - type: bind + source: ./dexidp/config-demo.yaml + target: /etc/dex/config-demo.yaml + read_only: true + - type: volume + source: dex_data + target: /var/sqlite/dex + volume: {} + ports: + - mode: ingress + target: 5556 + published: "5556" + protocol: tcp + - mode: ingress + target: 5557 + published: "5557" + protocol: tcp +networks: + default: + name: sitrep_default +volumes: + db_data: + name: sitrep_db_data + dex_data: + name: sitrep_dex_data