class CfnGuardian::Stacks::Main

Attributes

parameters[R]
template[R]

Public Class Methods

new() click to toggle source
# File lib/cfnguardian/stacks/main.rb, line 11
def initialize()
  @parameters = []
  @template = CloudFormation("Guardian main stack")
end

Public Instance Methods

add_iam_role(ssm_parameters) click to toggle source
# File lib/cfnguardian/stacks/main.rb, line 40
def add_iam_role(ssm_parameters)
  policies = []
  policies << {
    PolicyName: 'logging',
    PolicyDocument: {
      Version: '2012-10-17',
      Statement: [{
        Effect: 'Allow',
        Action: [ 'logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents' ],
        Resource: 'arn:aws:logs:*:*:*'
      }]
    }
  }
  policies << {
    PolicyName: 'metrics',
    PolicyDocument: {
      Version: '2012-10-17',
      Statement: [{
        Effect: 'Allow',
        Action: [ 'cloudwatch:PutMetricData' ],
        Resource: '*'
      }]
    }
  }
  policies << {
    PolicyName: 'attach-network-interface',
    PolicyDocument: {
      Version: '2012-10-17',
      Statement: [{
        Effect: 'Allow',
        Action: [ 'ec2:CreateNetworkInterface', 'ec2:DescribeNetworkInterfaces', 'ec2:DeleteNetworkInterface' ],
        Resource: '*'
      }]
    }
  }
  policies << {
    PolicyName: 'maintenance-group-actions',
    PolicyDocument: {
      Version: '2012-10-17',
      Statement: [{
        Effect: 'Allow',
        Action: [ 'cloudwatch:DescribeAlarms', 'cloudwatch:DisableAlarmActions', 'cloudwatch:EnableAlarmActions', 'cloudwatch:SetAlarmState' ],
        Resource: FnSub("arn:aws:cloudwatch:${AWS::Region}:${AWS::AccountId}:alarm:*")
      }]
    }
  }
  if ssm_parameters.any?
    policies << {
      PolicyName: 'ssm-parameters',
      PolicyDocument: {
        Version: '2012-10-17',
        Statement: [{
          Effect: 'Allow',
          Action: [ 'ssm:GetParameter', 'ssm:GetParametersByPath', 'ssm:GetParameters' ],
          Resource: ssm_parameters.map {|param| FnSub("arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter#{param}") }
        }]
      }
    }
  end
  @template.declare do
    IAM_Role(:LambdaExecutionRole) do
      AssumeRolePolicyDocument({
        Version: '2012-10-17',
        Statement: [{
          Effect: 'Allow',
          Principal: { Service: [ 'lambda.amazonaws.com' ] },
          Action: [ 'sts:AssumeRole' ]
        }]
      })
      Path '/guardian/'
      Policies(policies)
      Tags([
        { Key: 'Name', Value: 'guardian-lambda-role' },
        { Key: 'Environment', Value: 'guardian' }
      ])
    end
  end
end
add_lambda(check) click to toggle source
# File lib/cfnguardian/stacks/main.rb, line 119
def add_lambda(check)
  vpc_config = {}
  if !check.vpc.nil?
    @template.declare do
      EC2_SecurityGroup("#{check.name}SecurityGroup#{check.environment}") do
        VpcId check.vpc
        GroupDescription "Guardian lambda function #{check.group} check"
        Tags([
          { Key: 'Name', Value: "guardian-#{check.name}-#{check.environment}" },
          { Key: 'Environment', Value: 'guardian' }
        ])
      end
    end
    
    vpc_config[:SecurityGroupIds] = [Ref("#{check.name}SecurityGroup#{check.environment}")]
    vpc_config[:SubnetIds] = check.subnets
  end
  
  @template.declare do
    Lambda_Function("#{check.name}Function#{check.environment}") do
      Code({ 
        S3Bucket: FnSub("base2.guardian.lambda.checks.${AWS::Region}"), 
        S3Key: "#{check.package}/master/#{check.version}.zip"
      })
      Handler check.handler
      MemorySize check.memory
      Runtime check.runtime
      Timeout check.timeout
      Role FnGetAtt(:LambdaExecutionRole, :Arn)
      VpcConfig vpc_config unless vpc_config.empty?
      Tags([
        { Key: 'Name', Value: "guardian-#{check.name}-#{check.group}" },
        { Key: 'Environment', Value: 'guardian' }
      ])
    end
    
    Lambda_Permission("#{check.name}Permissions#{check.environment}") do
      FunctionName Ref("#{check.name}Function#{check.environment}")
      Action 'lambda:InvokeFunction'
      Principal 'events.amazonaws.com'
    end
  end

  return FnGetAtt("#{check.name}Function#{check.environment}", :Arn)
