PR feedback

This commit is contained in:
Jasmine Schladen 2020-12-03 11:30:34 -08:00
parent b40cb5562a
commit 589df0e230
6 changed files with 113 additions and 36 deletions

View File

@ -262,22 +262,101 @@ and are used when Lemur creates the CSR for your certificates.
LEMUR_DEFAULT_AUTHORITY = "verisign"
.. _NotificationOptions:
Notification Options
--------------------
Lemur currently has very basic support for notifications. Currently only expiration notifications are supported. Actual notification
is handled by the notification plugins that you have configured. Lemur ships with the 'Email' notification that allows expiration emails
to be sent to subscribers.
Lemur supports a small variety of notification types through a set of notification plugins.
By default, Lemur configures a standard set of email notifications for all certificates.
Templates for expiration emails are located under `lemur/plugins/lemur_email/templates` and can be modified for your needs.
Notifications are sent to the certificate creator, owner and security team as specified by the `LEMUR_SECURITY_TEAM_EMAIL` configuration parameter.
**Plugin-capable notifications**
Certificates marked as inactive will **not** be notified of upcoming expiration. This enables a user to essentially
silence the expiration. If a certificate is active and is expiring the above will be notified according to the `LEMUR_DEFAULT_EXPIRATION_NOTIFICATION_INTERVALS` or
30, 15, 2 days before expiration if no intervals are set.
These notifications can be configured to use all available notification plugins.
Lemur supports sending certificate expiration notifications through SES and SMTP.
Supported types:
* Certificate expiration
**Email-only notifications**
These notifications can only be sent via email and cannot use other notification plugins.
Supported types:
* CA certificate expiration
* Pending ACME certificate failure
* Certificate rotation (currently disabled in code)
**Default notifications**
When a certificate is created, the following email notifications are created for it if they do not exist.
If these notifications already exist, they will be associated with the new certificate.
* ``DEFAULT_<OWNER>_X_DAY``, where X is the set of values specified in ``LEMUR_DEFAULT_EXPIRATION_NOTIFICATION_INTERVALS`` and defaults to 30, 15, and 2 if not specified. The owner's username will replace ``<OWNER>``.
* ``DEFAULT_SECURITY_X_DAY``, where X is the set of values specified in ``LEMUR_SECURITY_TEAM_EMAIL_INTERVALS`` and defaults to ``LEMUR_DEFAULT_EXPIRATION_NOTIFICATION_INTERVALS`` if not specified (which also defaults to 30, 15, and 2 if not specified).
These notifications can be disabled if desired. They can also be unassociated with a specific certificate.
**Disabling notifications**
Notifications can be disabled either for an individual certificate (which disables all notifications for that certificate)
or for an individual notification object (which disables that notification for all associated certificates).
At present, disabling a notification object will only disable certificate expiration notifications, and not other types,
since other notification types don't use notification objects.
**Certificate expiration**
Certificate expiration notifications are sent when the scheduled task to send certificate expiration notifications runs
(see :ref:`PeriodicTasks`). Specific patterns of certificate names may be excluded using ``--exclude`` (when using
cron; you may specify this multiple times for multiple patterns) or via the config option ``EXCLUDE_CN_FROM_NOTIFICATION``
(when using celery; this is a list configuration option, meaning you specify multiple values, such as
``['exclude', 'also exclude']``). The specified exclude pattern will match if found anywhere in the certificate name.
When the periodic task runs, Lemur checks for certificates meeting the following conditions:
* Certificate has notifications enabled
* Certificate is not expired
* Certificate is not revoked
* Certificate name does not match the `exclude` parameter
* Certificate has at least one associated notification object
* That notification is active
* That notification's configured interval and unit match the certificate's remaining lifespan
All eligible certificates are then grouped by owner and applicable notification. For each notification and certificate group,
Lemur will send the expiration notification using whichever plugin was configured for that notification object.
In addition, Lemur will send an email to the certificate owner and security team (as specified by the
``LEMUR_SECURITY_TEAM_EMAIL`` configuration parameter).
**CA certificate expiration**
Certificate authority certificate expiration notifications are sent when the scheduled task to send authority certificate
expiration notifications runs (see :ref:`PeriodicTasks`). Notifications are sent via the intervals configured in the
configuration parameter ``LEMUR_AUTHORITY_CERT_EXPIRATION_EMAIL_INTERVALS``, with a default of 365 and 180 days.
When the periodic task runs, Lemur checks for certificates meeting the following conditions:
* Certificate has notifications enabled
* Certificate is not expired
* Certificate is not revoked
* Certificate is associated with a CA
* Certificate's remaining lifespan matches one of the configured intervals
All eligible certificates are then grouped by owner and expiration interval. For each interval and certificate group,
Lemur will send the CA certificate expiration notification via email to the certificate owner and security team
(as specified by the ``LEMUR_SECURITY_TEAM_EMAIL`` configuration parameter).
**Pending ACME certificate failure**
Whenever a pending ACME certificate fails to be issued, Lemur will send a notification via email to the certificate owner
and security team (as specified by the ``LEMUR_SECURITY_TEAM_EMAIL`` configuration parameter). This email is not sent if
the pending certificate had notifications disabled.
**Email notifications**
Templates for emails are located under `lemur/plugins/lemur_email/templates` and can be modified for your needs.
The following configuration options are supported:
.. data:: LEMUR_EMAIL_SENDER
:noindex:
@ -318,7 +397,7 @@ Lemur supports sending certificate expiration notifications through SES and SMTP
::
LEMUR_EMAIL = 'lemur.example.com'
LEMUR_EMAIL = 'lemur@example.com'
.. data:: LEMUR_SECURITY_TEAM_EMAIL
@ -333,7 +412,7 @@ Lemur supports sending certificate expiration notifications through SES and SMTP
.. data:: LEMUR_DEFAULT_EXPIRATION_NOTIFICATION_INTERVALS
:noindex:
Lemur notification intervals
Lemur notification intervals. If unspecified, the value [30, 15, 2] is used.
::

