Custom assessments and standards in Microsoft Defender for Cloud for AWS workloads (Preview)
Published Jan 20 2022 05:34 AM 7,770 Views

Microsoft Defender for Cloud implements AWS security recommendations in the Defender for Cloud portal right alongside Azure recommendations. There are more than 160 out-of-box recommendations for IaaS and PaaS services as well as support for regulatory standards including CIS, PCI and AWS Foundational Security Best Practices. Check out the security recommendations for AWS resources here. To learn more about Defender for cloud and it’s support for AWS, check out this article. You should continuously review the security recommendations to assess and evaluate the current status of your platform's security posture and identify important configuration gaps. 

 

Security standards contain comprehensive sets of security recommendations to help secure your cloud environments.Security teams can either use the readily available regulatory standards like AWS CIS 1.2.0, AWS Foundational Security Best Practices, AWS PCI DSS 3.2.1 and also can create their own custom standards and assessments to meet specific internal requirements.  

 

It is important to understand, there are three types of resources to create and manage custom assessments:

            1.   Assessment – contains:
                      a. assessment details (name, description, severity, remediation logic, etc.)
                      b. assessment logic in KQL
                      c. the standard it belongs to
            2.  Standard – defines a set of assessments
            3.  Standard assignment – defines the scope which the standard will evaluate (e.g. specific AWS account/s)

 

As mentioned, you can either use the built-in regulatory compliance standard or create your own custom standards and assessments.

 

To assign a built-in regulatory compliance standard or a custom standard that has already been created:

           1.  Navigate to environment settings

           2.  Select the relevant account

           3.  Select ‘Standards’

           4.  Select ‘Add’ -> ‘Standard’

           5.  Choose a standard from the drop-down menu

           6.  Select ‘Save’

 

To create a new custom standard:

          1. Navigate to environment settings

          2. Select the relevant account

          3. Select ‘Standards’

          4. Select ‘Add’ -> ‘Standard’

          5. Select ‘New standard’

          6. Fill in a name and description, and select the assessment you want to be included in this standard

          7. Select ‘Save’

 

Picture1.png

This standard will now be assigned on the account you’ve created it in. You can assign the same on other accounts that you have Contributor and up access to.

 

To assign a built-in assessment, or a custom assessment that has already been created:

  1. Navigate to environment settings
  2. Select the relevant account
  3. Select ‘Standards’
  4. Select ‘Add’ -> ‘Assessment’
  5. Select the assessment/s you’d like to assign
  6. Select the standard/s you’d like to add these assessments to
  7. Elect ‘Save’

To create a new custom assessment:

  1. Navigate to environment settings
  2. Select the relevant account
  3. Select ‘Standards’
  4. Select ‘Add’ -> ‘Assessment’
  5. Fill in the assessment details (e.g. name, severity)
  6. Paste the KQL query which will define the assessment logic
    1. If you’d like to create a new query, click the link for ‘Azure Data Explorer’. The explorer will contain mock data on all the native APIs we support, to assist in constructing the queries. The data will appear in the same structure as contracted in the API.
  7. Select the standard/s you’d like to add this assessment to
  8. Select ‘Save’

Picture2.png

 

Table structure

