From 1936e4eac579cf7862d1e967bb0ee0b7f9714948 Mon Sep 17 00:00:00 2001 From: Kyle Bowman Date: Sat, 11 Oct 2025 13:32:24 -0400 Subject: [PATCH] automate keys; add hosting; update README --- .gitignore | 2 ++ Makefile | 33 +++++++++++++++++++++-- README.md | 54 +++++++++++++++++-------------------- deb-repo.conf | 13 +++++++++ reprepro/conf/distributions | 6 ++--- scripts/_make_keyinit.sh | 27 +++++++++++++++++++ scripts/_make_keyspecs.sh | 13 +++++++++ scripts/download.sh | 9 ++++--- scripts/generate_index.sh | 25 ++++++++++------- scripts/replace_key.sh | 6 ----- update_all.sh | 13 ++++++--- 11 files changed, 145 insertions(+), 56 deletions(-) create mode 100644 deb-repo.conf create mode 100755 scripts/_make_keyinit.sh create mode 100755 scripts/_make_keyspecs.sh delete mode 100755 scripts/replace_key.sh diff --git a/.gitignore b/.gitignore index d661e00..a8df2d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ packages reprepro/db store/ +.keyspecs +.keyid \ No newline at end of file diff --git a/Makefile b/Makefile index fba5151..e31e4ca 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,12 @@ help: @echo "" @echo "The following targets are available:" @echo "" - @echo "init: Initializes the repository structure according to the .env file." + @echo "clean removes hosted packages and index." + @echo "help prints this help message." + @echo "full-reset WARNING: cleans, then removes additional settings, like keys." + @echo "key initializes a GPG key and populates it throughout the package." + @echo "update installs packages and updates index." + @echo "" .PHONY: clean: @@ -14,7 +19,31 @@ clean: rm -rf $(DOWNLOAD_DIR)/bookworm/* rm -rf $(DOWNLOAD_DIR)/trixie/* rm -rf $(DOWNLOAD_DIR)/sid/* - rm reprepro/db/* + rm -rf reprepro/db/* + +.PHONY: +full-reset: clean + rm -f pub-signing-key.asc + rm -f .keyspecs + gpg --delete-secret-keys $(shell cat .keyid) && gpg --delete-keys $(shell cat .keyid) + sed --in-place --expression "s/$(shell cat .keyid)/KEY_ID_PLACEHOLDER/g" ./reprepro/conf/distributions + rm -f .keyid + +.keyspecs: + ./scripts/_make_keyspecs.sh + +# NOTE: This only works if the key has been made +.keyid: .keyspecs + . ./.keyspecs && gpg --list-keys --with-colons $$NAME_EMAIL | grep fpr | cut -d ':' -f 10 > .keyid + +.PHONY: +key: pub-signing-key.asc + sed --in-place --expression "s/KEY_ID_PLACEHOLDER/$(shell cat .keyid)/g" ./reprepro/conf/distributions + +pub-signing-key.asc: .keyspecs + ./scripts/_make_keyinit.sh | gpg --batch --pinentry-mode ask --gen-key + make .keyid + cat .keyid | gpg --armor --export > pub-signing-key.asc .PHONY: update: $(DOWNLOAD_DIR)/bookworm $(DOWNLOAD_DIR)/trixie $(DOWNLOAD_DIR)/sid diff --git a/README.md b/README.md index 8e640b1..9aa66de 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,54 @@ # Overview This repository helps you bootstrap a Debian repository. It does not archive -old versions by default. +old versions by default. It was largely inspired by +[The Ultimate Guide to Debian Repository Hosting](https://dario.griffo.io/posts/ultimate-guide-debian-repository-hosting/). -# Set Up +# Client side Set Up -## Prerequisites - -``` bash -sudo apt install gnupg reprepro -``` - -## Create a GPG Key - -A GPG key enables you to cryptographically sign packages to assure people that -you are the one who packaged it. +Do this for whatever "yourdomain" is. ``` bash -gpg --full-generate-key +curl -sS https://debian.yourdomain.com/repository-key.asc | sudo gpg --dearmor --yes -o /etc/apt/trusted.gpg.d/yourrepo.gpg +echo "deb https://debian.yourdomain.com $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/yourrepo.list +sudo apt update ``` -1. Select "RSA (sign only)". -2. Select a key size of 4096 +# Repository Set Up -## Add your GPG Key to the Repository +This section is for people who want to host their own repository. -Get your Key ID by by running the following command: +## Prerequisites ``` bash -gpg --list-keys --keyid-format long +sudo apt install gnupg reprepro ``` -Copy it into the repository so people can validate against it with the following command: +## Generate your Key -``` bash -gpg --armor --export YOUR_KEY_ID > repository-key.asc -``` +Use `make key`. It will ask you some questions, but otherwise do everything for +you. -Apply it throughout the repository by using `./scripts/replace_key.sh YOUR_KEY_ID `. +## Set up your Web Server -Okay, that's confusing. The first `YOUR_KEY_ID` is the literal string. The second -is your actual key ID. The script does a targeted search and replace throughout -the repository. +There is an Apache configuration file in `deb-repo.conf`. Modify it where you +see `PLACEHOLDER`, include it into your server configuration and restart the +server. # Add packages to GitHub Use [Cookiecutter-deb](https://github.com/rocketbowman/cookiecutter-deb) to create a new template of a package. -The GitHub action produces a draft build. You must convert that draft into a -proper release. +The GitHub action produces a draft build. **You must convert that draft into a +proper release for it to be visible to this repository. ** # Add packages to this Repository Add the new package to the `update_all.sh` script. -# Use the Makefile +# Update the packages via the Makefile + +Use `make update` to fetch the latest releases from GitHub to your repo. -Use `make update` to fetch the latest releases from GitHub to your repo. \ No newline at end of file +Alternatively, you can use the scripts to pull specific versions from GitHub. \ No newline at end of file diff --git a/deb-repo.conf b/deb-repo.conf new file mode 100644 index 0000000..ce2372b --- /dev/null +++ b/deb-repo.conf @@ -0,0 +1,13 @@ + + ServerName SERVER_NAME_PLACEHOLDER + DocumentRoot /path/to/STORE_PLACEHOLDER + + + Options Indexes FollowSymLinks + AllowOverride None + Require all granted + + + ErrorLog ${APACHE_LOG_DIR}/debian-repo-error.log + CustomLog ${APACHE_LOG_DIR}/debian-repo-access.log combined + \ No newline at end of file diff --git a/reprepro/conf/distributions b/reprepro/conf/distributions index 96f82c7..f5e3273 100644 --- a/reprepro/conf/distributions +++ b/reprepro/conf/distributions @@ -2,16 +2,16 @@ Codename: bookworm Architectures: amd64 Components: main Description: Apt repository for unofficial packages -SignWith: YOUR_KEY_ID +SignWith: KEY_ID_PLACEHOLDER Codename: trixie Architectures: amd64 Components: main Description: Apt repository for unofficial packages -SignWith: YOUR_KEY_ID +SignWith: KEY_ID_PLACEHOLDER Codename: sid Architectures: amd64 Components: main Description: Apt repository for unofficial packages -SignWith: YOUR_KEY_ID +SignWith: KEY_ID_PLACEHOLDER diff --git a/scripts/_make_keyinit.sh b/scripts/_make_keyinit.sh new file mode 100755 index 0000000..83fee90 --- /dev/null +++ b/scripts/_make_keyinit.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +ROOTDIR=$(dirname "$SCRIPT_DIR") + +# Get variables for the template +if [ -f "$ROOTDIR"/.keyspecs ]; then + # shellcheck disable=SC1091 + . "$ROOTDIR"/.keyspecs +else + echo "Keyspecs could not be found." > /dev/stderr + exit 1 +fi; + +# Print the template after resolving variables +cat << EOF +%echo Generating a basic OpenPGP key +Key-Type: RSA +Key-Length: 4096 +Key-Usage: sign +Name-Real: $NAME_REAL +Name-Comment: $NAME_COMMENT +Name-Email: $NAME_EMAIL +Expire-Date: 0 +%commit +%echo done +EOF \ No newline at end of file diff --git a/scripts/_make_keyspecs.sh b/scripts/_make_keyspecs.sh new file mode 100755 index 0000000..2b139ff --- /dev/null +++ b/scripts/_make_keyspecs.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Get entries from user +printf "Real Name: " && read -r NAME_REAL +printf "Email: " && read -r NAME_EMAIL +printf "Comment for Key: " && read -r NAME_COMMENT + +# Write .keyspecs file to stdout (which should be redirected for use) +cat << EOF > .keyspecs +NAME_REAL="$NAME_REAL" +NAME_EMAIL="$NAME_EMAIL" +NAME_COMMENT="$NAME_COMMENT" +EOF \ No newline at end of file diff --git a/scripts/download.sh b/scripts/download.sh index e9794c1..6be6a68 100755 --- a/scripts/download.sh +++ b/scripts/download.sh @@ -2,6 +2,9 @@ # download.sh # Usage: ./download uv 0.8.22 1 "amd64" +# Magic to get this directory +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + PACKAGE_NAME="$1" PACKAGE_VERSION=${2:-"default"} BUILD_VERSION=${3:-"1"} @@ -12,10 +15,10 @@ REPO="deb-$PACKAGE_NAME" # If PACKAGE_VERSION is unspecified, check GitHub to get the latest. if [ "$PACKAGE_VERSION" == "default" ]; then - read -r PACKAGE_VERSION <<< "$(./check_latest.sh "$PACKAGE_NAME" |sed 's/\r$//')" + read -r PACKAGE_VERSION <<< "$("$SCRIPT_DIR"/check_latest.sh "$PACKAGE_NAME" | sed 's/\r$//')" fi -echo $PACKAGE_VERSION +echo "$PACKAGE_VERSION" # Get deb for all Debian distributions declare -a arr=("bookworm" "trixie" "sid") @@ -23,6 +26,6 @@ for i in "${arr[@]}" do DEBIAN_DIST=$i filename="${PACKAGE_NAME}_${PACKAGE_VERSION}-${BUILD_VERSION}+${DEBIAN_DIST}_${ARCHITECTURES}" - wget -O "../store/${DEBIAN_DIST}/${filename}.deb" \ + wget -O "$SCRIPT_DIR/../store/${DEBIAN_DIST}/${filename}.deb" \ "https://github.com/rocketbowman/${REPO}/releases/download/${PACKAGE_VERSION}/${filename}.deb" done \ No newline at end of file diff --git a/scripts/generate_index.sh b/scripts/generate_index.sh index a9c5dac..056ac9c 100755 --- a/scripts/generate_index.sh +++ b/scripts/generate_index.sh @@ -1,19 +1,26 @@ #!/bin/bash # generate_index.sh # Usage: ./generate_index.sh -KEY_ID=YOUR_KEY_ID -root=$(pwd)/.. -reprepro=$root/reprepro +# Magic to get the directory of this script +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +# Derived Constants +cd "$SCRIPT_DIR"/.. || exit 1 +ROOTDIR=$(pwd) +KEY_ID=$(cat "$ROOTDIR"/.keyid) +REPREPRO="$ROOTDIR"/reprepro + +# Iterate over distributions to create package information. declare -a arr=("bookworm" "trixie" "sid") for i in "${arr[@]}" do DEBIAN_DIST=$i - reprepro --dbdir "$reprepro"/db \ - --confdir "$reprepro"/conf \ - --outdir="$root"/packages \ + reprepro --dbdir "$REPREPRO"/db \ + --confdir "$REPREPRO"/conf \ + --outdir="$ROOTDIR"/packages \ --component main \ - includedeb "$DEBIAN_DIST" "$root"/store/"$DEBIAN_DIST"/*.deb - package_dir="$root/packages/dists/$DEBIAN_DIST" - cat "$package_dir"/Release | gpg -s --default-key "$KEY_ID" -abs > "$package_dir"/Release.gpg + includedeb "$DEBIAN_DIST" "$ROOTDIR"/store/"$DEBIAN_DIST"/*.deb + package_dir="$ROOTDIR/packages/dists/$DEBIAN_DIST" + cat "$package_dir"/Release | gpg --sign --default-key "$KEY_ID" -abs > "$package_dir"/Release.gpg done \ No newline at end of file diff --git a/scripts/replace_key.sh b/scripts/replace_key.sh deleted file mode 100755 index 96c9321..0000000 --- a/scripts/replace_key.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -rootdir=$(pwd)/.. -OLD_KEY_ID=$1 -NEW_KEY_ID=$2 -sed --in-place --expression "s/$OLD_KEY_ID/$NEW_KEY_ID/g" "$rootdir/reprepro/conf/distributions" -sed --in-place --expression "s/$OLD_KEY_ID/$NEW_KEY_ID/g" "$rootdir/scripts/generate_index.sh" \ No newline at end of file diff --git a/update_all.sh b/update_all.sh index d46f6a5..55c283e 100755 --- a/update_all.sh +++ b/update_all.sh @@ -1,10 +1,17 @@ #!/bin/bash -cd scripts || return 1 + +ROOTDIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +SCRIPT_DIR="$ROOTDIR"/scripts + + declare -a packages=("uv") + +# Download all packages for i in "${packages[@]}" do package=$i - ./download.sh "$package" + "$SCRIPT_DIR"/download.sh "$package" done -./generate_index.sh \ No newline at end of file +# Generate Index +"$SCRIPT_DIR"/generate_index.sh \ No newline at end of file -- 2.39.5