Skip to content

Commit c58ee77

Browse files
authored
Merge pull request moby#3760 from jedevc/with-credentials-system-certs
Add client opts to enable system certificates
2 parents 0a8e5cf + 8f66706 commit c58ee77

File tree

2 files changed

+106
-36
lines changed

2 files changed

+106
-36
lines changed

client/client.go

Lines changed: 101 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error
4545
grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)),
4646
}
4747
needDialer := true
48-
needWithInsecure := true
49-
tlsServerName := ""
5048

5149
var unary []grpc.UnaryClientInterceptor
5250
var stream []grpc.StreamClientInterceptor
@@ -56,19 +54,17 @@ func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error
5654
var tracerDelegate TracerDelegate
5755
var sessionDialer func(context.Context, string, map[string][]string) (net.Conn, error)
5856
var customDialOptions []grpc.DialOption
57+
var creds *withCredentials
5958

6059
for _, o := range opts {
6160
if _, ok := o.(*withFailFast); ok {
6261
gopts = append(gopts, grpc.FailOnNonTempDialError(true))
6362
}
6463
if credInfo, ok := o.(*withCredentials); ok {
65-
opt, err := loadCredentials(credInfo)
66-
if err != nil {
67-
return nil, err
64+
if creds == nil {
65+
creds = &withCredentials{}
6866
}
69-
gopts = append(gopts, opt)
70-
needWithInsecure = false
71-
tlsServerName = credInfo.ServerName
67+
creds = creds.merge(credInfo)
7268
}
7369
if wt, ok := o.(*withTracer); ok {
7470
customTracer = true
@@ -89,6 +85,16 @@ func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error
8985
}
9086
}
9187

88+
if creds == nil {
89+
gopts = append(gopts, grpc.WithTransportCredentials(insecure.NewCredentials()))
90+
} else {
91+
credOpts, err := loadCredentials(creds)
92+
if err != nil {
93+
return nil, err
94+
}
95+
gopts = append(gopts, credOpts)
96+
}
97+
9298
if !customTracer {
9399
if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() {
94100
tracerProvider = span.TracerProvider()
@@ -108,9 +114,6 @@ func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error
108114
}
109115
gopts = append(gopts, grpc.WithContextDialer(dialFn))
110116
}
111-
if needWithInsecure {
112-
gopts = append(gopts, grpc.WithTransportCredentials(insecure.NewCredentials()))
113-
}
114117
if address == "" {
115118
address = appdefaults.Address
116119
}
@@ -122,7 +125,10 @@ func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error
122125
// ref: https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.3
123126
// - However, when TLS specified, grpc-go requires it must match
124127
// with its servername specified for certificate validation.
125-
authority := tlsServerName
128+
var authority string
129+
if creds != nil && creds.serverName != "" {
130+
authority = creds.serverName
131+
}
126132
if authority == "" {
127133
// authority as hostname from target address
128134
uri, err := url.Parse(address)
@@ -201,47 +207,108 @@ func WithContextDialer(df func(context.Context, string) (net.Conn, error)) Clien
201207
}
202208

203209
type withCredentials struct {
204-
ServerName string
205-
CACert string
206-
Cert string
207-
Key string
210+
// server options
211+
serverName string
212+
caCert string
213+
caCertSystem bool
214+
215+
// client options
216+
cert string
217+
key string
218+
}
219+
220+
func (opts *withCredentials) merge(opts2 *withCredentials) *withCredentials {
221+
result := *opts
222+
if opts2 == nil {
223+
return &result
224+
}
225+
226+
// server options
227+
if opts2.serverName != "" {
228+
result.serverName = opts2.serverName
229+
}
230+
if opts2.caCert != "" {
231+
result.caCert = opts2.caCert
232+
}
233+
if opts2.caCertSystem {
234+
result.caCertSystem = opts2.caCertSystem
235+
}
236+
237+
// client options
238+
if opts2.cert != "" {
239+
result.cert = opts2.cert
240+
}
241+
if opts2.key != "" {
242+
result.key = opts2.key
243+
}
244+
245+
return &result
208246
}
209247

210248
func (*withCredentials) isClientOpt() {}
211249

212250
// WithCredentials configures the TLS parameters of the client.
213251
// Arguments:
214-
// * serverName: specifies the name of the target server
215-
// * ca: specifies the filepath of the CA certificate to use for verification
216-
// * cert: specifies the filepath of the client certificate
217-
// * key: specifies the filepath of the client key
218-
func WithCredentials(serverName, ca, cert, key string) ClientOpt {
219-
return &withCredentials{serverName, ca, cert, key}
252+
// * cert: specifies the filepath of the client certificate
253+
// * key: specifies the filepath of the client key
254+
func WithCredentials(cert, key string) ClientOpt {
255+
return &withCredentials{
256+
cert: cert,
257+
key: key,
258+
}
259+
}
260+
261+
// WithServerConfig configures the TLS parameters to connect to the server.
262+
// Arguments:
263+
// * serverName: specifies the server name to verify the hostname
264+
// * caCert: specifies the filepath of the CA certificate
265+
func WithServerConfig(serverName, caCert string) ClientOpt {
266+
return &withCredentials{
267+
serverName: serverName,
268+
caCert: caCert,
269+
}
270+
}
271+
272+
// WithServerConfigSystem configures the TLS parameters to connect to the
273+
// server, using the system's certificate pool.
274+
func WithServerConfigSystem(serverName string) ClientOpt {
275+
return &withCredentials{
276+
serverName: serverName,
277+
caCertSystem: true,
278+
}
220279
}
221280

222281
func loadCredentials(opts *withCredentials) (grpc.DialOption, error) {
223-
ca, err := os.ReadFile(opts.CACert)
224-
if err != nil {
225-
return nil, errors.Wrap(err, "could not read ca certificate")
282+
cfg := &tls.Config{}
283+
284+
if opts.caCertSystem {
285+
cfg.RootCAs, _ = x509.SystemCertPool()
286+
}
287+
if cfg.RootCAs == nil {
288+
cfg.RootCAs = x509.NewCertPool()
226289
}
227290

228-
certPool := x509.NewCertPool()
229-
if ok := certPool.AppendCertsFromPEM(ca); !ok {
230-
return nil, errors.New("failed to append ca certs")
291+
if opts.caCert != "" {
292+
ca, err := os.ReadFile(opts.caCert)
293+
if err != nil {
294+
return nil, errors.Wrap(err, "could not read ca certificate")
295+
}
296+
if ok := cfg.RootCAs.AppendCertsFromPEM(ca); !ok {
297+
return nil, errors.New("failed to append ca certs")
298+
}
231299
}
232300

233-
cfg := &tls.Config{
234-
ServerName: opts.ServerName,
235-
RootCAs: certPool,
301+
if opts.serverName != "" {
302+
cfg.ServerName = opts.serverName
236303
}
237304

238305
// we will produce an error if the user forgot about either cert or key if at least one is specified
239-
if opts.Cert != "" || opts.Key != "" {
240-
cert, err := tls.LoadX509KeyPair(opts.Cert, opts.Key)
306+
if opts.cert != "" || opts.key != "" {
307+
cert, err := tls.LoadX509KeyPair(opts.cert, opts.key)
241308
if err != nil {
242309
return nil, errors.Wrap(err, "could not read certificate/key")
243310
}
244-
cfg.Certificates = []tls.Certificate{cert}
311+
cfg.Certificates = append(cfg.Certificates, cert)
245312
}
246313

247314
return grpc.WithTransportCredentials(credentials.NewTLS(cfg)), nil

cmd/buildctl/common/common.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,11 @@ func ResolveClient(c *cli.Context) (*client.Client, error) {
8282
}
8383
}
8484

85-
if caCert != "" || cert != "" || key != "" {
86-
opts = append(opts, client.WithCredentials(serverName, caCert, cert, key))
85+
if caCert != "" {
86+
opts = append(opts, client.WithServerConfig(serverName, caCert))
87+
}
88+
if cert != "" || key != "" {
89+
opts = append(opts, client.WithCredentials(cert, key))
8790
}
8891

8992
timeout := time.Duration(c.GlobalInt("timeout"))

0 commit comments

Comments
 (0)