Просмотр исходного кода

cmd/derper: add --acme-email flag for GCP cert mode (#18278)

GCP Certificate Manager requires an email contact on ACME accounts.
Add --acme-email flag that is required for --certmode=gcp and
optional for --certmode=letsencrypt.

Fixes #18277

Signed-off-by: Raj Singh <[email protected]>
Raj Singh 2 месяцев назад
Родитель
Сommit
d451cd54a7
3 измененных файлов с 21 добавлено и 7 удалено
  1. 8 1
      cmd/derper/cert.go
  2. 11 5
      cmd/derper/cert_test.go
  3. 2 1
      cmd/derper/derper.go

+ 8 - 1
cmd/derper/cert.go

@@ -44,7 +44,7 @@ type certProvider interface {
 	HTTPHandler(fallback http.Handler) http.Handler
 }
 
-func certProviderByCertMode(mode, dir, hostname, eabKID, eabKey string) (certProvider, error) {
+func certProviderByCertMode(mode, dir, hostname, eabKID, eabKey, email string) (certProvider, error) {
 	if dir == "" {
 		return nil, errors.New("missing required --certdir flag")
 	}
@@ -59,6 +59,9 @@ func certProviderByCertMode(mode, dir, hostname, eabKID, eabKey string) (certPro
 			if eabKID == "" || eabKey == "" {
 				return nil, errors.New("--certmode=gcp requires --acme-eab-kid and --acme-eab-key flags")
 			}
+			if email == "" {
+				return nil, errors.New("--certmode=gcp requires --acme-email flag")
+			}
 			keyBytes, err := decodeEABKey(eabKey)
 			if err != nil {
 				return nil, err
@@ -73,6 +76,10 @@ func certProviderByCertMode(mode, dir, hostname, eabKID, eabKey string) (certPro
 		}
 		if hostname == "derp.tailscale.com" {
 			certManager.HostPolicy = prodAutocertHostPolicy
+		}
+		if email != "" {
+			certManager.Email = email
+		} else if hostname == "derp.tailscale.com" {
 			certManager.Email = "[email protected]"
 		}
 		return certManager, nil

+ 11 - 5
cmd/derper/cert_test.go

@@ -91,7 +91,7 @@ func TestCertIP(t *testing.T) {
 		t.Fatalf("Error closing key.pem: %v", err)
 	}
 
-	cp, err := certProviderByCertMode("manual", dir, hostname, "", "")
+	cp, err := certProviderByCertMode("manual", dir, hostname, "", "", "")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -174,19 +174,25 @@ func TestGCPCertMode(t *testing.T) {
 	dir := t.TempDir()
 
 	// Missing EAB credentials
-	_, err := certProviderByCertMode("gcp", dir, "test.example.com", "", "")
+	_, err := certProviderByCertMode("gcp", dir, "test.example.com", "", "", "[email protected]")
 	if err == nil {
 		t.Fatal("expected error when EAB credentials are missing")
 	}
 
+	// Missing email
+	_, err = certProviderByCertMode("gcp", dir, "test.example.com", "kid", "dGVzdC1rZXk", "")
+	if err == nil {
+		t.Fatal("expected error when email is missing")
+	}
+
 	// Invalid base64
-	_, err = certProviderByCertMode("gcp", dir, "test.example.com", "kid", "not-valid!")
+	_, err = certProviderByCertMode("gcp", dir, "test.example.com", "kid", "not-valid!", "[email protected]")
 	if err == nil {
 		t.Fatal("expected error for invalid base64")
 	}
 
 	// Valid base64url (no padding)
-	cp, err := certProviderByCertMode("gcp", dir, "test.example.com", "kid", "dGVzdC1rZXk")
+	cp, err := certProviderByCertMode("gcp", dir, "test.example.com", "kid", "dGVzdC1rZXk", "[email protected]")
 	if err != nil {
 		t.Fatalf("base64url: %v", err)
 	}
@@ -195,7 +201,7 @@ func TestGCPCertMode(t *testing.T) {
 	}
 
 	// Valid standard base64 (with padding, gcloud format)
-	cp, err = certProviderByCertMode("gcp", dir, "test.example.com", "kid", "dGVzdC1rZXk=")
+	cp, err = certProviderByCertMode("gcp", dir, "test.example.com", "kid", "dGVzdC1rZXk=", "[email protected]")
 	if err != nil {
 		t.Fatalf("base64: %v", err)
 	}

+ 2 - 1
cmd/derper/derper.go

@@ -65,6 +65,7 @@ var (
 	hostname    = flag.String("hostname", "derp.tailscale.com", "TLS host name for certs, if addr's port is :443. When --certmode=manual, this can be an IP address to avoid SNI checks")
 	acmeEABKid  = flag.String("acme-eab-kid", "", "ACME External Account Binding (EAB) Key ID (required for --certmode=gcp)")
 	acmeEABKey  = flag.String("acme-eab-key", "", "ACME External Account Binding (EAB) HMAC key, base64-encoded (required for --certmode=gcp)")
+	acmeEmail   = flag.String("acme-email", "", "ACME account contact email address (required for --certmode=gcp, optional for letsencrypt)")
 	runSTUN     = flag.Bool("stun", true, "whether to run a STUN server. It will bind to the same IP (if any) as the --addr flag value.")
 	runDERP     = flag.Bool("derp", true, "whether to run a DERP server. The only reason to set this false is if you're decommissioning a server but want to keep its bootstrap DNS functionality still running.")
 	flagHome    = flag.String("home", "", "what to serve at the root path. It may be left empty (the default, for a default homepage), \"blank\" for a blank page, or a URL to redirect to")
@@ -345,7 +346,7 @@ func main() {
 	if serveTLS {
 		log.Printf("derper: serving on %s with TLS", *addr)
 		var certManager certProvider
-		certManager, err = certProviderByCertMode(*certMode, *certDir, *hostname, *acmeEABKid, *acmeEABKey)
+		certManager, err = certProviderByCertMode(*certMode, *certDir, *hostname, *acmeEABKid, *acmeEABKey, *acmeEmail)
 		if err != nil {
 			log.Fatalf("derper: can not start cert provider: %v", err)
 		}