hq/app/model/models.scala (197 lines of code) (raw):
package model
import com.gu.anghammarad.models.{App, Stack, Target, Stage => AnghammaradStage}
import org.joda.time.DateTime
import software.amazon.awssdk.regions.Region
case class AwsAccount(
id: String,
name: String,
roleArn: String,
accountNumber: String
)
case class AwsStack(
id: String,
name: String,
region: String
)
case class IAMCredentialsReport(
generatedAt: DateTime,
entries: List[IAMCredential]
)
case class IAMCredential(
user: String,
arn: String,
creationTime: DateTime,
stack: Option[AwsStack],
passwordEnabled: Option[Boolean],
passwordLastUsed: Option[DateTime],
passwordLastChanged: Option[DateTime],
passwordNextRotation: Option[DateTime],
mfaActive: Boolean,
accessKey1Active: Boolean,
accessKey1LastRotated: Option[DateTime],
accessKey1LastUsedDate: Option[DateTime],
accessKey1LastUsedRegion: Option[Region],
accessKey1LastUsedService: Option[String],
accessKey2Active: Boolean,
accessKey2LastRotated: Option[DateTime],
accessKey2LastUsedDate: Option[DateTime],
accessKey2LastUsedRegion: Option[Region],
accessKey2LastUsedService: Option[String],
cert1Active: Boolean,
cert1LastRotated: Option[DateTime],
cert2Active: Boolean,
cert2LastRotated: Option[DateTime],
tags: List[Tag] = List()
) {
val rootUser = IAMCredential.isRootUser(user)
}
object IAMCredential {
def isRootUser(user: String): Boolean = user == "<root_account>"
}
case class TrustedAdvisorCheck(
id: String,
name: String,
description: String,
category: String
)
case class TrustedAdvisorDetailsResult[A <: TrustedAdvisorCheckDetails](
checkId: String,
status: String,
timestamp: DateTime,
flaggedResources: List[A],
resourcesIgnored: Long,
resourcesFlagged: Long,
resourcesSuppressed: Long
)
sealed trait TrustedAdvisorCheckDetails
case class SGOpenPortsDetail(
status: String,
region: String,
name: String,
id: String,
vpcId: String,
protocol: String,
port: String,
alertLevel: String,
isSuppressed: Boolean,
vpcName: Option[String] = None,
stackId : Option[String] = None,
stackName : Option[String] = None
) extends TrustedAdvisorCheckDetails
case class RDSSGsDetail(
region: String,
rdsSgId: String,
ec2SGId: String,
alertLevel: String,
isSuppressed: Boolean
) extends TrustedAdvisorCheckDetails
case class ExposedIAMKeyDetail(
keyId: String,
username: String,
fraudType: String,
caseId: String,
updated: String,
location: String,
deadline: String,
usage: String
) extends TrustedAdvisorCheckDetails
case class BucketDetail(
region: String,
bucketName: String,
status: String,
aclAllowsRead: Boolean,
aclAllowsWrite: Boolean,
policyAllowsAccess: Boolean,
isSuppressed: Boolean,
reportStatus: Option[ReportStatus] = None,
isEncrypted: Boolean = false
) extends TrustedAdvisorCheckDetails
sealed trait BucketEncryptionResponse
case object Encrypted extends BucketEncryptionResponse
case object NotEncrypted extends BucketEncryptionResponse
case object BucketNotFound extends BucketEncryptionResponse
sealed trait Stage
case object DEV extends Stage
case object PROD extends Stage
case class CredentialReportDisplay(
reportDate: DateTime,
machineUsers: Seq[MachineUser] = Seq.empty,
humanUsers: Seq[HumanUser] = Seq.empty
)
sealed trait KeyStatus
object AccessKeyEnabled extends KeyStatus
object AccessKeyDisabled extends KeyStatus
object NoKey extends KeyStatus
case class AccessKey(
keyStatus: KeyStatus,
lastRotated: Option[DateTime]
)
sealed trait ReportStatus {
def reasons(): Seq[ReportStatusReason] = Seq.empty
}
case class Red(override val reasons: Seq[ReportStatusReason] = Seq.empty) extends ReportStatus
case class Amber(override val reasons: Seq[ReportStatusReason] = Seq.empty) extends ReportStatus
case object Green extends ReportStatus
case object Blue extends ReportStatus
sealed trait ReportStatusReason
object MissingMfa extends ReportStatusReason
object OutdatedKey extends ReportStatusReason
object ActiveAccessKey extends ReportStatusReason
object MissingUsernameTag extends ReportStatusReason
case class Tag(key: String, value: String)
object Tag {
val EMPTY_SSAID = "no-ssa-tags"
def findAnghammaradTarget(key: String, toTarget: String => Target, tags: List[Tag]): Option[Target] = {
val value = tags.find(_.key.toLowerCase() == key.toLowerCase()).map(_.value)
value.map(toTarget)
}
def tagsToAnghammaradTargets(tags: List[Tag]): List[Target] = {
List (
findAnghammaradTarget("stack", Stack, tags),
findAnghammaradTarget("stage", AnghammaradStage, tags),
findAnghammaradTarget("app", App, tags),
).flatten
}
def tagsToSSAID(tags: List[Tag]): String = {
val ssaTags = tags.filter(t => List("stack", "stage", "app").contains(t.key.toLowerCase))
if (ssaTags.nonEmpty) {
ssaTags.sortBy(_.key).map(_.value).mkString("-")
} else {
EMPTY_SSAID
}
}
}
sealed trait IAMUser {
def username: String
def key1: AccessKey
def key2: AccessKey
def reportStatus: ReportStatus
def lastActivityDay: Option[Long]
def stack: Option[AwsStack]
def tags: List[Tag]
def isHuman: Boolean
}
case class HumanUser(
username: String,
hasMFA: Boolean,
key1: AccessKey,
key2: AccessKey,
reportStatus: ReportStatus,
lastActivityDay: Option[Long],
stack: Option[AwsStack],
tags: List[Tag]
) extends IAMUser {
val isHuman = true
}
case class MachineUser(
username: String,
key1: AccessKey,
key2: AccessKey,
reportStatus: ReportStatus,
lastActivityDay: Option[Long],
stack: Option[AwsStack],
tags: List[Tag]
) extends IAMUser {
val isHuman = false
}
case class Documentation(title: String, description: String, icon: String, slug: String)