AWSTemplateFormatVersion: 2010-09-09
Description: Create IAM roles and CloudWatch Dashboard widgets for visualizing EC2-based VPN metrics.

Parameters:
  IAMInstanceProfileName:
    Type: String
    Default: EC2-CloudWatch-Metrics
    MinLength: '1'
    MaxLength: '128'
    AllowedPattern: '[\w+=,.@-]+'
    Description: The name for the IAM instance profile.
  BGPLogGroupName:
    Type: String
    Default: EC2-VPN-BGPRoutesReceived
    MinLength: '1'
    MaxLength: '512'
    AllowedPattern: '[\.\-_/#A-Za-z0-9]+'
    Description: The name for the CloudWatch Logs log group.
  CWDashboardName:
    Type: String
    MinLength: '1'
    MaxLength: '255'
    Default: EC2-VPN-Dashboard
    Description: The name for the CloudWatch dashboard.
  EC2InstanceId:
    Type: AWS::EC2::Instance::Id
    Description: The EC2 instance ID of the instance running VPN software that will be monitored.
  TargetIPv4Address:
    Type: String
    MinLength: '7'
    MaxLength: '15'
    Description: An IPv4 address on the remote end of the VPN that will be monitored for latency.
    
Resources:
  EC2CloudWatchRole:
    Type: AWS::IAM::Role
    Properties: 
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - 
            Effect: "Allow"
            Principal: 
              Service: 
                - "ec2.amazonaws.com"
            Action: 
              - "sts:AssumeRole"
              
  EC2CloudWatchPolicy:
    Type: AWS::IAM::Policy
    Properties: 
      PolicyName: "EC2CloudWatchPolicy"
      PolicyDocument: 
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action: cloudwatch:PutMetricData
            Resource: "*"
            Condition:
              StringEquals:
                "cloudwatch:namespace": "EC2-VPN"
          - Effect: Allow
            Action: logs:DescribeLogStreams
            Resource: !Join ['',['arn:aws:logs:', !Ref 'AWS::Region', ':', !Ref 'AWS::AccountId', ':log-group:', !Ref BGPLogGroupName, ':log-stream:*']]
          - Effect: Allow
            Action: logs:PutLogEvents
            Resource: !Join ['',['arn:aws:logs:', !Ref 'AWS::Region', ':', !Ref 'AWS::AccountId', ':log-group:', !Ref BGPLogGroupName, ':log-stream:*']]
      Roles: 
        - !Ref EC2CloudWatchRole

  EC2IAMInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties: 
      InstanceProfileName: !Ref IAMInstanceProfileName
      Roles: 
        - !Ref EC2CloudWatchRole
  
  CloudWatchLogsLogGroup:  
    Type: AWS::Logs::LogGroup
    Properties: 
      LogGroupName: !Ref BGPLogGroupName
      RetentionInDays: 400
  
  CloudWatchLogsLogStream:  
    Type: AWS::Logs::LogStream
    Properties: 
      LogGroupName: !Ref BGPLogGroupName
      LogStreamName: !Ref EC2InstanceId
    DependsOn: CloudWatchLogsLogGroup
    
  CloudWatchInsightsRule:
    Type: AWS::CloudWatch::InsightRule
    Properties:
      RuleBody: !Sub
         |-
            {
                "AggregateOn": "Count",
                "Contribution": {
                    "Filters": [],
                    "Keys": [
                        "$.bgp_route"
                    ]
                },
                "LogFormat": "JSON",
                "LogGroupNames": [
                    "EC2-VPN-BGPRoutesReceived"
                ],
                "Schema": {
                    "Name": "CloudWatchLogRule",
                    "Version": 1
                }
            }
      RuleName: "BGP-Routes"
      RuleState: ENABLED

  DashboardSideBySide:
    Type: AWS::CloudWatch::Dashboard
    Properties:
      DashboardName: !Ref CWDashboardName
      DashboardBody: !Sub
        - |
            {
                "widgets": [
                    {
                        "height": 6,
                        "width": 9,
                        "y": 0,
                        "x": 0,
                        "type": "metric",
                        "properties": {
                            "view": "timeSeries",
                            "stacked": false,
                            "metrics": [
                                [ "EC2-VPN", "LatencyAverage", "Target", "${TargetIPv4Address}", "InstanceId", "${EC2InstanceId}" ]
                            ],
                            "region": "${AWS::Region}",
                            "yAxis": {
                                "left": {
                                    "label": "Latency (ms)",
                                    "showUnits": false
                                }
                            },
                            "period": 300,
                            "stat": "Average",
                            "title": "Latency Avg to ${TargetIPv4Address}"
                        }
                    },
                    {
                        "height": 6,
                        "width": 9,
                        "y": 0,
                        "x": 9,
                        "type": "metric",
                        "properties": {
                            "view": "timeSeries",
                            "stacked": false,
                            "metrics": [
                                [ "EC2-VPN", "ReceivedBGPRouteCount", "InstanceId", "${EC2InstanceId}" ]
                            ],
                            "region": "${AWS::Region}",
                            "yAxis": {
                                "left": {
                                    "label": "Count",
                                    "showUnits": false
                                }
                            },
                            "period": 300,
                            "title": "ReceivedBGPRouteCount"
                        }
                    },
                    {
                        "height": 6,
                        "width": 12,
                        "y": 6,
                        "x": 12,
                        "type": "log",
                        "properties": {
                            "query": "SOURCE 'EC2-VPN-BGPRoutesReceived' | fields @timestamp, @message\n| sort @timestamp desc\n| limit 20",
                            "region": "${AWS::Region}",
                            "stacked": false,
                            "view": "table"
                        }
                    },
                    {
                        "type": "metric",
                        "x": 0,
                        "y": 6,
                        "width": 12,
                        "height": 6,
                        "properties": {
                            "period": 300,
                            "region": "${AWS::Region}",
                            "stacked": false,
                            "timezone": "local",
                            "title": "BGP Prefix Insights",
                            "view": "timeSeries",
                            "insightRule": {
                                "maxContributorCount": 30,
                                "orderBy": "Sum",
                                "ruleName": "BGP-Routes"
                            },
                            "legend": {
                                "position": "bottom"
                            }
                        }
                    }
                ]
            }
        - TargetIPv4Address: !Ref TargetIPv4Address
          EC2InstanceId: !Ref EC2InstanceId
          BGPLogGroupName: !Ref BGPLogGroupName
Outputs:
    Dashboard:
        Description: "Dashboard created to monitor EC2-based VPN"
        Value: !Sub |
            https://${AWS::Region}.console.aws.amazon.com/cloudwatch/home#dashboards:name=${CWDashboardName}