For each executed command in server context, send the information about the command to the systemd journal. The resulting string is similar to what is recored in httpd's error_log for API requests coming through the RPC layer. In server mode operations are performed directly on the server over LDAPI unix domain socket, so httpd end-point is not used and therefore operations aren't recorded in the error_log. With this change any IPA API operation is sent as an audit event to the journal, alog with additional information collected by the journald itself. To aid with identification of these messages, an application name is replaced with IPA.API and the actual name from api.env.script is made a part of the logged message. The actual application script name is available as part of the journal metadata anyway. If no Kerberos authentication was used but rather LDAPI autobind was in use, the name of the authenticated principal will be replaced with [autobind]. Messages sent with syslog NOTICE priority. More information is available in the design document 'audit-ipa-api.md' Fixes: https://pagure.io/freeipa/issue/9589 Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com> Reviewed-By: Rob Crittenden <rcritten@redhat.com>
12 KiB
Audit IPA API operations
Overview
IPA servers present an API to perform various actions that change the state of the deployment. These actions include, among others, modifications of user and group databases, add or remove information about hosts and Kerberos services, HBAC and SUDO rules, and many other action types.
It is possible to observe IPA API actions through the web server logs. Each IPA
server logs their API calls in /var/log/httpd/error_log
log file, as part of
standard Apache webserver logs. However, IPA command line utilities, when run
as root
on IPA server, operate directly against LDAP database and results of
these operations only present in LDAP logs.
Thus, current IPA API implementation does not provide a unified method to collect logs to audit API operations. The goal of this change is to make sure IPA API backend logs externally-initiated operations, regardless how these operations were invoked.
Use Cases
-
As an administrator, I'd like to collect details on who and when has called a particular IPA API on a particular IPA server. This information needs to be easily queried and it should be possible to correlate it across all servers in the IPA deployment.
-
As an administrator, I'd like to make sure operations performed as part of IPA administrative utilities are audited as well.
How to Use
journalctl
tool can be used to query and filter through the IPA
API audit details. Each logged entry will be tagged with an 'IPA.API' label and
thus can easily be queried:
# journalctl -g IPA.API
...
journalctl -g
allows to search through the content of the log entries'
messages. Each found entry has associated metadata which can be retrieved in a
different format, depending on other options to journalctl
invocation.
Design
Audit of IPA API operations should happen independently. Operations should be logged whenever they happen.
IPA deployment heavily relies on a working systemd setup. systemd provides logging facilities in the form of a system journal. systemd journal allows centralized collection of the journals from individual systems, forward secure sealing of the forwarded data, and rich metadata associated with the log entries. Thus, it already provides an infrastructure to allow secure centralized collection of actions performed through IPA API on IPA servers.
From administrator's point of view, when IPA API operations logged through the systemd journal, standard journal commands can be used to retrieve and manipulate logged entries.
Implementation
All IPA API calls end up in Command.__do_call()
internal method. This method
prepares execution of the command and runs it. After the command was performed,
the output is formatted. If operations require forwarding the request to a
remote IPA server, this will be performed automatically. As a result,
Command.__do_call()
is executed by both IPA client and IPA server components.
It is possible to derive a context of operations through IPA API environment,
using api.env.in_server
boolean.
systemd journal provides a simple Python binding, systemd.journal
, that
allows structured logging of the messages against a journald
daemon running
on the system. If such operation is performed in the server context, system
journal will be updated.
To aid with identification of these messages, an application name is replaced
with IPA.API and the actual name from api.env.script is made a part of the
logged message. The actual application script name is available as part of the
journal metadata anyway. Additionally, a MESSAGE_ID
property is set to IPA
API-specific application UID, generated with Python's
uuid.uuid3(uuid.NAMESPACE_DNS, 'IPA.API')
function call. This value is
available in IPA constants (ipalib/constants.py
) as SD_IPA_API_MESSAGE_ID
.
The value of the constant is 6d70f1b493df36478bc3499257cd3b17
.
If no Kerberos authentication was used but rather LDAPI autobind was in use,
the name of the authenticated principal will be replaced with [autobind]
text.
Messages sent with syslog NOTICE
priority.
An example session looks like the following output:
# ipa -e in_server=True console
(Custom IPA interactive Python console)
api: IPA API object
pp: pretty printer
>>> api.Command.user_del('foobar')
{'result': {'failed': []}, 'value': ['foobar'], 'messages': [{'type':
'warning', 'name': 'VersionMissing', 'message': "API Version number was not
sent, forward compatibility not guaranteed. Assuming server's API version,
2.253", 'code': 13001, 'data': {'server_version': '2.253'}}], 'summary':
'Deleted user "foobar"'}
>>> ^D
now exiting InteractiveConsole...
# journalctl -g IPA.API
May 21 11:31:33 master1.ipa1.test /usr/bin/ipa[247422]: [IPA.API] [autobind]: user_del: SUCCESS [ldap2_140328582446688] {"uid": ["foobar"], "continue": false, "version": "2.253"}
All operations triggered through IPA API logged, including locally initiated,
as can be seen in the output above. For httpd end-point operations will be
logged as requested by the /mod_wsgi
binary:
May 21 11:35:19 master1.ipa1.test /mod_wsgi[247035]: [IPA.API] admin@IPA1.TEST: ping: SUCCESS [ldap2_139910420944784] {"version": "2.253"}
The message includes following fields:
- executable name and PID (
/mod_wsgi
for HTTP end-point) [IPA.API]
marker to allow searches withjournalctl -g IPA.API
- authenticated Kerberos principal or
[autobind]
marker for LDAPI-based access as root - name of the command executed
- result of execution:
SUCCESS
or an exception name - LDAP backend instance identifier. The identifier will be the same for all operations performed under the same request. This allows to identify operations which were executed as a part of the same API request instance. For API operations that didn't result in LDAP access, there will be
[no_connection_id]
marker. - finally, a list of arguments and options passed to the command is provided in JSON format
If an API call results in multiple operations triggered by the internal
implementation of the API command, only the external operation is recorded.
This means, for example, that a user_del
API call will only be recorded as a
user_del
command and not a sequence of a user_find
, otptoken_find
,
subid_find
, and corresponding deletion commands which user_del
implementation is using.
IPA supplies a message catalog to systemd journal which allows to explain
content of the audited message and provide references to corresponding IPA API
documentation. This feature is triggered by journalctl -x
systemd journal
command.
Full journal entry looks like the one below and can be obtained with journalctl -o json-pretty
command:
{
"PRIORITY" : "5",
"_HOSTNAME" : "master1.ipa1.test",
"__SEQNUM" : "608971",
"_COMM" : "ipa",
"_AUDIT_LOGINUID" : "0",
"CODE_FUNC" : "__audit_to_journal",
"_TRANSPORT" : "journal",
"__SEQNUM_ID" : "aa96317d3ab84c16b5f131922414af11",
"_CAP_EFFECTIVE" : "1ffffffffff",
"_MACHINE_ID" : "5582ad1e90354a2e82710afb4cd4477f",
"_RUNTIME_SCOPE" : "system",
"MESSAGE" : "[IPA.API] [autobind]: user_del: SUCCESS [ldap2_140155643874720] {\"uid\": [\"zuser3\"], \"continue\": false, \"version\": \"2.253\"}",
"CODE_LINE" : "495",
"__REALTIME_TIMESTAMP" : "1716360895014405",
"__MONOTONIC_TIMESTAMP" : "5952405665424",
"_SYSTEMD_OWNER_UID" : "0",
"_SYSTEMD_UNIT" : "session-30.scope",
"_SYSTEMD_CGROUP" : "/user.slice/user-0.slice/session-30.scope",
"CODE_FILE" : "/usr/lib/python3.12/site-packages/ipalib/frontend.py",
"_SYSTEMD_SESSION" : "30",
"_SYSTEMD_INVOCATION_ID" : "d166c864dba04b478d01658aa180d50d",
"_PID" : "255232",
"IPA_API_PARAMS" : "{\"uid\": [\"zuser3\"], \"continue\": false, \"version\": \"2.253\"}",
"MESSAGE_ID" : "6d70f1b493df36478bc3499257cd3b17",
"IPA_API_ACTOR" : "[autobind]",
"_SYSTEMD_SLICE" : "user-0.slice",
"IPA_API_COMMAND" : "user_del",
"_BOOT_ID" : "cce41ab07f404ced8676400eb01bf220",
"__CURSOR" : "s=aa96317d3ab84c16b5f131922414af11;i=94acb;b=cce41ab07f404ced8676400eb01bf220;m=569e7067690;t=6190569742605;x=265dd38af30f934c",
"_AUDIT_SESSION" : "30",
"SYSLOG_IDENTIFIER" : "/usr/bin/ipa",
"_UID" : "0",
"_SYSTEMD_USER_SLICE" : "-.slice",
"_SOURCE_REALTIME_TIMESTAMP" : "1716360895014364",
"_SELINUX_CONTEXT" : "unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023",
"_CMDLINE" : "/usr/bin/python3 -I /usr/bin/ipa -e in_server=True console",
"_EXE" : "/usr/bin/python3.12",
"_GID" : "0",
"IPA_API_RESULT" : "SUCCESS"
}
An explanation for this audit message can be generated with journalctl -x
command:
# journalctl -x -g ldap2_140155643874720
May 22 06:54:55 master1.ipa1.test /usr/bin/ipa[255232]: [🡕] [IPA.API] [autobind]: user_del: SUCCESS [ldap2_140155643874720] {"uid": ["zuser3"], "continue": false, "version": "2.253"}
░░ Subject: IPA API command was executed and result of its execution was audited
░░ Defined-by: FreeIPA
░░ Support: https://lists.fedorahosted.org/archives/list/freeipa-users@lists.fedorahosted.org/
░░ Documentation: man:ipa(1)
░░ Documentation: https://freeipa.readthedocs.io/en/latest/api/index.html
░░ Documentation: https://freeipa.readthedocs.io/en/latest/api/user_del.html
░░ FreeIPA provides an extensive API that allows to manage all aspects of IPA deployments.
░░ The following information about the API command executed is available:
░░ [IPA.API] [autobind]: user_del: SUCCESS [ldap2_140155643874720] {"uid": ["zuser3"], "continue": false, "version": "2.253"}
░░ The command was executed by '/usr/bin/ipa' utility. If the utility name
░░ is '/mod_wsgi`, then this API command came from a remote source through the IPA
░░ API end-point.
░░ The message includes following fields:
░░ - executable name and PID ('/mod_wsgi' for HTTP end-point; in this case it
░░ was '/usr/bin/ipa' command)
░░ - '[IPA.API]' marker to allow searches with 'journalctl -g IPA.API'
░░ - authenticated Kerberos principal or '[autobind]' marker for LDAPI-based
░░ access as root. In this case it was '[autobind]'
░░ - name of the command executed, in this case 'user_del'
░░ - result of execution: `SUCCESS` or an exception name. In this case it was
░░ 'SUCCESS'
░░ - LDAP backend instance identifier. The identifier will be the same for all
░░ operations performed under the same request. This allows to identify operations
░░ which were executed as a part of the same API request instance. For API
░░ operations that didn't result in LDAP access, there will be
░░ '[no_connection_id]' marker.
░░ - finally, a list of arguments and options passed to the command is provided
░░ in JSON format.
░░ ---------
░░ The following list of arguments and options were passed to the command
░░ 'user_del' by the '[autobind]' actor:
░░
░░ {"uid": ["zuser3"], "continue": false, "version": "2.253"}
░░ ---------
░░ A detailed information about FreeIPA API can be found at upstream documentation API reference:
░░ https://freeipa.readthedocs.io/en/latest/api/index.html
░░ For details on the IPA API command 'user_del' see
░░ https://freeipa.readthedocs.io/en/latest/api/user_del.html
Feature Management
There is no separate management of the IPA API audit logging. Logging is always active on IPA server.
systemd journal has own mechanisms to control rates of messages coming from the
services. The details can be found in the man page journald.conf(5)
.
Upgrade
There is no impact on upgrade. Once new IPA API code installed, any new application using it will start issuing log entries to the journald.
Test plan
Test of IPA API audit logging can be done by observing systemd journal.