-
Notifications
You must be signed in to change notification settings - Fork 18
Conversation
Codecov Report
@@ Coverage Diff @@
## master #40 +/- ##
==========================================
+ Coverage 64.94% 65.81% +0.86%
==========================================
Files 8 9 +1
Lines 368 430 +62
==========================================
+ Hits 239 283 +44
- Misses 115 126 +11
- Partials 14 21 +7
Continue to review full report at Codecov.
|
There's probably a better name than "rootsanalyzer" for this - maybe "rootswatcher" or "rootsmonitor"? |
@taknira, will you have time to review this soon? |
Yup, on it :) |
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.
Have looked at everything except the tests so far - have some comments (mostly tiny things or thinking out loud) to be going on with :)
@@ -41,3 +41,19 @@ type STHWriter interface { | |||
type RootsWriter interface { | |||
WriteRoots(ctx context.Context, l *ctlog.Log, roots []*x509.Certificate, receivedAt time.Time) error | |||
} | |||
|
|||
// RootSetID uniquely identifies a specific set of certificates, regardless of their order. | |||
type RootSetID string |
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.
You had a bunch of reasons for making this a string instead of []byte - what were they again?
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.
As a string, it can be used as the key in a map. This is helpful since that's exactly what it is - a key for referring to a set of certificates. If I make it a []byte, I have to cast it to string whenever I used it with a map. It is also trivially comparable with other RootSetIDs as a string. However, there aren't any significant obstacles to making it a []byte so I'd be fine with changing it, if you've got strong reasons for doing so? The only one I can think of is that it's not really a printable string, so []byte is semantically more accurate.
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 relaxed, I've been going back and forth on this in my head. It looks like the only map place it's used atm is for testing, and so that shouldn't be the sole reason for it to be a string, but I also don't have strong reasons why it should be []byte, so whichever is fine. I think in my head we'd be calculating it by doing a bunch of hashing, so that felt bytey, but then having the ID as []byte might cause problems if we want to use it as part of a primary key in a DB, depending on the db type. So author's choice - I leave it up to you :)
glog.Errorf("rootsanalyzer: %s", err) | ||
return | ||
} | ||
addedCerts, removedCerts := diffRootSets(oldRoots, newRoots) |
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.
A thought, that can be done in a different PR if you agree with it - it might be useful to also store the diffs alongside the root sets or RootSetIDs or something, so that that changes are stored somewhere that's not just in the incident DB? Just a thought. Depends on your db schema of course, but having a list of rootSetIDs in the order that we saw them (or something), and storing any change (or maybe a representation of the change if the change could be too hefty) between that one and the previous one might be useful? WDYT?
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.
@Mercurrent once you're familiar with this stuff it'd be good to get your take on this too!
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.
That's something I planned to have in the design doc, but haven't actually run into a need for so far. @Mercurrent may wish to add this when it becomes necessary.
@@ -41,3 +41,19 @@ type STHWriter interface { | |||
type RootsWriter interface { | |||
WriteRoots(ctx context.Context, l *ctlog.Log, roots []*x509.Certificate, receivedAt time.Time) 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.
Does WriteRoots need some sort of comment or potential future tweaking to either comment on the fact it should create or take as an argument a RootSetID, now that this concept has been introduced? It may be that (again, in a diff PR) the Roots Getter sorts and de-dupes the set of roots it gets, and calculates the RootSetID before calling WriteRoots, or something.... This is thinking about where the interface line should be drawn - I'm pro making as much of the useful functionality sit above the interface line as possible, at least in cases where we have a clear idea of how it should work. WDYT?
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 was letting the RootsWriter implementation handle calculating the RootSetID, since it's arguably implementation-specific. The RootSetID isn't defined by Monologue to be anything but an opaque, deterministic identifier. I could make WriteRoots() return the RootSetID, which makes this a bit more obvious?
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.
Aaaand looked at the tests :)
{{ end }}{{ end }}{{ if gt (len .RemovedCerts) 0 }} | ||
Certificates removed ({{ len .RemovedCerts }}): | ||
{{ range .RemovedCerts }}{{ .Subject }} | ||
{{ end }}{{ end }}`)) |
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 only the subject of the certs will be going in to the incident reports, it's almost definitely worth storing the complete cert diff data along side the RootSetID or something (as mentioned in another comment), just in case there end up being roots with the same subject field, but different keys, or something? It'd be good to have the full diff info somewhere I think?
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 could include the full diff in here; I can imagine that being useful.
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.
For now, I've just included the SHA256 hash of the cert, which makes it clear if something about the cert has changed (if it's in both the added and removed sections). That hash can be thrown into https://crt.sh to get the full cert details. I think the full diff could be deferred for a future PR.
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.
Yup, SHA256 hash should do the trick for now :)
704e6dc
to
c149aaa
Compare
glog.Errorf("rootsanalyzer: %s", err) | ||
return | ||
} | ||
addedCerts, removedCerts := diffRootSets(oldRoots, newRoots) |
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.
@Mercurrent once you're familiar with this stuff it'd be good to get your take on this too!
{{ end }}{{ end }}{{ if gt (len .RemovedCerts) 0 }} | ||
Certificates removed ({{ len .RemovedCerts }}): | ||
{{ range .RemovedCerts }}{{ .Subject }} | ||
{{ end }}{{ end }}`)) |
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.
Yup, SHA256 hash should do the trick for now :)
@@ -41,3 +41,19 @@ type STHWriter interface { | |||
type RootsWriter interface { | |||
WriteRoots(ctx context.Context, l *ctlog.Log, roots []*x509.Certificate, receivedAt time.Time) error | |||
} | |||
|
|||
// RootSetID uniquely identifies a specific set of certificates, regardless of their order. | |||
type RootSetID string |
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 relaxed, I've been going back and forth on this in my head. It looks like the only map place it's used atm is for testing, and so that shouldn't be the sole reason for it to be a string, but I also don't have strong reasons why it should be []byte, so whichever is fine. I think in my head we'd be calculating it by doing a bunch of hashing, so that felt bytey, but then having the ID as []byte might cause problems if we want to use it as part of a primary key in a DB, depending on the db type. So author's choice - I leave it up to you :)
There are just a couple of small things left to tweak (logStr, testonly doc comment location) so approving so you can go ahead and merge once those are done. |
fe03d39
to
51bc7d8
Compare
Creates incident reports when the root certificates return by a CT Log's get-roots endpoint change.
51bc7d8
to
e49d05f
Compare
Creates incident reports when the root certificates returned by a CT Log's get-roots endpoint change.