Skip to content
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

Merged
merged 23 commits into from
Sep 16, 2022
Merged

Fetch CRLs from a user defined URL #17136

merged 23 commits into from
Sep 16, 2022

Conversation

sgmiller
Copy link
Contributor

@sgmiller sgmiller commented Sep 14, 2022

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.

@sgmiller sgmiller requested a review from a team September 14, 2022 19:42
@sgmiller sgmiller changed the title Fetch CRLs from a user defined CDP (PoC) Fetch CRLs from a user defined CDP Sep 14, 2022
Copy link
Contributor

@stevendpclark stevendpclark left a 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.)

@sgmiller sgmiller changed the title Fetch CRLs from a user defined CDP Fetch CRLs from a user defined URL Sep 14, 2022
@sgmiller
Copy link
Contributor Author

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.

}

b.crlUpdateMutex.RLock()
if crl, ok := b.crls[name]; ok {
Copy link
Contributor

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!

Copy link
Contributor Author

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.

Copy link
Contributor

@cipherboy cipherboy Sep 15, 2022

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?

Copy link
Contributor

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?

Copy link
Contributor

@cipherboy cipherboy Sep 15, 2022

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.

Copy link
Contributor Author

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 {
Copy link
Contributor

@cipherboy cipherboy Sep 15, 2022

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).

Copy link
Contributor Author

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Contributor

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 ;-)

Copy link
Contributor

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
==================

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Contributor

@cipherboy cipherboy left a 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!

@@ -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 {
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to lockThenPopulateCRLs

Copy link
Contributor

@cipherboy cipherboy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!!

@sgmiller sgmiller merged commit f5cc167 into main Sep 16, 2022
@sgmiller sgmiller deleted the cert-auth-crl-autofetch branch September 16, 2022 21:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants