Files
authentik/internal/outpost/ak/crypto.go
Marc 'risson' Schmitt 2f70351c90 packages/client-go: init (#21139)
* packages/client-go: init

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>

* format

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* remove mod/sum

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix translate

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* no go replace

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* update rust makefile with pwd

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>

* fix build

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix docs

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* don't need a version ig?

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* exclude go client from cspell

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix main docker build

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2026-03-25 15:26:50 +01:00

109 lines
2.6 KiB
Go

package ak
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/pem"
log "github.com/sirupsen/logrus"
api "goauthentik.io/packages/client-go"
)
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 {
// Check if the cached fingerprint matches the certificate,
// if not, we re-fetch it
if sfp, ok := cs.fingerprints[uuid]; ok {
fp := cs.getFingerprint(uuid)
if sfp == fp {
return nil
}
}
// reset fingerprint to force update
cs.fingerprints[uuid] = ""
err := cs.Fetch(uuid)
if err != nil {
return err
}
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.GetFingerprintSha256()
}
func (cs *CryptoStore) Fetch(uuid string) error {
cfp := cs.getFingerprint(uuid)
if cfp == cs.fingerprints[uuid] {
cs.log.WithField("uuid", uuid).Debug("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
}
var tcert tls.Certificate
if key.Data != "" {
x509cert, err := tls.X509KeyPair([]byte(cert.Data), []byte(key.Data))
if err != nil {
return err
}
tcert = x509cert
} else {
p, _ := pem.Decode([]byte(cert.Data))
x509cert, err := x509.ParseCertificate(p.Bytes)
if err != nil {
return err
}
tcert = tls.Certificate{
Certificate: [][]byte{x509cert.Raw},
Leaf: x509cert,
}
}
cs.certificates[uuid] = &tcert
cs.fingerprints[uuid] = cfp
return nil
}
func (cs *CryptoStore) Get(uuid string) *tls.Certificate {
c, ok := cs.certificates[uuid]
if ok {
return c
}
err := cs.Fetch(uuid)
if err != nil {
cs.log.WithError(err).Warning("failed to fetch certificate")
}
return cs.certificates[uuid]
}