Skip to content

Commit c63e1d3

Browse files
committed
feat: support grpc sds server
1 parent 1727c9d commit c63e1d3

File tree

14 files changed

+468
-73
lines changed

14 files changed

+468
-73
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,5 @@ release/certdx_*
3434
*.service.toml
3535
*_config.service.toml
3636
/private
37-
/cert
37+
/sds
38+
cache.json

.vscode/launch.json

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "server debug",
9+
"type": "go",
10+
"request": "launch",
11+
"mode": "auto",
12+
"program": "${workspaceFolder}/exec/server/main.go",
13+
"args": ["-c", "${workspaceFolder}/server-test.toml"],
14+
"cwd": "${workspaceFolder}"
15+
}
16+
]
17+
}

exec/server/main.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"io"
66
"log"
77
"os"
8+
"os/signal"
9+
"syscall"
810
"time"
911

1012
"github.com/BurntSushi/toml"
@@ -96,6 +98,25 @@ func init() {
9698

9799
func main() {
98100
if config.HttpServer.Enabled {
99-
server.HttpSrv()
101+
go server.HttpSrv()
102+
}
103+
104+
stopSDS := make(chan struct{}, 1)
105+
if config.GRPCSDSServer.Enabled {
106+
go server.SDSSrv(stopSDS)
107+
}
108+
109+
stop := make(chan os.Signal, 1)
110+
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
111+
112+
<-stop
113+
114+
go func() {
115+
<-stop
116+
log.Fatalln("[ERR] Fast dying...")
117+
}()
118+
119+
if config.GRPCSDSServer.Enabled {
120+
stopSDS <- struct{}{}
100121
}
101122
}

exec/tools/make-server.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func makeServer() {
1414

1515
srvDomains = srvCMD.StringSliceP("dns-names", "d", []string{}, "CertDX grpc server certificate dns names, combine multiple names with \",\"")
1616
srvOrganization = srvCMD.StringP("organization", "o", "CertDX Private", "Subject Organization")
17-
srvCommonName = srvCMD.StringP("common-name", "c", "CertDX Service", "Subject Common Name")
17+
srvCommonName = srvCMD.StringP("common-name", "c", "CertDX Secret Discovery Service", "Subject Common Name")
1818
srvHelp = srvCMD.BoolP("help", "h", false, "Print help")
1919
)
2020
srvCMD.Parse(os.Args[2:])

go.mod

+6-9
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,16 @@ require (
77
github.com/go-acme/lego/v4 v4.16.1
88
github.com/spf13/pflag v1.0.5
99
google.golang.org/appengine v1.6.8
10-
)
11-
12-
require (
13-
github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 // indirect
14-
github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
15-
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect
16-
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
10+
google.golang.org/grpc v1.64.0
11+
google.golang.org/protobuf v1.34.1
1712
)
1813

1914
require (
2015
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
2116
github.com/cloudflare/cloudflare-go v0.96.0 // indirect
17+
github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 // indirect
2218
github.com/envoyproxy/go-control-plane v0.12.0
19+
github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
2320
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
2421
github.com/goccy/go-json v0.10.3 // indirect
2522
github.com/golang/protobuf v1.5.4 // indirect
@@ -37,6 +34,6 @@ require (
3734
golang.org/x/text v0.15.0 // indirect
3835
golang.org/x/time v0.5.0 // indirect
3936
golang.org/x/tools v0.21.0 // indirect
40-
google.golang.org/grpc v1.64.0
41-
google.golang.org/protobuf v1.34.1 // indirect
37+
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect
38+
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
4239
)

pkg/client/client.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import (
55
"log"
66
"os"
77
"os/exec"
8+
"os/signal"
89
"path/filepath"
910
"strings"
11+
"syscall"
1012
"time"
1113

1214
"pkg.para.party/certdx/pkg/config"
@@ -150,6 +152,9 @@ func (r *CertDXClientDaemon) HttpMain() {
150152
<-t
151153
}
152154
}
153-
blockingChan := make(chan struct{})
155+
blockingChan := make(chan os.Signal, 1)
156+
signal.Notify(blockingChan, syscall.SIGINT, syscall.SIGTERM)
157+
154158
<-blockingChan
159+
log.Println("[INF] Stopping client")
155160
}

pkg/config/config.go

+37-24
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package config
22

33
import (
44
"fmt"
5-
"google.golang.org/appengine"
65
"path"
76
"time"
7+
8+
"google.golang.org/appengine"
89
)
910

1011
const (
@@ -25,15 +26,15 @@ type DnsProvider struct {
2526
SecretKey string `toml:"secretKey" json:"secret_key,omitempty"`
2627
}
2728

28-
func (p DnsProvider) Validate() error {
29+
func (p *DnsProvider) Validate() error {
2930
switch p.Type {
3031
case DnsProviderTypeCloudflare:
3132
if p.Email == "" || p.APIKey == "" {
32-
return fmt.Errorf("DnsProvider Cloudflare: empty email or key")
33+
return fmt.Errorf("DnsProvider Cloudflare: empty Email or APIKey")
3334
}
3435
case DnsProviderTypeTencentCloud:
3536
if p.SecretID == "" || p.SecretKey == "" {
36-
return fmt.Errorf("DnsProvider TencentCloud: empty email or key")
37+
return fmt.Errorf("DnsProvider TencentCloud: empty SecretID or SecretKey")
3738
}
3839
}
3940
return nil
@@ -44,7 +45,8 @@ type ServerConfigT struct {
4445

4546
DnsProvider DnsProvider `toml:"DnsProvider" json:"dns_provider,omitempty"`
4647

47-
HttpServer HttpServerConfig `toml:"HttpServer" json:"http_server,omitempty"`
48+
HttpServer HttpServerConfig `toml:"HttpServer" json:"http_server,omitempty"`
49+
GRPCSDSServer GRPCServerConfig `toml:"gRPCSDSServer" json:"grpc_sds_server,omitempty"`
4850
}
4951

5052
type ACMEConfig struct {
@@ -59,7 +61,7 @@ type ACMEConfig struct {
5961
RenewTimeLeftDuration time.Duration `toml:"-" json:"-"`
6062
}
6163

62-
func (c ACMEConfig) Validate() error {
64+
func (c *ACMEConfig) Validate() error {
6365
if len(c.AllowedDomains) == 0 {
6466
return fmt.Errorf("AllowedDomains is empty")
6567
}
@@ -75,19 +77,33 @@ type HttpServerConfig struct {
7577
Token string `toml:"token" json:"token,omitempty"`
7678
}
7779

78-
func (c HttpServerConfig) Validate() error {
80+
func (c *HttpServerConfig) Validate() error {
81+
if !c.Enabled {
82+
return nil
83+
}
84+
7985
if c.Secure && len(c.Names) == 0 {
8086
return fmt.Errorf("secure http server with no name")
8187
}
8288
return nil
8389
}
8490

85-
// type GRPCServerConfig struct {
86-
// Listen string `toml:"listen"`
87-
// Secure bool `toml:"secure"`
88-
// Name string `toml:"name"`
89-
// Token string `toml:"token"`
90-
// }
91+
type GRPCServerConfig struct {
92+
Enabled bool `toml:"enabled" json:"enabled,omitempty"`
93+
Listen string `toml:"listen" json:"listen,omitempty"`
94+
Names []string `toml:"names" json:"names,omitempty"`
95+
}
96+
97+
func (c *GRPCServerConfig) Validate() error {
98+
if !c.Enabled {
99+
return nil
100+
}
101+
102+
if len(c.Names) == 0 {
103+
return fmt.Errorf("no grpc server name")
104+
}
105+
return nil
106+
}
91107

92108
func (c *ServerConfigT) SetDefault() {
93109
c.ACME = ACMEConfig{
@@ -101,6 +117,10 @@ func (c *ServerConfigT) SetDefault() {
101117
APIPath: "/",
102118
Secure: false,
103119
}
120+
121+
c.GRPCSDSServer = GRPCServerConfig{
122+
Listen: ":10002",
123+
}
104124
}
105125

106126
func (c *ServerConfigT) Validate() error {
@@ -118,6 +138,10 @@ func (c *ServerConfigT) Validate() error {
118138
ret = append(ret, err)
119139
}
120140

141+
if err := c.GRPCSDSServer.Validate(); err != nil {
142+
ret = append(ret, err)
143+
}
144+
121145
if len(ret) > 0 {
122146
return ret
123147
}
@@ -132,11 +156,6 @@ type ClientConfigT struct {
132156
StandbyServer ClientHttpServer `toml:"StandbyServer" json:"standby_server,omitempty"`
133157
} `toml:"Http" json:"http,omitempty"`
134158

135-
// GRPC struct {
136-
// MainServer ClientGRPCServer `toml:"MainServer"`
137-
// StandbyServer ClientGRPCServer `toml:"StandbyServer"`
138-
// } `toml:"GRPC"`
139-
140159
Certifications []ClientCertification `toml:"Certifications" json:"certifications,omitempty"`
141160
}
142161

@@ -151,12 +170,6 @@ type ClientHttpServer struct {
151170
Token string `toml:"token" json:"token,omitempty"`
152171
}
153172

154-
// type ClientGRPCServer struct {
155-
// Secure bool `toml:"secure"`
156-
// Server string `toml:"server"`
157-
// Token string `toml:"token"`
158-
// }
159-
160173
type ClientCertification struct {
161174
Name string `toml:"name" json:"name,omitempty"`
162175
SavePath string `toml:"savePath" json:"save_path,omitempty"`

pkg/server/acme.go

+20-9
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,26 @@ func RegisterAccount(ACMEProvider, Email, Kid, Hmac string) error {
124124
return fmt.Errorf("failed constructing acme client: %w", err)
125125
}
126126

127-
var eabOptions = registration.RegisterEABOptions{
128-
TermsOfServiceAgreed: true,
129-
Kid: Kid,
130-
HmacEncoded: Hmac,
131-
}
132-
myUser.Registration, err = client.Registration.RegisterWithExternalAccountBinding(eabOptions)
133-
if err != nil {
134-
os.Remove(keyPath)
135-
return fmt.Errorf("failed register: %s", err)
127+
if Hmac != "" && Kid != "" {
128+
var eabOptions = registration.RegisterEABOptions{
129+
TermsOfServiceAgreed: true,
130+
Kid: Kid,
131+
HmacEncoded: Hmac,
132+
}
133+
myUser.Registration, err = client.Registration.RegisterWithExternalAccountBinding(eabOptions)
134+
if err != nil {
135+
os.Remove(keyPath)
136+
return fmt.Errorf("failed register: %s", err)
137+
}
138+
} else {
139+
var regOptions = registration.RegisterOptions{
140+
TermsOfServiceAgreed: true,
141+
}
142+
myUser.Registration, err = client.Registration.Register(regOptions)
143+
if err != nil {
144+
os.Remove(keyPath)
145+
return fmt.Errorf("failed register: %s", err)
146+
}
136147
}
137148

138149
reg, err := json.Marshal(myUser.Registration)

pkg/server/http.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package server
22

33
import (
4-
"fmt"
5-
"io"
64
"crypto/tls"
75
"encoding/json"
6+
"fmt"
7+
"io"
88
"log"
99
"net/http"
1010
"strings"
@@ -66,7 +66,7 @@ func handleCertReq(w *http.ResponseWriter, r *http.Request) {
6666
}
6767

6868
cachedCert = ServerCertCache.GetEntry(req.Domains)
69-
if !cachedCert.Listening.Load() {
69+
if !cachedCert.IsSubcribing() {
7070
_, err = cachedCert.Renew(false)
7171
if err != nil {
7272
goto ERR
@@ -98,8 +98,7 @@ func serveHttps() {
9898
cert_ := entry.Cert()
9999
certValid := cert_.IsValid()
100100

101-
// when starting up, no cert is listening, just start a watch dog anyway
102-
go entry.CertWatchDog()
101+
entry.Subscrib()
103102

104103
if !certValid {
105104
<-*entry.Updated.Load()
@@ -136,7 +135,8 @@ func HttpSrv() {
136135

137136
if !Config.HttpServer.Secure {
138137
log.Printf("[INF] Http server started")
139-
http.ListenAndServe(Config.HttpServer.Listen, nil)
138+
err := http.ListenAndServe(Config.HttpServer.Listen, nil)
139+
log.Printf("[INF] Http server stopped: %s", err)
140140
} else {
141141
serveHttps()
142142
}

pkg/server/path.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func getPrivateKeySavePath(email string, ACMEProvider string) (string, error) {
1515
keyName := fmt.Sprintf("%s_%s.key", email, ACMEProvider)
1616

1717
if _, err := os.Stat(saveDir); os.IsNotExist(err) {
18-
err := os.Mkdir(saveDir, 0o600)
18+
err := os.Mkdir(saveDir, 0o755)
1919
if err != nil {
2020
return "", fmt.Errorf("cannot create path: %s to save account key: %w", saveDir, err)
2121
}

0 commit comments

Comments
 (0)