end
add_maintenance_group(group,config,parameters) click to toggle source
# File lib/cfnguardian/stacks/main.rb, line 179
def add_maintenance_group(group,config,parameters)
  group_name = "#{group}MaintenanceGroup"
  schedules = config.fetch('Schedules', {})
  logging = config.dig('Schedules', 'Debug').to_s

  topic = @template.SNS_Topic(group_name)
  topic.TopicName group_name
  topic.Tags([{ Key: 'Environment', Value: 'guardian' }])
  parameters[group_name] = Ref(group_name)

  if schedules.any?
    event = @template.Events_Rule("#{group_name}EnableEvent")
    event.Name "#{group_name}EnableEvent"
    event.ScheduleExpression "cron(#{schedules['Enable']})"
    event.Targets([{ 
      Arn: FnGetAtt('MaintenanceGroupCheckFunction', 'Arn'), 
      Id: "#{group_name}EnableTarget", 
      Input: {action:"enable_alarms", maintenance_group: group_name, logging: logging}.to_json
    }])

    event = @template.Events_Rule("#{group_name}DisableEvent")
    event.Name "#{group_name}DisableEvent"
    event.ScheduleExpression "cron(#{schedules['Disable']})"            
    event.Targets([{ 
      Arn: FnGetAtt('MaintenanceGroupCheckFunction', 'Arn'), 
      Id: "#{group_name}DisableTarget", 
      Input: {action:"disable_alarms", maintenance_group: group_name, logging: logging}.to_json
    }])
  end
end
add_stack(name,url,stack_parameters,stack_id) click to toggle source
# File lib/cfnguardian/stacks/main.rb, line 165
def add_stack(name,url,stack_parameters,stack_id)
  @template.declare do
    CloudFormation_Stack(name) do
      Parameters stack_parameters
      TemplateURL url
      TimeoutInMinutes 15
      Tags([
        { Key: 'Name', Value: "guardian-stack-#{name}" },
        { Key: 'guardian:stack-id', Value: "stk#{stack_id}"}
      ])
    end
  end
end
build_template(stacks,checks,topics,maintenance_groups,ssm_parameters) click to toggle source
# File lib/cfnguardian/stacks/main.rb, line 16
def build_template(stacks,checks,topics,maintenance_groups,ssm_parameters)     
  parameters = {}
     
  topics.each do |name, sns|
    parameter = @template.Parameter(name)
    parameter.Type 'String'
    parameter.Description "SNS topic ARN for #{name} notifications"
    parameter.Default sns
    parameters[name] = Ref(name)
  end

  if maintenance_groups.any?
    add_lambda(CfnGuardian::Models::MaintenanceGroupCheck.new(maintenance_groups))
    maintenance_groups.each {|group,config| add_maintenance_group(group,config,parameters)}
  end
  
  add_iam_role(ssm_parameters)
          
  checks.each {|check| parameters["#{check.name}Function#{check.environment}"] = add_lambda(check)}
  stacks.each {|stack| add_stack(stack['Name'],stack['TemplateURL'],parameters,stack['Reference'])}
  
  @parameters = parameters.keys
end