diff --git a/Dockerfile.controller b/Dockerfile.controller
index cfe8eab..50da121 100644
--- a/Dockerfile.controller
+++ b/Dockerfile.controller
@@ -1,9 +1,10 @@
-FROM alpine:edge
+FROM alpine:3.20
+
ARG $TARGETARCH
+
WORKDIR /root
-RUN echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories \
- && apk add --update --no-cache python3 py3-pillow py3-future py3-jinja2 py3-bottle py3-pip py3-usb imagemagick ttf-opensans libqrencode-tools step-cli openssl bash curl libusb fontconfig ttf-dejavu jq kubectl@testing timg@testing \
+RUN apk add --update --no-cache python3 py3-pillow py3-future py3-jinja2 py3-bottle py3-pip py3-usb imagemagick ttf-opensans libqrencode-tools step-cli openssl bash curl libusb fontconfig ttf-dejavu jq kubectl timg \
&& python3 -m venv /venv && . /venv/bin/activate \
&& pip3 install --no-cache-dir --upgrade brother_ql \
&& curl -sSL https://github.com/pklaus/brother_ql_web/archive/refs/heads/master.tar.gz | tar xz -C /root \
diff --git a/README.md b/README.md
index 6cc61e4..0ddbbcb 100644
--- a/README.md
+++ b/README.md
@@ -31,9 +31,9 @@ work forever, the other URLs and IPs presented in this README are temporary.
- [Local development](#local-development)
- [Local development on the UI](#local-development-on-the-ui)
- [Local development on the controller (that creates PNGs and prints them)](#local-development-on-the-controller-that-creates-pngs-and-prints-them)
- - [`pem-to-png`](#pem-to-png)
+ - [`cert-card`](#cert-card)
- [Testing the printer](#testing-the-printer)
- - [Testing pem-to-png](#testing-pem-to-png)
+ - [Testing cert-card](#testing-cert-card)
- [Troubleshooting](#troubleshooting)
- [From the CLI: `usb.core.USBError: [Errno 13] Access denied (insufficient permissions)`](#from-the-cli-usbcoreusberror-errno-13-access-denied-insufficient-permissions)
- [From the CLI: `usb.core.USBError: [Errno 16] Resource busy`](#from-the-cli-usbcoreusberror-errno-16-resource-busy)
@@ -227,8 +227,7 @@ https://print-your-cert.cert-manager.io
## Staff: test things
-For anyone who is in the cert-manager org and wants to test or debug
-things:
+For anyone who is authorized and wants to test or debug things:
- [Install tailscale](https://tailscale.com/download/).
- Run `tailscale up`, it should open something in your browser → "Sign in
@@ -243,9 +242,6 @@ things:
ssh pi@100.121.173.5
```
- > The public keys of each cert-manager org member have been added to the
- > `authorized_keys` of the Pi.
-
## Running everything on the Raspberry Pi (on the booth)
Once on the booth, you will need to perform these ten tasks:
@@ -273,29 +269,16 @@ upgrade` on the first day of KubeCon in Amsterdam and ended up spending half
First, unplug the micro SD card from the Raspberry Pi and plug it into your
laptop using a micro-SD-to-SD card adaptor.
-Then, install Raspberry OS (Debian Bookworm) on the Pi using the Imager program.
-In the Imager program settings, I changed the username to `pi` and the password
-to something secret (usually the default password is `raspberry`, I changed it;
-see the label on the side of the Raspberry Pi).
-
-Then, you will need to mount the micro SD card to your laptop using a
-SD-to-micro-SD adaptor. Once the SD card is mounted, set the following variable
-to where the SD card is mounted:
+Then, install Raspberry OS on the microSD card using the Imager program.
+In the Imager program settings, change the username to `certmanager` and the password
+to something secret.
-```sh
-# On macOS:
-PI=/Volumes/bootfs
-```
+Be sure also to enable SSH with password authentication.
-Then, enable SSH on the Pi:
-
-```bash
-touch $PI/ssh
-```
+You can also use the imager to setup a WiFi connection, which might be helpful
+with initial setup at home.
-There used to be a way to configure the Wifi password without a screen and
-keyboard, but that's not possible anymore with Bookworm
-([source](https://www.raspberrypi.com/documentation/computers/configuration.html#connect-to-a-wireless-network)).
+At the conference, you should be able to use the GUI to set up a WiFi connection.
> If the Wifi doesn't work, somehow SSH into the Pi and run `wpa_cli`:
>
@@ -322,7 +305,7 @@ keyboard, but that's not possible anymore with Bookworm
> sudo ifconfig wlan0 up
> ```
-Then, unmount the micro SD card from your laptop and plug it into the Raspberry.
+Then, unmount the micro SD card from your laptop and plug it into the Raspberry Pi.
### Booth: Set Up Tailscale on the Raspberry Pi
@@ -352,8 +335,13 @@ machine with your Tailnet in . That
way, you can stay logged to your tailnet but still be able to access the
Raspberry Pi.
-Then, go back to your laptop and run the following command to make sure everyone
-in the cert-manager org can SSH into the Pi:
+#### Allowing SSH Access to cert-manager org members
+
+If desired, the script below will allow SSH access to cert-manager org members.
+
+This might be overkill; you can also just download any GitHub user's SSH keys
+using `curl -LO https://github.com/.keys` and then append the contents of
+that file to `.ssh/authorized_keys`.
```bash
curl -sH "Authorization: token $(lpass show github.com -p)" https://api.github.com/orgs/cert-manager/members \
@@ -482,8 +470,7 @@ To create the VM `print-your-cert`, you can use the following command:
> [!NOTE]
>
> Use the GCP zone closest to the KubeCon venue. The examples below use
-> `europe-west1-c` (Belgium) since the venue was in Paris (I didn't pick Paris
-> as it doesn't have f1-micro VMs).
+> `europe-west1-c` (Belgium). Try to pick a zone with low CO2 emissions.
> [!NOTE]
>
@@ -581,6 +568,17 @@ sudo systemctl restart caddy.service
EOF
```
+Finally, you'll need to ensure that the tailscale ACLs allow traffic to the pi.
+
+Visit [the Tailscale admin panel](https://login.tailscale.com/admin/acls/file) and set the "hosts" key
+to include the Pi, and ensure that there's an ACL allowing traffic:
+
+```text
+"acls": [
+ {"action": "accept", "users": ["*"], "ports": ["raspberrypi:*"]},
+]
+```
+
### Prerequisite: install k3s on the Raspberry Pi
This prerequisite is useful both for local development and for running the
@@ -677,7 +675,7 @@ Now, ssh into the Raspberry Pi and launch the UI:
# From your laptop.
ssh pi docker rm -f print-your-cert-ui
ssh pi docker run -d --restart=always --name print-your-cert-ui --net=host \
- -v '/home/pi/.kube/config:/home/nonroot/.kube/config' \
+ -v '/home/certmanager/.kube/config:/home/nonroot/.kube/config' \
ghcr.io/cert-manager/print-your-cert-ui:latest \
--issuer print-your-cert-ca \
--issuer-kind ClusterIssuer \
@@ -761,7 +759,7 @@ Now, SSH into the Raspberry Pi and launch the controller:
```sh
ssh pi sudo chmod a+r ~/.kube/config
ssh pi docker rm -f print-your-cert-controller
-ssh pi docker run -d --restart=always --name print-your-cert-controller --privileged -v /dev/bus/usb:/dev/bus/usb -v /home/pi/.kube/config:/root/.kube/config --net=host ghcr.io/cert-manager/print-your-cert-controller:latest
+ssh pi docker run -d --restart=always --name print-your-cert-controller --privileged -v /dev/bus/usb:/dev/bus/usb -v /home/certmanager/.kube/config:/root/.kube/config --net=host ghcr.io/cert-manager/print-your-cert-controller:latest
```
You can also run the "debug" printer UI (brother_ql_web) if you want to make
@@ -933,16 +931,16 @@ To use the guestbook, make sure the UI is running locally too (see above).
### Local development on the controller (that creates PNGs and prints them)
-The controller is made in two pieces: `pem-to-png` that turns one PEM into two
-PNGs, and `print-your-cert-controller` that runs `pem-to-png` every time a
+The controller is made in two pieces: `cert-card` which produces a PNG with the label(s),
+and `print-your-cert-controller` that runs `cert-card` every time a
certificate object in Kubernetes becomes ready.
-#### `pem-to-png`
+#### `cert-card`
-pem-to-png is what turns a PEM file into two PNGs: `front.png` and `back.png`.
+`cert-card` which produces a PNG with the label(s)
```sh
-brew install imagemagick qrencode step svn
+brew install imagemagick qrencode step
brew install homebrew/cask-fonts/font-open-sans
brew install homebrew/cask-fonts/font-dejavu
```
@@ -950,7 +948,7 @@ brew install homebrew/cask-fonts/font-dejavu
To run it, for example:
```sh
-./pem-to-png </O=Jetstack" -reqexts v3_req -extensions v3_ca -out ca.crt
step certificate create "CN=Foo Bar " foo.crt foo.key --ca ca.crt --ca-key ca.key --password-file /dev/null
-pem-to-png "
fi
@@ -67,32 +69,43 @@ cat >/tmp/crt-$certname
line1=$(
cat <&2
-echo "$url" | qrencode --type PNG --margin 4 -o - | convert -size 696x492 canvas:white \
- \( -gravity Center -monochrome -filter point -interpolate nearest - -resize 492 \) -composite back-$certname.png
+
+echo "$url" | qrencode --type PNG --margin 4 -o - | convert -size 696x1109 canvas:white \
+ \( -gravity SouthWest -font Open-Sans-Regular -pointsize 22 -fill black -annotate +0-0 "$line1" \) -geometry +0+0 \
+ \( -gravity SouthWest -font Open-Sans-Regular -pointsize 22 -fill black -annotate +0+115 "$line2" \) -geometry +0+0 \
+ \( -gravity SouthEast -font Open-Sans-Regular -pointsize 44 -fill black -annotate +0-0 "$cardcolor" \) -geometry +0+0 \
+ \( -gravity SouthEast -annotate +415+415 -monochrome -filter point -interpolate nearest - -resize 492 \) -geometry +0+0 \
+ -background None -layers Flatten front-$certname.png
+
+#echo "$url" >&2
+#echo "$url" | qrencode --type PNG --margin 4 -o - | convert -size 696x1109 canvas:white \
+# \( -gravity Center -monochrome -filter point -interpolate nearest - -resize 492 \) -composite back-$certname.png
diff --git a/cluster_issuer.yaml b/cluster_issuer.yaml
index cd47aad..e0559b7 100644
--- a/cluster_issuer.yaml
+++ b/cluster_issuer.yaml
@@ -23,7 +23,9 @@ spec:
organizationalUnits:
- cert-manager
countries: # Change for the country you're issuing in!
- - FR
+ - US
+ localities: # Change for the city you're issuing in!
+ - Salt Lake City
duration: 438000h # 50 years.
issuerRef:
name: root-print-your-cert-ca-issuer
diff --git a/guestbook/README.md b/guestbook/README.md
index 6bab5f9..936dc85 100644
--- a/guestbook/README.md
+++ b/guestbook/README.md
@@ -2,12 +2,28 @@
## Setup
-1. Manually copied a locally built guestbook binary, litestream.yml, the systemd service, the cert, key and CA files to the remote VM.
-2. Installed litestream manually, then moved litestream.yml to /etc/litestream.yml
-3. Moved the systemd unit to /usr/lib/systemd/system
-4. Created /var/guestbook
-5. Ran the guestbook with init-db to create the db, moved it to /var/guestbook
-6. Enabled litestream and the systemd unit
+1. Create a VM for running the guestbook in the cert-manager-general GCP project.
+ - Example CLI command is below
+ - Be sure to use a debian-based Linux distro
+2. On a running k8s cluster with cert-manager (not on the guestbook VM):
+ - Set up a [Google Cloud DNS secret](https://cert-manager.io/docs/configuration/acme/dns01/google/)
+ - Be sure to use the cert-manager-general project!
+ - Apply `letsencrypt-cert.yaml`
+ - Export the resulting cert and key
+3. Manually copy the following files to the remote guestbook VM:
+ - Locally built guestbook binary
+ - litestream.yml
+ - guestbook.service
+ - The cert chain and key from Let's Encrypt
+ - The root CA from the Pi (used for mTLS)
+4. Install litestream [manually](https://litestream.io/install/debian/) with `dpkg`
+5. Move `litestream.yml` to `/etc/litestream.yml`
+ - Check that the bucket configuration is correct and that the VM's SA has access to the bucket
+ - Litestream will back the database up to GCS when a write occurs
+6. Move `guestbook.service` to `/usr/lib/systemd/system`
+7. Create `/var/guestbook`
+8. Run `sudo guestbook -init-db -db-path /var/guestbook/guestbook.sqlite`
+9. `sudo systemctl enable --now guestbook.service litestream.service`
## Root CA
@@ -66,3 +82,24 @@ Certificate:
40:02:20:66:ad:b0:9f:97:d9:56:ec:7c:65:71:7b:07:1d:b6:
64:4a:6c:b7:6d:c6:58:0c:1f:6a:64:d4:98:12:e5:80:50
```
+
+## gcloud CLI for VM
+
+```bash
+gcloud compute instances create print-your-cert-guestbook-20241127-090928 \
+ --project=cert-manager-general \
+ --zone=us-central1-f \
+ --machine-type=e2-medium \
+ --network-interface=network-tier=PREMIUM,stack-type=IPV4_ONLY,subnet=default \
+ --maintenance-policy=MIGRATE \
+ --provisioning-model=STANDARD \
+ --service-account=guestbook-sa@cert-manager-general.iam.gserviceaccount.com \
+ --scopes=https://www.googleapis.com/auth/devstorage.read_write,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring.write,https://www.googleapis.com/auth/service.management.readonly,https://www.googleapis.com/auth/servicecontrol,https://www.googleapis.com/auth/trace.append \
+ --tags=https-server \
+ --create-disk=auto-delete=yes,boot=yes,device-name=print-your-cert-guestbook,image=projects/debian-cloud/global/images/debian-12-bookworm-v20241009,mode=rw,size=10,type=pd-balanced \
+ --no-shielded-secure-boot \
+ --shielded-vtpm \
+ --shielded-integrity-monitoring \
+ --labels=goog-ec-src=vm_add-gcloud \
+ --reservation-affinity=any
+```
diff --git a/guestbook/guestbook.service b/guestbook/guestbook.service
index f68dfb8..0521936 100644
--- a/guestbook/guestbook.service
+++ b/guestbook/guestbook.service
@@ -6,7 +6,7 @@ After=network.target
# TODO: Add custom user
# User=guestbook
# Group=guestbook
-ExecStart=/usr/bin/guestbook -ca-cert /var/guestbook/ca.crt -tls-chain /etc/ssl/tls.chain -tls-key /etc/ssl/tls.key -db-path /var/guestbook/guestbook.sqlite
+ExecStart=/usr/bin/guestbook -ca-cert /var/guestbook/ca.crt -tls-chain /etc/ssl/tls.chain -tls-key /etc/ssl/tls.key -db-path /var/guestbook/guestbook.sqlite -listen 0.0.0.0:443
StandardOutput=journal
StandardError=journal
Type=simple
diff --git a/guestbook/letsencrypt-cert.yaml b/guestbook/letsencrypt-cert.yaml
new file mode 100644
index 0000000..d07287a
--- /dev/null
+++ b/guestbook/letsencrypt-cert.yaml
@@ -0,0 +1,46 @@
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: le-issuer
+spec:
+ acme:
+ email: ashley.davis@venafi.com
+ server: https://acme-v02.api.letsencrypt.org/directory
+ privateKeySecretRef:
+ name: le-account-key
+ solvers:
+ - dns01:
+ cloudDNS:
+ project: cert-manager-general
+ serviceAccountSecretRef:
+ name: clouddns-dns01-solver-svc-acct
+ key: key.json
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: guestbook-tls
+ namespace: default
+spec:
+ privateKey:
+ algorithm: ECDSA
+ size: 256
+ secretName: guestbook-tls
+ commonName: guestbook.print-your-cert.cert-manager.io
+ subject:
+ organizations:
+ - CNCF
+ organizationalUnits:
+ - cert-manager
+ countries:
+ - GB
+ - US
+ - FR
+ - ES
+ - NL
+ dnsNames:
+ - guestbook.print-your-cert.cert-manager.io
+ - readonly-guestbook.print-your-cert.cert-manager.io
+ issuerRef:
+ name: le-issuer
+ kind: Issuer
diff --git a/landing.html b/landing.html
index 947cec5..8896992 100644
--- a/landing.html
+++ b/landing.html
@@ -16,7 +16,8 @@
Powered by cert-manager
"
>
Your email will not be displayed on-screen, just your name. These
- details are only used to fill in the "Subject" field of the X.509
- certificate, and will be removed within six months.
+ details are used to fill in the "Subject" field of the X.509
+ certificate, and will be removed within six months.
+ We may send a follow-up thank you email using the address provided.