Skip to content

Commit

Permalink
Add docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Dref360 committed Aug 16, 2024
1 parent 42f1ece commit 448dba7
Show file tree
Hide file tree
Showing 8 changed files with 499 additions and 16 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/docsci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: docs_ci
on:
push:
branches:
- master
- main
permissions:
contents: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure Git Credentials
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
- uses: actions/setup-python@v5
with:
python-version: 3.x
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@v4
with:
key: mkdocs-material-${{ env.cache_id }}
path: .cache
restore-keys: |
mkdocs-material-
- run: pip install mkdocs-material
- run: mkdocs gh-deploy --force
57 changes: 57 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Welcome to Kharon


This project solves the problem of sharing applications with other people around the world. This way, you can safely create dashboards with private data and share it with specific people without setting up the AuthN/Z yourself.

Kharon is a FastAPI-based reverse proxy server with Google Authentication. It allows you to secure your applications by requiring users to authenticate via their Google accounts before accessing web servers using an SSH tunnel.

<p align="center">
<img src="assets/diagram.png" width="50%">
</p>

### Getting Started

1. Login at [https://kharon.app](https://kharon.app)
2. Create an API Key in the `Settings` tab.
1. Keep it close! Kharon doesn't remember the key
3. Log into your VM

!!! note

Your VM **must** have the following requirements:

1. An External IP (static or not)
2. Port 2222 must be open
3. Your HTTP app must be on port 8080
4. Docker must be installed

Run the following command to start the Kharon Daemon.
```bash
export KHARON_API_KEY= ... # Your api key
curl -O https://raw.githubusercontent.com/Dref360/kharon/main/service/docker-compose.yml && docker-compose up -d
```

4. Your Cluster will now show on the [Dashboard](https://kharon.app/dashboard)
1. You can now allow users to access your cluster and access it yourself.

### Features

***Google Authentication:** Users must log in with their Google accounts to access protected resources.
***Authorization:** Authorize people to access jobs (using [Casbin](https://dev.to/teresafds/authorization-on-fastapi-with-casbin-41og) would be a great future implementation for fine-grained AuthZ).
***FastAPI:** Utilizes the FastAPI framework for efficient and fast development.
***API Key Management:** Users can create/delete keys.
***KharonDaemon (KHD):** Small daemon that we can [tunnel](https://pypi.org/project/sshtunnel/) into with SSH.
***SSH Server**
***Automatic registration to host**
***Reverse Proxy:** Directs incoming requests to the appropriate backend services.


!!! warning

I know the app isn't super fast. It's due to a bunch of factor that I will improve over time. For example, we create a new tunnel for every request and the backend runs on a small Cloud Run.

If there is some demand for this product, I will improve it :)




6 changes: 6 additions & 0 deletions kharon/models/clusters.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from enum import Enum
from typing import Optional

from pydantic.v1 import BaseModel
from sqlmodel import Field

from kharon.models.model_utils import ResourceSQLModel
Expand All @@ -24,3 +25,8 @@ class Cluster(ResourceSQLModel, table=True): # type: ignore
status: ClusterStatus
# Unused for now
type: ClusterType = ClusterType.docker


class HealthCheck(BaseModel):
local_service_alive: bool
ssh_service_alive: bool
23 changes: 18 additions & 5 deletions kharon/routers/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import fastapi
import httpx
import names_generator
from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi import APIRouter, Body, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlmodel import Session, select
from starlette.requests import Request
Expand All @@ -13,10 +13,10 @@
from kharon.auth import oauth2_scheme
from kharon.dependencies import get_cluster, get_current_user, get_session
from kharon.models import Cluster, User
from kharon.models.clusters import ClusterStatus
from kharon.models.clusters import ClusterStatus, HealthCheck
from kharon.typing import assert_not_none

api = APIRouter()
api = APIRouter(redirect_slashes=False)

log = logging.getLogger()

Expand All @@ -43,7 +43,7 @@ def get_connect_daemon(
is_new_cluster = name in ("", None)
cluster_name = name if not is_new_cluster else names_generator.generate_name(style="hyphen")

client_host = assert_not_none(request.client).host
client_host = request.headers.get("x-forwarded-for") or assert_not_none(request.client).host
_, ssh_public_key = sshutils.get_ssh_keys(cluster_name)
if is_new_cluster:
log.info(f"New Cluster {cluster_name}")
Expand All @@ -59,7 +59,8 @@ def get_connect_daemon(
session.add(cluster)
session.commit()
else:
log.info(f"Existing Cluster: {cluster_name}")
print(f"Existing Cluster: {cluster_name}, {client_host=}, {remote_host=} ")
print("Headers", dict(request.headers))
check_exist = session.exec(
select(Cluster).where(Cluster.name == name).where(Cluster.creator == user.id)
).first()
Expand All @@ -71,6 +72,8 @@ def get_connect_daemon(
check_exist.remote_host = remote_host
session.add(check_exist)
session.commit()
session.refresh(check_exist)
print("Update", check_exist)
return ConnectionResponse(name=cluster_name, public_key=open(ssh_public_key, "r").read())


Expand Down Expand Up @@ -126,6 +129,16 @@ def remove_user_to_cluster(
return "OK"


@api.post("/clusters/health_check/{cluster_name}", summary="Daemon reporting back")
def cluster_daemon_healthcheck(
cluster: Cluster = Depends(get_cluster),
session: Session = Depends(get_session),
health_check: HealthCheck = Body(...),
):
# TODO Should update the db probably
return "OK"


async def get_stream(r):
async for i in r.aiter_raw():
yield i
Expand Down
13 changes: 13 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
site_name: Kharon
site_url: https://dref360.github.io/kharon
theme:
name: material
logo: assets/logo.svg
palette:
primary: deep purple
features:
- content.code.copy
markdown_extensions:
- admonition
- pymdownx.details
- pymdownx.superfences
Loading

0 comments on commit 448dba7

Please sign in to comment.