-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fetch CRLs from a user defined URL #17136
Conversation
… as trusted certs for CRL fetch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to update https://github.com/hashicorp/vault/blob/main/website/content/docs/auth/cert.mdx as part of this as there is an explicit call out
(Note: Vault does not fetch CRLs; the CRLs themselves and any updates must be pushed into Vault when desired, such as via a cron job that fetches them from the source and pushes them into Vault.)
Fixed. |
Co-authored-by: Steven Clark <[email protected]>
… into cert-auth-crl-autofetch
builtin/credential/cert/path_crls.go
Outdated
} | ||
|
||
b.crlUpdateMutex.RLock() | ||
if crl, ok := b.crls[name]; ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit puzzled by this, nothing will use the crl we are populating within this lock and it would be reset anyways by the setCRL within the fetchCRL call
Also note a make fmt
is needed. Everything else looks good though!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the CRL already existed and it's valid until was in the future, it would be a no-op in fetchCRL. So we wouldn't validate the URL and wouldn't setCRL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah this is tricky, I like what you're doing here: re-setting the same URL on the same existing CRL name will allow users to force a re-fetch of the CRL. I like it! (I was going to ask elsewhere how we'd refresh an existing CRL manually, but this does answer it).
But shouldn't this be a write lock in that case, strictly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eugh, fetchCRL
doesn't look at the crl.CDP.ValidUntil
value, updateCRLs
does? So right now we will always reload the URL data?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In particular, fetchCRL
takes a new reference, not the modified value here in b.crls
. I think Steve is correct, and while we later need a write lock (see my other comment), we don't need the read lock here. And we don't need the entire if block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah gotcha, now that it's straight to fetchURL there's no conditional. Removed the if block and had earlier redone the locking.
return fmt.Errorf("unexpected response code %d fetching CRL from %s", response.StatusCode, crl.CDP.Url) | ||
} | ||
|
||
func (b *backend) updateCRLs(ctx context.Context, req *logical.Request) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to hold a write lock, in order for us to safely iterate over b.crls
-- and eventually update it. A read lock isn't sufficient (even with a duplication) as we can modify the contents in setCRL
or pathCRLWrite
during this I think and deadlock.
I think what needs to happen is the lock needs to be propagated up out of setCRL
(which'll assume it is locked) and its callers will instead acquire that correctly (i.e., if they're going to call updateCRLs or fetchCRL eventually, they'll just proactively acquire the write lock).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Something did feel off about that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sgmiller -- @stevendpclark pointed out you didn't add lock here in the periodic func ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually the race test failure:
Failed
=== RUN TestCRLFetch
==================
WARNING: DATA RACE
Write at 0x00c002bf1440 by goroutine 9745:
runtime.mapassign_faststr()
/usr/local/go/src/runtime/map_faststr.go:203 +0x0
github.com/hashicorp/vault/builtin/credential/cert.(*backend).setCRL()
/home/circleci/go/src/github.com/hashicorp/vault/builtin/credential/cert/path_crls.go:270 +0x226
github.com/hashicorp/vault/builtin/credential/cert.(*backend).fetchCRL()
/home/circleci/go/src/github.com/hashicorp/vault/builtin/credential/cert/backend.go:87 +0x28c
github.com/hashicorp/vault/builtin/credential/cert.(*backend).pathCRLWrite()
/home/circleci/go/src/github.com/hashicorp/vault/builtin/credential/cert/path_crls.go:233 +0xe50
github.com/hashicorp/vault/builtin/credential/cert.TestCRLFetch()
/home/circleci/go/src/github.com/hashicorp/vault/builtin/credential/cert/path_crls_test.go:151 +0x1df4
testing.tRunner()
/usr/local/go/src/testing/testing.go:1446 +0x216
testing.(*T).Run.func1()
/usr/local/go/src/testing/testing.go:1493 +0x47
Previous read at 0x00c002bf1440 by goroutine 9746:
runtime.mapiterinit()
/usr/local/go/src/runtime/map.go:815 +0x0
github.com/hashicorp/vault/builtin/credential/cert.(*backend).updateCRLs()
/home/circleci/go/src/github.com/hashicorp/vault/builtin/credential/cert/backend.go:93 +0xaa
github.com/hashicorp/vault/builtin/credential/cert.(*backend).updateCRLs-fm()
<autogenerated>:1 +0x64
github.com/hashicorp/vault/builtin/credential/cert.TestCRLFetch.func1()
/home/circleci/go/src/github.com/hashicorp/vault/builtin/credential/cert/path_crls_test.go:41 +0x1e6
Goroutine 9745 (running) created at:
testing.(*T).Run()
/usr/local/go/src/testing/testing.go:1493 +0x75d
testing.runTests.func1()
/usr/local/go/src/testing/testing.go:1846 +0x99
testing.tRunner()
/usr/local/go/src/testing/testing.go:1446 +0x216
testing.runTests()
/usr/local/go/src/testing/testing.go:1844 +0x7ec
testing.(*M).Run()
/usr/local/go/src/testing/testing.go:1726 +0xa84
main.main()
_testmain.go:95 +0x2e9
Goroutine 9746 (running) created at:
github.com/hashicorp/vault/builtin/credential/cert.TestCRLFetch()
/home/circleci/go/src/github.com/hashicorp/vault/builtin/credential/cert/path_crls_test.go:36 +0x385
testing.tRunner()
/usr/local/go/src/testing/testing.go:1446 +0x216
testing.(*T).Run.func1()
/usr/local/go/src/testing/testing.go:1493 +0x47
==================
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test and locking updates look good, thanks Scott!
builtin/credential/cert/path_crls.go
Outdated
@@ -42,10 +49,13 @@ using the same name as specified here.`, | |||
} | |||
} | |||
|
|||
func (b *backend) populateCRLs(ctx context.Context, storage logical.Storage) error { | |||
func (b *backend) populateCRLsWithoutLock(ctx context.Context, storage logical.Storage) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not to nitpick what is otherwise a good PR, but perhaps we want to call this populateCRLsGrabbingLocks
? Just found Without
rather confusing the first time when it is used elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to lockThenPopulateCRLs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!!
Extends path_crl to accept either a CRL in PEM or DER format or a URL for the CRL Distribution Point. In the latter case, we periodically fetch that CRL according to it's validity dates.