Skip to content

Commit fbf726b

Browse files
committed
Update legacy certificates in storage with expiration date
af15771 and 3b0038d added the field "expiry" to the certificate, which speeds up the renewal check considerably for certificates that have this information set. For existing ones that don't, use the most recent backup timestamp to establish the expiration date, and add this information to storage, so that future renewal jobs are faster for those as well. This is in preparation for the following patch in the series, which uses the "expiry" field to purge certificates where renewal has failed repeatedly.
1 parent e7d7c39 commit fbf726b

File tree

3 files changed

+78
-8
lines changed

3 files changed

+78
-8
lines changed

lib/resty/auto-ssl/jobs/renewal.lua

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,43 @@ local function renew_check_cert(auto_ssl_instance, storage, domain)
7979
cert = {}
8080
end
8181

82-
-- Attempt to retrieve expiry date from storage. If it is not found try renewal.
83-
-- If expiry date is found, we attempt renewal if it's within 30 days.
82+
if not cert["fullchain_pem"] then
83+
ngx.log(ngx.ERR, "auto-ssl: attempting to renew certificate for domain without certificates in storage: ", domain)
84+
renew_check_cert_unlock(domain, storage, local_lock, distributed_lock_value)
85+
return
86+
end
87+
88+
-- If we don't have an expiry date yet, try to update the stored cert
89+
-- with a date based on backup timestamps
90+
if not cert["expiry"] then
91+
local keys, err = storage.adapter:keys_with_prefix(domain .. ":")
92+
if err then
93+
ngx.log(ngx.ERR, "auto-ssl: error fetching certificate backups from storage for ", domain, ": ", err)
94+
else
95+
local most_recent = 0
96+
for _, key in ipairs(keys) do
97+
local timestamp = string.sub(key, string.find(key, ":") + 1)
98+
timestamp = tonumber(timestamp)
99+
if timestamp and most_recent < timestamp then
100+
most_recent = timestamp
101+
end
102+
end
103+
if most_recent ~= 0 then
104+
-- Backup timestamp used milliseconds, convert to seconds
105+
cert["expiry"] = math.floor(most_recent/1000) + (90 * 24 * 60 * 60)
106+
-- Update stored certificate to include expiry information
107+
ngx.log(ngx.NOTICE, "auto-ssl: setting expiration date of ", domain, " to ", cert["expiry"])
108+
local _, err = storage:set_cert(domain, cert["fullchain_pem"], cert["privkey_pem"], cert["cert_pem"], cert["expiry"])
109+
if err then
110+
ngx.log(ngx.ERR, "auto-ssl: failed to update cert: ", err)
111+
end
112+
else
113+
ngx.log(ngx.ERR, "auto-ssl: no certificate backups in storage for ", domain, ", unable to set expiration date")
114+
end
115+
end
116+
end
117+
118+
-- If expiry date is known, attempt renewal if it's within 30 days.
84119
if cert["expiry"] then
85120
local now = ngx.now()
86121
if now + (30 * 24 * 60 * 60) < cert["expiry"] then
@@ -90,12 +125,6 @@ local function renew_check_cert(auto_ssl_instance, storage, domain)
90125
end
91126
end
92127

93-
if not cert["fullchain_pem"] then
94-
ngx.log(ngx.ERR, "auto-ssl: attempting to renew certificate for domain without certificates in storage: ", domain)
95-
renew_check_cert_unlock(domain, storage, local_lock, distributed_lock_value)
96-
return
97-
end
98-
99128
-- We didn't previously store the cert.pem (since it can be derived from the
100129
-- fullchain.pem). So for backwards compatibility, set the cert.pem value to
101130
-- the fullchain.pem value, since that should work for our date checking

lib/resty/auto-ssl/storage_adapters/file.lua

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,23 @@ function _M.delete(self, key)
7272
end
7373
end
7474

75+
function _M.keys_with_prefix(self, prefix)
76+
local base_dir = self.options["dir"]
77+
local _, output, err = run_command("find " .. base_dir .. "/storage/file -name '" .. ngx.escape_uri(prefix) .. "*'")
78+
if err then
79+
return nil, err
80+
end
81+
82+
local keys = {}
83+
for path in string.gmatch(output, "[^\r\n]+") do
84+
local filename = ngx.re.sub(path, ".*/", "")
85+
local key = ngx.unescape_uri(filename)
86+
table.insert(keys, key)
87+
end
88+
89+
return keys
90+
end
91+
7592
function _M.keys_with_suffix(self, suffix)
7693
local base_dir = self.options["dir"]
7794
local _, output, err = run_command("find " .. base_dir .. "/storage/file -name '*" .. ngx.escape_uri(suffix) .. "'")

lib/resty/auto-ssl/storage_adapters/redis.lua

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,30 @@ function _M.delete(self, key)
106106
return connection:del(prefixed_key(self, key))
107107
end
108108

109+
function _M.keys_with_prefix(self, prefix)
110+
local connection, connection_err = self:get_connection()
111+
if connection_err then
112+
return false, connection_err
113+
end
114+
115+
local keys, err = connection:keys(prefixed_key(self, prefix .. "*"))
116+
117+
if keys and self.options["prefix"] then
118+
local unprefixed_keys = {}
119+
-- First character past the prefix and a colon
120+
local offset = string.len(self.options["prefix"]) + 2
121+
122+
for _, key in ipairs(keys) do
123+
local unprefixed = string.sub(key, offset)
124+
table.insert(unprefixed_keys, unprefixed)
125+
end
126+
127+
keys = unprefixed_keys
128+
end
129+
130+
return keys, err
131+
end
132+
109133
function _M.keys_with_suffix(self, suffix)
110134
local connection, connection_err = self:get_connection()
111135
if connection_err then

0 commit comments

Comments
 (0)