ocsp/responder/redis: serve stale responses if live signing fails (#6243)

This commit is contained in:
Jacob Hoffman-Andrews 2022-07-21 12:08:53 -07:00 committed by GitHub
parent d2efdf5929
commit d988c39123
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 3 deletions

View File

@ -1,4 +1,18 @@
package responder // Package redis provides a Redis-based OCSP responder.
//
// This responder will first look for a response cached in Redis. If there is
// no response, or the response is too old, it will make a request to the RA
// for a freshly-signed response. If that succeeds, this responder will return
// the response to the user right away, while storing a copy to Redis in a
// separate goroutine.
//
// If the response was too old, but the request to the RA failed, this
// responder will serve the response anyhow. This allows for graceful
// degradation: it is better to serve a response that is 5 days old (outside
// the Baseline Requirements limits) than to serve no response at all.
// It's assumed that this will be wrapped in a responder.filterSource, which
// means that if a response is past its NextUpdate, we'll generate a 500.
package redis
import ( import (
"context" "context"
@ -82,7 +96,11 @@ func (src *redisSource) Response(ctx context.Context, req *ocsp.Request) (*respo
if src.isStale(resp) { if src.isStale(resp) {
src.counter.WithLabelValues("stale").Inc() src.counter.WithLabelValues("stale").Inc()
return src.signAndSave(ctx, req, "stale_redis") freshResp, err := src.signAndSave(ctx, req, "stale_redis")
if err != nil {
return &responder.Response{Response: resp, Raw: respBytes}, nil
}
return freshResp, nil
} }
src.counter.WithLabelValues("success").Inc() src.counter.WithLabelValues("success").Inc()

View File

@ -1,4 +1,4 @@
package responder package redis
import ( import (
"context" "context"
@ -227,3 +227,20 @@ func TestCertificateNotFound(t *testing.T) {
t.Errorf("expected NotFound error, got %s", err) t.Errorf("expected NotFound error, got %s", err)
} }
} }
func TestServeStale(t *testing.T) {
clk := clock.NewFake()
src, err := NewRedisSource(nil, errorSigner{}, time.Second, clk, metrics.NoopRegisterer, log.NewMock())
test.AssertNotError(t, err, "making source")
staleRedis := &staleRedis{
serialStored: nil,
thisUpdate: clk.Now().Add(-time.Hour),
}
src.client = staleRedis
serial := big.NewInt(111111)
_, err = src.Response(context.Background(), &ocsp.Request{
SerialNumber: serial,
})
test.AssertNotError(t, err, "expected to serve stale response when signer was down")
}