AWSTemplateFormatVersion: "2010-09-09" Transform: "AWS::Serverless-2016-10-31" Description: Cribl LogStream Free Deployment x86_64 (qs-1skh1tk65) Parameters: vpcId: Description: "REQUIRED: ID of your existing VPC." Type: AWS::EC2::VPC::Id subnetIds: Description: "REQUIRED: ID of one of your existing Subnet IDs. This subnet must be in the same VPC as VPC ID above." Type: List webAccessCidr: Type: String AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/x Description: "REQUIRED: The CIDR IP range permitted to access the LogStream web console. We recommend you set this value to a trusted IP range." SQS: Description: Name of the SQS for VPCFlow Logs. Type: String Default: cribl-vpc-sqs instanceType: Description: EC2 instance type to provision the LogStream instance. If none specified, c5.2xlarge will be used. Type: String Default: c5.xlarge AllowedValues: - c5.xlarge - c5.large - c5d.xlarge - c5d.large - c5a.xlarge - c5a.large - c5ad.xlarge - c5ad.large ConstraintDescription: Must contain valid instance type Metadata: cfn-lint: config: ignore_checks: - E9007 ignore_reasons: - "A combination of Serverless Transform and metadata not being passed through (yet) means that we need to globally exclude E9007 until an upstream workaround is available." AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Instance Configuration Parameters: - instanceType - SQS - Label: default: Network Configuration Parameters: - vpcId - subnetIds - webAccessCidr ParameterLabels: instanceType: default: EC2 Instance Type SQS: default: SQS For VPC Flow vpcId: default: VPC ID subnetIds: default: Subnet ID webAccessCidr: default: Web Access CIDR Rules: SubnetsInVPC: Assertions: - Assert: !EachMemberIn - !ValueOfAll - AWS::EC2::Subnet::Id - VpcId - !RefAll "AWS::EC2::VPC::Id" AssertDescription: All subnets must in the VPC # AMIs are for Cribl Stream 3.5.2 - x86_64 Mappings: RegionMap: eu-north-1: ami: ami-0fddc3a120b42abde ap-south-1: ami: ami-01fb369f309b04964 eu-west-3: ami: ami-0071c8c8ecdfefb15 eu-west-2: ami: ami-033ff967626475475 eu-west-1: ami: ami-0b08b4da6556eff4b ap-northeast-2: ami: ami-093d94eeadadfa752 ap-northeast-1: ami: ami-01f96a48dafa133a0 sa-east-1: ami: ami-0b0f08c465a75877b ca-central-1: ami: ami-0f7018c93e26a01a6 ap-southeast-1: ami: ami-0f9698333c541fa14 ap-southeast-2: ami: ami-03546c3b32d765565 eu-central-1: ami: ami-07406ad5e89a6b6f2 us-east-1: ami: ami-07c1a630ffed73dc6 us-east-2: ami: ami-05c9d3923a591d295 us-west-1: ami: ami-0f859d60acbc06076 us-west-2: ami: ami-0bffe570320ddb944 Resources: ec2SingleSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Cribl LogStream Access VpcId: !Ref vpcId SecurityGroupIngress: - IpProtocol: tcp FromPort: 9000 ToPort: 9000 CidrIp: !Ref webAccessCidr Description: UI access to the LogStream instance SecurityGroupEgress: - IpProtocol: "-1" CidrIp: 0.0.0.0/0 Description: Egress access LoadBalancerExternal: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Type: application Scheme: internet-facing IpAddressType: ipv4 SecurityGroups: - !Ref ec2SingleSecurityGroup Subnets: - !Select [0, !Ref 'subnetIds'] - !Select [1, !Ref 'subnetIds'] CriblTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup DependsOn: LoadBalancerExternal Properties: HealthCheckPort: '9000' HealthCheckProtocol: HTTP Port: 9000 Protocol: HTTP TargetType: instance VpcId: !Ref vpcId CriblWebListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref CriblTargetGroup LoadBalancerArn: !Ref LoadBalancerExternal Port: 9000 Protocol: HTTP CriblWebListenerRule1: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: Actions: - Type: forward TargetGroupArn: !Ref CriblTargetGroup Conditions: - Field: http-request-method HttpRequestMethodConfig: Values: - GET_OR_HEAD ListenerArn: !Ref CriblWebListener Priority: 1 s3DefaultDestinationBucket: Type: AWS::S3::Bucket Properties: PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true Tags: - Key: Name Value: Cribl LogStream default destination bucket LogstreamRole: Type: AWS::IAM::Role Properties: Path: !Sub "/logstream/${AWS::StackName}/" Description: Cribl LogStream default IAM role AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: S3Destinations PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - s3:PutObject - s3:GetObject - s3:ListBucket - s3:GetBucketLocation Resource: - !Sub ${s3DefaultDestinationBucket.Arn} - !Sub ${s3DefaultDestinationBucket.Arn}/* - PolicyName: S3Sources PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - s3:GetObject - s3:GetBucketLocation Resource: - !Sub ${s3DefaultDestinationBucket.Arn} - !Sub ${s3DefaultDestinationBucket.Arn}/* - PolicyName: SQSSources PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - sqs:ReceiveMessage - sqs:DeleteMessage - sqs:GetQueueAttributes - sqs:GetQueueUrl Resource: - !Sub arn:${AWS::Partition}:sqs:${AWS::Region}::${AWS::AccountId}::${SQS} Tags: - Key: Name Value: Cribl LogStream IAM role iamDefaultInstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: !Sub "/logstream/${AWS::StackName}/" Roles: - !Ref LogstreamRole ec2WorkersAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: VPCZoneIdentifier: - !Select [0, !Ref 'subnetIds'] - !Select [1, !Ref 'subnetIds'] TargetGroupARNs: - !Ref CriblTargetGroup DesiredCapacity: "1" MaxSize: "1" MinSize: "0" HealthCheckType: EC2 LaunchTemplate: LaunchTemplateId: !Ref ec2WorkerslaunchTemplate Version: !GetAtt ec2WorkerslaunchTemplate.LatestVersionNumber Tags: - Key: Name Value: Cribl LogStream Worker Nodes ASG PropagateAtLaunch: false ec2WorkersAutoScalingGroupLifecycleHook: Type: AWS::AutoScaling::LifecycleHook Properties: AutoScalingGroupName: !Ref ec2WorkersAutoScalingGroup DefaultResult: ABANDON HeartbeatTimeout: 3600 LifecycleHookName: cribl-logstream-worker-shutdown LifecycleTransition: "autoscaling:EC2_INSTANCE_TERMINATING" ec2WorkerslaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateData: InstanceInitiatedShutdownBehavior: terminate ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", ami] InstanceType: !Ref instanceType IamInstanceProfile: Arn: !GetAtt iamDefaultInstanceProfile.Arn SecurityGroupIds: - !Ref ec2SingleSecurityGroup UserData: !Base64 Fn::Sub: - | #cloud-config runcmd: - /usr/local/bin/configure_logstream.sh -m single -b ${s3DefaultDestinationBucket} - sleep 10 - cloud-init query -f "$(cat /opt/cribl_build/users.json.j2)" > /opt/cribl/local/cribl/auth/users.json - chown -R cribl:cribl /opt/cribl - s3DefaultDestinationBucket: !Ref s3DefaultDestinationBucket TagSpecifications: - ResourceType: instance Tags: - Key: Name Value: Cribl LogStream Worker Instance - Key: Purpose Value: Machine data analysis workerShutdownEventRule: Type: AWS::Events::Rule Properties: Description: "Cribl LogStream Worker Shutdown Event" EventPattern: source: - "aws.autoscaling" detail-type: - "EC2 Instance-terminate Lifecycle Action" detail: AutoScalingGroupName: - !Ref ec2WorkersAutoScalingGroup State: "ENABLED" Targets: - Arn: !GetAtt functionWorkerShutdown.Arn Id: "WorkerShutdownFunction" lamdbaPermissionWorkerShutdownEventRule: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref functionWorkerShutdown Action: "lambda:InvokeFunction" Principal: "events.amazonaws.com" SourceArn: !GetAtt workerShutdownEventRule.Arn functionWorkerShutdown: Type: AWS::Serverless::Function Properties: Description: Cribl LogStream Worker Shutdown InlineCode: | import boto3 import logging import json import time import os ssm = boto3.client('ssm') autoscaling = boto3.client('autoscaling') # Logging log = logging.getLogger() log.setLevel(logging.DEBUG) def handler(event, context): log.debug("Received event {}".format(json.dumps(event))) command = ssm.send_command( InstanceIds=[event['detail']['EC2InstanceId'],], DocumentName='AWS-RunShellScript', Comment='Gracefully terminate Cribl LogStream worker node', Parameters={"commands":["systemctl disable cribl","systemctl daemon-reload","systemctl stop cribl"],"workingDirectory":[""],"executionTimeout":["3600"]}, CloudWatchOutputConfig={ 'CloudWatchOutputEnabled': True } ) command_id = command['Command']['CommandId'] for x in range(0,59): time.sleep(10) response = ssm.get_command_invocation( CommandId=command_id, InstanceId=event['detail']['EC2InstanceId'], ) if response.get('Status') == 'Success': break else: continue autoscaling.complete_lifecycle_action( LifecycleHookName=event['detail']['LifecycleHookName'], AutoScalingGroupName=event['detail']['AutoScalingGroupName'], LifecycleActionToken=event['detail']['LifecycleActionToken'], LifecycleActionResult='CONTINUE', InstanceId=event['detail']['EC2InstanceId'] ) Policies: - Statement: - Action: ["ssm:SendCommand"] Effect: Allow Resource: "*" Condition: StringEquals: "aws:ResourceTag/aws:ec2launchtemplate:id": !Ref ec2WorkerslaunchTemplate - Action: ["ssm:SendCommand"] Effect: Allow Resource: !Sub "arn:${AWS::Partition}:ssm:${AWS::Region}::document/AWS-RunShellScript" - Action: ["autoscaling:CompleteLifecycleAction"] Effect: Allow Resource: !Sub "arn:${AWS::Partition}:autoscaling:${AWS::Region}:${AWS::AccountId}:autoScalingGroup:*:autoScalingGroupName/${ec2WorkersAutoScalingGroup}" - Action: ["ssm:GetCommandInvocation"] Effect: Allow Resource: "*" Runtime: python3.7 Timeout: 600 Handler: index.handler Outputs: logstreamWebUrlPublic: Value: !Sub http://${LoadBalancerExternal.DNSName}:9000/login Description: Cribl LogStream Web URL (PublicIp) logstreamWebAccessCreds: Value: "admin / EC2 Instance ID" Description: Default Web Access Credentials