mirror of
https://github.com/domainaware/parsedmarc.git
synced 2026-05-27 06:05:41 +00:00
ae1e5adb66
* Add DMARCbis report support; rename forensic→failure project-wide
Rebased on top of master @ 2cda5bf (9.9.0), which added the ASN
source attribution work (#712, #713, #714, #715). Individual Copilot
iteration commits squashed into this single commit — the per-commit
history on the feature branch was iterative (add tests, fix lint,
move field, revert, etc.) and not worth preserving; GitHub squash-
merges PRs anyway.
New fields from the DMARCbis XSD, plumbed through types, parsing, CSV
output, and the Elasticsearch / OpenSearch mappings:
- ``np`` — non-existent subdomain policy (``none`` / ``quarantine`` /
``reject``)
- ``testing`` — testing mode flag (``n`` / ``y``), replaces RFC 7489
``pct``
- ``discovery_method`` — policy discovery method (``psl`` /
``treewalk``)
- ``generator`` — report generator software identifier (metadata)
- ``human_result`` — optional descriptive text on DKIM / SPF results
RFC 7489 reports parse with ``None`` for DMARCbis-only fields.
Forensic reports have been renamed to failure reports throughout the
project to reflect the proper naming since RFC 7489.
- Core: ``types.py``, ``__init__.py`` — ``ForensicReport`` →
``FailureReport``, ``parse_forensic_report`` →
``parse_failure_report``, report type ``"failure"``.
- Output modules: ``elastic.py``, ``opensearch.py``, ``splunk.py``,
``kafkaclient.py``, ``syslog.py``, ``gelf.py``, ``webhook.py``,
``loganalytics.py``, ``s3.py``.
- CLI: ``cli.py`` — args, config keys, index names
(``dmarc_failure``).
- Docs + dashboards: all markdown, Grafana JSON, Kibana NDJSON,
Splunk XML.
Backward compatibility preserved: old function / type names remain as
aliases (``parse_forensic_report = parse_failure_report``,
``ForensicReport = FailureReport``, etc.), CLI accepts both the old
(``save_forensic``, ``forensic_topic``) and new (``save_failure``,
``failure_topic``) config keys, and updated dashboards query both
old and new index / sourcetype names so data from before and after
the rename appears together.
Merge conflicts resolved in ``parsedmarc/constants.py`` (took bis's
10.0.0 bump), ``parsedmarc/__init__.py`` (combined bis's "failure"
wording with master's IPinfo MMDB mention), ``parsedmarc/elastic.py``
and ``parsedmarc/opensearch.py`` (kept master's ``source_asn`` /
``source_asn_name`` / ``source_asn_domain`` on the failure doc path
while renaming ``forensic_report`` → ``failure_report``), and
``CHANGELOG.md`` (10.0.0 entry now sits above the 9.9.0 entry).
All 324 tests pass; ``ruff check`` / ``ruff format --check`` clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Apply post-RFC review fixes: RFC 9990 detection, langAttrString, CFWS-aware RUF parsing
Aligns the implementation with the final RFCs (9989/9990/9991) instead of
inferring DMARCbis support from the version element or the namespace alone.
Aggregate parsing (RFC 9990):
- _text() helper unwraps langAttrString values (extra_contact_info, error,
comment, human_result, generator) — when reporters include the lang
attribute, xmltodict yields {"#text": ..., "@lang": ...} dicts instead
of strings; the parser now stores the text payload in both shapes.
- New xml_namespace field on AggregateReport records the declared XML
namespace (urn:ietf:params:xml:ns:dmarc-2.0 for RFC 9990 reports).
- RFC 9990 detection accepts namespaceless reports that follow the
RFC 9990 shape (presence of np / testing / discovery_method / generator),
so reporters that don't declare the namespace still receive RFC 9990-
aware validation.
- Warnings: missing DKIM <selector> (REQUIRED in RFC 9990); legacy
forwarded / sampled_out policy-override types (removed by RFC 9990);
unknown policy-override types per the RFC 9990 enumeration.
- xml_namespace added to Elasticsearch and OpenSearch document mappings.
Failure parsing (RFC 9991):
- Identity-Alignment and Auth-Failure are split on commas with CFWS
whitespace stripped per the RFC 9991 ABNF; previously "dkim, spf"
yielded ["dkim", " spf"] with a leading space on the second token.
- Warnings logged when either REQUIRED field is missing.
Terminology: every reference to "DMARCbis" in code, tests, sample
filenames, AGENTS.md, and CHANGELOG.md is replaced with the appropriate
RFC number (9989 for the policy spec, 9990 for aggregate reports, 9991
for failure reports). Sample contents are unchanged.
Docs: corrects the prior claim that fo was dropped from RFC 9990 (only
pct was), reframes testing as a new field (not a pct replacement, since
RFC 9989 Appendix A.6 removed pct with no per-message substitute), and
documents the policy_override_reason enum changes (added policy_test_mode;
removed forwarded / sampled_out).
Tests: 8 new tests covering xml_namespace capture, RFC 9990 detection
from field shape, missing-DKIM-selector warning, legacy-override-type
warning, langAttrString unwrapping across all four affected elements,
and CFWS-aware Identity-Alignment / Auth-Failure parsing plus their
missing-field warnings. 276 tests total, all passing; ruff clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Sean Whalen <44679+seanthegeek@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
237 lines
6.8 KiB
Markdown
237 lines
6.8 KiB
Markdown
# Elasticsearch and Kibana
|
|
|
|
To set up visual dashboards of DMARC data, install Elasticsearch and Kibana.
|
|
|
|
:::{note}
|
|
Elasticsearch and Kibana 6 or later are required
|
|
:::
|
|
|
|
## Installation
|
|
|
|
On Debian/Ubuntu based systems, run:
|
|
|
|
```bash
|
|
sudo apt-get install -y apt-transport-https
|
|
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
|
|
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
|
|
sudo apt-get update
|
|
sudo apt-get install -y elasticsearch kibana
|
|
```
|
|
|
|
For CentOS, RHEL, and other RPM systems, follow the Elastic RPM guides for
|
|
[Elasticsearch] and [Kibana].
|
|
|
|
:::{note}
|
|
Previously, the default JVM heap size for Elasticsearch was very small (1g),
|
|
which will cause it to crash under a heavy load. To fix this, increase the
|
|
minimum and maximum JVM heap sizes in `/etc/elasticsearch/jvm.options` to
|
|
more reasonable levels, depending on your server's resources.
|
|
|
|
Make sure the system has at least 2 GB more RAM than the assigned JVM
|
|
heap size.
|
|
|
|
Always set the minimum and maximum JVM heap sizes to the same
|
|
value.
|
|
|
|
For example, to set a 4 GB heap size, set
|
|
|
|
```bash
|
|
-Xms4g
|
|
-Xmx4g
|
|
```
|
|
|
|
See <https://www.elastic.co/guide/en/elasticsearch/reference/current/important-settings.html#heap-size-settings>
|
|
for more information.
|
|
:::
|
|
|
|
```bash
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable elasticsearch.service
|
|
sudo systemctl enable kibana.service
|
|
sudo systemctl start elasticsearch.service
|
|
sudo systemctl start kibana.service
|
|
```
|
|
|
|
As of Elasticsearch 8.7, activate secure mode (xpack.security.*.ssl)
|
|
|
|
```bash
|
|
sudo vim /etc/elasticsearch/elasticsearch.yml
|
|
```
|
|
|
|
Add the following configuration
|
|
|
|
```text
|
|
# Enable security features
|
|
xpack.security.enabled: true
|
|
xpack.security.enrollment.enabled: true
|
|
# Enable encryption for HTTP API client connections, such as Kibana, Logstash, and Agents
|
|
xpack.security.http.ssl:
|
|
enabled: true
|
|
keystore.path: certs/http.p12
|
|
# Enable encryption and mutual authentication between cluster nodes
|
|
xpack.security.transport.ssl:
|
|
enabled: true
|
|
verification_mode: certificate
|
|
keystore.path: certs/transport.p12
|
|
truststore.path: certs/transport.p12
|
|
```
|
|
|
|
```bash
|
|
sudo systemctl restart elasticsearch
|
|
```
|
|
|
|
To create a self-signed certificate, run:
|
|
|
|
```bash
|
|
openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout kibana.key -out kibana.crt
|
|
```
|
|
|
|
Or, to create a Certificate Signing Request (CSR) for a CA, run:
|
|
|
|
```bash
|
|
openssl req -newkey rsa:4096-nodes -keyout kibana.key -out kibana.csr
|
|
```
|
|
|
|
Fill in the prompts. Watch out for Common Name (e.g. server FQDN or YOUR
|
|
domain name), which is the IP address or domain name that you will use to access Kibana. it is the most important field.
|
|
|
|
If you generated a CSR, remove the CSR after you have your certs
|
|
|
|
```bash
|
|
rm -f kibana.csr
|
|
```
|
|
|
|
Move the keys into place and secure them:
|
|
|
|
```bash
|
|
sudo mv kibana.* /etc/kibana
|
|
sudo chmod 660 /etc/kibana/kibana.key
|
|
```
|
|
|
|
Activate the HTTPS server in Kibana
|
|
|
|
```bash
|
|
sudo vim /etc/kibana/kibana.yml
|
|
```
|
|
|
|
Add the following configuration
|
|
|
|
```text
|
|
server.host: "SERVER_IP"
|
|
server.publicBaseUrl: "https://SERVER_IP"
|
|
server.ssl.enabled: true
|
|
server.ssl.certificate: /etc/kibana/kibana.crt
|
|
server.ssl.key: /etc/kibana/kibana.key
|
|
```
|
|
|
|
:::{note}
|
|
For more security, you can configure Kibana to use a local network connexion
|
|
to elasticsearch :
|
|
```text
|
|
elasticsearch.hosts: ['https://SERVER_IP:9200']
|
|
```
|
|
=>
|
|
```text
|
|
elasticsearch.hosts: ['https://127.0.0.1:9200']
|
|
```
|
|
:::
|
|
|
|
```bash
|
|
sudo systemctl restart kibana
|
|
```
|
|
|
|
Enroll Kibana in Elasticsearch
|
|
|
|
```bash
|
|
sudo /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s kibana
|
|
```
|
|
|
|
Then access to your web server at `https://SERVER_IP:5601`, accept the self-signed
|
|
certificate and paste the token in the "Enrollment token" field.
|
|
|
|
```bash
|
|
sudo /usr/share/kibana/bin/kibana-verification-code
|
|
```
|
|
|
|
Then put the verification code to your web browser.
|
|
|
|
End Kibana configuration
|
|
|
|
```bash
|
|
sudo /usr/share/elasticsearch/bin/elasticsearch-setup-passwords interactive
|
|
sudo /usr/share/kibana/bin/kibana-encryption-keys generate
|
|
sudo vim /etc/kibana/kibana.yml
|
|
```
|
|
|
|
Add previously generated encryption keys
|
|
|
|
```text
|
|
xpack.encryptedSavedObjects.encryptionKey: xxxx...xxxx
|
|
xpack.reporting.encryptionKey: xxxx...xxxx
|
|
xpack.security.encryptionKey: xxxx...xxxx
|
|
```
|
|
|
|
```bash
|
|
sudo systemctl restart kibana
|
|
sudo systemctl restart elasticsearch
|
|
```
|
|
|
|
Now that Elasticsearch is up and running, use `parsedmarc` to send data to
|
|
it.
|
|
|
|
Download (right-click the link and click save as) [export.ndjson].
|
|
|
|
Connect to kibana using the "elastic" user and the password you previously provide
|
|
on the console ("End Kibana configuration" part).
|
|
|
|
Import `export.ndjson` the Saved Objects tab of the Stack management
|
|
page of Kibana. (Hamburger menu -> "Management" -> "Stack Management" ->
|
|
"Kibana" -> "Saved Objects")
|
|
|
|
It will give you the option to overwrite existing saved dashboards or
|
|
visualizations, which could be used to restore them if you or someone else
|
|
breaks them, as there are no permissions/access controls in Kibana without
|
|
the commercial [X-Pack].
|
|
|
|
```{image} _static/screenshots/saved-objects.png
|
|
:align: center
|
|
:alt: A screenshot of setting the Saved Objects Stack management UI in Kibana
|
|
:target: _static/screenshots/saved-objects.png
|
|
```
|
|
|
|
```{image} _static/screenshots/confirm-overwrite.png
|
|
:align: center
|
|
:alt: A screenshot of the overwrite conformation prompt
|
|
:target: _static/screenshots/confirm-overwrite.png
|
|
```
|
|
|
|
## Upgrading Kibana index patterns
|
|
|
|
`parsedmarc` 5.0.0 makes some changes to the way data is indexed in
|
|
Elasticsearch. if you are upgrading from a previous release of
|
|
`parsedmarc`, you need to complete the following steps to replace the
|
|
Kibana index patterns with versions that match the upgraded indexes:
|
|
|
|
1. Login in to Kibana, and click on Management
|
|
2. Under Kibana, click on Saved Objects
|
|
3. Check the checkboxes for the `dmarc_aggregate` and `dmarc_failure`
|
|
index patterns
|
|
4. Click Delete
|
|
5. Click Delete on the conformation message
|
|
6. Download (right-click the link and click save as)
|
|
the latest version of [export.ndjson]
|
|
7. Import `export.ndjson` by clicking Import from the Kibana
|
|
Saved Objects page
|
|
|
|
## Records retention
|
|
|
|
Starting in version 5.0.0, `parsedmarc` stores data in a separate
|
|
index for each day to make it easy to comply with records
|
|
retention regulations such as GDPR. For more information,
|
|
check out the Elastic guide to [managing time-based indexes efficiently](https://www.elastic.co/blog/managing-time-based-indices-efficiently).
|
|
|
|
[elasticsearch]: https://www.elastic.co/guide/en/elasticsearch/reference/current/rpm.html
|
|
[export.ndjson]: https://raw.githubusercontent.com/domainaware/parsedmarc/master/dashboards/opensearch/opensearch_dashboards.ndjson
|
|
[kibana]: https://www.elastic.co/guide/en/kibana/current/rpm.html
|
|
[x-pack]: https://www.elastic.co/products/x-pack
|