Re: pgaudit - an auditing extension for PostgreSQL - Mailing list pgsql-hackers

From Abhijit Menon-Sen
Subject Re: pgaudit - an auditing extension for PostgreSQL
Date
Msg-id 20150119065424.GA16276@toroid.org
Whole thread Raw
In response to Re: pgaudit - an auditing extension for PostgreSQL  (Stephen Frost <sfrost@snowman.net>)
Responses Re: pgaudit - an auditing extension for PostgreSQL
List pgsql-hackers
Hello Stephen.

Thanks very much for having a look at the revised pgaudit.

At 2015-01-18 22:28:37 -0500, sfrost@snowman.net wrote:
>
> > 2. Set pgaudit.roles = 'r1, r2, …', which logs everything done by r1,
> >    r2, and any of their descendants.
>
> If these roles were the 'audit' roles as considered under #1 then
> couldn't administrators control what pgaudit.roles provide today using
> role memberships granted to the roles listed?

Yes. But then there would be no convenient way to say "just log
everything this particular role does".

> > 3. Set pgaudit.log = 'read, write, …', which logs any events in any
> >    of the listed classes.
> 
> Approach #1 addresses this too, doesn't it?

Approach #1 applies only to things you can grant permissions for. What
if you want to audit other commands?

> As currently implemented, role-level auditing is required to have DDL
> be logged, but you may very well want to log all DDL and no DML, for
> example.

Well, as formerly implemented, you could do this by adding r1 to .roles
and then setting .log appropriately. But you know that already and, if
I'm not mistaken, have said you don't like it.

I'm all for making it possible to configure fine-grained auditing, but
I don't think that should come at the expense of being able to whack
things with a simpler, heavier^Wmore inclusive hammer if you want to.

> My feeling is that we should strip down what goes into contrib to be
> 9.5 based.

I do not think I can express a constructive opinion about this. I will
go along with whatever people agree is best.

> I'm also wondering if pieces of that are now out-of-date with where
> core is.

Yes, they are. I'll clean that up.

> I don't particularly like how pgaudit will need to be kept in sync
> with what's in ProcessUtility (normal and slow).

Sure, it's a pain.

> I'd really like to see this additional information regarding what kind
> a command is codified in core.  Ideally, we'd have a single place
> which tracks the kind of command and possibly other information which
> can then be addressed all at once when new commands are added.

What would this look like, and is it a realistic goal for 9.5?

> Also, we could allow more granularity by using the actual classes
> which we already have for objects.

Explain?

> > /*
> >  * This module collects AuditEvents from various sources (event
> >  * triggers, and executor/utility hooks) and passes them to the
> >  * log_audit_event() function.
> >  *
> >  * An AuditEvent represents an operation that potentially affects a
> >  * single object. If an underlying command affects multiple objects,
> >  * multiple AuditEvents must be created to represent it.
> >  */
> 
> The above doesn't appear to be accurate (perhaps it once was?) as
> log_audit_event() only takes a single AuditEvent structure at a time
> and it's not a list.  I'm not sure that needs to change, just pointing
> out that the comment appears to be inaccurate.

If multiple AuditEvents are created (as the ExecutorCheckPerms_hook may
do), log_audit_event() will be called multiple times. The comment is
correct, but I'll try to make it more clear.

> I'm inclined to suggest that the decision be made earlier on about if
> a given action should be logged, as the earlier we do that the less
> work we have to do and we could avoid having to pass in things like
> 'granted' to the log_audit_event function at all.

I considered that, but it makes it much harder to review all of the
places where such decisions are made. It's partly because I wrote the
code in this way that I was able to quickly change it to work the way
you suggested (at least once I understood what you suggested).

I prefer the one-line function and a few «if (pgaudit_configured())»
checks (to avoid creating AuditEvents if they won't be needed at all)
and centralising the decision-making rather than spreading the latter
around the whole code.

> > /*
> >  * Takes a role OID and returns true if the role is mentioned in
> >  * pgaudit.roles or if it inherits from a role mentioned therein;
> >  * returns false otherwise.
> >  */
> > 
> > static bool
> > role_is_audited(Oid roleid)
> > {
> > …
> 
> The results here should be cached, as was discussed earlier, iirc.

I'll look into that, but it's a peripheral matter.

> Whatever is considered 'noise' should at least be explicitly listed,
> so we know we're covering everything.

OK.

> > /*
> >  * Takes an AuditEvent and, if it should_be_logged(), writes it to the
> >  * audit log. The AuditEvent is assumed to be completely filled in by
> >  * the caller (unknown values must be set to "" so that they can be
> >  * logged without error checking).
> >  */
> > 
> > static void
> > log_audit_event(AuditEvent *e)
> > {
> 
> So, clearly, this is an area which could use some improvement.
> Specifically, being able to write to an independent file instead of just
> using ereport(), supporting other output formats (JSON, maybe even a
> table..).  Also, have you considered using a dynamic shared memory block
> to queue the logging messages to and then a background worker to write
> them out in-order to a file?  It'd clearly be similar to our existing
> ereport() mechanism, but importantly you'd be able to send it to another
> file.  Being able to log directly to syslog or other message queues
> would be great also.
> 
> These are things which could be added later, of course.

I have considered all of those things and, as I have said before, taken
a conscious decision to not do any of them. I strongly feel they should
be added only later, after we have agreed on the basic approach.

> >         /*
> >          * We don't have access to the parsetree here, so we have to
> >          * generate the node type, object type, and command tag by
> >          * decoding rte->requiredPerms and rte->relkind.
> >          */
> 
> This seems like it could be improved- have you considered suggesting a
> hook which is, perhaps, in a better place and could pass in this
> information instead of having to attempt to regenerate it?

No. (I don't see how that could work.)

> >         /*
> >          * If a role named "audit" exists, we check if it has been
> >          * granted permission to perform the operation identified above.
> >          * If so, we must log the event regardless of the static pgaudit
> >          * settings.
> >          */
> 
> This isn't quite what was intended.  This isn't about what the audit
> role could do but rather auditing specifically what the role has
> access to.

This is what you said earlier:
   «The magic "audit" role has SELECT rights on a given table.  When   any user does a SELECT against that table,
ExecCheckRTPermsis   called and there's a hook there which the module can use to say "ok,   does the audit role have
anypermissions here?" and, if the result   is yes, then the command is audited.»
 

As far as I can tell, that's exactly what the code does. In what way
have I misunderstood your suggestion now?

> As an example, if an UPDATE with a WHERE clause is executed and the
> audit user has SELECT rights on the table, then the UPDATE should be
> logged due to the WHERE clause.

Sorry, that makes my head hurt. I will think about it and respond later.

> > /*
> >  * Create AuditEvents for certain kinds of CREATE and ALTER statements,
> >  * as detected by log_object_access() in lieu of event trigger support
> >  * for them.
> >  */
> 
> Just to comment on this, the object access framework feels like it
> should, perhaps, be reworked to be based on event triggers..

The point of that code in the object access hook is to stand in when
event triggers are not available.

> > log_function_execution(Oid objectId)
> > {
> > …
> 
> This doesn't address overloaded functions, does it?  It probably
> should include the arguments and types in 'name'.

OK. I'll look into that.

-- Abhijit



pgsql-hackers by date:

Previous
From: Kyotaro HORIGUCHI
Date:
Subject: Re: Async execution of postgres_fdw.
Next
From: Pavel Stehule
Date:
Subject: Re: proposal: disallow operator "=>" and use it for named parameters