in traffic_ops/traffic_ops_golang/cdn/dnssecrefresh.go [132:355]
func doDNSSECKeyRefresh(tx *sql.Tx, asyncDB *sqlx.DB, tv trafficvault.TrafficVault, jobID int, user *auth.CurrentUser) {
doCommit := true
defer func() {
if doCommit {
tx.Commit()
} else {
tx.Rollback()
}
}()
defer unsetInDNSSECKeyRefresh()
cdnDNSSECKeyParams, err := getDNSSECKeyRefreshParams(tx)
if err != nil {
log.Errorln("refreshing DNSSEC Keys: getting cdn parameters: " + err.Error())
doCommit = false
if asyncErr := api.UpdateAsyncStatus(asyncDB, api.AsyncFailed, "DNSSEC refresh failed", jobID, true); asyncErr != nil {
log.Errorf("updating async status for id %d: %v", jobID, asyncErr)
}
return
}
cdns := []string{}
for _, inf := range cdnDNSSECKeyParams {
if inf.DNSSECEnabled {
cdns = append(cdns, string(inf.CDNName))
}
}
// TODO change to return a slice, map is slow and unnecessary
dsInfo, err := getDNSSECKeyRefreshDSInfo(tx, cdns)
if err != nil {
log.Errorln("refreshing DNSSEC Keys: getting ds info: " + err.Error())
doCommit = false
if asyncErr := api.UpdateAsyncStatus(asyncDB, api.AsyncFailed, "DNSSEC refresh failed", jobID, true); asyncErr != nil {
log.Errorf("updating async status for id %d: %v", jobID, asyncErr)
}
return
}
dses := []string{}
for ds, _ := range dsInfo {
dses = append(dses, string(ds))
}
dsMatchlists, err := deliveryservice.GetDeliveryServicesMatchLists(dses, tx)
if err != nil {
log.Errorln("refreshing DNSSEC Keys: getting ds matchlists: " + err.Error())
doCommit = false
if asyncErr := api.UpdateAsyncStatus(asyncDB, api.AsyncFailed, "DNSSEC refresh failed", jobID, true); asyncErr != nil {
log.Errorf("updating async status for id %d: %v", jobID, asyncErr)
}
return
}
exampleURLs := map[tc.DeliveryServiceName][]string{}
for ds, inf := range dsInfo {
exampleURLs[ds] = deliveryservice.MakeExampleURLs(inf.Protocol, inf.Type, inf.RoutingName, dsMatchlists[string(ds)], inf.CDNDomain)
}
errCount := 0
updateCount := 0
putErr := false
for _, cdnInf := range cdnDNSSECKeyParams {
keys, ok, err := tv.GetDNSSECKeys(string(cdnInf.CDNName), tx, context.Background()) // TODO get all in a map beforehand
if err != nil {
log.Warnln("refreshing DNSSEC Keys: getting cdn '" + string(cdnInf.CDNName) + "' keys from Traffic Vault, skipping: " + err.Error())
continue
}
if !ok {
log.Warnln("refreshing DNSSEC Keys: cdn '" + string(cdnInf.CDNName) + "' has no keys in Traffic Vault, skipping")
continue
}
ttl := DNSSECKeyRefreshDefaultTTL
if cdnInf.TLDTTLsDNSKEY != nil {
ttl = time.Duration(*cdnInf.TLDTTLsDNSKEY) * time.Second
}
genMultiplier := DNSSECKeyRefreshDefaultGenerationMultiplier
if cdnInf.DNSKEYGenerationMultiplier != nil {
genMultiplier = *cdnInf.DNSKEYGenerationMultiplier
}
effectiveMultiplier := DNSSECKeyRefreshDefaultEffectiveMultiplier
if cdnInf.DNSKEYEffectiveMultiplier != nil {
effectiveMultiplier = *cdnInf.DNSKEYEffectiveMultiplier
}
nowPlusTTL := time.Now().Add(ttl * time.Duration(genMultiplier)) // "key_expiration" in the Perl this was transliterated from
defaultKSKExpiration := DNSSECKeyRefreshDefaultKSKExpiration
for _, key := range keys[string(cdnInf.CDNName)].KSK {
if key.Status != tc.DNSSECKeyStatusNew {
continue
}
defaultKSKExpiration = time.Unix(key.ExpirationDateUnix, 0).Sub(time.Unix(key.InceptionDateUnix, 0))
break
}
defaultZSKExpiration := DNSSECKeyRefreshDefaultZSKExpiration
for _, key := range keys[string(cdnInf.CDNName)].ZSK {
if key.Status != tc.DNSSECKeyStatusNew {
continue
}
expiration := time.Unix(key.ExpirationDateUnix, 0)
inception := time.Unix(key.InceptionDateUnix, 0)
defaultZSKExpiration = expiration.Sub(inception)
if expiration.After(nowPlusTTL) {
continue
}
log.Infoln("The ZSK keys for '" + string(cdnInf.CDNName) + "' are expired! Regenerating them now.")
effectiveDate := expiration.Add(ttl * time.Duration(effectiveMultiplier) * -1) // -1 to subtract
isKSK := false
cdnDNSDomain := cdnInf.CDNDomain + "."
newKeys, err := regenExpiredKeys(isKSK, cdnDNSDomain, keys[string(cdnInf.CDNName)], effectiveDate, false, false)
if err != nil {
log.Errorln("refreshing DNSSEC Keys: regenerating expired ZSK keys: " + err.Error())
errCount++
} else {
keys[string(cdnInf.CDNName)] = newKeys
updateCount++
}
}
for _, ds := range dsInfo {
if ds.CDNName != cdnInf.CDNName {
continue
}
if t := ds.Type; !t.UsesDNSSECKeys() {
continue
}
dsKeys, dsKeysExist := keys[string(ds.DSName)]
if !dsKeysExist {
log.Infoln("Keys do not exist for ds '" + string(ds.DSName) + "'")
cdnKeys, ok := keys[string(ds.CDNName)]
if !ok {
log.Errorln("refreshing DNSSEC Keys: cdn has no keys, cannot create ds keys")
errCount++
continue
}
overrideTTL := false
dsKeys, err := deliveryservice.CreateDNSSECKeys(exampleURLs[ds.DSName], cdnKeys, defaultKSKExpiration, defaultZSKExpiration, ttl, overrideTTL)
if err != nil {
log.Errorln("refreshing DNSSEC Keys: creating missing ds keys: " + err.Error())
errCount++
}
keys[string(ds.DSName)] = dsKeys
updateCount++
continue
}
for _, key := range dsKeys.KSK {
if key.Status != tc.DNSSECKeyStatusNew {
continue
}
expiration := time.Unix(key.ExpirationDateUnix, 0)
if expiration.After(nowPlusTTL) {
continue
}
log.Infoln("The KSK keys for '" + ds.DSName + "' are expired! Regenerating them now.")
effectiveDate := expiration.Add(ttl * time.Duration(effectiveMultiplier) * -1) // -1 to subtract
isKSK := true
newKeys, err := regenExpiredKeys(isKSK, string(ds.DSName), dsKeys, effectiveDate, false, false)
if err != nil {
log.Errorln("refreshing DNSSEC Keys: regenerating expired KSK keys for ds '" + string(ds.DSName) + "': " + err.Error())
errCount++
} else {
keys[string(ds.DSName)] = newKeys
updateCount++
}
}
for _, key := range dsKeys.ZSK {
if key.Status != tc.DNSSECKeyStatusNew {
continue
}
expiration := time.Unix(key.ExpirationDateUnix, 0)
if expiration.After(nowPlusTTL) {
continue
}
log.Infoln("The ZSK keys for '" + ds.DSName + "' are expired! Regenerating them now.")
effectiveDate := expiration.Add(ttl * time.Duration(effectiveMultiplier) * -1) // -1 to subtract
isKSK := false
newKeys, err := regenExpiredKeys(isKSK, string(ds.DSName), dsKeys, effectiveDate, false, false)
if err != nil {
log.Errorln("refreshing DNSSEC Keys: regenerating expired ZSK keys for ds '" + string(ds.DSName) + "': " + err.Error())
errCount++
} else {
if existingNewKeys, ok := keys[string(ds.DSName)]; ok {
existingNewKeys.ZSK = newKeys.ZSK
newKeys = existingNewKeys
}
keys[string(ds.DSName)] = newKeys
updateCount++
}
}
}
if updateCount > 0 {
if err := tv.PutDNSSECKeys(string(cdnInf.CDNName), keys, tx, context.Background()); err != nil {
log.Errorln("refreshing DNSSEC Keys: putting keys into Traffic Vault for cdn '" + string(cdnInf.CDNName) + "': " + err.Error())
putErr = true
}
}
}
clMsg := fmt.Sprintf("Refreshed %d DNSSEC keys", updateCount)
status := api.AsyncSucceeded
msg := fmt.Sprintf("DNSSEC refresh completed successfully (%d keys were updated)", updateCount)
if putErr {
status = api.AsyncFailed
msg = fmt.Sprintf("DNSSEC refresh failed (attempted to update %d keys, but an error occurred while attempting to store in Traffic Vault)", updateCount)
clMsg = fmt.Sprintf("Attempted to refresh %d DNSSEC keys, but an error occurred while attempting to store in Traffic Vault", updateCount)
} else if errCount > 0 {
status = api.AsyncFailed
msg = fmt.Sprintf("DNSSEC refresh failed (updated %d keys, but %d errors occurred)", updateCount, errCount)
clMsg = fmt.Sprintf("Refreshed %d DNSSEC keys, but %d errors occurred", updateCount, errCount)
}
if updateCount > 0 || errCount > 0 || putErr {
api.CreateChangeLogRawTx(api.ApiChange, clMsg, user, tx)
}
if asyncErr := api.UpdateAsyncStatus(asyncDB, status, msg, jobID, true); asyncErr != nil {
log.Errorf("updating async status for id %d: %v", jobID, asyncErr)
}
log.Infoln("Done refreshing DNSSEC keys")
}