outposts: save certificate fingerprint and check before re-fetching to cleanup logs

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-07-21 23:53:43 +02:00
parent a3abbcec6a
commit 253f345fc4
6 changed files with 97 additions and 35 deletions

View File

@ -0,0 +1,85 @@
package ak
import (
"context"
"crypto/tls"
log "github.com/sirupsen/logrus"
"goauthentik.io/api"
)
type CryptoStore struct {
api *api.CryptoApiService
log *log.Entry
fingerprints map[string]string
certificates map[string]*tls.Certificate
}
func NewCryptoStore(cryptoApi *api.CryptoApiService) *CryptoStore {
return &CryptoStore{
api: cryptoApi,
log: log.WithField("logger", "authentik.outpost.cryptostore"),
fingerprints: make(map[string]string),
certificates: make(map[string]*tls.Certificate),
}
}
func (cs *CryptoStore) AddKeypair(uuid string) error {
// If they keypair was already added, don't
// do it again
if _, ok := cs.fingerprints[uuid]; ok {
return nil
}
// reset fingerprint to force update
cs.fingerprints[uuid] = ""
err := cs.Fetch(uuid)
if err != nil {
return err
}
cs.fingerprints[uuid] = cs.getFingerprint(uuid)
return nil
}
func (cs *CryptoStore) getFingerprint(uuid string) string {
kp, _, err := cs.api.CryptoCertificatekeypairsRetrieve(context.Background(), uuid).Execute()
if err != nil {
cs.log.WithField("uuid", uuid).WithError(err).Warning("Failed to fetch certificate's fingerprint")
return ""
}
return kp.FingerprintSha256
}
func (cs *CryptoStore) Fetch(uuid string) error {
cfp := cs.getFingerprint(uuid)
if cfp == cs.fingerprints[uuid] {
cs.log.WithField("uuid", uuid).Info("Fingerprint hasn't changed, not fetching cert")
return nil
}
cs.log.WithField("uuid", uuid).Info("Fetching certificate and private key")
cert, _, err := cs.api.CryptoCertificatekeypairsViewCertificateRetrieve(context.Background(), uuid).Execute()
if err != nil {
return err
}
key, _, err := cs.api.CryptoCertificatekeypairsViewPrivateKeyRetrieve(context.Background(), uuid).Execute()
if err != nil {
return err
}
x509cert, err := tls.X509KeyPair([]byte(cert.Data), []byte(key.Data))
if err != nil {
return err
}
cs.certificates[uuid] = &x509cert
return nil
}
func (cs *CryptoStore) Get(uuid string) *tls.Certificate {
err := cs.Fetch(uuid)
if err != nil {
cs.log.WithError(err).Warning("failed to fetch certificate")
}
return cs.certificates[uuid]
}

View File

@ -1,8 +1,6 @@
package ak package ak
import ( import (
"context"
"crypto/tls"
"net/http" "net/http"
"os" "os"
"strings" "strings"
@ -11,7 +9,6 @@ import (
"github.com/getsentry/sentry-go" "github.com/getsentry/sentry-go"
httptransport "github.com/go-openapi/runtime/client" httptransport "github.com/go-openapi/runtime/client"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"goauthentik.io/api"
"goauthentik.io/internal/constants" "goauthentik.io/internal/constants"
) )
@ -69,21 +66,3 @@ func GetTLSTransport() http.RoundTripper {
} }
return tlsTransport return tlsTransport
} }
// ParseCertificate Load certificate from Keyepair UUID and parse it into a go Certificate
func ParseCertificate(kpUuid string, cryptoApi *api.CryptoApiService) (*tls.Certificate, error) {
cert, _, err := cryptoApi.CryptoCertificatekeypairsViewCertificateRetrieve(context.Background(), kpUuid).Execute()
if err != nil {
return nil, err
}
key, _, err := cryptoApi.CryptoCertificatekeypairsViewPrivateKeyRetrieve(context.Background(), kpUuid).Execute()
if err != nil {
return nil, err
}
x509cert, err := tls.X509KeyPair([]byte(cert.Data), []byte(key.Data))
if err != nil {
return nil, err
}
return &x509cert, nil
}

View File

