Skip to content

Commit

Permalink
feat: refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
fgouteroux committed Jan 16, 2025
1 parent b9cb68c commit 9df0165
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 97 deletions.
57 changes: 42 additions & 15 deletions api_certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func checkAuth(r *http.Request) (certstore.Token, error) {

reqTokenHash := utils.SHA1Hash(token[1])

if tokenExists && reqTokenHash != tokenValue.Hash {
if tokenExists && reqTokenHash != tokenValue.TokenHash {
return tokenValue, fmt.Errorf("Invalid token")
}
return tokenValue, nil
Expand Down Expand Up @@ -407,7 +407,7 @@ func updateCertificateHandler() http.HandlerFunc {
return
}

if certParams.RenewalDays >= certParams.Days {
if certParams.Days != 0 && certParams.RenewalDays >= certParams.Days {
responseJSON(w, nil, fmt.Errorf("'renewal_days' (%d) should be lower than 'days' (%d)", certParams.RenewalDays, certParams.Days), http.StatusBadRequest)
return
}
Expand Down Expand Up @@ -475,27 +475,54 @@ func updateCertificateHandler() http.HandlerFunc {
return
}

err = certstore.DeleteRemoteCertificateResource(certData.Domain, certData.Issuer, certstore.AmStore.Logger)
if err != nil {
responseJSON(w, nil, err, http.StatusInternalServerError)
return
secretKeyPath := fmt.Sprintf("%s/%s/%s", config.GlobalConfig.Storage.Vault.CertPrefix, certData.Issuer, certData.Domain)

var recreateCert bool
if certData.SAN != data[idx].SAN {
recreateCert = true
}
if certData.Days != data[idx].Days {
recreateCert = true
}
if certData.Bundle != data[idx].Bundle {
recreateCert = true
}
if certData.DNSChallenge != data[idx].DNSChallenge {
recreateCert = true
}
if certData.HTTPChallenge != data[idx].HTTPChallenge {
recreateCert = true
}
metrics.DecManagedCertificate(certData.Issuer)

data = slices.Delete(data, idx, idx+1)
if recreateCert {
err = certstore.DeleteRemoteCertificateResource(certData.Domain, certData.Issuer, certstore.AmStore.Logger)
if err != nil {
responseJSON(w, nil, err, http.StatusInternalServerError)
return
}
metrics.DecManagedCertificate(certData.Issuer)

newCert, err := certstore.CreateRemoteCertificateResource(certData, certstore.AmStore.Logger)
if err != nil {
responseJSON(w, nil, err, http.StatusInternalServerError)
return
data = slices.Delete(data, idx, idx+1)

newCert, err := certstore.CreateRemoteCertificateResource(certData, certstore.AmStore.Logger)
if err != nil {
responseJSON(w, nil, err, http.StatusInternalServerError)
return
}
metrics.IncManagedCertificate(certData.Issuer)
data = append(data, newCert)
} else {
data[idx].RenewalDays = certData.RenewalDays
err = vault.GlobalClient.PutSecretWithAppRole(secretKeyPath, utils.StructToMapInterface(data[idx]))
if err != nil {
responseJSON(w, nil, err, http.StatusInternalServerError)
return
}
}
metrics.IncManagedCertificate(certData.Issuer)
data = append(data, newCert)

// udpate kv store
certstore.AmStore.PutKVRing(certstore.AmRingKey, data)

secretKeyPath := fmt.Sprintf("%s/%s/%s", config.GlobalConfig.Storage.Vault.CertPrefix, certData.Issuer, certData.Domain)
secret, err := vault.GlobalClient.GetSecretWithAppRole(secretKeyPath)
if err != nil {
responseJSON(w, nil, err, http.StatusInternalServerError)
Expand Down
16 changes: 8 additions & 8 deletions api_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,10 @@ func createTokenHandler() http.HandlerFunc {
}

data[ID] = certstore.Token{
Hash: tokenHash,
Scope: token.Scope,
Username: token.Username,
Expires: expires,
TokenHash: tokenHash,
Scope: token.Scope,
Username: token.Username,
Expires: expires,
}

// udpate kv store
Expand Down Expand Up @@ -308,10 +308,10 @@ func updateTokenHandler() http.HandlerFunc {
}

data[token.ID] = certstore.Token{
Hash: tokenHash,
Scope: token.Scope,
Username: token.Username,
Expires: expires,
TokenHash: tokenHash,
Scope: token.Scope,
Username: token.Username,
Expires: expires,
}

// udpate kv store
Expand Down
4 changes: 1 addition & 3 deletions certificate/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,9 @@ type Certificate struct {
}

type CertMap struct {
Certificate
Cert string `json:"cert" example:"LS0tLS1CRUdJTiBDR..."`
Key string `json:"key" example:"LS0tLS1CRUdJTiBSU..."`
CAIssuer string `json:"ca_issuer" example:"Ci0tLS0tQkVHSU4gQ0..."`
Issuer string `json:"issuer" example:"letsencrypt"`
URL string `json:"url" example:"https://acme-staging-v02.api.letsencrypt.org/acme/cert/4b63b4e8b6109"`
Domain string `json:"domain" example:"testfgx.example.com"`
Owner string `json:"owner" example:"testfgx"`
}
44 changes: 16 additions & 28 deletions certstore/certstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ type CertStore struct {
}

type Token struct {
Hash string `json:"hash"`
Scope []string `json:"scope"`
Username string `json:"username"`
Expires string `json:"expires"`
TokenHash string `json:"tokenHash"`
Scope []string `json:"scope"`
Username string `json:"username"`
Expires string `json:"expires"`
}

type MapDiff struct {
Expand Down Expand Up @@ -79,9 +79,6 @@ func SaveResource(logger log.Logger, filepath string, certRes *certificate.Resou
}

func kvStore(data cert.Certificate, cert, key []byte) (cert.Certificate, error) {
//Override this key to avoid kvring changes
data.RenewalDays = 0

if len(cert) > 0 {
x509Cert, err := certcrypto.ParsePEMCertificate(cert)
if err != nil {
Expand Down Expand Up @@ -337,17 +334,20 @@ func CreateRemoteCertificateResource(certData cert.Certificate, logger log.Logge
// save in local in case of vault failure
SaveResource(logger, baseCertificateFilePath, resource)

data := &cert.CertMap{
Cert: string(resource.Certificate),
Key: string(resource.PrivateKey),
CAIssuer: string(resource.IssuerCertificate),
Issuer: certData.Issuer,
URL: resource.CertStableURL,
Domain: resource.Domain,
Owner: certData.Owner,
newCert, err = kvStore(certData, resource.Certificate, resource.PrivateKey)
if err != nil {
return newCert, err
}

data := cert.CertMap{
Certificate: newCert,
Cert: string(resource.Certificate),
Key: string(resource.PrivateKey),
CAIssuer: string(resource.IssuerCertificate),
URL: resource.CertStableURL,
}

err = vault.GlobalClient.PutSecretWithAppRole(vaultSecretPath, structToMapInterface(data))
err = vault.GlobalClient.PutSecretWithAppRole(vaultSecretPath, utils.StructToMapInterface(data))
if err != nil {
_ = level.Error(logger).Log("err", err)
return newCert, err
Expand All @@ -358,11 +358,6 @@ func CreateRemoteCertificateResource(certData cert.Certificate, logger log.Logge
_ = level.Error(logger).Log("err", err)
}

newCert, err = kvStore(certData, resource.Certificate, resource.PrivateKey)
if err != nil {
return newCert, err
}

return newCert, nil
}

Expand Down Expand Up @@ -611,13 +606,6 @@ func CheckAPICertExpiration(amStore *CertStore, logger log.Logger) error {
return nil
}

func structToMapInterface(data interface{}) map[string]interface{} {
val, _ := json.Marshal(data)
var result map[string]interface{}
_ = json.Unmarshal(val, &result)
return result
}

func MapInterfaceToCertMap(data map[string]interface{}) cert.CertMap {
val, _ := json.Marshal(data)
var result cert.CertMap
Expand Down
59 changes: 24 additions & 35 deletions certstore/startup.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package certstore

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -84,19 +85,7 @@ func OnStartup(logger log.Logger, configPath string, enableAPI bool) error {
return c.Domain == certData.Domain && c.Issuer == certData.Issuer
})

if idx >= 0 {
c := vaultCertList[idx]
c.Bundle = certData.Bundle
c.SAN = certData.SAN

if certData.Days == 0 {
c.Days = config.GlobalConfig.Common.CertDays
} else {
c.Days = certData.Days
}

content = append(content, c)
} else {
if idx == -1 {
newCert, err := CreateRemoteCertificateResource(certData, logger)
if err != nil {
_ = level.Error(logger).Log("err", err)
Expand Down Expand Up @@ -184,16 +173,6 @@ func getVaultAllCertificate(logger log.Logger) []cert.Certificate {
var vaultCertCount int
for _, secretKey := range vaultSecrets {
secretKeyPath := config.GlobalConfig.Storage.Vault.CertPrefix + "/" + secretKey

secretKeyPathArr := strings.Split(secretKeyPath, "/")
issuer := secretKeyPathArr[len(secretKeyPathArr)-2]
name := secretKeyPathArr[len(secretKeyPathArr)-1]

tmp := cert.Certificate{
Domain: name,
Issuer: issuer,
}

secret, err := vault.GlobalClient.GetSecretWithAppRole(secretKeyPath)
if err != nil {
_ = level.Error(logger).Log("err", err)
Expand All @@ -215,13 +194,17 @@ func getVaultAllCertificate(logger log.Logger) []cert.Certificate {
continue
}

if owner, ok := secret["owner"]; ok {
tmp.Owner = owner.(string)
val, err := json.Marshal(secret)
if err != nil {
_ = level.Error(logger).Log("err", err)
continue
}

vaultCert, err := kvStore(tmp, vaultCertBytes, vaultKeyBytes)
var vaultCert cert.Certificate
err = json.Unmarshal(val, &vaultCert)
if err != nil {
_ = level.Error(logger).Log("err", err)
continue
}

var certBytes, keyBytes []byte
Expand All @@ -248,7 +231,7 @@ func getVaultAllCertificate(logger log.Logger) []cert.Certificate {
}

if config.GlobalConfig.Common.CertDeploy {
currentCert, err := kvStore(tmp, certBytes, keyBytes)
currentCert, err := kvStore(vaultCert, certBytes, keyBytes)
if err != nil {
_ = level.Error(logger).Log("err", err)
}
Expand Down Expand Up @@ -299,7 +282,6 @@ func getVaultAllToken(logger log.Logger) map[string]Token {
secretKeyPath := config.GlobalConfig.Storage.Vault.TokenPrefix + "/" + secretKey

secretKeyPathArr := strings.Split(secretKeyPath, "/")
username := secretKeyPathArr[len(secretKeyPathArr)-2]
ID := secretKeyPathArr[len(secretKeyPathArr)-1]

secret, err := vault.GlobalClient.GetSecretWithAppRole(secretKeyPath)
Expand All @@ -308,15 +290,22 @@ func getVaultAllToken(logger log.Logger) map[string]Token {
continue
}

var scope []string
if secret["scope"] != nil {
for _, item := range secret["scope"].([]interface{}) {
scope = append(scope, item.(string))
}
val, err := json.Marshal(secret)
if err != nil {
_ = level.Error(logger).Log("err", err)
continue
}

tokenMap[ID] = Token{Hash: secret["tokenHash"].(string), Scope: scope, Username: username, Expires: secret["expires"].(string)}
vaultTokenCount++
var token Token
err = json.Unmarshal(val, &token)
if err != nil {
_ = level.Error(logger).Log("err", err)
continue
}

tokenMap[ID] = token
vaultTokenCount++

}
_ = level.Info(logger).Log("msg", fmt.Sprintf("Found %d tokens from vault", vaultTokenCount))
} else {
Expand Down
37 changes: 32 additions & 5 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ var (
)

func CheckAndDeployLocalCertificate(logger log.Logger, acmeClient *restclient.Client) {
if !certConfig.Common.CertDeploy {
return
}

certificates, err := acmeClient.GetAllCertificateMetadata()
if err != nil {
_ = level.Error(logger).Log("err", err)
Expand Down Expand Up @@ -175,7 +179,7 @@ func applyCertFileChanges(acmeClient *restclient.Client, diff certstore.MapDiff,
_ = level.Info(logger).Log("msg", fmt.Sprintf("certificate '%s' deleted", certData.Domain))
metrics.DecManagedCertificate(certData.Issuer)
if certConfig.Common.CertDeploy {
deleteLocalCertificateResource(cert.CertMap{Issuer: certData.Issuer, Domain: certData.Domain}, logger)
deleteLocalCertificateResource(cert.CertMap{Certificate: certData}, logger)
}
}

Expand Down Expand Up @@ -274,11 +278,16 @@ func CheckCertificate(logger log.Logger, configPath string, acmeClient *restclie
if idx == -1 {
newCertList = append(newCertList, certData)
} else {

// Ignoring this field
certData.RenewalDays = 0

var toUpdate bool
if certData.RenewalDays != old[idx].RenewalDays {
toUpdate = true
_ = level.Info(logger).Log("msg", fmt.Sprintf(
"Certificate '%s' renewal_days changed from '%d' to '%d'.",
certData.Domain,
old[idx].RenewalDays,
certData.RenewalDays,
))
}
if certData.SAN != old[idx].SAN {
toUpdate = true
_ = level.Info(logger).Log("msg", fmt.Sprintf(
Expand Down Expand Up @@ -306,6 +315,24 @@ func CheckCertificate(logger log.Logger, configPath string, acmeClient *restclie
certData.Bundle,
))
}
if certData.DNSChallenge != old[idx].DNSChallenge {
toUpdate = true
_ = level.Info(logger).Log("msg", fmt.Sprintf(
"Certificate '%s' dns_challenge changed from '%s' to '%s'.",
certData.Domain,
old[idx].DNSChallenge,
certData.DNSChallenge,
))
}
if certData.HTTPChallenge != old[idx].HTTPChallenge {
toUpdate = true
_ = level.Info(logger).Log("msg", fmt.Sprintf(
"Certificate '%s' http_challenge changed from '%s' to '%s'.",
certData.Domain,
old[idx].HTTPChallenge,
certData.HTTPChallenge,
))
}

if toUpdate {
newCertList = append(newCertList, certData)
Expand Down
Loading

0 comments on commit 9df0165

Please sign in to comment.