class Chef::Provider::AwsNetworkAcl

Public Instance Methods

action_create() click to toggle source
Calls superclass method
# File lib/chef/provider/aws_network_acl.rb, line 10
def action_create
  network_acl = super

  apply_rules(network_acl)
end

Protected Instance Methods

create_aws_object() click to toggle source
# File lib/chef/provider/aws_network_acl.rb, line 18
def create_aws_object
  converge_by "create network ACL #{new_resource.name} in #{region}" do
    options = {}
    options[:vpc_id] = new_resource.vpc if new_resource.vpc
    options = AWSResource.lookup_options(options, resource: new_resource)

    Chef::Log.debug("VPC: #{options[:vpc_id]}")

    network_acl = new_resource.driver.ec2_resource.create_network_acl(options)
    retry_with_backoff(::Aws::EC2::Errors::InvalidNetworkAclIDNotFound) do
      network_acl.create_tags(tags: [{ key: "Name", value: new_resource.name }])
    end
    network_acl
  end
end
destroy_aws_object(network_acl) click to toggle source
# File lib/chef/provider/aws_network_acl.rb, line 43
def destroy_aws_object(network_acl)
  # TODO: if purging, do we need to destory the linked subnets?
  converge_by "delete #{new_resource} in #{region}" do
    network_acl.delete
  end
end
update_aws_object(network_acl) click to toggle source
# File lib/chef/provider/aws_network_acl.rb, line 34
def update_aws_object(network_acl)
  unless new_resource.vpc.nil?
    desired_vpc = Chef::Resource::AwsVpc.get_aws_object_id(new_resource.vpc, resource: new_resource)
    if desired_vpc != network_acl.vpc_id
      raise "Network ACL VPC cannot be changed after being created!  Desired VPC for #{new_resource} was #{new_resource.vpc} (#{desired_vpc}) and actual VPC is #{network_acl.vpc_id}"
    end
  end
end

Private Instance Methods

add_rules(network_acl, rules) click to toggle source
# File lib/chef/provider/aws_network_acl.rb, line 110
def add_rules(network_acl, rules)
  rules.each do |rule|
    action_handler.report_progress "  add #{rule_direction(rule)} rule #{rule[:rule_number]}"
    network_acl.create_entry(rule)
  end
end
apply_rules(network_acl) click to toggle source
# File lib/chef/provider/aws_network_acl.rb, line 52
def apply_rules(network_acl)
  current_rules = network_acl.entries.map { |entry| entry_to_hash(entry) }
  inbound_rules = new_resource.inbound_rules
  outbound_rules = new_resource.outbound_rules
  # AWS requires a deny all rule at the end. Delete here so we don't
  # try to compare.
  current_rules.delete_if { |rule| rule[:rule_number] == 32_767 }

  current_inbound_rules = current_rules.select { |rule| rule[:egress] == false }
  # If inbound_rules is nil, leave rules alone. If empty array, delete all.
  if inbound_rules
    desired_inbound_rules = inbound_rules.map { |rule| rule[:egress] = false; rule }
    compare_and_apply_rules(network_acl, :ingress, current_inbound_rules, desired_inbound_rules)
  end

  current_outbound_rules = current_rules.select { |rule| rule[:egress] == true }
  if outbound_rules
    desired_outbound_rules = outbound_rules.map { |rule| rule[:egress] = true; rule }
    compare_and_apply_rules(network_acl, :egress, current_outbound_rules, desired_outbound_rules)
  end
end
compare_and_apply_rules(network_acl, direction, current_rules, desired_rules) click to toggle source
# File lib/chef/provider/aws_network_acl.rb, line 74
def compare_and_apply_rules(network_acl, direction, current_rules, desired_rules)
  replace_rules = []

  # Get the desired rules in a comparable state
  desired_rules.clone.each do |desired_rule|
    matching_rule = current_rules.select { |r| r[:rule_number] == desired_rule[:rule_number] }.first
    next unless matching_rule
    # Anything unhandled will be removed
    current_rules.delete(matching_rule)
    # Anything unhandled will be added
    desired_rules.delete(desired_rule)

    # Converting matching_rule [:rule_action] and [:port_range] to symbol & hash to match correctly with desired_rule
    matching_rule[:rule_action] = matching_rule[:rule_action].to_sym unless matching_rule[:rule_action].nil?
    matching_rule[:port_range] = matching_rule[:port_range].to_hash unless matching_rule[:port_range].nil?
    if matching_rule.merge(desired_rule) != matching_rule
      # Replace anything with a matching rule number but different attributes
      replace_rules << desired_rule
    end
  end

  unless replace_rules.empty? && desired_rules.empty? && current_rules.empty?
    action_handler.report_progress "update network ACL #{new_resource.name} #{direction} rules"
    replace_rules(network_acl, replace_rules)
    add_rules(network_acl, desired_rules)
    remove_rules(network_acl, current_rules)
  end
end
entry_to_hash(entry) click to toggle source
# File lib/chef/provider/aws_network_acl.rb, line 128
def entry_to_hash(entry)
  options = %i{
    rule_number rule_action protocol cidr_block egress
    port_range icmp_type_code
  }
  entry_hash = {}
  options.each { |option| entry_hash.merge!(option => entry.send(option.to_sym)) }
  entry_hash
end
remove_rules(network_acl, rules) click to toggle source
# File lib/chef/provider/aws_network_acl.rb, line 117
def remove_rules(network_acl, rules)
  rules.each do |rule|
    action_handler.report_progress "  remove #{rule_direction(rule)} rule #{rule[:rule_number]}"
    network_acl.delete_entry(egress: rule[:egress], rule_number: rule[:rule_number])
  end
end
replace_rules(network_acl, rules) click to toggle source
# File lib/chef/provider/aws_network_acl.rb, line 103
def replace_rules(network_acl, rules)
  rules.each do |rule|
    action_handler.report_progress "  update #{rule_direction(rule)} rule #{rule[:rule_number]}"
    network_acl.replace_entry(rule)
  end
end
rule_direction(rule) click to toggle source
# File lib/chef/provider/aws_network_acl.rb, line 124
def rule_direction(rule)
  rule[:egress] == true ? "egress" : "ingress"
end