Linux에서 IPsec implementation은 userspace part와 kernel park로 구성되어 있다. 이번 게시물에서 다룰 userspace part IPsec implementation은 strongSwan이며. Linux kernel part IPsec implementation은 netkey stack 이라고도 불리는 xfrm framework다. 아래의 그림에서 strongSwan과 xfrm framework의 책임 영역을 확인할 수 있으며 이 둘의 상호작용 과정을 생각해 볼 수 있다.
Strongswan
strongSwan의 핵심은 userspace daemon인 charon이다. charon은 IKEv1/IKEv2를 구현하고 각 VPN endpoint host에서 IPsec-based VPN tunnel(connection)의 중앙 관제사 역할을 하고 있다.
charon은 system에서 IPsec configuration을 위해 user/admin에게 interface를 제공하고 있으며, 더 정확히는 두 개의 다른 interface를 제공하고 있다. 첫 번째는 stroke interface로 IPsec을 구성하기 위해 /etc/ipsec.conf, /etc/ipsec.secrets 이 두 개의 main config 파일을 제공하고 있다.
두 번째는 IPC(Inter-Process Communication)처럼 동작하는 vici interface로, charon daemon이 Unix Domain Socket에서 대기하고 있어, strongSwan의 cmd tool인 swanctl과 같은 클라이언트 도구가 이 Socket에 연결돼 IPsec을 구성할 수 있다. 이 구성 방식은 다른 도구들이 언제든지 동적으로 이벤트 기반 configuration을 제공하고 조정하기가 더 쉽기 때문에 앞선 방식보다 더 선호된다. 이 방식은 /etc/swanctl/swanctl.conf 파일이 charon daemon에 의해 직접 해석되는 것이 아니라, swanctl cmdline tool에 의해 해석되어 configuration 정보가 vici IPC interface를 통해 charon daemon에 전달된다는 점이다. 추가로 /etc/strongswan.conf 파일도 존재하는데, 개별적인 VPN Connection과 직접적으로 관련된 설정이 아니라 글로벌한 strongSwan 설정 관련 파일이다.
양쪽 VPN endpoint host 각각에 VPN tunnel 구성을 위한 swanctl.conf 파일을 두고. swanctl tool을 사용해 이 configuration 정보를 charon daemon에 로드해 peer endpoint 간의 IKE handshake를 시작했다고 해보자. IKE handshake를 실행할 때 charon daemon은 peer와 VPN tunnel에 대한 모든 세부 사항을 협상해 VPN Connection을 정의하는 SA와 SP instance를 생성한다. IKE_SA는 peer endpoint와의 IKE 통신을 위한 자체 보안 채널이기 때문에 userspace에 유지하고 다른 SA와 SP instance는 Netlink Socket을 통해 kernel에 전달한다. 이제 VPN Connection/Tunnel이 활성화된 상태이고, 나중에 VPN 연결을 종료하게 되면 charon은 커널에서 SA와 SP instance를 제거한다.
The xfrm framework
iproute2 man page: xfrm framework is IP framework for transforming packets (such as encrypting their payloads
xfrm(transform) 프레임워크는 리눅스 커널 내의 구성 요소다. userspace part IPsec implementation인 strongSwan이 VPN connection/tunnel을 위해 전반적인 IPsec 오케스트레이션을 처리하고 VPN connection/tunnel을 설정 및 해제하기 위해 IKEv1/IKEv2 프로토콜을 실행하는 동안, kernel part IPsec implementation인 xfrm framework는 VPN tunnel 안에서 이동하는 network packet의 encrypting+encapsulating과 decrypting+decapsulating을 수행하며 어떤 패킷이 VPN tunnel을 통해 이동할지 선택하고 결정한다. 이를 위해서는 커널 내에 VPN connection/tunnel을 정의하는 SA와 SP instance가 존재해야 한다. 그래야만 어떤 패킷을 암호화/복호화할지, 어떤 암호화 알고리즘과 키를 사용할지에 대한 결정을 내릴 수 있다.
xfrm framework는 SA와 SP instance를 유지하기 위해 SAD(SA Database)와 SPD(SP Datebase)를 구현한다. SA는 커널 내에서 xfrm_state 구조체에 의해 표현되고 SP는 xfrm_policy 구조체를 통해 표현된다. strongSwan 같은 userspace 컴포넌트는 커널 내의 SAD와 SPD의 SA, SP를 crud 하기 위해 Netlink socket를 사용하고 있다. ip 명령어로 현재 SAD와 SPD 내에 저장된 SA와 SP instance를 확인할 수 있다.
ip xfrm state # shows SA instances
ip xfrm policy # shows SP instances
SP instance는 세 가지 정책에 적용될 수 있다.
SP(security policy) | syntax | meaning |
output policy | dir out | 이 정책은 송신 패킷에 적용된다. 송신 패킷이 encrypted + encapsulated될지 여부를 결정한다. 즉, 어떤 패킷이 VPN 터널을 통해 전송될지 결정한다. |
input policy | dir in | 이 정책은 수신 패킷에 적용된다. decrypted + decapsulated된 패킷 중 시스템의 로컬 IP 주소를 목적지로 하는 패킷을 선택한다. 즉, 시스템에 들어오는 패킷이 VPN 터널에서 온 것인지 결정한다. |
forward policy | dir fwd | 이 정책은 전달 패킷에 적용된다. decrypted + decapsulated된 패킷 중 시스템의 로컬 IP 주소가 아닌 다른 목적지로 향하는 패킷을 선택한다. 즉, 패킷이 시스템을 경유해 다른 네트워크로 전달될지 결정한다. |
VPN에 대해서 공부를 하고 있는 사람이라면 Netfilter packet flow 이미지를 본적이 있을 것이다. 여기에는 xfrm implementation에 대한 작은 오해들이 존재한다. 실제로는 4개 이상의 지점에서 xfrm이 수행되고, 실제로 수행되는 지점도 사진과는 다르다. 아래의 사진은 Netfilter와 xfrm framework를 중심으로 packet flow를 간략하게 보여준다. Netfilter hook은 파란색 그리고 xfrm framework의 동작은 빨간색으로 표현되었다.
두개의 routing lookup은 incoming packet과 outgoing packet 모두에 대해서 실행된다. 함수 fib_lookup()은 policy routing rule과 routing table에 대한 lookup을 수행한다. lookup을 통해 확인된 routing 정보는 라우팅 테이블을 경유하는(traversing) network packet(skb)에 부탁된다. 이 패킷은 dst_entry 구조체를 감싸는 rtable 구조체의 인스턴스로 output network interface, ip address of next hop gateway, 다음으로 패킷이 향해야 할 곳을 가리키는 함수 포인터 등의 정보를 갖고 있다. 언뜻 보기에는 routing은 xfrm framework와 관련이 없어보이지만, 이 글을 읽다보면 관련성을 발견해나갈 수 있을 것이다. | |
xfrm lookup out policy는 routing 조회 후 forward된 packet과 outgoing packet 모두에 대해서 실행된다.함수 xfrm_lookup()은 IPsec SPD에서 일치하는 output policy(dir out SP)를 조회한다. 일치하는 policy가 없으면 패킷은 변경되지 않고 그대로 계속 진행되지만, 일치하는 policy가 있다면 일치하는 SP에 해당하는 SA를 해석하기 위해 SAD에서 조회가 수행된다(Xfrm lookup state). 해석된(resolved) SA가 tunnel-mode를 지정하면, 이번에는 현재 패킷을 나중에 캡슐화할 외부 IPv4 패킷에 대한 또 다른 라우팅(Routing) 조회가 수행된다. 실제 패킷 변환이 수행되지는 않지만, 이 패킷에 대한 변환 지침의 bundle이 조립된다. 여기서 bundle은 커널 소스 코드에서 비롯되며 서로를 가리키는 여러 구조체 인스턴스를 의미하는데 여기에는 원래 routing decision , SP, SA, 미래의 외부 IP 패킷에 대한 routing decision 등이 포함되어 xfrm_dst 인스턴스에 조립된다. 이렇게 만들어진 bundle은 network packet(skb)에 부착되어 원래 부착된 routing decision을 대체한다. bundle 내 함수 포인터는 패킷이 커널 네트워크 스택의 나머지 부분을 통해 다른 경로를 따르도록 보장한다. |
|
여기서는 VPN 터널을 통과해야 하는 패킷이 암호화되고 캡슐화된다. xfrm framework는 패킷에 부착된 bundle의 지침에 따라 패킷을 변환한다. bundle 내의 함수 포인터는 패킷이 Netfilter POSTROUTING hock을 통과한 후 변환 code로 우회하도록 한다. IPv4 패킷의 경우 패킷을 이 경로로 이끄는 진입 함수는 xfrm4_output()이다. tunnel-mode의 경우, 이 변환은 IP 패킷을 새로운 외부 IP 패킷으로 캡슐화한 다음, 내부 IP 패킷을 ESP 프로토콜로 캡슐화하고 이를 암호화하는 것을 의미한다. 변환이 완료되면 xfrm components/instructions은 bundle에서 제거되고 외부 IP 패킷에 대한 라우팅 결정만이 패킷에 부착된 채로 남게 된다. | |
여기서는 VPN 터널을 통해 들어온 패킷이 복호화되고 역캡슐화(decapsulate)된다. local input path의 IP 패킷이 ESP 패킷을 포함하고 있다면 xfrm framework는 SPI(SA identifier)를 기반으로 SAD(xfrm lookup state)를 조회해 일치하는 SA가 있다면 ESP 패킷을 복호화하고 역캡슐화한다. 일치하는 SA가 존재하지 않으면 해당 패킷은 드롭된다. tunnel-mode에서 outer IP 패킷은 역캡슐화되고, inner IP 패킷은 L2 receive path에 재삽입되며 이 패킷은 자신에게 사용된 SA를 추적해 추후 xfrm lookup in policy, xfrm lookup fwd policy 혹은 라우팅에 사용한다. |
|
이미 복호화되고 역캡슐화된 패킷이 이곳에 도착하면, 해당 패킷을 복호화하고 역캡슐화 하는데 사용된 SA와 input policy(dir in SP)가 일치해야 한다. 일치하지 않는 패킷은 드롭된다. VPN 터널을 통해 들어오지 않은 Nomal 패킷은 기본적으로 input policy와 일치하지 않으면 그냥 통과한다. |
|
여기에 도착한 복호화되고 암호화된 패킷은 패킷을 복호화하고 역캡슐화하는 데 사용된 SA와 일치하는 forward policy(dir fwd SP)와 일치해야 한다. 일치하지 않는 패킷은 드롭된다. Nomal 패킷은 기본적으로 forward policy와 일치하지 않으면 그냥 통과한다. |
xfrm framework implementation은 VPN 트래픽과 Non-VPN 트래픽을 구별하기 위해 VNI(Virtual Network Interface)를 사용하지 않는다. 이는 SP의 개념이 VPN 운영에 필요한 모든 구별을 수행하기 때문이다. 그러나 VNI가 없으면 iptables 및 nftables와 같은 Netfilter 기반 패킷 필터링 시스템이 VPN 및 Non-VPN 패킷을 규칙 내에서 구별하기 더 어려워진다. VPN 트래픽이 특정 VNI를 통해 전달되면 필터링 규칙을 쉽게 작성할 수 있기 때문이다.
xfrm 프레임워크의 경우 기본적으로는 VNI를 사용하지 않지만 xfrm framework 위에 VNI 개념을 도입해 사용성을 높인 추가 기능이 도입되었다. strongSwan에서는 이런 VNI(vti, xfrm)를 기반으로 한 VPN 설정을 Route-based VPN이라 부른다.
다음 게시글에서는 VPN Tunnel을 구성해 SAD와 SPD를 확인하고 터널 내에서 실제로 패킷이 송신되고 수신될 때 Packet Flow를 확인해 VNI의 도입 여부를 결정하는 주제를 다루겠다.
이 글은 GOAT 블로그를 읽고 정리한 내용입니다. 원문을 읽어 보시길 강력 추천드립니다.
'VPN' 카테고리의 다른 글
strongSwan이란? (0) | 2024.05.31 |
---|---|
IPSec Protocol이란? (0) | 2024.05.29 |