@ -13,7 +13,6 @@ import (
"github.com/go-openapi/strfmt" "github.com/go-openapi/strfmt"
"github.com/pires/go-proxyproto" "github.com/pires/go-proxyproto"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"goauthentik.io/internal/outpost/ak"
) )
func (ls *LDAPServer) Refresh() error { func (ls *LDAPServer) Refresh() error {
@ -45,14 +44,12 @@ func (ls *LDAPServer) Refresh() error {
gidStartNumber: *provider.GidStartNumber, gidStartNumber: *provider.GidStartNumber,
} }
if provider.Certificate.Get() != nil { if provider.Certificate.Get() != nil {
logger.WithField("provider", provider.Name).Debug("Enabling TLS") kp := provider.Certificate.Get()
cert, err := ak.ParseCertificate(*provider.Certificate.Get(), ls.ac.Client.CryptoApi) err := ls.cs.AddKeypair(*kp)
if err != nil { if err != nil {
logger.WithField("provider", provider.Name).WithError(err).Warning("Failed to fetch certificate") ls.log.WithError(err).Warning("Failed to initially fetch certificate")
} else {
providers[idx].cert = cert
logger.WithField("provider", provider.Name).Debug("Loaded certificates")
} }
providers[idx].cert = ls.cs.Get(*kp)
} }
} }
ls.providers = providers ls.providers = providers

View File

@ -47,6 +47,7 @@ type LDAPServer struct {
s *ldap.Server s *ldap.Server
log *log.Entry log *log.Entry
ac *ak.APIController ac *ak.APIController
cs *ak.CryptoStore
defaultCert *tls.Certificate defaultCert *tls.Certificate
providers []*ProviderInstance providers []*ProviderInstance
} }
@ -69,6 +70,7 @@ func NewServer(ac *ak.APIController) *LDAPServer {
s: s, s: s,
log: log.WithField("logger", "authentik.outpost.ldap"), log: log.WithField("logger", "authentik.outpost.ldap"),
ac: ac, ac: ac,
cs: ak.NewCryptoStore(ac.Client.CryptoApi),
providers: []*ProviderInstance{}, providers: []*ProviderInstance{},
} }
defaultCert, err := crypto.GenerateSelfSignedCert() defaultCert, err := crypto.GenerateSelfSignedCert()

View File

@ -15,7 +15,6 @@ import (
"github.com/oauth2-proxy/oauth2-proxy/pkg/validation" "github.com/oauth2-proxy/oauth2-proxy/pkg/validation"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"goauthentik.io/api" "goauthentik.io/api"
"goauthentik.io/internal/outpost/ak"
) )
type providerBundle struct { type providerBundle struct {
@ -89,14 +88,12 @@ func (pb *providerBundle) prepareOpts(provider api.ProxyOutpostConfig) *options.
} }
if provider.Certificate.Get() != nil { if provider.Certificate.Get() != nil {
pb.log.WithField("provider", provider.Name).Debug("Enabling TLS") kp := provider.Certificate.Get()
cert, err := ak.ParseCertificate(*provider.Certificate.Get(), pb.s.ak.Client.CryptoApi) err := pb.s.cs.AddKeypair(*kp)
if err != nil { if err != nil {
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to fetch certificate") pb.log.WithError(err).Warning("Failed to initially fetch certificate")
return providerOpts
} }
pb.cert = cert pb.cert = pb.s.cs.Get(*kp)
pb.log.WithField("provider", provider.Name).Debug("Loaded certificates")
} }
return providerOpts return providerOpts
} }

View File

@ -21,6 +21,7 @@ type Server struct {
stop chan struct{} // channel for waiting shutdown stop chan struct{} // channel for waiting shutdown
logger *log.Entry logger *log.Entry
ak *ak.APIController ak *ak.APIController
cs *ak.CryptoStore
defaultCert tls.Certificate defaultCert tls.Certificate
} }
@ -35,6 +36,7 @@ func NewServer(ac *ak.APIController) *Server {
logger: log.WithField("logger", "authentik.outpost.proxy-http-server"), logger: log.WithField("logger", "authentik.outpost.proxy-http-server"),
defaultCert: defaultCert, defaultCert: defaultCert,
ak: ac, ak: ac,
cs: ak.NewCryptoStore(ac.Client.CryptoApi),
} }
} }