hq/app/logging/Cloudwatch.scala (61 lines of code) (raw):

package logging import logic.CredentialsReportDisplay.{ReportSummary, reportStatusSummary} import model.{AwsAccount, CredentialReportDisplay} import play.api.Logging import utils.attempt.FailedAttempt import scala.jdk.CollectionConverters._ import scala.util.{Failure, Success, Try} import software.amazon.awssdk.services.cloudwatch.CloudWatchClient import software.amazon.awssdk.services.cloudwatch.model.{Dimension, MetricDatum, PutMetricDataRequest, StandardUnit} object Cloudwatch extends Logging { val cloudwatchClient = CloudWatchClient.builder.build() val defaultNamespace = "SecurityHQ" object DataType extends Enumeration { val s3Total = Value("s3/total") val iamCredentialsTotal = Value("iam/credentials/total") val iamCredentialsCritical = Value("iam/credentials/critical") val iamCredentialsWarning = Value("iam/credentials/warning") val iamKeysTotal = Value("iam/keys/total") } object ReaperExecutionStatus extends Enumeration { val success = Value("Success") val failure = Value("Failure") } def logMetricsForCredentialsReport(data: Map[AwsAccount, Either[FailedAttempt, CredentialReportDisplay]] ) : Unit = { data.toSeq.foreach { case (account: AwsAccount, Right(details: CredentialReportDisplay)) => val reportSummary: ReportSummary = reportStatusSummary(details) putAwsMetric(account, DataType.iamCredentialsCritical, reportSummary.errors) putAwsMetric(account, DataType.iamCredentialsWarning, reportSummary.warnings) putAwsMetric(account, DataType.iamCredentialsTotal, reportSummary.errors + reportSummary.warnings) case (account: AwsAccount, Left(_)) => logger.error(s"Attempt to log cloudwatch metric failed. IAM data is missing for account ${account.name}.") } } def logAsMetric[T](data: Map[AwsAccount, Either[FailedAttempt, List[T]]], dataType: DataType.Value ) : Unit = { data.toSeq.foreach { case (account: AwsAccount, Right(details: List[T])) => putAwsMetric(account, dataType, details.length) case (account: AwsAccount, Left(_)) => logger.error(s"Attempt to log cloudwatch metric failed. Data of type ${dataType} is missing for account ${account.name}.") } } def putAwsMetric(account: AwsAccount, dataType: DataType.Value , value: Int): Unit = { putMetric(defaultNamespace, "Vulnerabilities", Seq(("Account", account.name),("DataType", dataType.toString)), value) } def putIamRemovePasswordMetric(reaperExecutionStatus: ReaperExecutionStatus.Value, value: Int): Unit = { putMetric(defaultNamespace, "IamRemovePassword", Seq(("ReaperExecutionStatus", reaperExecutionStatus.toString)), value) } def putIamDisableAccessKeyMetric(reaperExecutionStatus: ReaperExecutionStatus.Value): Unit = { putMetric(defaultNamespace, "IamDisableAccessKey", Seq(("ReaperExecutionStatus", reaperExecutionStatus.toString)), 1) } private def putMetric(namespace: String, metricName: String, metricDimensions: Seq[(String, String)] , value: Int): Unit = { val dimension = metricDimensions.map( d => Dimension.builder.name(d._1).value(d._2).build()).toList val datum = MetricDatum.builder.metricName(metricName).unit(StandardUnit.COUNT).value(value.toDouble).dimensions(dimension.asJava).build() val request = PutMetricDataRequest.builder.namespace(namespace).metricData(datum).build() Try(cloudwatchClient.putMetricData(request)) match { case Success(_) => logger.debug(s"putMetric success: $datum") case Failure(e) => logger.error(s"putMetric failure: $datum", e) } } }