-
Notifications
You must be signed in to change notification settings - Fork 130
Authenticate audit events #571
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
Conversation
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've reviewed everything except the authenticate_controller code that you're changing, and only glanced at the tests. I'll give them a closer look when I do the final review but they look good so far anyway.
| logger_method, syslog_severity = details | ||
| define_method meth do |msg, msgid, facility: nil, **data| | ||
| logger.send logger_method, LogMessage.new(msg, msgid, data, syslog_severity, facility) | ||
| 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.
Just a suggestion here: Not that this is super cryptic, but I'd still prefer a more straightforward approach of defining the 3 methods explicitly, and then DRYing up repetition by having them delegate their implementation to a private method that does most of the work. Lmk if that isn't clear, but I think you'll know what I mean. Two advantages would be:
- Less likely to violate the principle of least surprise: If I see one of these methods being used in client code, I'd expect there to be a
def <method_name>somewhere. - For IDEs like rubymine (I don't use it atm, but I sometimes do...) I believe this will break that autolookup / jump to definition type features.
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're probably right, however I'll leave this as is for now.
| ACTION = conjur_sdid 'action' | ||
| end | ||
|
|
||
| class LogMessage < 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.
Add a note clarifying the reasons you inheritied from String here, since it's an choice and might confuse:
Yeah, that's a funny thing. I wanted to make it compatible with Ruby's built-in log formatter and it actually checks if a message is a
Stringand uses#inspectif it isn't. I'm not very happy with that solution and I might actually end up ditching the compatibility on some refactor, but that's how it is for now.
So in short it's a workaround for a bug inLogger::Formatteror whatever it's called. Which is also duplicated by ActiveSupport's formatter.
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'll add it, thanks.
| CONJUR_PEN = 43868 | ||
| def self.conjur_sdid label | ||
| [label, CONJUR_PEN].join('@').freeze | ||
| [label, CONJUR_PEN].join('@').intern |
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'd like to see some more comments about what this SDID is used for.
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 not sure what you mean. The SD-IDs are documented in audit.md.
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.
After your experience with my code, I now believe that any time something in code needs an explanation, having it documented elsewhere is not enough. Either repeat the explanation directly in the code comments, or include a link to the explanation in the code comments.
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.
Fair :) Could you say more about what do you feel needs explanation?
| attr_reader :msgid, :structured_data, :severity, :facility | ||
| end | ||
|
|
||
| # Middleware to store request ID in a thread variable |
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.
Confusing to me why this is here as part of audit. If there is a good reason, I'd add a comment explaining 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.
There is no specific reason. It'll be moved out at some point.
| msgid = msg.msgid if msg.respond_to? :msgid | ||
| sd = format_sd sd | ||
|
|
||
| facility = msg.try(:facility) || 4 |
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'd move the whole RFC5424Formatter class to its own file, as it stands independently.
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.
Yeah, I'll probably do that eventually.
app/models/audit/event/authn.rb
Outdated
| end | ||
| end | ||
|
|
||
| SUCCESS_TEMPLATE = "%s successfully authenticated with authenticator %s service %s".freeze |
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 like to put constants at top per ruby style guide
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 they'd been meant for external use, I would. But since these are in a way only local, I like to keep them near the code that uses them.
| @@ -0,0 +1,53 @@ | |||
| require 'ostruct' | |||
|
|
|||
| class Audit::Event::Authn < OpenStruct | |||
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.
Currently the interface for this class is only implicit: you have to read through every method to figure out what attribute assignments must be made before it can be used. It must be made explicit one way or the other. My preference would be:
- Write a normal intializer which accepts the member variables. This has the advantage of not only being explicit, but also making the client code interface clear and consistent. There's really no reason anyone should be using attr setters with this object. Also, you can enforce immutability.
- If you don't want to do 1. right now, please at least document the intended interface in comments.
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.
Good point, I'll make it clearer.
app/models/audit/event/authn.rb
Outdated
| end | ||
|
|
||
| def service_id | ||
| service.try :id |
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'd prefer not to rely on Rails methods in our domain code. I'd like to see a require active_support if you want to keep it (just to make that dep clear) or else service.id rescue nil
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 understand where you're coming from, but I like the expressiveness of some of ActiveSupport utilities and this code is unlikely to be moved out.
| require 'ostruct' | ||
|
|
||
| class Audit::Event::Authn < OpenStruct | ||
| def emit_success |
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 don't need to fix this, but there's something confusing to me about the naming. we have an "event" emitting a "success" (a "success event"). so an event is emitting an event, which reads oddly.
There's also a kind of strange inversion in the design, in that this object delegates to the thing that actually writes the log. Ie, we have an Event with an Audit (the actually log writer) inside of it, and the event calls its own emit_success which then calls Audit, passing the events own structured data to Audit.info.
I think a simpler, clearer design would be to just have pass events to Audit's writer methods, and allow client code to use Audit. But that's a larger (though not very large) refactor -- just food for thought.
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.
Spent some time thinking about it actually. Maybe it'll get refactored at some point.
| end | ||
|
|
||
| # Specialization to allow lookup by composite ids, | ||
| # eg. Resource[account, kind, id] |
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.
Just a note for later (not specific to your code), but just to make you aware: we have similar logic to this in multiple places in our code base (and others I believe) including my rotator code. At some point we should DRY it all up.
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. That's why I added this method in lieu of copying the same functionality again, even though I didn't go the one step further and found all the places where it could be used.
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 don't understand you what you mean, this does copy the same functionality again. It can't be reused beause here it exists in a very specific context (inside an audit event object), whereas in the codebase in general it's used in many different contexts. I'm not saying this because I want you to change anything atm, just want to clarify my initial point.
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.
What prevents this method from being used in all the other different contexts?
8827ec2 to
20c5f96
Compare
|
Some of your answers to the questions in the PR really seem like they would
be very helpful as comments in the code. For example, why you inherit from
String.
…On Tue, Jun 19, 2018 at 5:50 AM Rafał Rzepecki ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In app/models/resource.rb
<#571 (comment)>:
> @@ -52,6 +52,12 @@ def find_if_visible role, *a
res = find *a
res if res.try :visible_to?, role
end
+
+ # Specialization to allow lookup by composite ids,
+ # eg. Resource[account, kind, id]
Agreed. That's why I added this method in lieu of copying the same
functionality again, even though I didn't go the one step further and found
all the places where it could be used.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#571 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAFRexaFrSfjEtZyG5VsWikfiS5Uw8nEks5t-MlQgaJpZM4UqSSP>
.
|
|
Listen @jonahx , I spent all night trying to get to a working solution that would make us both happy, but I spent way too much time on it already and am over any reasonable timebox. Let's leave this as is and please file a tech debt issue if you want. Not that the time has been wasted, as I added a lot of test code and noticed and fixed a couple bugs on the way, which is why this PR grown a little bit; you might want to give it another look-over. I tried to address some of your concerns (however some are outside the scope of this change). The commits are clean so you can go through them one-by-one, and also if you're going to merge do either rebase merge or straight merge. For the record here are WIPs of two approached I tried: |
|
@dividedmind: I like the approach you and Jonah have taken on this one. I'd ask that you please file issues for work that we reasonably plan to address in the future. As the implementor and visionary of this work, you're in the best place to understand the work that is being pushed out to a future date. |
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 am effectively approving this unreviewed.
It breaks the authentication design per our previous conversation, and my previous WIP with a an unfinished suggestion for how to integrate into the existing design:
f1387b6.
In addition, many other places have what amount to undone TODOs, and I didn't have time to do a thorough review of the test code.
I'm just noting all this for the record. We can address it all later.
| CONJUR_PEN = 43868 | ||
| def self.conjur_sdid label | ||
| [label, CONJUR_PEN].join('@').freeze | ||
| [label, CONJUR_PEN].join('@').intern |
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.
After your experience with my code, I now believe that any time something in code needs an explanation, having it documented elsewhere is not enough. Either repeat the explanation directly in the code comments, or include a link to the explanation in the code comments.
| end | ||
|
|
||
| # Specialization to allow lookup by composite ids, | ||
| # eg. Resource[account, kind, id] |
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 don't understand you what you mean, this does copy the same functionality again. It can't be reused beause here it exists in a very specific context (inside an audit event object), whereas in the codebase in general it's used in many different contexts. I'm not saying this because I want you to change anything atm, just want to clarify my initial point.
2cb604b to
c9ada67
Compare
|
Since somebody pointed out to me that it might not be entirely clear from this thread and the rebased history, I'll note that (except for the central disagreement) I addressed most of the comments that pertain to the changed code and responded to the rest. I've also addressed some comments on parts of code that didn't change, and those of these which I haven't addressed I've responded to and acknowledged, and they're good points but addressing them would require refactoring beyond the scope of this PR and we're trying not to 'big batch', however the refactoring is likely to happen at some point in the future when the code in question is touched again. (In fact, I am currently changing that code doing other work, so this is most probably a closer rather than farther point in the future.) If I did miss something and the above comment is not accurate, please do tell me :) |
security-scan.sh
Outdated
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.
Thank you! I was just about to add this :)
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.
No worries. I think we need to start building our own utility containers for stuff like this....
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 don't think it's worth the effort for one-tool containers like that. I do think, however, that we ought to start pinning known good versions. Even better, actually review the images to make sure there are no backdoors or surprises of some sort, and then pin by specific SHA that we reviewed.
|
I need to take a look at why are those new cukes failing in Jenkins. Stay tuned. |
|
(I'll go ahead and merge after I fix that, if there aren't any objections.) |
9af4cbb to
8f75532
Compare
Note, currently this only works when running cukes locally.
8f75532 to
074156a
Compare
CNJR-5196 update REXML to mitigate CVE-2024-49761
This adds 'authenticate' audit events to the audit stream.
Note the volume of these messages is substantial so we should consider whether they should be enabled by default, or somehow filtered. (These messages weren't present in v4.)
Comments welcome especially on the message schema (see docs/audit.md).