| author | |
| committer | |
| log | e402d6ef71dfc310caeeb4d3579bddd9d0710594 |
| tree | 5f1900497cf85c0c5a0f8bd4626576a23e207549 |
| parent | c94f61522e07ad2783764708af19703355c3e999 |
| signature |
to avoid having a separate user like `ssh evil-git@git.evil.inc`,
instead the gambit is to have two intercept scripts to perform
routing based on the repo that is being pushed to.9 files changed, 119 insertions(+), 28 deletions(-)
compose.yaml+2-2| ... | ... | @@ -152,7 +152,6 @@ services: |
| 152 | 152 | image: code.forgejo.org/forgejo/forgejo:13 |
| 153 | 153 | entrypoint: ["/bin/sh", "/custom/init/entry.sh"] |
| 154 | 154 | ports: |
| 155 | - 40243:22 | |
| 156 | 155 | - 40244:3000 # port used for forgejo-runner |
| 157 | 156 | environment: |
| 158 | 157 | USER_UID: "$USER_ID" |
| ... | ... | @@ -167,6 +166,7 @@ services: |
| 167 | 166 | FORGEJO_OAUTH2_JWT_SECRET: "${FORGEJO_OAUTH2_JWT_SECRET:?}" |
| 168 | 167 | FORGEJO_SECURITY_SECRET_KEY: "${FORGEJO_SECURITY_SECRET_KEY:?}" |
| 169 | 168 | FORGEJO_SECURITY_INTERNAL_TOKEN: "${FORGEJO_SECURITY_INTERNAL_TOKEN:?}" |
| 169 | HOME_INFRA_HOST_DIR: "${HOME_INFRA_HOST_DIR:?}" | |
| 170 | 170 | restart: unless-stopped |
| 171 | 171 | volumes: |
| 172 | 172 | - "${APP_ROOT}/keycloak:/shared-keys:ro" |
| ... | ... | @@ -590,7 +590,6 @@ services: |
| 590 | 590 | image: code.forgejo.org/forgejo/forgejo:13 |
| 591 | 591 | entrypoint: ["/bin/sh", "/custom/init/entry.sh"] |
| 592 | 592 | ports: |
| 593 | - 22666:22 | |
| 594 | 593 | - 40666:3000 # port used for forgejo-runner |
| 595 | 594 | environment: |
| 596 | 595 | USER_UID: "$USER_ID" |
| ... | ... | @@ -604,6 +603,7 @@ services: |
| 604 | 603 | FORGEJO_SECURITY_SECRET_KEY: "${EVIL_FORGEJO_SECURITY_SECRET_KEY}" |
| 605 | 604 | FORGEJO_SECURITY_INTERNAL_TOKEN: "${EVIL_FORGEJO_SECURITY_INTERNAL_TOKEN}" |
| 606 | 605 | POSTGRES_PASSWORD_EVIL_FORGEJO: "${POSTGRES_PASSWORD_EVIL_FORGEJO:?}" |
| 606 | HOME_INFRA_HOST_DIR: "${HOME_INFRA_HOST_DIR:?}" | |
| 607 | 607 | restart: unless-stopped |
| 608 | 608 | volumes: |
| 609 | 609 | - "${APP_ROOT}/evil-infra/forgejo:/data:rw" |
config/evil-infra/forgejo/init/app.ini+3-3| ... | ... | @@ -31,13 +31,13 @@ DOMAIN=git.evil.inc |
| 31 | 31 | SSH_DOMAIN=git.evil.inc |
| 32 | 32 | HTTP_PORT=3000 |
| 33 | 33 | ROOT_URL=https://git.evil.inc |
| 34 | DISABLE_SSH=false | |
| 35 | SSH_PORT=22 | |
| 36 | SSH_LISTEN_PORT=22 | |
| 37 | 34 | LFS_JWT_SECRET=$FORGEJO_SERVER_LFS_JWT_SECRET |
| 38 | 35 | LFS_START_SERVER=true |
| 39 | 36 | OFFLINE_MODE=true |
| 40 | 37 | LANDING_PAGE=/evil |
| 38 | START_SSH_SERVER=false | |
| 39 | SSH_CREATE_AUTHORIZED_KEYS_FILE=false | |
| 40 | SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE=$HOME_INFRA_HOST_DIR/config/forgejo/ssh/route.sh {{.Key.ID}} | |
| 41 | 41 | |
| 42 | 42 | [database] |
| 43 | 43 | DB_TYPE=postgres |
config/forgejo/init/app.ini+3-3| ... | ... | @@ -32,13 +32,13 @@ DOMAIN=git.$HOME_DOMAIN |
| 32 | 32 | SSH_DOMAIN=git.$HOME_DOMAIN |
| 33 | 33 | HTTP_PORT=3000 |
| 34 | 34 | ROOT_URL=https://git.$HOME_DOMAIN/ |
| 35 | DISABLE_SSH=false | |
| 36 | SSH_PORT=22 | |
| 37 | SSH_LISTEN_PORT=22 | |
| 38 | 35 | LFS_JWT_SECRET=$FORGEJO_SERVER_LFS_JWT_SECRET |
| 39 | 36 | LFS_START_SERVER=true |
| 40 | 37 | OFFLINE_MODE=true |
| 41 | 38 | LANDING_PAGE=/clo |
| 39 | START_SSH_SERVER=false | |
| 40 | SSH_CREATE_AUTHORIZED_KEYS_FILE=false | |
| 41 | SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE=$HOME_INFRA_HOST_DIR/config/forgejo/ssh/route.sh {{.Key.ID}} | |
| 42 | 42 | |
| 43 | 43 | [database] |
| 44 | 44 | DB_TYPE=postgres |
config/forgejo/ssh/config created+3| ... | ... | @@ -0,0 +1,3 @@ |
| 1 | Match User git | |
| 2 | AuthorizedKeysCommand /bin/python /mnt/storage1/apps/home-infra/config/forgejo/ssh/keys.py %u %t %k | |
| 3 | AuthorizedKeysCommandUser git |
config/forgejo/ssh/keys.py created+57| ... | ... | @@ -0,0 +1,57 @@ |
| 1 | #!/usr/bin/env python3 | |
| 2 | import sys | |
| 3 | import subprocess | |
| 4 | import re | |
| 5 | ||
| 6 | user, key_type, key = sys.argv[1:4] | |
| 7 | ||
| 8 | ||
| 9 | def get_key_id(container: str): | |
| 10 | try: | |
| 11 | result = subprocess.run( | |
| 12 | [ | |
| 13 | "sudo", | |
| 14 | "/usr/bin/docker", | |
| 15 | "exec", | |
| 16 | "-u", | |
| 17 | "3000:3000", | |
| 18 | container, | |
| 19 | "/usr/local/bin/forgejo", | |
| 20 | "keys", | |
| 21 | "-c", | |
| 22 | "/custom/conf/app.ini", | |
| 23 | "-e", | |
| 24 | "git", | |
| 25 | "-u", | |
| 26 | user, | |
| 27 | "-t", | |
| 28 | key_type, | |
| 29 | "-k", | |
| 30 | key, | |
| 31 | ], | |
| 32 | capture_output=True, | |
| 33 | text=True, | |
| 34 | check=False, | |
| 35 | ) | |
| 36 | match = re.search(r"route\.sh (\d+)", result.stdout) | |
| 37 | return match.group(1) if match else None | |
| 38 | except: | |
| 39 | return None | |
| 40 | ||
| 41 | ||
| 42 | clover_id = get_key_id("forgejo") | |
| 43 | evil_id = get_key_id("evil-forgejo") | |
| 44 | ||
| 45 | if not clover_id and not evil_id: | |
| 46 | sys.exit(0) | |
| 47 | ||
| 48 | args: list[str] = [] | |
| 49 | if clover_id: | |
| 50 | args.extend(["--clover", clover_id]) | |
| 51 | if evil_id: | |
| 52 | args.extend(["--evil", evil_id]) | |
| 53 | ||
| 54 | cmd = "/mnt/storage1/apps/home-infra/config/forgejo/ssh/route.sh " + " ".join(args) | |
| 55 | print( | |
| 56 | f'command="{cmd}",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict {key_type} {key}' | |
| 57 | ) |
config/forgejo/ssh/route.sh created+48| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | #!/bin/sh | |
| 2 | clover_id="" | |
| 3 | evil_id="" | |
| 4 | ||
| 5 | while [ $# -gt 0 ]; do | |
| 6 | case "$1" in | |
| 7 | --clover) | |
| 8 | clover_id="$2" | |
| 9 | shift 2 | |
| 10 | ;; | |
| 11 | --evil) | |
| 12 | evil_id="$2" | |
| 13 | shift 2 | |
| 14 | ;; | |
| 15 | *) shift ;; | |
| 16 | esac | |
| 17 | done | |
| 18 | ||
| 19 | repo="${SSH_ORIGINAL_COMMAND#* }" | |
| 20 | repo="${repo%\'*}" | |
| 21 | repo="${repo#\'}" | |
| 22 | repo="${repo#/}" | |
| 23 | ||
| 24 | case "$repo" in | |
| 25 | *[!a-zA-Z0-9/_.-]*) | |
| 26 | echo "invalid repo name: $repo" >&2 | |
| 27 | exit 1 | |
| 28 | ;; | |
| 29 | *..*) | |
| 30 | echo "invalid repo name: $repo" >&2 | |
| 31 | exit 1 | |
| 32 | ;; | |
| 33 | /*) | |
| 34 | echo "invalid repo name: $repo" >&2 | |
| 35 | exit 1 | |
| 36 | ;; | |
| 37 | esac | |
| 38 | ||
| 39 | if [ -d "/mnt/storage1/apps/forgejo/git/repositories/${repo}" ]; then | |
| 40 | [ -z "$clover_id" ] && echo "ssh key is not configured for repository on git.paperclover.net" >&2 && exit 1 | |
| 41 | exec sudo docker exec -i -u git forgejo /usr/bin/env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" /usr/local/bin/forgejo --config=/custom/conf/app.ini serv key-"$clover_id" | |
| 42 | elif [ -d "/mnt/storage1/apps/evil-infra/forgejo/git/repositories/${repo}" ]; then | |
| 43 | [ -z "$evil_id" ] && echo "ssh key is not configured for repository on git.evil.inc" >&2 && exit 1 | |
| 44 | exec sudo docker exec -i -u git evil-forgejo /usr/bin/env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" /usr/local/bin/forgejo --config=/custom/conf/app.ini serv key-"$evil_id" | |
| 45 | else | |
| 46 | echo "repo not found" >&2 | |
| 47 | exit 1 | |
| 48 | fi |
docker.sh created+2| ... | ... | @@ -0,0 +1,2 @@ |
| 1 | #!/bin/sh | |
| 2 | ssh clo@192.168.0.1 -- cd /mnt/storage1/apps/home-infra \&\& sudo docker "$@" |
generate-env.sh+1| ... | ... | @@ -10,6 +10,7 @@ fi |
| 10 | 10 | printf "generating...\n" |
| 11 | 11 | |
| 12 | 12 | template() { |
| 13 | add "HOME_INFRA_HOST_DIR" "$PWD" | |
| 13 | 14 | add "HOME_DOMAIN" "local.test" |
| 14 | 15 | add "ADMIN_EMAIL" "" |
| 15 | 16 | add "USER_ID" "$(id -u)" |
readme.md-20| ... | ... | @@ -3,26 +3,6 @@ |
| 3 | 3 | this codebase is used for all docker services on my home nas, including personal |
| 4 | 4 | customization. |
| 5 | 5 | |
| 6 | ## usage | |
| 7 | ||
| 8 | ``` | |
| 9 | git clone https://git.paperclover.net/clo/home-infra.git | |
| 10 | cd home-infra | |
| 11 | ||
| 12 | # setup repo | |
| 13 | rm config/font/* | |
| 14 | git clone https://git.paperclover.net/clo/sitegen.git | |
| 15 | cp .env.example .env | |
| 16 | ||
| 17 | # fill secrets | |
| 18 | vi .env | |
| 19 | vi secrets/openvpn-credentials.txt | |
| 20 | ||
| 21 | docker compose up -d | |
| 22 | ``` | |
| 23 | ||
| 24 | ## license | |
| 25 | ||
| 26 | 6 | this repository is for example usage only. you may not re-host it in full, |
| 27 | 7 | privately or publicly, but you may learn from my usage. please note that some |
| 28 | 8 | components here are under licenses which do not permit redistribution. |