AWSTemplateFormatVersion: '2010-09-09' Description: This template deploys a scaling vSensor cluster for monitoring existing VPC subnets. **WARNING** You will be billed for AWS resources you use if you create a stack from this template. (qs-1rmjte82s) Metadata: QuickStartDocumentation: EntrypointName: Parameters for deploying into an existing VPC Order: 2 AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Darktrace appliance configuration Parameters: - ApplianceHostname - AppliancePort - AppliancePushtoken - Label: default: Darktrace vSensor configuration Parameters: - InstanceType - KeyPairName - InstanceSecurityGroups - VsensorUpdatekey - DesiredCapacityASG - MinSizeASG - MaxSizeASG - osSensorHMAC - Label: default: Network configuration Parameters: - DeploymentVPC - VpcCIDRBlock - SshCIDRBlock - Subnets - Label: default: VPC Traffic Mirror configuration Parameters: - TrafficMirrorRuleNumber - TrafficMirrorSourceCIDR - TrafficMirrorDestCIDR - Label: default: Logs and captured packet retention Parameters: - LogGroupRetention - LifecycleS3BucketDays - Label: default: Quick Start configuration Parameters: - QSS3BucketName - QSS3BucketRegion - QSS3KeyPrefix - ShortID ParameterLabels: # Appliance Config ApplianceHostname: default: Appliance host name AppliancePort: default: Appliance port AppliancePushtoken: default: Appliance push token # vSensor Config InstanceType: default: EC2 instance type KeyPairName: default: EC2 key pair Name InstanceSecurityGroups: default: Security groups VsensorUpdatekey: default: Update key DesiredCapacityASG: default: Desired vSensor instance capacity MinSizeASG: default: Minimum vSensor instance capacity MaxSizeASG: default: Maximum vSensor instance capacity osSensorHMAC: default: osSensor HMAC Token # Networking Config DeploymentVPC: default: Deployment VPC VpcCIDRBlock: default: VPC CIDR block SshCIDRBlock: default: SSH CIDR block Subnets: default: Subnets # Traffic Mirror Config TrafficMirrorRuleNumber: default: Traffic Mirror rule number TrafficMirrorSourceCIDR: default: Source traffic CIDR to filter (0.0.0.0/0 for all traffic) TrafficMirrorDestCIDR: default: Destination traffic CIDR to filter (0.0.0.0/0 for all traffic) # Logs and PCAPs Config LogGroupRetention: default: CloudWatch logs retention (days) LifecycleS3BucketDays: default: Captured packets storage retention (days) # Quickstart Config QSS3BucketName: default: Quick Start S3 bucket name QSS3BucketRegion: default: Quick Start S3 bucket Region QSS3KeyPrefix: default: Quick Start S3 key prefix ShortID: default: Quick Start unique run ID (12 characters or less) Parameters: # Appliance Config ApplianceHostname: Type: String Description: Host name of the Darktrace appliance. AppliancePort: Type: Number Description: Connection port between vSensor and the Darktrace appliance. Default: 443 AppliancePushtoken: AllowedPattern: ^[a-zA-Z0-9-]{4,64}:[a-zA-Z0-9]{5,63}$ Type: String Description: Push token to authenticate with the appliance. For more information, see the https://customerportal.darktrace.com/login[Darktrace Customer Portal]. NoEcho: true # vSensor Config InstanceType: Default: t3.medium Type: String Description: EC2 instance type. Default is `t3.medium`. AllowedValues: - t3.medium - m5.large - m5.2xlarge - m5.4xlarge KeyPairName: Type: 'AWS::EC2::KeyPair::KeyName' Description: EC2 key pair to use to connect to vSensor. InstanceSecurityGroups: Type: 'CommaDelimitedList' Description: Darktrace vSensor security group IDs. A basic vSensor connectivity Security Group (port 80, 443, 4789 for the VPC) will be additionally added by this cloudformation. VsensorUpdatekey: AllowedPattern: ^[a-zA-Z0-9%\.]+:[a-zA-Z0-9]+$ Type: String Description: Darktrace update key. If you don't have one, contact your Darktrace representative. Default: 'XXXXXX:XXXX' NoEcho: true DesiredCapacityASG: Type: Number Description: Desired number of vSensor instances in the Auto-Scaling group. Default: 1 MinSizeASG: Type: String Description: Minimum number of vSensor instances in the Auto-Scaling group. Default: 1 MaxSizeASG: Type: Number Description: Maximum number of vSensor instances in the Auto-Scaling group. Default: 5 osSensorHMAC: Type: String Description: Hash-based message authentication code (HMAC) token to authenticate osSensors with vSensor. Default: "" NoEcho: true # Networking Config DeploymentVPC: Type: 'AWS::EC2::VPC::Id' Description: VPC of target deployment. VpcCIDRBlock: Type: String Default: '172.16.0.0/12' Description: VPC CIDR block. # TODO: Do we need this? We should find it from DeploymentVPC. SshCIDRBlock: Type: String Default: '172.16.0.0/12' Description: Allowed CIDR block for SSH (Secure Shell) access to vSensor. Subnets: Type: 'List' Description: >- List the Subnet Ids that the vSensor should be launched into. You can specify at most one subnet per Availability Zone. # Traffic Mirror Config TrafficMirrorRuleNumber: Type: Number Description: Enter a priority to assign to the rule. Default: 100 TrafficMirrorSourceCIDR: Type: String Default: '0.0.0.0/0' Description: Source CIDR for the Traffic Mirror filter. Enter `0.0.0.0/0` for all traffic. TrafficMirrorDestCIDR: Type: String Default: '0.0.0.0/0' Description: Destination CIDR for the Traffic Mirror filter. Enter `0.0.0.0/0` for all traffic. # Logs & PCAPs Config LogGroupRetention: Type: Number AllowedValues: - 1 - 3 - 5 - 7 - 14 - 30 - 60 - 90 - 120 - 150 - 180 - 365 - 400 - 545 - 731 - 1827 - 3653 Description: Number of days to retain Cloudwatch logs. Default: 30 LifecycleS3BucketDays: Type: Number Description: Number of days to retain captured packets in Amazon S3. Default: 7 # Quickstart Config QSS3BucketName: AllowedPattern: '^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$' ConstraintDescription: The Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Default: aws-quickstart Description: Name of the S3 bucket for your copy of the Quick Start assets. Keep the default name unless you are customizing the template. Changing the name updates code references to point to a new Quick Start location. This name can include numbers, lowercase letters, uppercase letters, and hyphens, but do not start or end with a hyphen (-). See https://aws-quickstart.github.io/option1.html. Type: String QSS3BucketRegion: Default: 'us-east-1' Description: 'AWS Region where the Quick Start S3 bucket (QSS3BucketName) is hosted. Keep the default Region unless you are customizing the template. Changing this Region updates code references to point to a new Quick Start location. When using your own bucket, specify the Region. See https://aws-quickstart.github.io/option1.html.' Type: String QSS3KeyPrefix: AllowedPattern: '^[0-9a-zA-Z-/]*$' ConstraintDescription: The Quick Start S3 key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slashes (/). The prefix should end with a forward slash (/). Default: quickstart-darktrace-vsensor/ Description: S3 key prefix that is used to simulate a directory for your copy of the Quick Start assets. Keep the default prefix unless you are customizing the template. Changing this prefix updates code references to point to a new Quick Start location. This prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slashes (/). End with a forward slash. See https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html and https://aws-quickstart.github.io/option1.html. Type: String ShortID: AllowedPattern: ^[0-9a-z-]{0,12}$ ConstraintDescription: Unique ID prefix can include up to 12 characters, including numbers, lowercase letters, hyphens (-). Description: Quick Start short unique ID used to identify resources from other installations of this Quick Start. If left empty, a random string is generated. Default: "" Type: String Conditions: UsingDefaultBucket: !Equals - !Ref QSS3BucketName - "aws-quickstart" NotUsingExtraInstanceSecurityGroups: !Equals - !Join [",", !Ref "InstanceSecurityGroups"] - "" Resources: ## Generate a short ID if the user does not define one. # This involves running a Lambda function. # From https://www.itonaut.com/2018/01/03/generate-passwords-in-aws-cloudformation-template/ # Modified to take a user submitted ShortID and return this if provided, else generate the random value. LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole RandomStringLambdaFunction: Type: AWS::Lambda::Function Properties: Code: ZipFile: > const response = require("cfn-response"); const randomString = (length, chars) => { var result = ''; for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)]; return result; }; exports.handler = (event, context) =>{ let str = ""; let length = 12; let shortID = ""; if ("ResourceProperties" in event) { if ("ShortID" in event['ResourceProperties'] && event['ResourceProperties']['ShortID'] != "") { str = event['ResourceProperties']['ShortID']; } else if ("Length" in event['ResourceProperties']) { length = Number(event['ResourceProperties']['Length']); } } if (str == "") { str = randomString(length, '0123456789abcdefghijklmnopqrstuvwxyz'); } const responseData = {IDString: str}; response.send(event, context, response.SUCCESS, responseData); }; Handler: index.handler Runtime: nodejs16.x Role: !GetAtt LambdaExecutionRole.Arn MemorySize: 128 Timeout: 20 Tags: - Key: darktrace-vsensor-quickstart Value: !Ref ShortID TracingConfig: Mode: Active RandomStringLambdaLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/aws/lambda/${RandomStringLambdaFunction}" RetentionInDays: !Ref LogGroupRetention RandomStringLambdaLogPermissions: Type: AWS::IAM::Policy Properties: Roles: - !Ref LambdaExecutionRole PolicyName: !Sub "${RandomStringLambdaFunction}-LogGroup" PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${RandomStringLambdaFunction}" - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${RandomStringLambdaFunction}:*" - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${RandomStringLambdaFunction}:*:*" ShortIDRand: Type: AWS::CloudFormation::CustomResource DependsOn: RandomStringLambdaLogPermissions Properties: Length: 12 ShortID: !Ref ShortID ServiceToken: !GetAtt RandomStringLambdaFunction.Arn vSensorAmiName: Type: AWS::SSM::Parameter Properties: Name: !Sub - "${ShortID}-vSensor-AMI" - ShortID: !GetAtt ShortIDRand.IDString Description: The AMI ID of the autogenerated Darktrace vSensor software AMI image. Type: String Value: "NOT_YET_SET" CreateAMIStack: Type: AWS::CloudFormation::Stack DeletionPolicy: Delete # Ignore Notification ARN in customer env. # kics-scan ignore-line Properties: TemplateURL: !Sub - https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/darktrace-vsensor-ami.template.yaml - S3Bucket: !If - UsingDefaultBucket - !Sub "aws-quickstart-${AWS::Region}" - !Ref "QSS3BucketName" S3Region: !If - UsingDefaultBucket - !Ref "AWS::Region" - !Ref "QSS3BucketRegion" Parameters: TargetAmiSSMName: !Sub - "${ShortID}-vSensor-AMI" - ShortID: !GetAtt ShortIDRand.IDString ShortID: !GetAtt ShortIDRand.IDString VsensorUpdatekey: !Ref VsensorUpdatekey LogGroupName: !Sub - "${ShortID}-vSensor-Logs" - ShortID: !GetAtt ShortIDRand.IDString LogGroupRetention: !Ref LogGroupRetention KeyPairName: !Ref KeyPairName VPCSubnetId: !Select - 0 - !Ref Subnets AMISecurityGroupId: !Ref SecurityGroupvSensor Tags: - Key: "Name" Value: !Sub - "${ShortID}-vSensor-CreateAMI-Stack" - ShortID: !GetAtt ShortIDRand.IDString SecurityGroupvSensor: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: "Security group for ASG vSensor" GroupName: !Sub - "${ShortID}-vSensor-SG" - ShortID: !GetAtt ShortIDRand.IDString VpcId: !Ref DeploymentVPC # SSH Access is configurable by customer # kics-scan ignore-line SecurityGroupIngress: - IpProtocol: tcp Description: Allow SSH management access from the configured SSH CIDR block FromPort: 22 ToPort: 22 CidrIp: !Ref SshCIDRBlock - IpProtocol: tcp Description: Allow osSensors from the VPC CIDR block to send mirrored traffic & allow health check FromPort: 80 ToPort: 80 CidrIp: !Ref VpcCIDRBlock - IpProtocol: tcp Description: Allow osSensors from the VPC CIDR block to register to the vSensor FromPort: 443 ToPort: 443 CidrIp: !Ref VpcCIDRBlock - IpProtocol: udp Description: Allow AWS Traffic Mirroring packets to be ingested FromPort: 4789 ToPort: 4789 CidrIp: !Ref VpcCIDRBlock SecurityGroupEgress: - Description: Allow all outbound traffic to access the Darktrace Packages / Ubuntu CDNs on HTTP. IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 - Description: Allow all outbound traffic to access the Darktrace Packages / Ubuntu CDNs on HTTPS. IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 ScalingPolicy: Type: AWS::AutoScaling::ScalingPolicy # Ignore Classic Load Balancer "LoadBalancerNames". # kics-scan ignore-line Properties: AutoScalingGroupName: !Ref ASG EstimatedInstanceWarmup: 600 PolicyType: TargetTrackingScaling TargetTrackingConfiguration: PredefinedMetricSpecification: PredefinedMetricType: ASGAverageCPUUtilization TargetValue: 75 LaunchTemplate: Type: 'AWS::EC2::LaunchTemplate' DependsOn: "CreateAMIStack" Properties: LaunchTemplateData: UserData: !Base64 'Fn::Sub': - | #!/bin/bash -xe function exittrap() { exitcode="$?" set +e if [ "$exitcode" -gt 0 ]; then echo "Failed to successfully configure vSensor, more details in /var/log/user-data.log" aws autoscaling complete-lifecycle-action --lifecycle-action-result ABANDON --instance-id $INSTANCE_ID --lifecycle-hook-name "${lifecycleHookName}" --auto-scaling-group-name "${autoScalingGroupName}" --region ${AWS::Region} fi systemctl enable unattended-upgrades exit "$exitcode" } touch /etc/darktrace/.userdata-started exec > >(tee -a /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1 trap "exittrap" EXIT # See https://youtu.be/unMiTRw8JVE for an example on how to review this console output if Cloudwatch logging fails. echo "Starting userdata" echo "Getting instance ID and attempt to disable source-dest checking metadata." TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 120" -s` INSTANCE_ID=`curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id -s` aws ec2 modify-instance-attribute --no-source-dest-check --instance-id $INSTANCE_ID --region ${AWS::Region} || echo "Failed to set source-dest. Continuing anyway." # Not serious if this doesn't succeed. cat >CW_AGENT.conf <<'EOF' { "agent": { "metrics_collection_interval": 60, "run_as_user": "root" }, "logs": { "logs_collected": { "files": { "collect_list": [ { "file_path": "/var/log/syslog", "log_group_name": "${vSensorLogGroup}", "log_stream_name": "{instance_id}" }, { "file_path": "/var/log/sabreserver/lite/sabreserverlite.log", "log_group_name": "${vSensorLogGroup}", "log_stream_name": "{instance_id}" }, { "file_path": "/var/log/darktrace-apt-dist-upgrade.log", "log_group_name": "${vSensorLogGroup}", "log_stream_name": "{instance_id}" }, { "file_path": "/var/log/dpkg.log", "log_group_name": "${vSensorLogGroup}", "log_stream_name": "{instance_id}" }, { "file_path": "/var/log/darktrace-bro-keepalive.log", "log_group_name": "${vSensorLogGroup}", "log_stream_name": "{instance_id}" }, { "file_path": "/var/log/apt/term.log", "log_group_name": "${vSensorLogGroup}", "log_stream_name": "{instance_id}" }, { "file_path": "/var/log/apt/history.log", "log_group_name": "${vSensorLogGroup}", "log_stream_name": "{instance_id}" }, { "file_path": "/var/log/darktrace-sabre-mole/manager.log", "log_group_name": "${vSensorLogGroup}", "log_stream_name": "{instance_id}" }, { "file_path": "/var/log/nginx/access.log", "log_group_name": "${vSensorLogGroup}", "log_stream_name": "{instance_id}" }, { "file_path": "/var/log/user-data.log", "log_group_name": "${vSensorLogGroup}", "log_stream_name": "{instance_id}-userdata" } ] } } }, "metrics": { "namespace": "vSensorMetrics", "append_dimensions": { "AutoScalingGroupName": "${!aws:AutoScalingGroupName}", "ImageId": "${!aws:ImageId}", "InstanceId": "${!aws:InstanceId}", "InstanceType": "${!aws:InstanceType}" }, "aggregation_dimensions": [["AutoScalingGroupName"], ["InstanceId", "InstanceType"]], "metrics_collected": { "cpu": { "measurement": [ "cpu_usage_active", "cpu_usage_iowait", "cpu_usage_user", "cpu_usage_system" ], "metrics_collection_interval": 60, "resources": [ "*" ], "totalcpu": false }, "disk": { "measurement": [ "used_percent", "inodes_free" ], "metrics_collection_interval": 60, "resources": [ "*" ] }, "diskio": { "measurement": [ "io_time" ], "metrics_collection_interval": 60, "resources": [ "*" ] }, "mem": { "measurement": [ "mem_used_percent" ], "metrics_collection_interval": 60 }, "net": { "measurement": [ "net_bytes_recv", "net_bytes_sent", "net_drop_in", "net_drop_out", "net_err_in", "net_err_out", "net_packets_sent", "net_packets_recv" ], "metrics_collection_interval": 60, "resources": [ "*" ] }, "statsd": { "metrics_aggregation_interval": 60, "metrics_collection_interval": 10, "service_address": ":8125" }, "swap": { "measurement": [ "swap_used_percent" ], "metrics_collection_interval": 60 } } } } EOF cp ./CW_AGENT.conf /etc/darktrace/ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:./CW_AGENT.conf -s sudo systemctl start amazon-cloudwatch-agent touch /etc/darktrace/.userdata-cw-complete echo "Cloudwatch configuration complete." echo "Running firstboot scripts" /usr/lib/inithooks/firstboot.d/15random-uuid /usr/lib/inithooks/firstboot.d/15regen-sslkeys touch /etc/darktrace/.userdata-firstboot-complete echo "Setting configuration" set_pushtoken.sh ${AppliancePushtoken} ${ApplianceHostname}:${AppliancePort} set_ossensor_loadbalancer_direct.sh 1 set_ephemeral.sh 1 # Configure vSensor for use in ASG. if [ -n "${osSensorHMAC}" ]; then set_ossensor_hmac.sh ${osSensorHMAC} fi set_pcap_s3_bucket.sh ${PCAPS} touch /etc/darktrace/.userdata-config-complete echo "Completed vSensor configuration" service confconsole restart || true # To update AWS screenshot with current config. #set updatekey, upgrade and enable daily updates set_updatekey.sh ${VsensorUpdatekey} touch /etc/darktrace/.userdata-confconsole-restart echo "Successful configuration of vSensor. Telling AWS vSensor is ready for ASG, without waiting for upgrades." aws autoscaling complete-lifecycle-action --lifecycle-action-result CONTINUE --instance-id $INSTANCE_ID --lifecycle-hook-name "${lifecycleHookName}" --auto-scaling-group-name "${autoScalingGroupName}" --region ${AWS::Region} touch /etc/darktrace/.userdata-sent-success apt-get update && /usr/sbin/cron-apt-dist-upgrade.sh || true touch /etc/darktrace/.userdata-completed echo "Userdata script complete." - autoScalingGroupName: !Sub - "${ShortID}-vSensor-ASG" - ShortID: !GetAtt ShortIDRand.IDString lifecycleHookName: !Sub - "${ShortID}-vSensor-LifecycleHook" - ShortID: !GetAtt ShortIDRand.IDString KeyName: !Ref KeyPairName InstanceType: !Ref InstanceType BlockDeviceMappings: - DeviceName: "/dev/sda1" Ebs: VolumeSize: 20 Encrypted: true DeleteOnTermination: true SecurityGroupIds: Fn::If: - NotUsingExtraInstanceSecurityGroups - - !Sub "${SecurityGroupvSensor}" - !Split - "," - !Sub - "${SecurityGroupvSensor},${customerSecurityGroups}" - customerSecurityGroups: !Join [",", !Ref "InstanceSecurityGroups"] IamInstanceProfile: Arn: !GetAtt vSensorIamInstanceProfile.Arn ImageId: !GetAtt vSensorAmiName.Value TagSpecifications: - ResourceType: 'instance' Tags: - Key: 'vSensorProbe' Value: 'YES' Monitoring: Enabled: true LaunchTemplateName: !Sub - "${ShortID}-vSensor-Launch-Template" - ShortID: !GetAtt ShortIDRand.IDString vSensorLogGroup: Type: 'AWS::Logs::LogGroup' Properties: LogGroupName: !Sub - "${ShortID}-vSensor-Logs" - ShortID: !GetAtt ShortIDRand.IDString RetentionInDays: !Ref LogGroupRetention TrafficMirrorTarget: Type: 'AWS::EC2::TrafficMirrorTarget' Properties: NetworkLoadBalancerArn: !Ref LoadBalancer Description: Traffic mirror target associated with a network load balancer Tags: - Key: "Name" Value: !Sub - "${ShortID}-vSensor-Traffic-Mirror-Target" - ShortID: !GetAtt ShortIDRand.IDString TrafficMirrorFilter: Type: 'AWS::EC2::TrafficMirrorFilter' Properties: Description: Mirror filter for scaling vSensor, allow all from given CIDR range Tags: - Key: "Name" Value: !Sub - "${ShortID}-vSensor-Traffic-Filter" - ShortID: !GetAtt ShortIDRand.IDString TrafficMirrorFilterRuleIngress: Type: AWS::EC2::TrafficMirrorFilterRule Properties: Description: 'allow all ingress' DestinationCidrBlock: !Ref TrafficMirrorDestCIDR RuleAction: 'accept' RuleNumber: !Ref TrafficMirrorRuleNumber SourceCidrBlock: !Ref TrafficMirrorSourceCIDR TrafficDirection: 'ingress' TrafficMirrorFilterId: !Ref TrafficMirrorFilter TrafficMirrorFilterRuleEgress: Type: AWS::EC2::TrafficMirrorFilterRule Properties: Description: 'allow all egress' DestinationCidrBlock: !Ref TrafficMirrorDestCIDR RuleAction: 'accept' RuleNumber: !Ref TrafficMirrorRuleNumber SourceCidrBlock: !Ref TrafficMirrorSourceCIDR TrafficDirection: 'egress' TrafficMirrorFilterId: !Ref TrafficMirrorFilter TargetGroupUDP4789: Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' Properties: Name: !Sub - "${ShortID}-vSensor-ASG-UDP4789" - ShortID: !GetAtt ShortIDRand.IDString HealthCheckEnabled: true HealthCheckIntervalSeconds: 30 HealthCheckPath: / HealthCheckPort: '443' HealthCheckProtocol: HTTPS Port: 4789 Protocol: 'UDP' TargetGroupAttributes: - Key: deregistration_delay.connection_termination.enabled Value: true TargetType: 'instance' VpcId: !Ref DeploymentVPC TargetGroupTCP443: Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' Properties: Name: !Sub - "${ShortID}-vSensor-ASG-TCP443" - ShortID: !GetAtt ShortIDRand.IDString HealthCheckEnabled: true HealthCheckIntervalSeconds: 30 HealthCheckPath: / HealthCheckPort: '443' HealthCheckProtocol: HTTPS Port: 443 Protocol: 'TCP' TargetGroupAttributes: - Key: deregistration_delay.connection_termination.enabled Value: true TargetType: 'instance' VpcId: !Ref DeploymentVPC TargetGroupTCP80: Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' Properties: Name: !Sub - "${ShortID}-vSensor-ASG-TCP80" - ShortID: !GetAtt ShortIDRand.IDString HealthCheckEnabled: true HealthCheckIntervalSeconds: 30 HealthCheckPath: / HealthCheckPort: '80' HealthCheckProtocol: HTTP Port: 80 Protocol: 'TCP' TargetGroupAttributes: - Key: deregistration_delay.connection_termination.enabled Value: true TargetType: 'instance' VpcId: !Ref DeploymentVPC ASG: DependsOn: PCAPCleanupBucketOnDelete # Such that on deletion, the ASG is removed before emptying S3. Type: 'AWS::AutoScaling::AutoScalingGroup' Properties: # Give the Autoscaling group itself a name. AutoScalingGroupName: !Sub - "${ShortID}-vSensor-ASG" - ShortID: !GetAtt ShortIDRand.IDString MinSize: !Ref MinSizeASG MaxSize: !Ref MaxSizeASG MetricsCollection: - Granularity: 1Minute DesiredCapacity: !Ref DesiredCapacityASG VPCZoneIdentifier: !Ref Subnets TargetGroupARNs: - !Ref TargetGroupUDP4789 - !Ref TargetGroupTCP443 - !Ref TargetGroupTCP80 LaunchTemplate: Version: !GetAtt - LaunchTemplate - LatestVersionNumber LaunchTemplateId: !Ref LaunchTemplate HealthCheckType: "ELB" HealthCheckGracePeriod: 60 # Give each vSensor a name too. Tags: - Key: Name PropagateAtLaunch: True Value: !Sub - "${ShortID}-vSensor-ASG" - ShortID: !GetAtt ShortIDRand.IDString LifecycleHookSpecificationList: - LifecycleHookName: !Sub - "${ShortID}-vSensor-LifecycleHook" - ShortID: !GetAtt ShortIDRand.IDString DefaultResult: ABANDON HeartbeatTimeout: 300 LifecycleTransition: "autoscaling:EC2_INSTANCE_LAUNCHING" # PCAPS S3 Bucket PCAPS: Type: 'AWS::S3::Bucket' # Ignore Bucket versioning for PCAPS. # kics-scan ignore-line Properties: PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 LifecycleConfiguration: Rules: - Id: !Sub 'DeleteAfter${LifecycleS3BucketDays}Days' ExpirationInDays: !Ref LifecycleS3BucketDays Status: Enabled BucketName: !Sub - "${ShortID}-vsensor-pcaps" - ShortID: !GetAtt ShortIDRand.IDString LoggingConfiguration: LogFilePrefix: "s3logging" PCAPSSSLOnlyPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref PCAPS PolicyDocument: Version: 2012-10-17 Statement: - Action: 's3:*' Effect: Deny Resource: - !Sub 'arn:${AWS::Partition}:s3:::${PCAPS}' Principal: '*' Condition: Bool: "aws:SecureTransport": "false" # From https://gist.github.com/drumadrian/e1601ab34e7f609b5075f65599108960 # Empty the PCAP bucket on Stack deletion to prevent failure. CleanupBucketOnDeleteLambdaRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: "/" Policies: - PolicyName: !Sub - "${ShortID}-vSensor-S3CleanupLambdaPolicy" - ShortID: !GetAtt ShortIDRand.IDString PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - s3:GetBucketVersioning - s3:PutBucketVersioning - s3:ListBucket - s3:ListBucketVersions Resource: - !Sub 'arn:${AWS::Partition}:s3:::${PCAPS}' - Effect: Allow Action: - s3:DeleteObject - s3:DeleteObjectVersion Resource: - !Sub 'arn:${AWS::Partition}:s3:::${PCAPS}/*' CleanupBucketOnDeleteLambda: DependsOn: PCAPS Type: "AWS::Lambda::Function" Properties: Code: ZipFile: | #!/usr/bin/env python # -*- coding: utf-8 -*- import json import boto3 import urllib3 def empty_delete_buckets(bucket_name): """ Empties and deletes the bucket :param bucket_name: :return: """ print("trying to delete the bucket {}".format(bucket_name)) s3_client = boto3.client('s3') s3 = boto3.resource('s3') try: bucket = s3.Bucket(bucket_name).load() except Exception: print("bucket {} does not exist".format(bucket_name)) return # Check if versioning is enabled response = s3_client.get_bucket_versioning(Bucket=bucket_name) status = response.get('Status','') if status == 'Enabled': response = s3_client.put_bucket_versioning(Bucket=bucket_name, VersioningConfiguration={'Status': 'Suspended'}) paginator = s3_client.get_paginator('list_object_versions') page_iterator = paginator.paginate( Bucket=bucket_name ) for page in page_iterator: print(page) if 'DeleteMarkers' in page: delete_markers = page['DeleteMarkers'] if delete_markers is not None: for delete_marker in delete_markers: key = delete_marker['Key'] versionId = delete_marker['VersionId'] s3_client.delete_object(Bucket=bucket_name, Key=key, VersionId=versionId) if 'Versions' in page and page['Versions'] is not None: versions = page['Versions'] for version in versions: print(version) key = version['Key'] versionId = version['VersionId'] s3_client.delete_object(Bucket=bucket_name, Key=key, VersionId=versionId) object_paginator = s3_client.get_paginator('list_objects_v2') page_iterator = object_paginator.paginate( Bucket=bucket_name ) for page in page_iterator: if 'Contents' in page: for content in page['Contents']: key = content['Key'] s3_client.delete_object(Bucket=bucket_name, Key=content['Key']) print ("Successfully emptied the bucket {}".format(bucket_name)) def lambda_handler(event, context): try: bucket = event['ResourceProperties']['BucketName'] if event['RequestType'] == 'Delete': empty_delete_buckets(bucket) else: print("Skipping PCAP bucket deletion, cloudformation stack is not deleting.") sendResponseCfn(event, context, "SUCCESS") except Exception as e: print(e) sendResponseCfn(event, context, "FAILED") def sendResponseCfn(event, context, responseStatus): response_body = {'Status': responseStatus, 'Reason': 'Log stream name: ' + context.log_stream_name, 'PhysicalResourceId': context.log_stream_name, 'StackId': event['StackId'], 'RequestId': event['RequestId'], 'LogicalResourceId': event['LogicalResourceId'], 'Data': json.loads("{}")} json_response_body = json.dumps(response_body) headers = { 'content-type' : '', 'content-length' : str(len(json_response_body)) } try: http = urllib3.PoolManager() response = http.request('PUT', event['ResponseURL'], headers=headers, body=json_response_body) print("Status code:", response.status) except Exception as e: print("send(..) failed executing http.request(..):", e) #requests.put(event['ResponseURL'], data=json.dumps(response_body)) Description: cleanup Bucket on Delete Lambda Lambda function. FunctionName: !Sub - "${ShortID}-vSensor-PCAPS-Cleanup" - ShortID: !GetAtt ShortIDRand.IDString Handler: index.lambda_handler Role: !GetAtt CleanupBucketOnDeleteLambdaRole.Arn Runtime: python3.8 Timeout: 60 Tags: - Key: darktrace-vsensor-quickstart Value: !Ref ShortID TracingConfig: Mode: Active CleanupBucketOnDeleteLambdaLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/aws/lambda/${CleanupBucketOnDeleteLambda}" RetentionInDays: !Ref LogGroupRetention CleanupBucketOnDeleteLambdaLogPermissions: Type: AWS::IAM::Policy Properties: Roles: - !Ref CleanupBucketOnDeleteLambdaRole PolicyName: !Sub "${ShortID}-vSensor-PCAPS-Cleanup-LambdaLogGroup" PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${CleanupBucketOnDeleteLambda}" - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${CleanupBucketOnDeleteLambda}:*" - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${CleanupBucketOnDeleteLambda}:*:*" PCAPCleanupBucketOnDelete: Type: AWS::CloudFormation::CustomResource Properties: ServiceToken: Fn::GetAtt: - "CleanupBucketOnDeleteLambda" - "Arn" BucketName: !Ref PCAPS # LoadBalancer LoadBalancer: Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer' Properties: Name: !Sub - "${ShortID}-vSensor-Balancer" - ShortID: !GetAtt ShortIDRand.IDString LoadBalancerAttributes: - Key: load_balancing.cross_zone.enabled Value: 'true' Subnets: !Ref Subnets Scheme: internal Type: network LoadBalancerListenerUDP4789: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: "forward" TargetGroupArn: !Ref TargetGroupUDP4789 LoadBalancerArn: !Ref LoadBalancer Port: 4789 Protocol: 'UDP' LoadBalancerListenerTCP443: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: "forward" TargetGroupArn: !Ref TargetGroupTCP443 LoadBalancerArn: !Ref LoadBalancer Port: 443 Protocol: 'TCP' LoadBalancerListenerTCP80: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: "forward" TargetGroupArn: !Ref TargetGroupTCP80 LoadBalancerArn: !Ref LoadBalancer Port: 80 Protocol: 'TCP' # vSensor IAM vSensorIamInstanceProfile: Type: 'AWS::IAM::InstanceProfile' Properties: Roles: - Ref: vSensorIamRole InstanceProfileName: !Sub - "${ShortID}-vSensor-IAM-Instance-Profile" - ShortID: !GetAtt ShortIDRand.IDString vSensorIamRole: Type: 'AWS::IAM::Role' Properties: RoleName: !Sub - "${ShortID}-vSensor-IAM-Role" - ShortID: !GetAtt ShortIDRand.IDString AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - 'sts:AssumeRole' ManagedPolicyArns: - !Sub "arn:${AWS::Partition}:iam::aws:policy/CloudWatchAgentServerPolicy" Policies: - PolicyName: ListPCAPBucket PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 's3:ListBucket' - 's3:GetBucketLocation' - 's3:GetLifecycleConfiguration' Resource: - !Sub 'arn:${AWS::Partition}:s3:::${PCAPS}' - PolicyName: AccessPCAPBucket PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 's3:PutObject' - 's3:GetObject' - 's3:DeleteObject' - 's3:PutObjectTagging' Resource: - !Sub 'arn:${AWS::Partition}:s3:::${PCAPS}/*' - PolicyName: "CompleteLifecycleActionAllowPolicy" PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: "autoscaling:CompleteLifecycleAction" Resource: !Sub - "arn:${AWS::Partition}:autoscaling:${AWS::Region}:${AWS::AccountId}:autoScalingGroup:*:autoScalingGroupName/${AutoScalingGroupName}" - AutoScalingGroupName: !Sub - "${ShortID}-vSensor-ASG" - ShortID: !GetAtt ShortIDRand.IDString - PolicyName: "AllowSourceDestCheckModificationPolicy" PolicyDocument: Statement: - Effect: "Allow" Action: "ec2:ModifyInstanceAttribute" Resource: !Sub "arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:instance/*" Outputs: BucketName: Description: Name of the PCAP S3 bucket. Value: !Ref PCAPS LoadBalancer: Description: Network Load Balancer, required for osSensor clients. Value: !Ref LoadBalancer LoadBalancerDNS: Description: DNS name of the Network Load Balancer, required for osSensor clients. Value: !GetAtt LoadBalancer.DNSName TrafficMirrorFilterId: Description: ID of the Traffic Mirror filter generated for Traffic Mirror sessions. Value: !Ref TrafficMirrorFilter TrafficMirrorTargetId: Description: ID of the Traffic Mirror target generated for Traffic Mirror sessions. Value: !Ref TrafficMirrorTarget Postdeployment: Description: See the deployment guide for post-deployment steps. Value: https://aws.amazon.com/quickstart/?quickstart-all.sort-by=item.additionalFields.sortDate&quickstart-all.sort-order=desc&awsm.page-quickstart-all=5