View File

@ -325,7 +325,7 @@ celery tasks or cron jobs that run these commands.
There are currently three commands that could/should be run on a periodic basis:
- `notify expirations` and `notify authority_expirations`
- `notify expirations` and `notify authority_expirations` (see :ref:`NotificationOptions` for configuration info)
- `check_revoked`
- `sync`

View File

@ -40,9 +40,7 @@ def expirations(exclude):
print("Starting to notify subscribers about expiring certificates!")
success, failed = send_expiration_notifications(exclude)
print(
"Finished notifying subscribers about expiring certificates! Sent: {success} Failed: {failed}".format(
success=success, failed=failed
)
f"Finished notifying subscribers about expiring certificates! Sent: {success} Failed: {failed}"
)
status = SUCCESS_METRIC_STATUS
except Exception as e:
@ -66,9 +64,7 @@ def authority_expirations():
success, failed = send_authority_expiration_notifications()
print(
"Finished notifying subscribers about expiring certificate authority certificates! "
"Sent: {success} Failed: {failed}".format(
success=success, failed=failed
)
f"Sent: {success} Failed: {failed}"
)
status = SUCCESS_METRIC_STATUS
except Exception as e:

View File

@ -132,7 +132,7 @@ def get_eligible_authority_certificates():
for owner, owner_certs in groupby(all_certs, lambda x: x.owner):
# group by expiration interval
for interval, interval_certs in groupby(owner_certs, lambda x: (x.not_after - now).days):
certificates[owner][interval] = list(interval_certs) # list(c for c in interval_certs)
certificates[owner][interval] = list(interval_certs)
return certificates

View File

@ -76,7 +76,9 @@
<tr>
<td style="font-family:Roboto-Regular,Helvetica,Arial,sans-serif;font-size:13px;color:#202020;line-height:1.5">
<br>This is a Lemur CA certificate expiration notice. The following CA certificates are expiring soon;
please take manual action to renew them if necessary. You may also disable notifications via the
please take manual action to renew them if necessary. Note that rotating a root CA requires
advanced planing and the respective trustStores need to be updated. A sub-CA, on the other hand,
does not require any changes to the trustStore. You may also disable notifications via the
Notify toggle in Lemur if they are no longer in use.
<table border="0" cellspacing="0" cellpadding="0"
style="margin-top:48px;margin-bottom:48px">

View File

@ -131,13 +131,13 @@ def test_send_pending_failure_notification(notification_plugin, async_issuer_plu
def test_get_authority_certificates():
from lemur.notifications.messaging import get_expiring_authority_certificates
certificate_1 = create_cert_that_expires_in_days(180)
certificate_2 = create_cert_that_expires_in_days(365)
create_cert_that_expires_in_days(364)
create_cert_that_expires_in_days(366)
create_cert_that_expires_in_days(179)
create_cert_that_expires_in_days(181)
create_cert_that_expires_in_days(1)
certificate_1 = create_ca_cert_that_expires_in_days(180)
certificate_2 = create_ca_cert_that_expires_in_days(365)
create_ca_cert_that_expires_in_days(364)
create_ca_cert_that_expires_in_days(366)
create_ca_cert_that_expires_in_days(179)
create_ca_cert_that_expires_in_days(181)
create_ca_cert_that_expires_in_days(1)
assert set(get_expiring_authority_certificates()) == {certificate_1, certificate_2}
@ -147,19 +147,19 @@ def test_send_authority_expiration_notifications():
from lemur.notifications.messaging import send_authority_expiration_notifications
verify_sender_email()
create_cert_that_expires_in_days(180)
create_cert_that_expires_in_days(180) # two on the same day results in a single email
create_cert_that_expires_in_days(365)
create_cert_that_expires_in_days(364)
create_cert_that_expires_in_days(366)
create_cert_that_expires_in_days(179)
create_cert_that_expires_in_days(181)
create_cert_that_expires_in_days(1)
create_ca_cert_that_expires_in_days(180)
create_ca_cert_that_expires_in_days(180) # two on the same day results in a single email
create_ca_cert_that_expires_in_days(365)
create_ca_cert_that_expires_in_days(364)
create_ca_cert_that_expires_in_days(366)
create_ca_cert_that_expires_in_days(179)
create_ca_cert_that_expires_in_days(181)
create_ca_cert_that_expires_in_days(1)
assert send_authority_expiration_notifications() == (2, 0)
def create_cert_that_expires_in_days(days):
def create_ca_cert_that_expires_in_days(days):
now = arrow.utcnow()
not_after = now + timedelta(days=days, hours=1) # a bit more than specified since we'll check in the future