70 lines
2.1 KiB
Go
70 lines
2.1 KiB
Go
package requests
|
|
|
|
import (
|
|
"crypto/x509"
|
|
"sync/atomic"
|
|
|
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util"
|
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/watcher"
|
|
)
|
|
|
|
// DynamicCALoader provides hot-reloadable CA certificates.
|
|
// It caches the certificate pool and reloads from disk when triggered
|
|
// by file system events via the watcher.
|
|
type DynamicCALoader struct {
|
|
caFiles []string
|
|
useSystemTrustStore bool
|
|
certPool atomic.Pointer[x509.CertPool]
|
|
}
|
|
|
|
// NewDynamicCALoader creates a new DynamicCALoader that loads CA certificates
|
|
// from the specified files. The certificates are reloaded automatically when
|
|
// files change on disk.
|
|
func NewDynamicCALoader(caFiles []string, useSystemTrustStore bool) (*DynamicCALoader, error) {
|
|
d := &DynamicCALoader{
|
|
caFiles: caFiles,
|
|
useSystemTrustStore: useSystemTrustStore,
|
|
}
|
|
if err := d.reload(); err != nil {
|
|
return nil, err
|
|
}
|
|
return d, nil
|
|
}
|
|
|
|
// GetCertPool returns the current CA certificate pool.
|
|
func (d *DynamicCALoader) GetCertPool() (*x509.CertPool, error) {
|
|
return d.certPool.Load(), nil
|
|
}
|
|
|
|
// reload loads CA certificates from disk and updates the cached pool.
|
|
func (d *DynamicCALoader) reload() error {
|
|
pool, err := util.GetCertPool(d.caFiles, d.useSystemTrustStore)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d.certPool.Store(pool)
|
|
logger.Printf("CA certificates reloaded from %v", d.caFiles)
|
|
return nil
|
|
}
|
|
|
|
// ForceReload forces immediate reload of CA certificates.
|
|
// This is called by file watcher when CA files change on disk.
|
|
func (d *DynamicCALoader) ForceReload() {
|
|
if err := d.reload(); err != nil {
|
|
logger.Errorf("CA reload failed: %v", err)
|
|
}
|
|
}
|
|
|
|
// StartWatching sets up file watchers for all CA files.
|
|
// When any CA file changes, the certificates are automatically reloaded.
|
|
// This supports Kubernetes ConfigMap/Secret mounts which use symlink replacement.
|
|
func (d *DynamicCALoader) StartWatching(done <-chan bool) error {
|
|
for _, caFile := range d.caFiles {
|
|
if err := watcher.WatchFileForUpdates(caFile, done, d.ForceReload); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|