Docker based proxy

This commit is contained in:
Maarten de Waard 2022-06-23 09:27:54 +00:00 committed by Varac
parent 812fc41c6e
commit 942e81775f
5 changed files with 152 additions and 149 deletions

123
README.md
View file

@ -50,9 +50,9 @@ Follow the instructions [in the dashboard-dev-overrides
repository](https://open.greenhost.net/stackspin/dashboard-dev-overrides#dashboard-dev-overrides) repository](https://open.greenhost.net/stackspin/dashboard-dev-overrides#dashboard-dev-overrides)
in order to set up a development-capable cluster. in order to set up a development-capable cluster.
The end-points for the Dashboard, The end-points for the Dashboard,
as well as Kratos and Hydra, will point to `localhost` in that cluster. as well as Kratos and Hydra, will point to `http://stackspin_proxy:8081` in that cluster.
As a result, you can run those components locally, and still log into Stackspin As a result, you can run components using the `docker-compose` file in
applications that run on the cluster. this repository, and still log into Stackspin applications that run on the cluster.
## Setting up the local development environment ## Setting up the local development environment
@ -63,115 +63,42 @@ After this process is finished, the following will run locally:
- The - The
[dashboard-backend](https://open.greenhost.net/stackspin/dashboard-backend) [dashboard-backend](https://open.greenhost.net/stackspin/dashboard-backend)
The following will be available on localhost through a proxy and port-forwards: The following will be available locally through a proxy and port-forwards:
- Hydra - Hydra admin
- Kratos - Kratos admin and public
- The MariaDB database connections - The MariaDB database connections
These need to be available locally, because Kratos wants to run on the same These need to be available locally, because Kratos wants to run on the same
domain as the front-end that serves the login interface. domain as the front-end that serves the login interface.
### 1. Setup port forwards ### 1. Setup hosts file
To be able to work on the dashboard, The application will run on `http://stackspin_proxy`. Add the following line to
we have to configure our development system to access all the remote services and endpoints. `/etc/hosts` to be able to access that from your browser:
A helper script is available in this directory
to setup and redirect the relevant ports locally.
It will open ports 8000, 8080, 4445, 3306 to get access to all APIs.
To use it, you'll need `kubectl` access to the cluster:
1. Install `kubectl` (available through `snap` on Linux)
2. Download the kubeconfig: `scp root@stackspin.example.com:/etc/rancher/k3s/k3s.yaml kube_config_stackspin.example.com.yaml`
3. Set `kubectl` to use the kubeconfig: `export KUBECONFIG=$PWD/kube_config_stackspin.example.com.yaml`.
4. Test if it works:
```
kubectl get ingress -n stackspin
```
Should return something like:
```
NAME CLASS HOSTS ADDRESS PORTS AGE
hydra-public <none> sso.stackspin.example.com 213.108.110.5 80, 443 39d
dashboard <none> dashboard.stackspin.example.com 213.108.110.5 80, 443 150d
kube-prometheus-stack-grafana <none> grafana.stackspin.example.com 213.108.110.5 80, 443 108d
kube-prometheus-stack-alertmanager <none> alertmanager.stackspin.example.com 213.108.110.5 80, 443 108d
kube-prometheus-stack-prometheus <none> prometheus.stackspin.example.com 213.108.110.5 80, 443 108d
```
5. Run the script to forward ports of the services to your local setup:
```
./set-port-forward.sh
```
As long as the script runs, your connection stays open.
End the script by pressing `ctrl + c` and your port-forwards will end as well.
### 2. Configure a local proxy
Because of strict CORS headers,
we have to map the public Kratos API and login app,
which we will run locally with a local proxy.
This can be done with any proxy server, here we use `nginx`.
Be sure you have NGINX installed and listening on port 80 locally:
`sudo apt-get install nginx` should be enough.
Now configure NGINX with this configuration in `/etc/nginx/sites-enabled/default`
``` ```
server { 127.0.0.1 stackspin_proxy
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.html;
server_name _;
# Flask app and dashboard-backend
location / {
proxy_pass http://127.0.0.1:5000/;
proxy_redirect default;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# Kratos APIs
location /kratos/ {
proxy_pass http://127.0.0.1:8080/;
proxy_redirect default;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
``` ```
Reload your NGINX: ### 2. Kubernetes access
The script needs you to have access to the Kubernetes cluster that runs
Stackspin. Point the `KUBECONFIG` environment variable to a kubectl config. That
kubeconfig will be mounted inside docker containers, so also make sure your
Docker user can read it.
### 3. Run it all
Now, run this script that sets a few environment variables based on what is in
your cluster secrets, and starts `docker-compose` to start a reverse proxy as
well as the flask application in this repository.
``` ```
sudo systemctl reload nginx.service ./run_app.sh
``` ```
### 3. Run FLASK app ### 4. Front-end developmenet
Now it is time to start the flask app. Start the [dashboard front-end app](https://open.greenhost.net/stackspin/dashboard/#yarn-start).
Please make sure you are using Python 3 in your environment.
And install the required dependencies:
```
pip3 install -r requirements.txt
```
Then copy `run_app.sh` to `run_app.local.sh` and change the secrets defined in it.
You can now start the app by running
```
./run_app.local.sh
```
Lastly, start the [dashboard front-end app](https://open.greenhost.net/stackspin/dashboard/#yarn-start)

75
docker-compose.yml Normal file
View file

@ -0,0 +1,75 @@
version: '3'
services:
stackspin_proxy:
image: nginx:1.22.0
ports:
- "8081:8081"
volumes:
- ./proxy/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- kube_port_kratos_public
- flask_app
flask_app:
build: .
environment:
- FLASK_APP=app.py
- FLASK_ENV=development
- HYDRA_CLIENT_ID=dashboard-local
# Domain-specific URL settings
- HYDRA_AUTHORIZATION_BASE_URL=https://sso.$DOMAIN/oauth2/auth
- TOKEN_URL=https://sso.$DOMAIN/oauth2/token
- HYDRA_PUBLIC_URL=https://sso.$DOMAIN
# Local path overrides
- KRATOS_PUBLIC_URL=http://stackspin_proxy:8081/kratos
- KRATOS_ADMIN_URL=http://kube_port_kratos_admin:8000
- HYDRA_ADMIN_URL=http://kube_port_hydra_admin:4445
- LOGIN_PANEL_URL=http://stackspin_proxy:8081/web/
- DATABASE_URL=mysql+pymysql://stackspin:$DATABASE_PASSWORD@kube_port_mysql/stackspin
# ENV variables that are deployment-specific
- SECRET_KEY=$FLASK_SECRET_KEY
- HYDRA_CLIENT_SECRET=$HYDRA_CLIENT_SECRET
# - OAUTHLIB_INSECURE_TRANSPORT=1
ports:
- "5000:5000"
volumes:
- .:/app
depends_on:
- kube_port_mysql
entrypoint: ["bash", "-c", "flask run --host $$(hostname -i)"]
kube_port_kratos_admin:
image: bitnami/kubectl:1.24.1
user: "${KUBECTL_UID}:${KUBECTL_GID}"
expose:
- 8000
volumes:
- "$KUBECONFIG:/.kube/config"
entrypoint: ["bash", "-c", "kubectl -n stackspin port-forward --address $$(hostname -i) service/kratos-admin 8000:80"]
kube_port_hydra_admin:
image: bitnami/kubectl:1.24.1
user: "${KUBECTL_UID}:${KUBECTL_GID}"
expose:
- 4445
volumes:
- "$KUBECONFIG:/.kube/config"
entrypoint: ["bash", "-c", "kubectl -n stackspin port-forward --address $$(hostname -i) service/hydra-admin 4445:4445"]
kube_port_kratos_public:
image: bitnami/kubectl:1.24.1
user: "${KUBECTL_UID}:${KUBECTL_GID}"
ports:
- "8080:8080"
expose:
- 8080
volumes:
- "$KUBECONFIG:/.kube/config"
entrypoint: ["bash", "-c", "kubectl -n stackspin port-forward --address $$(hostname -i) service/kratos-public 8080:80"]
kube_port_mysql:
image: bitnami/kubectl:1.24.1
user: "${KUBECTL_UID}:${KUBECTL_GID}"
expose:
- 3306
volumes:
- "$KUBECONFIG:/.kube/config"
entrypoint: ["bash", "-c", "kubectl -n stackspin port-forward --address $$(hostname -i) service/single-sign-on-database-mariadb 3306:3306"]

26
proxy/default.conf Normal file
View file

@ -0,0 +1,26 @@
# Default server configuration
#
server {
listen 8081 default_server;
listen [::]:8081 default_server;
root /var/www/html;
index index.html;
server_name _;
# Flask app
location / {
proxy_pass http://flask_app:5000/;
proxy_redirect default;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# Kratos Public
location /kratos/ {
proxy_pass http://kube_port_kratos_public:8080/;
proxy_redirect default;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

View file

@ -1,39 +1,32 @@
#!/usr/bin/env bash
GREEN='\033[0;32m' set -euo pipefail
RED='\033[1;31m'
NC='\033[0m' # No Color
# Check if kratos port is open export DATABASE_PASSWORD=$(kubectl get secret -n flux-system stackspin-single-sign-on-variables -o jsonpath --template '{.data.dashboard_database_password}' | base64 -d)
if nc -z localhost 8000; export DOMAIN=$(kubectl get secret -n flux-system stackspin-cluster-variables -o jsonpath --template '{.data.domain}' | base64 -d)
then export HYDRA_CLIENT_SECRET=$(kubectl get secret -n flux-system stackspin-dashboard-local-oauth-variables -o jsonpath --template '{.data.client_secret}' | base64 -d)
echo -e "${GREEN}Great! It looks like the Kratos Admin port is available${NC}" export FLASK_SECRET_KEY=$(kubectl get secret -n flux-system stackspin-dashboard-variables -o jsonpath --template '{.data.backend_secret_key}' | base64 -d)
else
echo -e "${RED}**********************************************************${NC}"
echo -e "${RED}WARNING! It looks like the Kratos Admin port NOT available${NC}" if [[ -z "$DATABASE_PASSWORD" ]]; then
echo -e "${RED}please run in a seperate terminal: ${NC}" echo "Could not find database password in stackspin-single-sign-on-variables secret"
echo -e "${RED} ${NC}" exit 1
echo -e "${RED}./set-port-forward.sh ${NC}"
echo -e "${RED} ${NC}"
echo -e "${RED}We will continue to start the app after 5 seconds. ${NC}"
echo -e "${RED}**********************************************************${NC}"
sleep 5
fi fi
export FLASK_APP=app.py if [[ -z "$DOMAIN" ]]; then
export FLASK_ENV=development echo "Could not find domain name in stackspin-cluster-variables secret"
export SECRET_KEY="e38hq!@0n64g@qe6)5csk41t=ljo2vllog(%k7njnm4b@kh42c" exit 1
export HYDRA_CLIENT_ID="dashboard-local" fi
export HYDRA_CLIENT_SECRET="gDSEuakxzybHBHJocnmtDOLMwlWWEvPh"
export HYDRA_AUTHORIZATION_BASE_URL="https://sso.init.stackspin.net/oauth2/auth"
export TOKEN_URL="https://sso.init.stackspin.net/oauth2/token"
# Login facilitator paths if [[ -z "$FLASK_SECRET_KEY" ]]; then
export KRATOS_PUBLIC_URL=http://localhost/kratos echo "Could not find backend_secret_key in stackspin-dashboard-variables secret"
export KRATOS_ADMIN_URL=http://localhost:8000 exit 1
export HYDRA_PUBLIC_URL="https://sso.init.stackspin.net" fi
export HYDRA_ADMIN_URL=http://localhost:4445
export LOGIN_PANEL_URL=http://localhost/web/
#export DATABASE_URL="mysql+pymysql://stackspin:stackspin@localhost/stackspin?charset=utf8mb4"
export DATABASE_URL="mysql+pymysql://stackspin:OZBSDkMdbdvEIOomnwpOqLdaiHDKbzWY@localhost/stackspin"
flask run if [[ -z "$HYDRA_CLIENT_SECRET" ]]; then
echo "Could not find client_secret in stackspin-dashboard-local-oauth-variables secret"
echo "make sure you add this secret following instructions in the dashboard-dev-overrides repository"
exit 1
fi
KUBECTL_UID=${UID:-1001} KUBECTL_GID=${GID:-0} docker compose up

View file

@ -1,18 +0,0 @@
#!/bin/bash
echo "
kratos admin port will be at localhost: 8000
kratos public port will be at localhost: 8080
hydra admin port will be at localhost: 4445
mysql port will be at localhost: 3306
"
# Kill all processes when this script ends
trap "exit" INT TERM ERR
trap "kill 0" EXIT
# Add forwarded ports for all processes
kubectl port-forward -n stackspin service/kratos-admin 8000:80 &
kubectl port-forward -n stackspin service/kratos-public 8080:80 &
kubectl port-forward -n stackspin service/hydra-admin 4445:4445 &
kubectl port-forward -n stackspin service/single-sign-on-database-mariadb 3306:3306