Skip to content

Commit 712f597

Browse files
committed
feat: add TLS support for gRPC connections to Dex
1 parent 9ca08f3 commit 712f597

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

config/config.go

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import (
77
"net/url"
88
"os"
99

10+
"crypto/tls"
11+
"crypto/x509"
12+
1013
"gopkg.in/yaml.v3"
1114
)
1215

@@ -45,7 +48,10 @@ type DynamicClientRegistration struct {
4548
}
4649

4750
type DexGRPCClient struct {
48-
Addr string `yaml:"addr"`
51+
Addr string `yaml:"addr"`
52+
TLSCert string `yaml:"tlsCert,omitempty"`
53+
TLSKey string `yaml:"tlsKey,omitempty"`
54+
TLSClientCA string `yaml:"tlsClientCA,omitempty"`
4955
}
5056

5157
type Proxy struct {
@@ -133,6 +139,50 @@ func (c *Config) YAMLString() (string, error) {
133139
}
134140
}
135141

142+
func (g *DexGRPCClient) ClientTLSConfig() (*tls.Config, error) {
143+
// Check if TLS fields are set - must be all or nothing
144+
tlsFieldsSet := 0
145+
if g.TLSCert != "" {
146+
tlsFieldsSet++
147+
}
148+
if g.TLSKey != "" {
149+
tlsFieldsSet++
150+
}
151+
if g.TLSClientCA != "" {
152+
tlsFieldsSet++
153+
}
154+
155+
if tlsFieldsSet == 0 {
156+
// No TLS configured - return nil for insecure connection
157+
return nil, nil
158+
}
159+
160+
if tlsFieldsSet != 3 {
161+
return nil, fmt.Errorf("all three TLS fields (tlsCert, tlsKey, tlsClientCA) must be set together or all left empty")
162+
}
163+
164+
// All three fields are set - configure mTLS
165+
cPool := x509.NewCertPool()
166+
caCert, err := os.ReadFile(g.TLSClientCA)
167+
if err != nil {
168+
return nil, fmt.Errorf("failed to read TLS client CA: %w", err)
169+
}
170+
if !cPool.AppendCertsFromPEM(caCert) {
171+
return nil, fmt.Errorf("failed to append TLS client CA certificate")
172+
}
173+
174+
clientCert, err := tls.LoadX509KeyPair(g.TLSCert, g.TLSKey)
175+
if err != nil {
176+
return nil, fmt.Errorf("failed to load TLS certificate and key: %w", err)
177+
}
178+
179+
clientTLSConfig := &tls.Config{
180+
RootCAs: cPool,
181+
Certificates: []tls.Certificate{clientCert},
182+
}
183+
return clientTLSConfig, nil
184+
}
185+
136186
func (c *Config) Validate() error {
137187
if c.Host == nil {
138188
return fmt.Errorf("host is required")
@@ -150,6 +200,12 @@ func (c *Config) Validate() error {
150200
if c.DexGRPCClient == nil || c.DexGRPCClient.Addr == "" {
151201
return fmt.Errorf("dexGRPCClient is required when dynamicClientRegistrationEnabled is true")
152202
}
203+
204+
_, err := c.DexGRPCClient.ClientTLSConfig()
205+
if err != nil {
206+
return fmt.Errorf("dexGRPCClient TLS configuration is invalid: %w", err)
207+
}
208+
153209
}
154210

155211
return nil

oauth/dynamic_client_registration.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/hyprmcp/mcp-gateway/config"
1212
"github.com/hyprmcp/mcp-gateway/log"
1313
"google.golang.org/grpc"
14+
"google.golang.org/grpc/credentials"
1415
"google.golang.org/grpc/credentials/insecure"
1516
)
1617

@@ -27,9 +28,22 @@ type ClientInformation struct {
2728
}
2829

2930
func NewDynamicClientRegistrationHandler(config *config.Config, meta map[string]any) (http.Handler, error) {
31+
clientTLSConfig, err := config.DexGRPCClient.ClientTLSConfig()
32+
if err != nil {
33+
return nil, err
34+
}
35+
36+
var creds credentials.TransportCredentials
37+
38+
if clientTLSConfig != nil {
39+
creds = credentials.NewTLS(clientTLSConfig)
40+
} else {
41+
creds = insecure.NewCredentials()
42+
}
43+
3044
grpcClient, err := grpc.NewClient(
3145
config.DexGRPCClient.Addr,
32-
grpc.WithTransportCredentials(insecure.NewCredentials()),
46+
grpc.WithTransportCredentials(creds),
3347
)
3448
if err != nil {
3549
return nil, err

0 commit comments

Comments
 (0)