diff --git a/certificate.html b/certificate.html
index bbdc0ae..8a391dc 100644
--- a/certificate.html
+++ b/certificate.html
@@ -98,6 +98,7 @@
Hi, {{.Name}} <{{.Email}}>!
+
{{end}}
diff --git a/guestbook/certificate.yaml b/guestbook/certificate.yaml
index bd7009e..40010b4 100644
--- a/guestbook/certificate.yaml
+++ b/guestbook/certificate.yaml
@@ -23,6 +23,10 @@ spec:
duration: 87600h # 10 years
dnsNames:
- guestbook.print-your-cert.cert-manager.io
+ - readonly-guestbook.print-your-cert.cert-manager.io
+ ipAddresses:
+ - 127.0.0.1
+ - "::1"
issuerRef:
name: root-print-your-cert-ca-issuer
kind: Issuer
diff --git a/guestbook/index-local.sh b/guestbook/index-local.sh
new file mode 100755
index 0000000..8d4bdfd
--- /dev/null
+++ b/guestbook/index-local.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -eu -o pipefail
+
+curl --cacert ca.crt --cert /tmp/chain.pem --key /tmp/pkey.pem --resolve guestbook.print-your-cert.cert-manager.io:9090:127.0.0.1 https://guestbook.print-your-cert.cert-manager.io:9090/
diff --git a/guestbook/index-readonly-local.sh b/guestbook/index-readonly-local.sh
new file mode 100755
index 0000000..c735287
--- /dev/null
+++ b/guestbook/index-readonly-local.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -eu -o pipefail
+
+curl --cacert ca.crt --resolve readonly-guestbook.print-your-cert.cert-manager.io:9090:127.0.0.1 https://readonly-guestbook.print-your-cert.cert-manager.io:9090/
diff --git a/guestbook/main.go b/guestbook/main.go
index 58967ec..a168a24 100644
--- a/guestbook/main.go
+++ b/guestbook/main.go
@@ -106,7 +106,7 @@ func allMessages(ctx context.Context, db *sql.DB, w io.Writer) ([]byte, error) {
func addMessage(ctx context.Context, db *sql.DB, email string, userAgent string, msg string) error {
timestamp := time.Now().Format(time.RFC3339Nano)
- _, err := db.ExecContext(ctx, `insert into entries(email, user_agent, date, message) values($1, $2, $3, $4);`, email, userAgent, timestamp, msg)
+ _, err := db.ExecContext(ctx, `insert into entries(email, user_agent, date, message) values($1, $2, $3, $4) on conflict(email) do update set user_agent=excluded.user_agent,date=excluded.date,message=excluded.message;`, email, userAgent, timestamp, msg)
if err != nil {
return err
}
@@ -138,7 +138,7 @@ func writePage(db *sql.DB) http.Handler {
err = addMessage(r.Context(), db, email, userAgent, message)
if err != nil {
- w.WriteHeader(http.StatusBadRequest)
+ logger.Error("failed to add message to database", "error", err)
http.Error(w, "failed to add message to database", http.StatusBadRequest)
return
}
@@ -146,7 +146,7 @@ func writePage(db *sql.DB) http.Handler {
logger.Info("added message", "email", email, "contents", message, "user-agent", userAgent)
w.WriteHeader(http.StatusOK)
- w.Write([]byte("successfully added message"))
+ w.Write([]byte("successfully added message, thanks for visiting the booth!\n"))
})
}
@@ -345,7 +345,7 @@ func createDB(ctx context.Context, path string) error {
defer db.Close()
- if _, err = db.ExecContext(ctx, `create table entries(email, user_agent, date, message);`); err != nil {
+ if _, err = db.ExecContext(ctx, `create table entries(email TEXT UNIQUE, user_agent TEXT, date TEXT, message TEXT);`); err != nil {
return err
}
diff --git a/guestbook/write-local.sh b/guestbook/write-local.sh
new file mode 100755
index 0000000..38bd1c0
--- /dev/null
+++ b/guestbook/write-local.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+set -eu -o pipefail
+
+curl --cacert ca.crt --cert /tmp/chain.pem --key /tmp/pkey.pem --resolve guestbook.print-your-cert.cert-manager.io:9090:127.0.0.1 https://guestbook.print-your-cert.cert-manager.io:9090/write \
+ -X POST \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "message=hello, world"
diff --git a/main.go b/main.go
index db38a59..f5952da 100644
--- a/main.go
+++ b/main.go
@@ -22,6 +22,7 @@ import (
"html/template"
"io"
"log"
+ "net"
"net/http"
"net/mail"
"net/url"
@@ -53,6 +54,7 @@ var (
guestbookURL = flag.String("guestbook-url", "https://guestbook.print-your-cert.cert-manager.io/write", "URL of the write path for the guestbook")
guestbookRootCAPath = flag.String("guestbook-ca", "guestbook/ca.crt", "Path to the CA certificate for the guestbook")
+ guestbookLocal = flag.Bool("guestbook-local", false, "If true, redirect guestbook requests to 127.0.0.1 for local testing while preserving the SNI header from guestbook-url")
)
const (
@@ -411,14 +413,18 @@ func downloadTarPage(kclient kubernetes.Interface, ns string) http.Handler {
var files = []struct {
Name string
Body []byte
+ Mode int64
}{
- {"chain.pem", certPEM},
- {"pkey.pem", keyPEM},
+ {"chain.pem", certPEM, 0o600},
+ {"pkey.pem", keyPEM, 0o600},
+ {"sign.sh", []byte(signSH), 0o700},
+ {"README.md", []byte(signREADME), 0o600},
}
+
for _, file := range files {
hdr := &tar.Header{
Name: file.Name,
- Mode: 0600,
+ Mode: file.Mode,
Size: int64(len(file.Body)),
}
@@ -491,14 +497,30 @@ func signGuestbookPage(guestbookURL string, remoteRoots *x509.CertPool, kclient
return
}
- guestbookClient := &http.Client{
- Transport: &http.Transport{
- TLSClientConfig: &tls.Config{
- Certificates: []tls.Certificate{clientCertKeyPair},
- RootCAs: remoteRoots,
- },
+ transport := &http.Transport{
+ TLSClientConfig: &tls.Config{
+ Certificates: []tls.Certificate{clientCertKeyPair},
+ RootCAs: remoteRoots,
},
- Timeout: 5 * time.Second,
+ }
+
+ if *guestbookLocal {
+ transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
+ // redirect all connections to 127.0.0.1
+ // should only be used for dev
+ dialer := &net.Dialer{
+ Timeout: 10 * time.Second,
+ KeepAlive: 2 * time.Second,
+ }
+
+ addr = "127.0.0.1" + addr[strings.LastIndex(addr, ":"):]
+ return dialer.DialContext(ctx, network, addr)
+ }
+ }
+
+ guestbookClient := &http.Client{
+ Transport: transport,
+ Timeout: 5 * time.Second,
}
postValues := url.Values{}
@@ -514,6 +536,7 @@ func signGuestbookPage(guestbookURL string, remoteRoots *x509.CertPool, kclient
req.Header.Add("content-type", "application/x-www-form-urlencoded")
req.Header.Add("user-agent", "kiosk")
+ req.Header.Add("host", "guestbook.print-your-cert.cert-manager.io")
guestbookResponse, err := guestbookClient.Do(req)
if err != nil {
@@ -1070,3 +1093,20 @@ func getPublicKeyAlgorithm(algorithm x509.PublicKeyAlgorithm, key interface{}) s
}
return fmt.Sprintf("%s %s", algorithm, params)
}
+
+const signSH = `#!/usr/bin/env bash
+
+set -eu -o pipefail
+
+curl --cert chain.pem --key pkey.pem https://guestbook.print-your-cert.cert-manager.io/write \
+ -X POST \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "message=I'm a star"
+`
+
+const signREADME = `Thanks for downloading your certificate from the cert-manager booth at KubeCon Paris 2024!
+
+You can run sign.sh to sign the guestbook - feel free to customise the message!
+
+You can fetch guestbook entries using: curl https://readonly-guestbook.print-your-cert.cert-manager.io
+`