diff --git a/docs/administration.rst b/docs/administration.rst index f7fd3ece..3ef484be 100644 --- a/docs/administration.rst +++ b/docs/administration.rst @@ -292,6 +292,25 @@ Lemur supports sending certificate expiration notifications through SES and SMTP you can send any mail. See: `Verifying Email Address in Amazon SES `_ +.. data:: LEMUR_SES_SOURCE_ARN + :noindex: + + Specifies an ARN to use as the SourceArn when sending emails via SES. + + .. note:: + This parameter is only required if you're using a sending authorization with SES. + See: `Using sending authorization with Amazon SES `_ + + +.. data:: LEMUR_SES_REGION + :noindex: + + Specifies a region for sending emails via SES. + + .. note:: + This parameter defaults to us-east-1 and is only required if you wish to use a different region. + + .. data:: LEMUR_EMAIL :noindex: diff --git a/lemur/certificates/views.py b/lemur/certificates/views.py index 18746636..a066f20f 100644 --- a/lemur/certificates/views.py +++ b/lemur/certificates/views.py @@ -1155,6 +1155,7 @@ class NotificationCertificatesList(AuthenticatedResource): ) parser.add_argument("creator", type=str, location="args") parser.add_argument("show", type=str, location="args") + parser.add_argument("showExpired", type=int, location="args") args = parser.parse_args() args["notification_id"] = notification_id diff --git a/lemur/plugins/lemur_aws/sns.py b/lemur/plugins/lemur_aws/sns.py index c98bbc0c..14109c11 100644 --- a/lemur/plugins/lemur_aws/sns.py +++ b/lemur/plugins/lemur_aws/sns.py @@ -15,16 +15,18 @@ from flask import current_app def publish(topic_arn, certificates, notification_type, **kwargs): sns_client = boto3.client("sns", **kwargs) message_ids = {} + subject = "Lemur: {0} Notification".format(notification_type.capitalize()) for certificate in certificates: - message_ids[certificate["name"]] = publish_single(sns_client, topic_arn, certificate, notification_type) + message_ids[certificate["name"]] = publish_single(sns_client, topic_arn, certificate, notification_type, subject) return message_ids -def publish_single(sns_client, topic_arn, certificate, notification_type): +def publish_single(sns_client, topic_arn, certificate, notification_type, subject): response = sns_client.publish( TopicArn=topic_arn, Message=format_message(certificate, notification_type), + Subject=subject, ) response_code = response["ResponseMetadata"]["HTTPStatusCode"] @@ -48,8 +50,9 @@ def format_message(certificate, notification_type): json_message = { "notification_type": notification_type, "certificate_name": certificate["name"], - "expires": arrow.get(certificate["validityEnd"]).format("YYYY-MM-ddTHH:mm:ss"), # 2047-12-T22:00:00 + "expires": arrow.get(certificate["validityEnd"]).format("YYYY-MM-DDTHH:mm:ss"), # 2047-12-31T22:00:00 "endpoints_detected": len(certificate["endpoints"]), + "owner": certificate["owner"], "details": create_certificate_url(certificate["name"]) } return json.dumps(json_message) diff --git a/lemur/plugins/lemur_aws/tests/test_sns.py b/lemur/plugins/lemur_aws/tests/test_sns.py index ce05c33c..59ef30f2 100644 --- a/lemur/plugins/lemur_aws/tests/test_sns.py +++ b/lemur/plugins/lemur_aws/tests/test_sns.py @@ -20,8 +20,9 @@ def test_format(certificate, endpoint): expected_message = { "notification_type": "expiration", "certificate_name": certificate["name"], - "expires": arrow.get(certificate["validityEnd"]).format("YYYY-MM-ddTHH:mm:ss"), + "expires": arrow.get(certificate["validityEnd"]).format("YYYY-MM-DDTHH:mm:ss"), "endpoints_detected": 0, + "owner": certificate["owner"], "details": "https://lemur.example.com/#/certificates/{name}".format(name=certificate["name"]) } assert expected_message == json.loads(format_message(certificate, "expiration")) @@ -57,7 +58,9 @@ def test_publish(certificate, endpoint): expected_message_id = message_ids[certificate["name"]] actual_message = next( (m for m in received_messages if json.loads(m["Body"])["MessageId"] == expected_message_id), None) - assert json.loads(actual_message["Body"])["Message"] == format_message(certificate, "expiration") + actual_json = json.loads(actual_message["Body"]) + assert actual_json["Message"] == format_message(certificate, "expiration") + assert actual_json["Subject"] == "Lemur: Expiration Notification" def get_options(): diff --git a/lemur/plugins/lemur_email/plugin.py b/lemur/plugins/lemur_email/plugin.py index 5b9c188e..f380c82e 100644 --- a/lemur/plugins/lemur_email/plugin.py +++ b/lemur/plugins/lemur_email/plugin.py @@ -38,7 +38,7 @@ def render_html(template_name, options, certificates): def send_via_smtp(subject, body, targets): """ - Attempts to deliver email notification via SES service. + Attempts to deliver email notification via SMTP. :param subject: :param body: @@ -55,21 +55,26 @@ def send_via_smtp(subject, body, targets): def send_via_ses(subject, body, targets): """ - Attempts to deliver email notification via SMTP. + Attempts to deliver email notification via SES service. :param subject: :param body: :param targets: :return: """ - client = boto3.client("ses", region_name="us-east-1") - client.send_email( - Source=current_app.config.get("LEMUR_EMAIL"), - Destination={"ToAddresses": targets}, - Message={ + ses_region = current_app.config.get("LEMUR_SES_REGION", "us-east-1") + client = boto3.client("ses", region_name=ses_region) + source_arn = current_app.config.get("LEMUR_SES_SOURCE_ARN") + args = { + "Source": current_app.config.get("LEMUR_EMAIL"), + "Destination": {"ToAddresses": targets}, + "Message": { "Subject": {"Data": subject, "Charset": "UTF-8"}, "Body": {"Html": {"Data": body, "Charset": "UTF-8"}}, }, - ) + } + if source_arn: + args["SourceArn"] = source_arn + client.send_email(**args) class EmailNotificationPlugin(ExpirationNotificationPlugin): diff --git a/lemur/static/app/angular/notifications/services.js b/lemur/static/app/angular/notifications/services.js index 02443701..9e8c9b33 100644 --- a/lemur/static/app/angular/notifications/services.js +++ b/lemur/static/app/angular/notifications/services.js @@ -27,7 +27,7 @@ angular.module('lemur') }; NotificationService.getCertificates = function (notification) { - notification.getList('certificates').then(function (certificates) { + notification.getList('certificates', {showExpired: 0}).then(function (certificates) { notification.certificates = certificates; }); }; @@ -40,7 +40,7 @@ angular.module('lemur') NotificationService.loadMoreCertificates = function (notification, page) { - notification.getList('certificates', {page: page}).then(function (certificates) { + notification.getList('certificates', {page: page, showExpired: 0}).then(function (certificates) { _.each(certificates, function (certificate) { notification.roles.push(certificate); });