1package lego 2 3import ( 4 "crypto/tls" 5 "crypto/x509" 6 "fmt" 7 "net" 8 "net/http" 9 "os" 10 "time" 11 12 "github.com/go-acme/lego/v4/certcrypto" 13 "github.com/go-acme/lego/v4/registration" 14) 15 16const ( 17 // caCertificatesEnvVar is the environment variable name that can be used to 18 // specify the path to PEM encoded CA Certificates that can be used to 19 // authenticate an ACME server with a HTTPS certificate not issued by a CA in 20 // the system-wide trusted root list. 21 caCertificatesEnvVar = "LEGO_CA_CERTIFICATES" 22 23 // caServerNameEnvVar is the environment variable name that can be used to 24 // specify the CA server name that can be used to 25 // authenticate an ACME server with a HTTPS certificate not issued by a CA in 26 // the system-wide trusted root list. 27 caServerNameEnvVar = "LEGO_CA_SERVER_NAME" 28 29 // LEDirectoryProduction URL to the Let's Encrypt production. 30 LEDirectoryProduction = "https://acme-v02.api.letsencrypt.org/directory" 31 32 // LEDirectoryStaging URL to the Let's Encrypt staging. 33 LEDirectoryStaging = "https://acme-staging-v02.api.letsencrypt.org/directory" 34) 35 36type Config struct { 37 CADirURL string 38 User registration.User 39 UserAgent string 40 HTTPClient *http.Client 41 Certificate CertificateConfig 42} 43 44func NewConfig(user registration.User) *Config { 45 return &Config{ 46 CADirURL: LEDirectoryProduction, 47 User: user, 48 HTTPClient: createDefaultHTTPClient(), 49 Certificate: CertificateConfig{ 50 KeyType: certcrypto.RSA2048, 51 Timeout: 30 * time.Second, 52 }, 53 } 54} 55 56type CertificateConfig struct { 57 KeyType certcrypto.KeyType 58 Timeout time.Duration 59} 60 61// createDefaultHTTPClient Creates an HTTP client with a reasonable timeout value 62// and potentially a custom *x509.CertPool 63// based on the caCertificatesEnvVar environment variable (see the `initCertPool` function). 64func createDefaultHTTPClient() *http.Client { 65 return &http.Client{ 66 Timeout: 2 * time.Minute, 67 Transport: &http.Transport{ 68 Proxy: http.ProxyFromEnvironment, 69 DialContext: (&net.Dialer{ 70 Timeout: 30 * time.Second, 71 KeepAlive: 30 * time.Second, 72 }).DialContext, 73 TLSHandshakeTimeout: 30 * time.Second, 74 ResponseHeaderTimeout: 30 * time.Second, 75 TLSClientConfig: &tls.Config{ 76 ServerName: os.Getenv(caServerNameEnvVar), 77 RootCAs: initCertPool(), 78 }, 79 }, 80 } 81} 82 83// initCertPool creates a *x509.CertPool populated with the PEM certificates 84// found in the filepath specified in the caCertificatesEnvVar OS environment 85// variable. If the caCertificatesEnvVar is not set then initCertPool will 86// return nil. If there is an error creating a *x509.CertPool from the provided 87// caCertificatesEnvVar value then initCertPool will panic. 88func initCertPool() *x509.CertPool { 89 if customCACertsPath := os.Getenv(caCertificatesEnvVar); customCACertsPath != "" { 90 customCAs, err := os.ReadFile(customCACertsPath) 91 if err != nil { 92 panic(fmt.Sprintf("error reading %s=%q: %v", 93 caCertificatesEnvVar, customCACertsPath, err)) 94 } 95 certPool := x509.NewCertPool() 96 if ok := certPool.AppendCertsFromPEM(customCAs); !ok { 97 panic(fmt.Sprintf("error creating x509 cert pool from %s=%q: %v", 98 caCertificatesEnvVar, customCACertsPath, err)) 99 } 100 return certPool 101 } 102 return nil 103} 104