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 +`