default_cert.go

 1// Copyright 2023 Google LLC
 2//
 3// Licensed under the Apache License, Version 2.0 (the "License");
 4// you may not use this file except in compliance with the License.
 5// You may obtain a copy of the License at
 6//
 7//      http://www.apache.org/licenses/LICENSE-2.0
 8//
 9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package cert
16
17import (
18	"crypto/tls"
19	"errors"
20	"sync"
21)
22
23// defaultCertData holds all the variables pertaining to
24// the default certificate provider created by [DefaultProvider].
25//
26// A singleton model is used to allow the provider to be reused
27// by the transport layer. As mentioned in [DefaultProvider] (provider nil, nil)
28// may be returned to indicate a default provider could not be found, which
29// will skip extra tls config in the transport layer .
30type defaultCertData struct {
31	once     sync.Once
32	provider Provider
33	err      error
34}
35
36var (
37	defaultCert defaultCertData
38)
39
40// Provider is a function that can be passed into crypto/tls.Config.GetClientCertificate.
41type Provider func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
42
43// errSourceUnavailable is a sentinel error to indicate certificate source is unavailable.
44var errSourceUnavailable = errors.New("certificate source is unavailable")
45
46// DefaultProvider returns a certificate source using the preferred EnterpriseCertificateProxySource.
47// If EnterpriseCertificateProxySource is not available, fall back to the legacy SecureConnectSource.
48//
49// If neither source is available (due to missing configurations), a nil Source and a nil Error are
50// returned to indicate that a default certificate source is unavailable.
51func DefaultProvider() (Provider, error) {
52	defaultCert.once.Do(func() {
53		defaultCert.provider, defaultCert.err = NewWorkloadX509CertProvider("")
54		if errors.Is(defaultCert.err, errSourceUnavailable) {
55			defaultCert.provider, defaultCert.err = NewEnterpriseCertificateProxyProvider("")
56			if errors.Is(defaultCert.err, errSourceUnavailable) {
57				defaultCert.provider, defaultCert.err = NewSecureConnectProvider("")
58				if errors.Is(defaultCert.err, errSourceUnavailable) {
59					defaultCert.provider, defaultCert.err = nil, nil
60				}
61			}
62		}
63	})
64	return defaultCert.provider, defaultCert.err
65}