Sample for table ‘EC2_Address’:

        - TimeStamp
                 2021-10-07T10:30:21.403732Z
        - SdksInfo
          {
                 "AWSSDK.EC2": "3.7.5.2"
          }

      - RecordProviderInfo
         {
                "CloudName": "AWS",
                 "CspmDiscoveryCloudRoleArn": "arn:aws:iam::123456789123:role/CSPMMonitoring",
                 "Type": "MultiCloudDiscoveryServiceDataCollector",
                 "HierarchyIdentifier": "123456789123",
                 "ConnectorId": "b3113210-63f9-43c5-a6a7-f14a2a5b3cd0"
           }
      - RecordOrganizationInfo
          {
                 "Type": "MyOrganization",
                 "TenantId": "bda8bc53-d9f8-4248-b9a9-3a6c7fe0b92f",
                 "SubscriptionId": "69444886-de6b-40c5-8b43-065f739fffb9",
                 "ResourceGroupName": "MyResourceGroupName"
           }

     - CorrelationId
        4f5e50e1d92c400caf507036a1237c72
    - RecordRegionalInfo
        {
                "Type": "MultiCloudRegion",
                "RegionUniqueName": "eu-west-2",
                "RegionDisplayName": "EU West (London)",
                "IsGlobalForRecord": false
        }

     - RecordIdentifierInfo
        {
               "Type": "MultiCloudDiscoveryServiceDataCollector",
                "RecordNativeCloudUniqueIdentifier": "arn:aws:ec2:eu-west-2:123456789123:elastic-ip/eipalloc-1234abcd5678efef9",
                "RecordAzureUniqueIdentifier": "/subscriptions/69444886-de6b-40c5-8b43-065f739fffb9/resourcegroups/MyResourceGroupName/providers/Microsoft.Security/securityconnectors/b3113210-63f9-43c5-a6a7-f14a2a5b3cd0/securityentitydata/aws-ec2-elastic-ip-eipalloc-1234abcd5678efef9-eu-west-2",
                "RecordIdentifier": "eipalloc-1234abcd5678efef9-eu-west-2",
                "ResourceProvider": "EC2",
                "ResourceType": "elastic-ip"
         }
      - Record
         {
               "AllocationId": "eipalloc-1234abcd5678efef9",
              "AssociationId": "eipassoc-234abcd5678efef90",
              "CarrierIp": null,
              "CustomerOwnedIp": null,
              "CustomerOwnedIpv4Pool": null,
              "Domain": {
                             "Value": "vpc"
               },
               "InstanceId": "i-0a8fcc00493c4625d",
               "NetworkBorderGroup": "eu-west-2",
               "NetworkInterfaceId": "eni-34abcd5678efef901",
               "NetworkInterfaceOwnerId": "123456789123",
               "PrivateIpAddress": "172.31.21.88",
               "PublicIp": "19.218.211.431",
               "PublicIpv4Pool": "amazon",
                "Tags": [
                            {
                                           "Value": "arn:aws:cloudformation:eu-west-2:123456789123:stack/awseb-e-sjuh4tkr7a-stack/4ff15da0-2512-11ec-ab59-023b28e97f64",
                                            "Key": "aws:cloudformation:stack-id"
                            },
                            {
                                           "Value": "e-sjuh4tkr7a",
                                            "Key": "elasticbeanstalk:environment-id"
                            },
                            {
                                           "Value": "AWSEBEIP",
                                           "Key": "aws:cloudformation:logical-id"
                            },
                            {
                                           "Value": "awseb-e-sjuh4tkr7a-stack",
                                            "Key": "aws:cloudformation:stack-name"
                            },
                            {
                                           "Value": "Mebrennetest3-env",
                                            "Key": "elasticbeanstalk:environment-name"
                             },
                             {
                                            "Value": "Mebrennetest3-env",
                                             "Key": "Name"
                             }
                        ]
                 }

 

The ‘Record’ field contains the data structure as it is returned from the AWS API. Use this field to define conditions which will determine if the resource is healthy or unhealthy.

Note: Access internal properties of ‘Record’ filed using a dot notation. Example: | extend EncryptionType = Record.Encryption.Type

 

Checkout these useful docs to learn and understand more on Kusto Queries:  

 

Query result schema

  1. The last row of the query should return all the original columns (don’t use ‘project’, ‘project-away). End the query with an iff statement that defines the healthy or unhealthy conditions: "| extend HealthStatus = iff([boolean-logic-here], 'UNHEALTHY','HEALTHY')". Check out the example queries below.

Write an assessment query

