From 6e77c1ada535473b6537e4968c62dac7418206db Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Sat, 20 Jun 2026 07:22:19 +0000 Subject: [PATCH] Automatic GPG creation on aptly deployment. --- aptly/app.yaml | 1 - aptly/versions/1/README.md | 83 +++++++++----------------------- aptly/versions/1/deployment.yaml | 22 +++++++++ aptly/versions/1/manifest.yaml | 3 +- 4 files changed, 46 insertions(+), 63 deletions(-) diff --git a/aptly/app.yaml b/aptly/app.yaml index 1be27cc..9f0b60d 100644 --- a/aptly/app.yaml +++ b/aptly/app.yaml @@ -2,5 +2,4 @@ name: aptly is: aptly description: Aptly is a Debian/Ubuntu APT repository management tool for mirroring, snapshotting, and publishing package repositories. icon: https://github.com/aptly-dev.png -category: infrastructure latest: "1" diff --git a/aptly/versions/1/README.md b/aptly/versions/1/README.md index c29014b..4ae4460 100644 --- a/aptly/versions/1/README.md +++ b/aptly/versions/1/README.md @@ -1,19 +1,20 @@ # Aptly -Aptly is a Debian/Ubuntu APT repository management tool. Use it to mirror upstream repositories, create package snapshots, and publish private or curated APT repositories that your machines can install from. +Aptly is a Debian/Ubuntu APT repository management tool. Use it to create and publish private APT repositories that your machines can install from. ## Configuration Key settings in your instance's `config.yaml`: - **domain** - Where aptly will be accessible (default: `aptly.{your-cloud-domain}`) -- **storage** - Persistent volume size for packages and mirrors (default: `50Gi` — adjust based on how many packages you plan to mirror) +- **storage** - Persistent volume size for packages (default: `5Gi`) ## Access After deployment: -- `https://aptly.{your-cloud-domain}` — Published repository root (for APT clients, no auth required) -- `https://aptly.{your-cloud-domain}/api` — REST API for managing repos, mirrors, and snapshots (requires credentials) +- `https://aptly.{your-cloud-domain}/` — Published repository root (for APT clients, no auth required) +- `https://aptly.{your-cloud-domain}/api` — REST API for managing repos and snapshots (requires credentials) +- `https://aptly.{your-cloud-domain}/public.key` — GPG public key for APT clients to import ## Credentials @@ -22,8 +23,6 @@ The API is protected by HTTP basic authentication. The username defaults to `apt To retrieve it: ```bash wild secret get aptly apiPassword -# or directly: -grep apiPassword path/to/secrets.yaml ``` To use the API with curl: @@ -31,24 +30,18 @@ To use the API with curl: curl -u aptly:{your-api-password} https://aptly.{your-cloud-domain}/api/version ``` -The published repository at `/` does not require credentials — APT clients can install packages without authenticating. +## GPG Signing -## First-Time Setup +A GPG signing key is generated automatically on first deployment and stored on the persistent volume. The public key is exported to `/public.key` and is accessible without authentication so APT clients can import it: -1. Add and deploy: - ```bash - wild app add aptly - wild app deploy aptly - ``` - -2. Verify the API is responding: - ```bash - curl -u aptly:{your-api-password} https://aptly.{your-cloud-domain}/api/version - ``` +```bash +curl -fsSL https://aptly.{your-cloud-domain}/public.key | \ + sudo tee /usr/share/keyrings/my-repo.gpg > /dev/null +``` ## Common Workflows -Aptly is managed entirely through its REST API or the `aptly` CLI (run inside the pod). The REST API docs are at https://www.aptly.info/doc/api/. +Aptly is managed through its REST API or the `aptly` CLI (run inside the pod). The REST API docs are at https://www.aptly.info/doc/api/. ### Running aptly commands inside the pod @@ -56,25 +49,7 @@ Aptly is managed entirely through its REST API or the `aptly` CLI (run inside th kubectl -n aptly exec -it deploy/aptly -- bash ``` -### Mirror a Debian repository - -```bash -# Create a mirror (run inside the pod, or via the REST API) -aptly mirror create debian-bookworm-main http://deb.debian.org/debian bookworm main - -# Download packages -aptly mirror update debian-bookworm-main - -# Snapshot the mirror -aptly snapshot create bookworm-snap from mirror debian-bookworm-main - -# Publish the snapshot -aptly publish snapshot bookworm-snap -``` - -The published repo will be available at `https://aptly.{your-cloud-domain}/debian bookworm main`. - -### Create a private package repository +### Publish a local repository ```bash # Create a local repo @@ -87,37 +62,23 @@ aptly repo add my-packages /path/to/package.deb aptly publish repo my-packages ``` +The published repo will be available at `https://aptly.{your-cloud-domain}/`. + ### Configure a machine to use the repository ```bash -# Add the repo to sources.list -echo "deb https://aptly.{your-cloud-domain}/ bookworm main" | \ - sudo tee /etc/apt/sources.list.d/my-aptly.list +# Import the signing key +curl -fsSL https://aptly.{your-cloud-domain}/public.key | \ + sudo tee /usr/share/keyrings/my-repo.gpg > /dev/null -# Import the signing key (generate one first if needed — see GPG section below) -curl -s https://aptly.{your-cloud-domain}/public.key | sudo apt-key add - +# Add the repo +echo "deb [signed-by=/usr/share/keyrings/my-repo.gpg] https://aptly.{your-cloud-domain}/ stable main" | \ + sudo tee /etc/apt/sources.list.d/my-repo.list sudo apt update ``` -## GPG Signing - -Published repositories should be signed with a GPG key. On first use, generate a key inside the pod: - -```bash -kubectl -n aptly exec -it deploy/aptly -- bash - -# Generate a signing key (stored in /opt/aptly/gpg) -gpg --gen-key - -# Export the public key for clients to import -gpg --export --armor > /opt/aptly/public/public.key -``` - -Then include `--distribution`, `--component`, and signing options in your `aptly publish` commands. See https://www.aptly.info/doc/aptly/publish/snapshot/ for details. - ## Notes -- GPG keys and all aptly data (database, package pool, published repos) are stored on the persistent volume at `/opt/aptly`. +- All aptly data (GPG keys, database, package pool, published repos) is stored on the persistent volume at `/opt/aptly`. - The REST API (port 8080) and the nginx file server (port 80) both run inside the pod via supervisord. The ingress routes to nginx (port 80). -- `storage` defaults to `50Gi`. A full Debian mirror for a single architecture is ~50–100 GiB; plan accordingly. diff --git a/aptly/versions/1/deployment.yaml b/aptly/versions/1/deployment.yaml index 8e3ce9d..babe9d9 100644 --- a/aptly/versions/1/deployment.yaml +++ b/aptly/versions/1/deployment.yaml @@ -18,6 +18,28 @@ spec: seccompProfile: type: RuntimeDefault initContainers: + - name: init-gpg + image: urpylka/aptly:1.6.2 + command: + - sh + - -c + - | + export GNUPGHOME=/opt/aptly/gpg + mkdir -p "$GNUPGHOME" /opt/aptly/public + chmod 700 "$GNUPGHOME" + if gpg --list-secret-keys 2>/dev/null | grep -q '^sec'; then + echo "GPG key already exists, skipping" + else + echo "Generating GPG signing key..." + printf '%%no-protection\nKey-Type: RSA\nKey-Length: 4096\nName-Real: Wild Cloud APT Repository\nName-Email: {{ .operatorEmail }}\nExpire-Date: 0\n%%commit\n' | gpg --batch --gen-key + echo "GPG key generated" + fi + gpg --export --armor > /opt/aptly/public/public.key + securityContext: + allowPrivilegeEscalation: false + volumeMounts: + - name: data + mountPath: /opt/aptly - name: init-htpasswd image: httpd:alpine command: diff --git a/aptly/versions/1/manifest.yaml b/aptly/versions/1/manifest.yaml index acb92e9..a13dc5c 100644 --- a/aptly/versions/1/manifest.yaml +++ b/aptly/versions/1/manifest.yaml @@ -1,4 +1,4 @@ -version: 1.6.2-1 +version: 1.6.2-3 defaultConfig: namespace: aptly externalDnsDomain: "{{ .cloud.domain }}" @@ -6,5 +6,6 @@ defaultConfig: tlsSecretName: wildcard-wild-cloud-tls storage: 5Gi apiUser: aptly + operatorEmail: "{{ .operator.email }}" defaultSecrets: - key: apiPassword