본문 바로가기

Ryu's Tech

suricata를 이용한 포트 미러링으로 오픈스택 IDS 테스트

Table of Contents

오픈스택 환경


2018/04/03 - [Ryu's Tech] - 체크포인트 방화벽으로 오픈스택 vRouter 를 대체

기반환경은 위의 글을 참조.

VM간 통신시 패킷을 직접적으로 모니터링 하려고 하고 이를 suricata로 모니터링 가능성까지 확인해보려 함.

위의 그림과 같이 svr1, svr3 트래픽을 suricata VM의 monitoring service 네트워크에 연결된 포트로 미러링.

Suricata 관련 HEAT 템플릿 배포

입력부분과 네트워크 생성 부분

heat_template_version: 2017-02-24
parameters:
suricata_ip:
type: string
default: 192.168.0.88
resources:
# network
monitoring service:
type: OS::Neutron::Net
properties:
name: monitoring service
# subnet
monitoring service-subnet:
type: OS::Neutron::Subnet
properties:
name: monitoring service-subnet
network_id: { get_resource: monitoring service }
cidr: 10.10.254.0/24
enable_dhcp: false
gateway_ip: null

모니터링을 위한 네트워크와 서브넷 생성 부분. 

해당 네트워크는 통신을 위한 네트워크가 아닌 미러링될 트래픽을 받을 포트만 필요함. 

다른 네트워크에 포트를 물리게 되면 다른 트래픽까지 들어오게 되므로 별도의 클린한 네트워크를 생성해서 수리카타 VM만 포트를 연결.

포트 생성 부분

# port
suricata_port:
type: OS::Neutron::Port
properties:
name: "suricata_port"
network: "provider"
port_security_enabled: False
fixed_ips:
- ip_address: { get_param: suricata_ip }

suricata_monitoring_port:
type: OS::Neutron::Port
properties:
name: "suricata_monitoring_port"
network: { get_resource: monitoring service}
port_security_enabled: False
fixed_ips:
- ip_address: "10.10.254.1"


suricata_monitoring_port의 경우 IP 를 안넣어도 되지만 IP를 넣지 않으면 생성 불가


Suricata VM 생성 부분


svr_config:
type: OS::Heat::SoftwareConfig
properties:
group: ungrouped
config: |
#!/bin/sh
(
echo "qwe123"
echo "qwe123"
) | passwd --stdin root
sed -i "s/^PasswordAuthentication no/PasswordAuthentication yes/g" /etc/ssh/sshd_config
echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config
echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
service sshd restart
yum remove -y firewalld
yum install -y epel-release
yum install -y suricata

suricata:
type: OS::Nova::Server
properties:
name: "suricata"
flavor: "c2r2d20"
image: "centos7custom"
availability_zone: "nova:compute2"
networks:
- port: { get_resource: suricata_port }
- port: { get_resource: suricata_monitoring_port }
user_data_format: SOFTWARE_CONFIG
user_data: { get_resource: svr_config }


suricata가 yum 패키지를 지원하므로 epel-release 설치 후 suricata 패키지 설치.

Suricata 설정

ICMP Rule추가

/etc/suricata/rules/tls-events.rules 파일에 아래 내용 한줄 추가

[root@suricata ~] # echo 'alert icmp any any -> any any (msg:"PING detected"; sid:2; rev:1;)' >> /etc/suricata/rules/rls-events.rules

Suricata 설정파일 수정

테스트를 위해 위에서 설정한 룰 파일을 로드 하는 지만 확인

[root@suricata rules] # cat /etc/suricata/suricata.yaml | grep tls-events.rules
- tls-events.rules # available in suricata sources under rules dir
[root@suricata rules] #

인터페이스 IPV6 disable

IPv6가 enable 상태로 사용하면 IPv6 트래픽이 들어와 그 외 트래픽이 보일 수 있음. 그렇기에 모니터링 할 인터페이스의 IPv6를 끄고 설정

[root@suricata ~] # cat /etc/sysconfig/network-scripts/ifcfg-eth1
TYPE= "Ethernet"
BOOTPROTO= "none"
IPV6INIT= "no"
DEVICE= "eth1"
ONBOOT= "yes"
[root@suricata ~] #

Suricata 서비스 시작

[root@suricata ~] # suricata -i eth1 -D
4/4/2018 -- 04:59:46 - <Notice> - This is Suricata version 4.0.4 RELEASE
[root@suricata ~] #


해당 인터페이스를 -i 로 지정하고 -D 를 통해 데몬형태로 실행

미러링 설정

getnet function

아래의 function을 만들어서 사용

function getnet {
VMNAME= $1
NETWORKNAME= $2
openstack server show $VMNAME > /tmp/showresult

COMPUTEHOST= $(cat /tmp/showresult | grep hypervisor_hostname | awk '{print $4}')
INSTANCENAME= $(cat /tmp/showresult | grep instance_name | awk '{print $4}')
ssh $COMPUTEHOST "cat /etc/libvirt/qemu/ $INSTANCENAME .xml" > /tmp/qemuresult

COUNT= $(echo $(cat /tmp/showresult | grep addresses | cut -f3 -d'|' | awk -F';' '{print NF-1}'))
let "COUNT = $COUNT + 1"

if [ " $COUNT " == 1 ]; then
NETWORKORDER=1
else
for ((i= 1 ; i<= $COUNT ; i++ )) do
SR1= $(echo $(cat /tmp/showresult | grep addresses | cut -f3 -d'|' | cut -c 2- | cut -f $i -d';' | cut -f1 -d=))
SR2= $(echo $NETWORKNAME )
if [ " $SR1 " == " $SR2 " ]
then
let "NETWORKORDER= $COUNT - ( $i - 1)"
fi
done
fi
echo $(sed -n '/interface type/,/\/interface/p' /tmp/qemuresult | grep target | cut -f2 -d"'" | sed -n ${NETWORKORDER} p)
}


동작을 간단하게 설명하면 openstack server show 에서 VM이 돌아가고 있는 호스트네임과 인스턴스명을 구할 수 있음.

[root@controller ~] # openstack server show svr1 | grep -e hypervisor_hostname
| OS-EXT-SRV-ATTR:hypervisor_hostname | compute2 |
[root@controller ~] # openstack server show svr1 | grep -e instance_name
| OS-EXT-SRV-ATTR:instance_name | instance-00000018 |


얻어진 값으로 해당 호스트에서 xml 파일을 열어보면 VM 의 인터페이스 정보가 담긴것을 알 수 있음.

[root@compute2 ~] # sed -n '/interface type/,/\/interface/p' /etc/libvirt/qemu/instance-00000018.xml
<interface type= 'bridge'>
<mac address= 'fa:16:3e:89:c0:2a'/>
<source bridge= 'brq923eace7-6f'/>
<target dev= 'tapc1aa70bd-bd'/>
<model type= 'virtio'/>
<address type= 'pci' domain= '0x0000' bus= '0x00' slot= '0x03' function= '0x0'/>
</interface>
[root@compute2 ~] #


해당 정보에서 target dev를 추출하면 실제 VM과 연결되는 인터페이스를 구할 수 있다.

[root@compute2 ~] # sed -n '/interface type/,/\/interface/p' /etc/libvirt/qemu/instance-00000018.xml | grep target | cut -f2 -d"'"
tapc1aa70bd-bd
[root@compute2 ~] #


위의 Function에서 COUNT 변수와 for loop를 사용하는 것은 네트워크 인터페이스가 다수일때 동작시키기 위함이다.

포트 미러링 스크립트

아래 스크립트를 사용하면 포트 미러링 가능.

#미러링 추가 src to dst
tc qdisc add dev $src ingress; :
tc filter add dev $src parent ffff: protocol all u32 match u8 0 0 action mirred egress mirror dev $dst; :
tc qdisc add dev $src handle 1: root prio; :
tc filter add dev $src parent 1: protocol all u32 match u8 0 0 action mirred egress mirror
#미러링 삭제
tc qdisc del dev $src ingress; :
tc qdisc del dev $src root; :


인터넷에서 얻은 스크립트이긴 하지만 미러링 추가 부분을 좀 더 보기 좋게 정리해보면 아래와 같음.

# mirror ingress traffic
tc qdisc add dev $ src ingress; :
tc filter add dev $ src parent ffff: \
protocol all \
u32 match u8 0 0 \
action mirred egress mirror dev $dst; :
# mirror egress traffic
tc qdisc add dev $ src handle 1: root prio; :
tc filter add dev $ src parent 1: \
protocol all \
u32 match u8 0 0 \
action mirred egress mirror dev $dst; :

전체 스크립트

전체 스크립트.

#!/bin/bash
. ~/admin-openrc
function getnet {
VMNAME= $1
NETWORKNAME= $2
openstack server show $VMNAME > /tmp/showresult

COMPUTEHOST= $(cat /tmp/showresult | grep hypervisor_hostname | awk '{print $4}')
INSTANCENAME= $(cat /tmp/showresult | grep instance_name | awk '{print $4}')
ssh $COMPUTEHOST "cat /etc/libvirt/qemu/ $INSTANCENAME .xml" > /tmp/qemuresult

COUNT= $(echo $(cat /tmp/showresult | grep addresses | cut -f3 -d'|' | awk -F';' '{print NF-1}'))
let "COUNT = $COUNT + 1"

if [ " $COUNT " == 1 ]; then
NETWORKORDER=1
else
for ((i= 1 ; i<= $COUNT ; i++ )) do
SR1= $(echo $(cat /tmp/showresult | grep addresses | cut -f3 -d'|' | cut -c 2- | cut -f $i -d';' | cut -f1 -d=))
SR2= $(echo $NETWORKNAME )
if [ " $SR1 " == " $SR2 " ]
then
let "NETWORKORDER= $COUNT - ( $i - 1)"
fi
done
fi
echo $(sed -n '/interface type/,/\/interface/p' /tmp/qemuresult | grep target | cut -f2 -d"'" | sed -n ${NETWORKORDER} p)
}

src= $(getnet $2 $3 )
dst= $(getnet "suricata" "monitoring service")
if [ " $1 " = "add" ]; then
echo $src ">>" $dst
ssh $COMPUTEHOST "tc qdisc add dev $src ingress;:"
ssh $COMPUTEHOST "tc filter add dev $src parent ffff: protocol all u32 match u8 0 0 action mirred egress mirror dev $dst ;:"
ssh $COMPUTEHOST "tc qdisc add dev $src handle 1: root prio;:"
ssh $COMPUTEHOST "tc filter add dev $src parent 1: protocol all u32 match u8 0 0 action mirred egress mirror dev $dst ;:"
elif [ " $1 " = "del" ]; then
echo "<<" $src
ssh $COMPUTEHOST "tc qdisc del dev $src ingress;:"
ssh $COMPUTEHOST "tc qdisc del dev $src root;:"
else
echo "failed add or del"
fi


동작 테스트

PING 동작

svr1은 8.8.8.8 로 ping, svr3은 svr1으로 ping

[root@svr1 ~] # ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=56 time=41.4 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=56 time=34.9 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=56 time=51.9 ms

[root@svr3 ~] # ping 10.0.1.11
PING 10.0.1.11 (10.0.1.11) 56(84) bytes of data.
64 bytes from 10.0.1.11: icmp_seq=1 ttl=63 time=3.45 ms
64 bytes from 10.0.1.11: icmp_seq=2 ttl=63 time=2.39 ms
64 bytes from 10.0.1.11: icmp_seq=3 ttl=63 time=2.55 ms

SVR3 포트 미러링

svr3의 포트를 미러링하면 10.0.1.11에 대한 트래픽의 icmp request, reply가 보여야함.

[root@controller openstack] # ./mirror.sh add "svr3" "internal service2"
tap5d81f410-f8 >> tapc29f45b9-b5
[root@controller openstack] #

SVR3 결과 확인

생성한 룰대로 정상적으로 들어오는 것을 확인

[root@suricata rules] # tail /var/log/suricata/fast.log
04/04/2018-22:12:12.390897 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:12:12.395434 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0
04/04/2018-22:12:13.392558 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:12:13.395079 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0
04/04/2018-22:12:14.393722 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:12:14.396133 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0
04/04/2018-22:12:15.395560 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:12:15.399132 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0
04/04/2018-22:12:16.396953 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:12:16.400217 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0
[root@suricata rules] #

SVR1 포트 미러링 추가

위와 동일한 방법으로 추가

[root@controller openstack] # ./mirror.sh add "svr1" "internal service1"
tapc1aa70bd-bd >> tapc29f45b9-b5
[root@controller openstack] #

SVR1 포트 미러링 추가 결과 확인

두 포트를 미러링했으므로 총 세가지 트래픽이 확인되어야 함.

1. svr1 <-> 8.8.8.8

2. svr1 <-> svr3

3. svr3 <-> svr1


미러링 제거 후 확인

[root@suricata rules] # tail -n20 /var/log/suricata/fast.log
04/04/2018-22:14:45.846433 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:8 -> 8.8.8.8:0
04/04/2018-22:14:45.880785 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 8.8.8.8:0 -> 10.0.1.11:0

04/04/2018-22:14:46.655567 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:14:46.657157 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:14:46.657537 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0
04/04/2018-22:14:46.658423 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0

04/04/2018-22:14:46.848821 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:8 -> 8.8.8.8:0
04/04/2018-22:14:46.883801 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 8.8.8.8:0 -> 10.0.1.11:0

04/04/2018-22:14:47.657488 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:14:47.658691 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:14:47.659204 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0
04/04/2018-22:14:47.660232 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0

04/04/2018-22:14:47.850350 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:8 -> 8.8.8.8:0
04/04/2018-22:14:47.884812 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 8.8.8.8:0 -> 10.0.1.11:0

04/04/2018-22:14:48.659047 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:14:48.660506 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:14:48.660955 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0
04/04/2018-22:14:48.661890 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0

04/04/2018-22:14:48.852617 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:8 -> 8.8.8.8:0
04/04/2018-22:14:48.887978 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 8.8.8.8:0 -> 10.0.1.11:0
[root@suricata rules] #

미러링 제거

[root@controller openstack] # ./mirror.sh del "svr1" "internal service1"
<< tapc1aa70bd-bd
[root@controller openstack] # ./mirror.sh del "svr3" "internal service2"
<< tap5d81f410-f8

결과 확인

[root@suricata rules] # tail -f /var/log/suricata/fast.log
04/04/2018-22:17:14.915152 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:17:14.917974 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0
04/04/2018-22:17:15.916910 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:17:15.919664 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0
04/04/2018-22:17:16.918801 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:17:16.920651 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0
04/04/2018-22:17:17.920290 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:17:17.922812 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0
04/04/2018-22:17:18.922150 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.2.11:8 -> 10.0.1.11:0
04/04/2018-22:17:18.924782 [**] [1:2:1] PING detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.1.11:0 -> 10.0.2.11:0
^C
[root@suricata rules] # date
Wed Apr 4 22:18:19 EDT 2018
[root@suricata rules] #

트래픽이 더이상 들어오지 않음.