Examples:

  • Stopped EC2 instances should be removed after a specified time period

         EC2_Instance

         | extend State = tolower(tostring(Record.State.Name.Value))

         | extend StoppedTime = todatetime(tostring(Record.StateTransitionReason))

         | extend HealthStatus = iff(not(State == 'stopped' and StoppedTime < ago(30d)), 'HEALTHY', 'UNHEALTHY')

 

  • EC2 subnets should not automatically assign public IP addresses

         EC2_Subnet

         | extend MapPublicIpOnLaunch = tolower(tostring(Record.MapPublicIpOnLaunch))

         | extend HealthStatus = iff(MapPublicIpOnLaunch == 'false' ,'HEALTHY', 'UNHEALTHY')

 

  • EC2 instances should not use multiple ENIs

         EC2_Instance

         | extend NetworkInterfaces = parse_json(Record)['NetworkInterfaces']

         | extend NetworkInterfaceCount = array_length(parse_json(NetworkInterfaces))

         | extend HealthStatus = iff(NetworkInterfaceCount == 1 ,'HEALTHY', 'UNHEALTHY')

 

  • S3 Block Public Access setting should be enabled at the bucket level

         let HealthyBuckets = S3_BucketPublicAccessBlockConfiguration

         | where Record.BlockPublicAcls == true and Record.IgnorePublicAcls == true and Record.BlockPublicPolicy == true and              Record.RestrictPublicBuckets == true

         | extend BucketName = tostring(Record.BucketName)

         | project BucketName; S3_S3Bucket

         | extend BucketName = tostring(Record.BucketName)

         | extend HealthStatus = iff(BucketName in (HealthyBuckets), 'HEALTHY', 'UNHEALTHY')

 

  • Link the query to a list that's dynamically updated, for allow-listing.

           In this example, the dynamic list is hosted as a CSV file in the Storage account and the query is correlating with the CSV file in the storage account.

           Make sure to create a SASToken from the storage account in order to use it in the query.

     

    Let AllowListInstance = externaldata(Instance:string)  [h"SASToken"] with (ignoreFirstRecord=true);

    EC2_Instance

    | extend Instance = Record.InstanceId

    | where Instance !in (AllowListInstance)

    | extend State = tolower(tostring(Record.State.Name.Value))

    | extend StoppedTime = todatetime(tostring(Record.StateTransitionReason))

    | extend HealthStatus = iff(not(State == 'stopped'andStoppedTime < ago(30d)), 'HEALTHY', 'UNHEALTHY')

To learn more on the externaldata operator, check out this link and this example.  

 

Notes:

  • No need to filter records by Timespan. The assessment service will filter the most recent records on each run.
  • No need to filter by resource ARN, unless intended. The assessment service will run the query on assigned resources.
  • Do not change the values of the original table columns, or use extend to override existing table columns.
  • You may use join and union to evaluate a data type based on another type, as long as the evaluated type is the left-hand of the join/union operator and all right-hand columns added by the operator are removed from the result.
  • If specific scope is filtered in the assessment query (e.g. specific account Id), it will apply on all resources assigned to this query.

For reference, below is a list of the available data types:

API Gateway

ApiGateway_RestApi

ApiGateway_Stage

Auto Scaling

ApplicationAutoScaling_ScalableTarget

AutoScaling_AutoScalingGroup

Certificate Manager (ACM)

CertificateManager_CertificateDetail

CertificateManager_CertificateSummary

CloudFormation

CloudFormation_StackInstance

CloudFormation_StackInstanceSummary

CloudFormation_StackSet

CloudFormation_StackSetSummary

CloudFront

CloudFront_DistributionConfig

CloudFront_DistributionSummary

CloudTrail

CloudTrail_EventSelector

CloudTrail_Trail

CloudTrail_TrailStatus

CloudWatch

CloudWatch_MetricAlarm

CloudWatchLogs_LogGroup

CloudWatchLogs_MetricFilter

CodeBuild

CodeBuild_Project

CodeBuild_ProjectName

CodeBuild_SourceCredentialsInfo

Config

ConfigService_ConfigurationRecorder

ConfigService_ConfigurationRecorderStatus

ConfigService_DeliveryChannel

Database Migration Service (DMS)

DatabaseMigrationService_ReplicationInstance

DynamoDB

DAX_Cluster

DynamoDB_ContinuousBackupsDescription

DynamoDB_TableDescription

DynamoDB_TableName

Elastic Compute Cloud (EC2)

EC2_Address

