RubyでVLANとアクセスリストを作成する
概要
私の前職がネットワークに関わる仕事だったので、プログラミングでTCP/IPを表現することに興味がありました。
(いきなり余談ですが、下記の記事はかなり面白いです)
ネットワークの概念にも様々あり、そして私はそのほとんどを忘れていましたが、その中でもなんとなく覚えていたVLANとアクセスリストを作りました。
アクセスリストはWebでいうバリデーションに若干似ており(通していいかどうかを判断する)、AWSなどだとセキュリティグループという名称で同様な概念があるので、なんとなく覚えていました。
用語
VLAN
VLAN( Virtual LAN )とは、物理的な接続形態とは独立して、仮想的なLANセグメントを作る技術です。
VLANはスイッチ内部で論理的にLANセグメントを分割するために使用されます。VLANを使用することでルータやL3スイッチと同じようにL2スイッチでもブロードキャストドメインの分割を行うことができます。
アクセスリスト(ACL)
アクセスコントロールリストとは、通信アクセスを制御するためのリストのことです。一般的には略して
ACLと呼ばれています。ネットワーク管理者は通信要件に従ってACL(Access Control List)を定義して
ルータを通過するパケットに対して、通過を許可するパケット、通過を拒否するパケットを決められます。
開発
1. Deviseクラスの作成
class Device
attr_accessor :ip_address, :vlan
def initialize(ip_address, vlan)
@ip_address = ip_address
@vlan = vlan
end
end
まず、サーバーやPC、スマホなどのインスタンスを後で作るために、Deviceというクラスを作成しておきます。持つのはIPアドレスとどのVLANに属するかという情報です。
2. VLANクラスの作成
class VLAN
attr_reader :id, :name, :subnet
def initialize(id, name, subnet)
@id = id
@name = name
@subnet = subnet
end
end
次にVLANクラスを作ります。持つのはVLAN_ID、VLANの名前、そのVLANのサブネットです。
サブネットは、ここでは192.168.100.0/24
のような形式のデータを指していて、ネットワークアドレスとサブネットマスクで構成されるものです。
3. アクセスリストクラスの作成
class AccessList
def initialize
@entries = []
end
def add_entry(action, source, destination)
@entries << AccessListEntry.new(action, source, destination)
end
def access_allowed?(source_ip, dest_ip)
if @entries.any? { |entry| entry.action == "deny" && entry.matches_traffic?(source_ip, dest_ip) }
return false
end
@entries.any? { |entry| entry.action == "permit" && entry.matches_traffic?(source_ip, dest_ip) }
end
def report_access_result(source_ip, dest_ip)
if access_allowed?(source_ip, dest_ip)
p "この通信は通す!"
else
p "この通信は通さない!"
end
end
class AccessListEntry
require 'ipaddr'
attr_accessor :action, :source, :destination
def ip_within_range?(ip, cidr)
ip_addr = IPAddr.new(ip)
network = IPAddr.new(cidr)
network.include?(ip_addr)
end
def initialize(action, source, destination)
@action = action
@source = source
@destination = destination
end
def matches_traffic?(source_ip, dest_ip)
ip_within_range?(source_ip, @source) && ip_within_range?(dest_ip, @destination)
end
end
end
AccessListEntryからいくと、この人はアクセスリスト本体(AccessList)に追加して、どのアクセスは許可、どのアクセスは拒否、というのを判断するための1つのルールです。
matches_traffic?
で、与えられた出発点IPと、目的地IPが、アクセスリストのエントリーの条件に合致するかを見ています。
AccessListの方は、matches_traffic?
を使用したaccess_allowed?
で、出発点IPと、目的地IP、そしてエントリー(ルール)をもとに、このアクセスを許可するかどうかを判断しています。
そのboolの結果をもとに、report_access_resultで通すか否かを出力しています。
4. 実際にシミュレーションを走らせる
require_relative 'device'
require_relative 'access_list'
require_relative 'vlan'
# VLANの作成
vlan_server = VLAN.new(10, "admin", "10.10.10.0/24")
vlan_engineer = VLAN.new(20, "engineer", "10.10.20.0/24")
vlan_marketing = VLAN.new(30, "marketing", "10.10.30.0/24")
vlan_guest = VLAN.new(40, "guest", "10.10.40.0/24")
# デバイスの作成
db_server = Device.new("10.10.10.1", vlan_server)
http_server = Device.new("10.10.10.2", vlan_server)
engineer_pc = Device.new("10.10.20.1", vlan_engineer)
marketing_pc = Device.new("10.10.30.1", vlan_marketing)
guest_sp = Device.new("10.10.40.1", vlan_guest)
# アクセスリストの作成
access_list = AccessList.new
access_list.add_entry("permit", "10.10.20.0/24", "10.10.10.0/24") # エンジニア部門からサーバー用セグメントへのアクセスを許可
access_list.add_entry("permit", "10.10.30.0/24", "10.10.10.1/32") # マーケティング部門からDBへのアクセスを許可
access_list.add_entry("deny", "10.10.30.0/24", "10.10.10.2/32") # マーケティング部門からHTTPサーバーへのアクセスをブロック
# エンジニア部門からDBへのアクセスは成功
access_list.report_access_result(engineer_pc.ip_address, db_server.ip_address)
# エンジニア部門からHTTPサーバーへのアクセスは成功
access_list.report_access_result(engineer_pc.ip_address, http_server.ip_address)
# マーケティング部門からHTTPサーバーへのアクセスは失敗
access_list.report_access_result(marketing_pc.ip_address, http_server.ip_address)
# マーケティング部門からDBサーバーへのアクセスは成功
access_list.report_access_result(marketing_pc.ip_address, db_server.ip_address)
# ゲストのスマホからDBへのアクセスは失敗
access_list.report_access_result(guest_sp.ip_address, db_server.ip_address)
作成したクラスたちをもとに、実際にシミュレーションを走らせてみます。
登場人物はDBサーバー、HTTPサーバー、エンジニア部門用PC、マーケティング部門用PC、ゲスト用スマホです。
まず、サーバー、エンジニア部門、マーケティング部門、ゲストでVLANを分けます。
そして登場する端末たちにIPを振り、各VLANに所属させます。
アクセスリストのエントリーには、以下の3つを追加します。
- エンジニア部門からサーバー用セグメントへのアクセスを許可
- マーケティング部門からDBへのアクセスを許可
- マーケティング部門からHTTPサーバーへのアクセスはブロック
各種設定が終わったので、最後に、以下パターンの出力結果を確認します。
-
エンジニア部門からHTTPサーバー
→ ルール1で許可してるので、「この通信は通す!」 -
エンジニア部門からDB
→ ルール1で許可してるので、「この通信は通す!」 -
マーケティング部門からHTTPサーバー
→ ルール3で拒否しているので、「この通信は通さない!」 -
マーケティング部門からDB
→ ルール2で許可してるので、「この通信は通す!」 -
ゲストのスマホからDB
→ どのルールにも明記されていないので、「この通信は通さない!」
ロジック的にホワイトリスト方式にしているので、最後のスマホ→DBも弾いています。
所感
とてもかんたんにですが、再現できてよかったです。
Discussion