pomerium/config/autocert.go
Caleb Doxsey a2fd95aae6
core/ci: update linting (#4844)
* core/ci: update linting

* re-add exportloopref

* re-add gocheckcompilerdirectives

* re-add stylecheck

* re-add usestdlibvars

* upgrade lint

---------

Co-authored-by: Denis Mishin <dmishin@pomerium.com>
2023-12-14 09:07:54 -08:00

97 lines
4.1 KiB
Go

package config
import (
"encoding/base64"
"errors"
"fmt"
"os"
"github.com/pomerium/pomerium/pkg/cryptutil"
)
// AutocertOptions contains the options to control the behavior of autocert.
type AutocertOptions struct {
// Enable enables fully automated certificate management including issuance
// and renewal from LetsEncrypt. Must be used in conjunction with Folder.
Enable bool `mapstructure:"autocert" yaml:"autocert,omitempty"`
// CA is the directory URL of a CA supporting the ACME protocol to request
// certificates from. This can be used to use an alternative CA than
// Let's Encrypt. This setting overrules the UseStaging setting.
CA string `mapstructure:"autocert_ca" yaml:"autocert_ca,omitempty"`
// Email is the email address to use for account registration with the ACME CA.
Email string `mapstructure:"autocert_email" yaml:"autocert_email,omitempty"`
// UseStaging tells autocert to use Let's Encrypt's staging CA which
// has less strict usage limits then the (default) production CA.
//
// https://letsencrypt.org/docs/staging-environment/
UseStaging bool `mapstructure:"autocert_use_staging" yaml:"autocert_use_staging,omitempty"`
// EABKeyID is an ASCII string identifier for the External Account Binding
// key that must be used to request a new account with an ACME CA supporting
// External Account Binding.
EABKeyID string `mapstructure:"autocert_eab_key_id" yaml:"autocert_eab_key_id,omitempty"`
// EABMACKey is a base64url-encoded secret key corresponding to the EABKeyID to use
// when creating a new account with an ACME CA supporting External Account Binding.
EABMACKey string `mapstructure:"autocert_eab_mac_key" yaml:"autocert_eab_mac_key,omitempty"`
// MustStaple will cause autocert to request a certificate with
// status_request extension. This will allow the TLS client (the browser)
// to fail immediately if Pomerium failed to get an OCSP staple.
// See also https://tools.ietf.org/html/rfc7633
// Only used when Enable is true.
MustStaple bool `mapstructure:"autocert_must_staple" yaml:"autocert_must_staple,omitempty"`
// Folder specifies the location to store, and load autocert managed
// TLS certificates.
// defaults to $XDG_DATA_HOME/pomerium
Folder string `mapstructure:"autocert_dir" yaml:"autocert_dir,omitempty"`
// TrustedCA is the base64-encoded certificate (bundle) to trust when communicating with an ACME CA.
TrustedCA string `mapstructure:"autocert_trusted_ca" yaml:"autocert_trusted_ca,omitempty"`
// TrustedCAFile points to a file that contains the certificate (bundle) to trust when communicating with an ACME CA.
TrustedCAFile string `mapstructure:"autocert_trusted_ca_file" yaml:"autocert_trusted_ca_file,omitempty"`
}
// Validate ensures the Options fields are valid, and hydrated.
func (o *AutocertOptions) Validate() error {
// validate ACME EAB settings
if o.EABKeyID != "" && o.EABMACKey == "" {
return errors.New("config: Autocert EAB MAC Key required when Key ID is provided")
}
if o.EABKeyID == "" && o.EABMACKey != "" {
return errors.New("config: Autocert EAB Key ID required when MAC Key is provided")
}
if o.EABMACKey != "" {
if _, err := base64.RawURLEncoding.DecodeString(o.EABMACKey); err != nil {
return fmt.Errorf("config: decoding base64-urlencoded MAC Key: %w", err)
}
}
// validate x509 roots to trust
if o.TrustedCA != "" && o.TrustedCAFile != "" {
return errors.New("config: providing both Autocert Trusted CA and Trusted CA File is not supported")
}
if o.TrustedCA != "" {
if _, err := base64.StdEncoding.DecodeString(o.TrustedCA); err != nil {
return fmt.Errorf("config: decoding trusted certificate pool base64: %w", err)
}
if _, err := cryptutil.GetCertPool(o.TrustedCA, ""); err != nil {
return fmt.Errorf("config: getting trusted certificate pool: %w", err)
}
}
if o.TrustedCAFile != "" {
if _, err := os.ReadFile(o.TrustedCAFile); err != nil {
return fmt.Errorf("config: bad trusted certificate (bundle) file: %w", err)
}
if _, err := cryptutil.GetCertPool("", o.TrustedCAFile); err != nil {
return fmt.Errorf("config: getting trusted certificate pool: %w", err)
}
}
return nil
}