EC2_CreateVolumePermission

EC2_EbsEncryptionByDefault

EC2_FlowLog

EC2_Image

EC2_Instance

EC2_InstanceStatus

EC2_NetworkAcl

EC2_NetworkInterface

EC2_Region

EC2_Reservation

EC2_RouteTable

EC2_SecurityGroup

EC2_Snapshot

EC2_Subnet

EC2_Volume

EC2_Vpc

EC2_VpcEndpoint

Elastic Container Service (ECS)

ECS_ClusterArn

ECS_Service

ECS_ServiceArn

ECS_TaskDefinition

ECS_TaskDefinitionArn

Elastic File System (EFS)

EFS_FileSystemDescription

Elastic Kubernetes Service (EKS)

EKS_Cluster

EKS_ClusterName

Elastic Beanstalk

ElasticBeanstalk_ConfigurationSettingsDescription

ElasticBeanstalk_EnvironmentDescription

Elastic Load Balancing

ElasticLoadBalancing_LoadBalancer

ElasticLoadBalancing_LoadBalancerAttributes

ElasticLoadBalancingV2_Listener

ElasticLoadBalancingV2_LoadBalancer

ElasticLoadBalancingV2_LoadBalancerAttribute

ElasticLoadBalancingV2_Rule

Elasticsearch

Elasticsearch_DomainInfo

Elasticsearch_DomainStatus

EMR (Amazon Elastic MapReduce)

EMR_Cluster

EMR_ClusterSummary

GuardDuty

GuardDuty_DetectorId

IAM

Iam_AccessKeyLastUsed

Iam_AccessKeyMetadata

Iam_AttachedPolicyType

Iam_CredentialReport

Iam_Group

Iam_ManagedPolicy

Iam_MFADevice

Iam_PasswordPolicy

Iam_PolicyGroup

Iam_PolicyName

Iam_PolicyRole

Iam_PolicyUser

Iam_PolicyVersion

Iam_SummaryMap

Iam_User

Iam_VirtualMFADevice

Key Management Service (KMS)

KMS_KeyListEntry

KMS_KeyMetadata

KMS_KeyRotationStatus

Lambda

Lambda_FunctionConfiguration

Lambda_FunctionPolicy

Network Firewall

NetworkFirewall_Firewall

NetworkFirewall_FirewallMetadata

NetworkFirewall_FirewallPolicy

NetworkFirewall_FirewallPolicyMetadata

NetworkFirewall_RuleGroup

NetworkFirewall_RuleGroupMetadata

Relational Database Service (RDS)

RDS_DBCluster

RDS_DBClusterSnapshot

RDS_DBInstance

RDS_DBSnapshot

RDS_DBSnapshotAttributesResult

RDS_EventSubscription

Redshift

Redshift_Cluster

RedShift_LoggingStatus

RedShift_Parameter

RedShift_ParameterGroup

S3

S3_BucketEncryption

S3_BucketPolicy

S3_BucketPublicAccessBlockConfiguration

S3_ReplicationConfiguration

S3_S3AccessControlList

S3_S3Bucket

S3_S3BucketLoggingConfig

S3_S3Region

S3Control_PublicAccessBlockConfiguration

SageMaker

SageMaker_DescribeNotebookInstanceResponse

SageMaker_NotebookInstanceSummary

Secrets Manager

SecretsManager_DescribeSecretResponse

SecretsManager_SecretListEntry

Simple Notification Service (SNS)

SNS_Subscription

SNS_Topic

SNS_TopicAttributes

Simple Queue Service (SQS)

SQS_Queue

SQS_QueueAttributes

Systems Manager (SSM)

SimpleSystemsManagement_InstanceInformation

SimpleSystemsManagement_ParameterMetadata

SimpleSystemsManagement_ResourceComplianceSummary

Web Application Firewall (WAF)

WAF_LoggingConfiguration

WAF_WebACL

WAF_WebACLSummary

 

Get started today

Co-author & Reviewer:

@OrSerokJeppa 

Version history
Last update:
‎Feb 01 2022 03:28 PM
Updated by: