MACsec (IEEE 802.1AE)
IEEE 802.1AE MACsec은 이더넷 L2 프레임을 홉 단위로 암호화(Encryption)·무결성(Integrity) 검증하는 표준입니다. Linux 커널의 drivers/net/macsec.c 구현을 중심으로 SecTAG/ICV 프레임 구조, GCM-AES 암호 스위트, MKA(802.1X-2010) 키 합의 프로토콜, CAK→SAK 키 계층, 커널 TX/RX 경로, NIC HW offload, ip macsec 운영 명령, 데이터센터 East-West 트래픽 보호 패턴, 성능 벤치마크와 트러블슈팅을 실전 운영 관점에서 정리합니다.
핵심 요약
- MACsec — IEEE 802.1AE 표준으로, 이더넷 프레임을 L2에서 홉 단위(hop-by-hop) 암호화·무결성 보호합니다.
- SecTAG — 원래 EtherType 자리에 삽입되는 보안 태그(8~16바이트)로, SCI와 패킷(Packet) 번호를 운반합니다.
- ICV — 프레임 끝에 추가되는 무결성 검증 값(Integrity Check Value, 8~16바이트)입니다.
- MKA — MACsec Key Agreement(IEEE 802.1X-2010)로, 피어 간 SAK(Secure Association Key)를 합의합니다.
- SAK — 실제 프레임 암복호화에 사용되는 대칭 키이며, CAK에서 파생됩니다.
- HW Offload — NIC가 암복호화를 하드웨어에서 처리해 CPU 부담을 제거합니다.
단계별 이해
- L2 암호화의 위치를 파악하기
MACsec은 이더넷 헤더 바로 뒤에서 동작합니다. IP 이상의 계층은 전혀 관여하지 않습니다. - 프레임 구조를 먼저 이해하기
SecTAG와 ICV가 원래 프레임의 어디에 삽입되는지 그림으로 확인하면 나머지가 쉬워집니다. - 키 합의와 데이터 경로를 분리해서 보기
MKA는 EAPoL 프레임으로 키를 교환하고, MACsec은 그 키로 데이터를 암호화합니다. 두 경로는 독립적입니다. - SW vs HW offload를 구분하기
소프트웨어 경로는 커널 crypto API를 사용하고, HW offload는 NIC 펌웨어(Firmware)가 처리합니다. 성능 차이가 극적입니다. - 문제는 통계와 카운터로 확인하기
ip -s macsec show의 InPktsOK, InPktsInvalid, OutPktsProtected가 첫 번째 진단 지표입니다.
drivers/net/macsec.c), 5.6에서 HW offload 인프라가 추가되었습니다.
최근 주요 배포판 커널에서는 CONFIG_MACSEC이 대체로 모듈로 활성화되어 있습니다.
IEEE 802.1AE 표준 개요
IEEE 802.1AE는 이더넷 LAN에서 데이터 기밀성(confidentiality), 데이터 무결성(integrity), 데이터 원본 인증(origin authentication)을 제공하는 표준입니다. 핵심 특징은 다음과 같습니다.
- 홉 단위(hop-by-hop) 보호: 종단 간(end-to-end) 보호가 아니라, 직접 연결된 두 장치(호스트↔스위치, 스위치↔스위치) 사이의 링크를 보호합니다.
- L2 투명성: IP 이상의 프로토콜에는 완전히 투명합니다. 상위 계층은 MACsec의 존재를 인식하지 못합니다.
- Secure Channel / Secure Association: 각 방향마다 독립된 Secure Channel(SC)이 존재하고, 각 SC 안에 최대 4개의 Secure Association(SA)이 키 로테이션을 위해 준비됩니다.
- 패킷 번호(PN): 각 SA는 단조 증가하는 32비트(또는 XPN에서 64비트) 패킷 번호를 유지하여 재전송(Retransmission) 공격을 방어합니다.
| 표준 문서 | 범위 | 핵심 내용 |
|---|---|---|
| IEEE 802.1AE-2006 | MACsec 프레임 형식, 보안 모델 | SecTAG, ICV, SCI, SC/SA 개념 정의 |
| IEEE 802.1AEbn-2011 | GCM-AES-256 추가 | 128비트 외에 256비트 키 지원 |
| IEEE 802.1AEbw-2013 | Extended Packet Numbering | 64비트 PN으로 고속 링크의 PN 소진 방지 |
| IEEE 802.1AEcg-2017 | 통합 개정판 | GCM-AES-XPN-128/256 추가 |
| IEEE 802.1X-2010 | MKA 프로토콜 | 키 합의, 키 서버 선출, SAK 분배 |
MACsec vs IPSec vs WireGuard vs kTLS 비교
네트워크 보안은 계층마다 다른 도구가 존재합니다. MACsec은 L2에서 동작하므로 다른 암호화 메커니즘과 경쟁이 아니라 보완 관계입니다.
| 항목 | MACsec (802.1AE) | IPSec / xfrm | WireGuard | kTLS |
|---|---|---|---|---|
| 동작 계층 | L2 (이더넷) | L3 (IP) | L3 (IP over UDP) | L4-7 (TLS) |
| 보호 범위 | 홉 단위 (point-to-point) | 종단 간 / 게이트웨이 | 종단 간 | 종단 간 |
| 암호 알고리즘 | GCM-AES-128/256, XPN | 다양 (협상) | ChaCha20-Poly1305 고정 | TLS 표준 스위트 |
| 키 합의 | MKA (EAPoL 기반) | IKEv2 | Noise_IKpsk2 | TLS 핸드셰이크 (유저스페이스) |
| 브로드캐스트/멀티캐스트 | 지원 | 제한적 | 미지원 | 미지원 |
| 라우팅(Routing) 가능성 | 중간 라우터가 복호화(Decryption) 필요 | 터널(Tunnel)/트랜스포트 모드 | AllowedIPs 라우팅 | TCP 커넥션 기반 |
| HW offload | NIC 레벨 (line-rate) | 일부 NIC/IPU | 미지원 | NIC TLS offload |
| 대표 용도 | 데이터센터 링크 암호화 | 사이트 간 VPN | 원격 접속 VPN | HTTPS 가속 |
SecTAG와 ICV 프레임 형식
MACsec은 원래 이더넷 프레임에 두 가지 요소를 추가합니다: 헤더 쪽의 SecTAG(Security Tag)와 꼬리 쪽의 ICV(Integrity Check Value)입니다.
| 필드 | 크기 | 설명 |
|---|---|---|
| MACsec EtherType | 2바이트 | 항상 0x88E5. 원래 EtherType 위치에 삽입됩니다. |
| TCI (Tag Control Info) | 6비트 | V(버전), ES(End Station), SC(SCI 포함 여부), SCB(Single Copy Broadcast), E(암호화), C(변경됨) 플래그 |
| AN (Association Number) | 2비트 | 현재 사용 중인 SA 번호 (0-3). 키 로테이션 시 변경됩니다. |
| SL (Short Length) | 1바이트 | Secure Data가 48바이트 미만일 때 실제 길이. 그 외에는 0입니다. |
| Packet Number (PN) | 4바이트 | 단조 증가하는 패킷 번호. replay protection과 GCM nonce 구성에 사용됩니다. |
| SCI (Secure Channel Identifier) | 8바이트 (선택) | 송신자 MAC 주소(6B) + Port Identifier(2B). point-to-point에서는 생략 가능합니다. |
| ICV | 8 또는 16바이트 | GCM-AES 인증 태그. 기본 16바이트, 단축(8바이트)은 보안성이 낮아 권장되지 않습니다. |
GCM-AES-128/256, GCM-AES-XPN 암호 스위트
MACsec은 AES-GCM (Galois/Counter Mode)만을 암호 스위트로 사용합니다. IPSec처럼 다양한 알고리즘을 협상하지 않으며, 표준에 정의된 4가지 스위트 중 하나를 선택합니다.
| Cipher Suite | Cipher Suite ID | 키 길이 | PN 크기 | 특징 |
|---|---|---|---|---|
| GCM-AES-128 | 0x0080C20001000001 | 128비트 | 32비트 | 기본(default) 스위트. 대부분의 구현이 지원합니다. |
| GCM-AES-256 | 0x0080C20001000002 | 256비트 | 32비트 | 더 강한 키. 양자 내성(quantum resistance) 여유를 확보합니다. |
| GCM-AES-XPN-128 | 0x0080C20001000003 | 128비트 | 64비트 | 고속 링크(40G/100G 이상)에서 PN 소진 방지. |
| GCM-AES-XPN-256 | 0x0080C20001000004 | 256비트 | 64비트 | 최고 보안 + 고속 링크 겸용. |
AES-GCM은 AEAD(Authenticated Encryption with Associated Data) 모드로, 암호화와 무결성 검증을 한 번의 연산으로 수행합니다. GCM의 nonce(IV)는 다음과 같이 구성됩니다:
/* GCM nonce (12바이트) 구성 */
struct macsec_gcm_nonce {
/* 표준 PN (32비트) */
u8 salt[4]; /* SAK와 함께 분배되는 고정 salt */
u8 iv[4]; /* 0으로 패딩 또는 SSCI */
u32 pn; /* 패킷 번호 (네트워크 바이트 순서) */
/* XPN (64비트) 일 때 */
/* salt[4] XOR SSCI || pn_upper[4] || pn_lower[4] */
};
MKA (MACsec Key Agreement) 프로토콜
MKA는 IEEE 802.1X-2010에 정의된 키 합의 프로토콜로, MACsec이 사용할 SAK를 안전하게 분배합니다. MKA는 EAPoL(Extensible Authentication Protocol over LAN) 프레임, 구체적으로 EAPoL-MKA (EtherType 0x888E)를 사용합니다.
MKA의 핵심 개념들:
- MKPDU (MKA Protocol Data Unit): EAPoL 프레임에 실려 전달되는 MKA 메시지입니다. 여러 Parameter Set을 포함합니다.
- MI (Member Identifier): 각 MKA 참여자를 식별하는 12바이트 랜덤 값입니다.
- MN (Message Number): MKPDU의 시퀀스 번호로, 재전송 공격을 방지합니다.
- CKN (Connectivity association Key Name): CAK를 식별하는 이름(최대 32바이트)입니다.
- Live Peer List / Potential Peer List: 인증 완료된 피어와 아직 확인 중인 피어의 목록입니다.
- Key Server: SAK 생성과 분배를 담당하는 참여자입니다. 우선순위(Priority)와 SCI로 선출됩니다.
CAK → ICK → KEK → SAK 키 계층 구조
MACsec의 키 계층은 단일 루트 키(CAK)에서 모든 운영 키를 파생하는 구조입니다.
| 키 | 파생 원본 | 용도 | 수명 |
|---|---|---|---|
| CAK | 사전 공유(PSK) 또는 EAP 인증 | 모든 하위 키의 루트. 직접 데이터 암호화에 사용되지 않음 | 관리자가 변경할 때까지 |
| CKN | 관리자 설정 또는 EAP MSK에서 파생 | CAK를 식별하는 이름 (키 자체가 아님) | CAK와 동일 |
| ICK | CAK + CKN (AES-CMAC KDF) | MKPDU의 ICV(무결성) 생성 및 검증 | CAK 변경 시 재파생 |
| KEK | CAK + CKN (AES-CMAC KDF) | SAK를 AES Key Wrap으로 래핑하여 분배 | CAK 변경 시 재파생 |
| SAK | 키 서버가 랜덤 생성 | 실제 데이터 프레임의 GCM-AES 암복호화 | 로테이션 주기 또는 PN 소진 시 |
# PSK 모드에서 CAK/CKN 예시
# CAK: 128비트 (16바이트 hex) 또는 256비트 (32바이트 hex)
CAK="0123456789abcdef0123456789abcdef"
# CKN: 최대 32바이트 hex, 보통 CAK와 같은 길이
CKN="0123456789abcdef0123456789abcdef"
SAK 로테이션과 키 서버 선출
MKA는 SAK를 주기적으로 로테이션하여 장기간 같은 키가 사용되는 것을 방지합니다. 키 서버 선출과 SAK 로테이션 메커니즘은 다음과 같습니다.
키 서버 선출 규칙
- 모든 참여자는 MKPDU에 Key Server Priority 값을 포함합니다 (0-255, 기본값 일반적으로 16).
- 낮은 우선순위 값이 더 높은 우선순위를 가집니다.
- 우선순위가 동일하면 낮은 SCI(MAC 주소 기반)가 키 서버가 됩니다.
- 키 서버만이 SAK를 생성하고 KEK로 래핑하여 분배할 수 있습니다.
SAK 로테이션 트리거
- PN 소진 임박: 32비트 PN이 임계값(기본 0xC0000000)에 도달하면 새 SAK가 필요합니다.
- 참여자 변경: 새 참여자가 합류하거나 기존 참여자가 이탈하면 새 SAK를 분배합니다.
- 정책 기반: 관리자가 설정한 주기에 따라 로테이션합니다.
- AN (Association Number) 순환: 새 SAK는 다음 AN(0→1→2→3→0)에 설치되고, 양측 확인 후 이전 SA가 제거됩니다.
Linux 커널 MACsec 아키텍처
Linux MACsec은 drivers/net/macsec.c에 구현된 가상 네트워크 디바이스입니다. 실제 물리 NIC(real_dev) 위에 MACsec 가상 디바이스(macsec_dev)를 얹는 구조로, VLAN 디바이스와 유사한 패턴입니다.
커널 MACsec 모듈의 주요 구성 요소:
- macsec_dev:
net_device를 확장한 가상 디바이스. 상위 스택에는 일반 이더넷 인터페이스처럼 보입니다. - real_dev: MACsec이 올라가는 실제 물리 NIC.
rx_handler가 등록되어 EtherType 0x88E5 프레임을 가로챕니다. - macsec_secy: SecY(Security Entity) 상태를 관리하는 구조체(Struct). TX SC, RX SC 목록, 암호 스위트, 검증 모드를 포함합니다.
- Crypto API 연동:
gcm(aes)AEAD transform을 사용. AES-NI가 있으면 하드웨어 가속됩니다. - Netlink 인터페이스:
RTM_NEWLINK/RTM_DELLINK와 MACsec 전용 속성으로 설정됩니다.
MACsec 가상 net_device 구조
MACsec 디바이스는 ARPHRD_ETHER 타입의 일반 이더넷 디바이스로 등록됩니다. ip link에서 macsec 타입으로 생성하며, 내부적으로 rtnl_link_ops를 통해 관리됩니다.
/* drivers/net/macsec.c - 주요 구조체 관계 */
struct macsec_dev {
struct macsec_secy secy; /* SecY 상태 */
struct net_device *real_dev; /* 하위 물리 NIC */
struct pcpu_secy_stats __percpu *stats; /* per-CPU 통계 */
struct list_head secys; /* real_dev 당 MACsec 디바이스 목록 */
struct gro_cells gro_cells; /* GRO 셀 */
enum macsec_offload offload; /* SW / HW offload 모드 */
};
/* net_device_ops */
static const struct net_device_ops macsec_netdev_ops = {
.ndo_init = macsec_dev_init,
.ndo_uninit = macsec_dev_uninit,
.ndo_open = macsec_dev_open,
.ndo_stop = macsec_dev_stop,
.ndo_start_xmit = macsec_start_xmit, /* TX 진입점 */
.ndo_change_mtu = macsec_change_mtu,
.ndo_set_mac_address = macsec_set_mac_address,
.ndo_get_stats64 = macsec_get_stats64,
.ndo_change_rx_flags = macsec_change_rx_flags,
.ndo_set_rx_mode = macsec_set_rx_mode,
};
MACsec 디바이스의 특징:
- MTU:
real_dev->mtu - (SecTAG 크기 + ICV 크기)로 자동 설정됩니다. - MAC 주소: 기본적으로 real_dev와 동일하지만, 독립적으로 변경할 수 있습니다.
- 하나의 real_dev에 여러 MACsec 디바이스: SCI가 다르면 동일 NIC 위에 여러 MACsec 인터페이스를 생성할 수 있습니다.
- promisc 모드: MACsec 디바이스가 올라오면 real_dev는 promiscuous 모드가 됩니다 (다른 MAC의 MACsec 프레임도 수신해야 하므로).
송신 경로: macsec_start_xmit() → SecTAG 삽입 → GCM 암호화
상위 스택이 MACsec 디바이스로 패킷을 보내면 macsec_start_xmit()이 호출됩니다. 이 함수는 원본 프레임에 SecTAG를 삽입하고 GCM-AES로 암호화한 뒤 real_dev를 통해 전송합니다.
/* TX 경로 핵심 코드 흐름 (단순화) */
static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct macsec_dev *macsec = macsec_priv(dev);
struct macsec_secy *secy = &macsec->secy;
struct macsec_tx_sc *tx_sc = &secy->tx_sc;
struct macsec_tx_sa *tx_sa;
/* 1. 활성 SA 선택 */
tx_sa = macsec_txsa_get(tx_sc->sa[tx_sc->encoding_sa]);
if (!tx_sa) goto drop;
/* 2. PN 할당 (32비트 또는 64비트) */
if (secy->xpn)
pn = atomic64_inc_return(&tx_sa->next_pn_halves.counter);
else
pn = atomic_inc_return(&tx_sa->next_pn_halves.pn32);
/* 3. PN 소진 체크 */
if (pn >= tx_sa->next_pn_halves.lower)
goto drop; /* PN wrapped - SAK 로테이션 필요 */
/* 4. SecTAG 삽입 + 암호화 */
macsec_encrypt(skb, dev);
return NETDEV_TX_OK;
}
수신 경로: macsec_handle_frame() → ICV 검증 → 복호화
real_dev에 도착한 EtherType 0x88E5 프레임은 rx_handler인 macsec_handle_frame()으로 전달됩니다.
수신 경로의 주요 검증 단계:
- SecTAG 유효성: EtherType, 버전 비트, TCI 플래그 조합이 유효한지 확인합니다.
- SCI 매칭: SecTAG의 SCI(또는 추론된 SCI)로 해당 RX SC를 검색합니다. 매칭되는 SC가 없으면 drop됩니다.
- SA 선택: AN 필드로 RX SA를 선택합니다. 해당 SA가 비활성이면 drop됩니다.
- GCM-AES 복호화: SA의 키로 페이로드를 복호화하고 ICV를 검증합니다. ICV 불일치는 즉시 drop + InPktsNotValid 증가.
- Replay check: PN이 윈도우 내에 있고 중복이 아닌지 확인합니다.
- 프레임 복원: SecTAG와 ICV를 제거하고 원래 EtherType을 복원하여 상위 스택으로 전달합니다.
패킷 번호 기반 Replay Protection
MACsec의 replay protection은 각 RX SA가 유지하는 패킷 번호 윈도우로 구현됩니다.
/* replay 윈도우 검사 (단순화) */
static bool macsec_pn_check(struct macsec_rx_sa *rx_sa, u32 pn)
{
u32 latest_pn = rx_sa->next_pn; /* 지금까지 수신한 최대 PN + 1 */
u32 window = rx_sa->replay_protect_window;
if (pn == 0)
return false; /* PN 0은 항상 무효 */
if (pn >= latest_pn)
return true; /* 새로운 PN → 항상 허용 */
if (latest_pn - pn > window)
return false; /* 윈도우 밖 → 너무 오래된 패킷 */
/* 윈도우 내 → 비트맵으로 중복 체크 */
return !test_bit(pn % window, rx_sa->replay_bitmap);
}
| 파라미터 | 설명 | 기본값 |
|---|---|---|
| replay_protect | replay protection 활성화 여부 | 활성 (on) |
| window | 허용하는 PN 순서 역전 범위 | 0 (엄격 순서, 역전 불허) |
SCI (Secure Channel Identifier)와 SA (Secure Association)
SCI와 SA의 관계는 MACsec 보안 모델의 핵심입니다.
| 개념 | 방향 | 수량 | 설명 |
|---|---|---|---|
| SecY | - | MACsec 디바이스당 1개 | 보안 엔티티. TX SC 1개 + RX SC 복수를 포함합니다. |
| SCI | - | SC당 1개 | MAC 주소(6B) + Port ID(2B) = 8바이트 식별자 |
| TX SC | 송신 | SecY당 정확히 1개 | 자신의 SCI를 가지며, 최대 4개의 TX SA를 포함 |
| RX SC | 수신 | 피어당 1개 (복수 가능) | 상대방의 SCI에 대응하며, 최대 4개의 RX SA를 포함 |
| SA | 양방향 | SC당 최대 4개 (AN 0-3) | 실제 키(SAK)와 PN 상태를 보유. 키 로테이션의 단위 |
| AN | 양방향 | 0, 1, 2, 3 | SecTAG에 포함되어 수신측이 어떤 SA/키를 사용할지 식별 |
주요 커널 자료구조
/* include/net/macsec.h - 핵심 자료구조 */
/* SecY: 보안 엔티티 */
struct macsec_secy {
struct net_device *netdev; /* 연결된 macsec net_device */
unsigned int n_rx_sc; /* RX SC 개수 */
sci_t sci; /* 자신의 SCI */
u16 key_len; /* SAK 길이 (16 또는 32바이트) */
u16 icv_len; /* ICV 길이 (8 또는 16바이트) */
enum macsec_validation_type validate_frames; /* strict/check/disabled */
bool xpn; /* Extended Packet Numbering */
bool operational; /* SecY 동작 상태 */
bool protect_frames; /* 송신 보호 활성화 */
bool replay_protect; /* replay protection */
u32 replay_window; /* replay 윈도우 크기 */
struct macsec_tx_sc tx_sc; /* 송신 SC (1개) */
struct macsec_rx_sc __rcu *rx_sc; /* 수신 SC 목록 (RCU) */
};
/* TX Secure Channel */
struct macsec_tx_sc {
bool encrypt; /* 암호화 활성화 (false면 무결성만) */
bool send_sci; /* SecTAG에 SCI 포함 여부 */
u8 encoding_sa; /* 현재 활성 TX SA 번호 (0-3) */
struct macsec_tx_sa __rcu *sa[MACSEC_NUM_AN]; /* TX SA 배열 */
struct pcpu_tx_sc_stats __percpu *stats;
};
/* TX Secure Association */
struct macsec_tx_sa {
struct macsec_key key; /* SAK + salt */
ssci_t ssci; /* Short SCI (XPN용) */
union {
atomic_t pn32; /* 32비트 PN 카운터 */
atomic64_t pn64; /* 64비트 PN 카운터 (XPN) */
} next_pn_halves;
bool active; /* SA 활성 상태 */
struct macsec_tx_sa_stats __percpu *stats;
struct rcu_head rcu;
};
/* RX Secure Channel */
struct macsec_rx_sc {
struct macsec_rx_sc __rcu *next; /* 다음 RX SC (linked list) */
sci_t sci; /* 상대방 SCI */
bool active;
struct macsec_rx_sa __rcu *sa[MACSEC_NUM_AN]; /* RX SA 배열 */
struct pcpu_rx_sc_stats __percpu *stats;
struct rcu_head rcu;
};
/* RX Secure Association */
struct macsec_rx_sa {
struct macsec_key key; /* SAK + salt */
ssci_t ssci;
atomic_t next_pn; /* 기대되는 다음 PN */
bool active;
struct macsec_rx_sa_stats __percpu *stats;
struct rcu_head rcu;
};
rcu_dereference()로, 구조체 변경은 rtnl_lock 아래에서 수행됩니다. 이는 MACsec이 고속 데이터 경로에서 잠금(Lock) 없이 동작할 수 있게 합니다.
MACsec HW Offload 아키텍처
Linux 5.6부터 MACsec은 NIC 하드웨어에 암복호화를 위임할 수 있는 offload 인프라를 제공합니다. HW offload가 활성화되면 CPU는 SecTAG 삽입/제거와 GCM 연산을 수행하지 않으며, NIC가 line-rate로 처리합니다.
offload 모드는 두 가지입니다:
| 모드 | enum 값 | 설명 |
|---|---|---|
| Off (SW) | MACSEC_OFFLOAD_OFF |
기본값. 커널이 Crypto API로 모든 암복호화를 수행합니다. |
| PHY offload | MACSEC_OFFLOAD_PHY |
PHY 칩이 MACsec 처리. phy_device->macsec_ops를 사용합니다. |
| MAC offload | MACSEC_OFFLOAD_MAC |
NIC MAC 레벨에서 처리. netdev->macsec_ops를 사용합니다. |
macsec_ops 콜백(Callback)과 드라이버 구현
NIC 드라이버가 MACsec HW offload을 지원하려면 struct macsec_ops를 구현하고 등록해야 합니다.
/* include/net/macsec.h */
struct macsec_ops {
/* SecY 관리 */
int (*mdo_dev_open)(struct macsec_context *ctx);
int (*mdo_dev_stop)(struct macsec_context *ctx);
int (*mdo_add_secy)(struct macsec_context *ctx);
int (*mdo_upd_secy)(struct macsec_context *ctx);
int (*mdo_del_secy)(struct macsec_context *ctx);
/* TX SA 관리 */
int (*mdo_add_txsa)(struct macsec_context *ctx);
int (*mdo_upd_txsa)(struct macsec_context *ctx);
int (*mdo_del_txsa)(struct macsec_context *ctx);
/* RX SC 관리 */
int (*mdo_add_rxsc)(struct macsec_context *ctx);
int (*mdo_upd_rxsc)(struct macsec_context *ctx);
int (*mdo_del_rxsc)(struct macsec_context *ctx);
/* RX SA 관리 */
int (*mdo_add_rxsa)(struct macsec_context *ctx);
int (*mdo_upd_rxsa)(struct macsec_context *ctx);
int (*mdo_del_rxsa)(struct macsec_context *ctx);
/* 통계 */
int (*mdo_get_dev_stats)(struct macsec_context *ctx);
int (*mdo_get_tx_sc_stats)(struct macsec_context *ctx);
int (*mdo_get_tx_sa_stats)(struct macsec_context *ctx);
int (*mdo_get_rx_sc_stats)(struct macsec_context *ctx);
int (*mdo_get_rx_sa_stats)(struct macsec_context *ctx);
/* 인서트 모드 (선택) */
int (*mdo_insert_tx_tag)(struct macsec_context *ctx);
};
드라이버 구현 시 핵심 사항:
- macsec_context: 커널이 콜백에 전달하는 컨텍스트로, SecY, SC, SA 정보와 SAK를 포함합니다.
- 원자적(Atomic) 업데이트: SA 키 교체 시 트래픽 중단 없이 NIC 내부 테이블을 업데이트해야 합니다.
- 통계 콜백: HW offload 시 NIC가 카운터를 유지하므로,
mdo_get_*_stats로 이를 커널에 보고합니다. - fallback 없음: HW offload가 설정된 후에는 SW fallback이 자동으로 활성화되지 않습니다. NIC가 지원하지 않는 기능(예: XPN)을 요청하면 에러를 반환합니다.
HW Offload 지원 NIC
| 벤더 / 드라이버 | 칩 | offload 모드 | 특이사항 |
|---|---|---|---|
| Mellanox (NVIDIA) / mlx5 | ConnectX-6 Dx (기본) / ConnectX-7 이상 (Full XPN offload) | MAC offload | ConnectX-6 Dx부터 GCM-AES-128/256 지원. ConnectX-7 이상은 GCM-AES-XPN-128/256까지 NIC에서 풀 오프로드(40/100/200/400 GbE에서 32비트 PN 소진 회피). 가장 완성도 높은 구현. |
| Intel / ice | E810 시리즈 | MAC offload | GCM-AES-128/256 지원. 6.x 커널에서 점진적으로 확장. ixgbe(82599/X540/X550) 계열은 MACsec 오프로드 미지원이며 인텔이 추가 계획이 없다고 공식 답변(Intel Community 포럼). |
| Marvell / mvpp2 | Armada 7K/8K | MAC offload | 임베디드/네트워킹 프로세서 기반. |
| NXP / felix (ocelot) | LS1028A, VSC7511 등 | MAC offload | 스위치 ASIC의 MACsec 엔진 활용. |
| Microchip / lan966x | LAN966x | MAC offload | 산업용/IoT 이더넷 스위치. |
| 다양한 PHY 벤더 | Vitesse/Microchip PHY 등 | PHY offload | PHY 내장 MACsec 엔진. MDIO로 제어. |
# NIC의 MACsec offload 지원 확인
ethtool -k eth0 | grep macsec
# macsec-hw-offload: on [requested on]
# offload 모드 설정 (ip link 생성 시)
ip link add link eth0 macsec0 type macsec sci 1 encrypt on offload mac
HW Offload 통계와 모니터링
HW offload 시 통계는 NIC 하드웨어 카운터에서 가져옵니다. ip -s macsec show는 offload 모드에 관계없이 동일한 형식으로 통계를 표시합니다.
# MACsec 통계 확인
ip -s macsec show
# 출력 예시:
# 3: macsec0: protect on validate strict sc off sa off encrypt on
# send_sci on end_station off scb off replay off
# cipher suite: GCM-AES-128, using ICV length 16
# TXSC: 001122334455005c on SA 0
# 0: PN 42857362, state on, key 01000000000000000000000000000000
# InPktsUntagged 0 InPktsNoTag 0
# InPktsOK 5827391
# InPktsInvalid 0 InPktsNotValid 0
# InPktsLate 0 InPktsDelayed 0
# InPktsNotUsingSA 0 InPktsUnusedSA 0
# OutPktsProtected 5827422
# OutPktsEncrypted 5827422
# 통계 카운터 의미:
# InPktsOK: 복호화+ICV 검증 성공
# InPktsInvalid: ICV 검증 실패 (validate=check 시에도 카운트)
# InPktsNotValid: ICV 검증 실패 + drop (validate=strict)
# InPktsLate: replay 윈도우 밖 (너무 오래된 PN)
# InPktsDelayed: replay 윈도우 내이지만 순서 역전
# OutPktsProtected: 보호된 송신 패킷 (무결성)
# OutPktsEncrypted: 암호화된 송신 패킷
ip macsec show 출력에 offload mac 또는 offload phy가 표시되면 HW offload가 활성화된 상태입니다. SW 모드에서는 이 필드가 나타나지 않습니다.
ip macsec 명령어 완전 가이드
iproute2의 ip macsec 하위 명령은 MACsec 디바이스와 SA를 관리하는 기본 도구입니다.
# === MACsec 디바이스 생성 ===
# 기본 생성 (GCM-AES-128, 암호화 활성)
ip link add link eth0 macsec0 type macsec encrypt on
# SCI 명시적 지정
ip link add link eth0 macsec0 type macsec \
sci 0x0011223344550001 encrypt on
# GCM-AES-256 스위트 사용
ip link add link eth0 macsec0 type macsec \
cipher gcm-aes-256 encrypt on
# GCM-AES-XPN-128 (64비트 PN, 고속 링크용)
ip link add link eth0 macsec0 type macsec \
cipher gcm-aes-xpn-128 encrypt on
# HW offload 활성화
ip link add link eth0 macsec0 type macsec \
encrypt on offload mac
# replay protection 활성화 (윈도우 크기 128)
ip link add link eth0 macsec0 type macsec \
encrypt on replay on window 128
# 무결성 전용 (암호화 안 함, ICV만)
ip link add link eth0 macsec0 type macsec \
encrypt off protect on
# === TX SA 설정 ===
# TX SA 추가 (AN 0, 초기 PN 1)
ip macsec add macsec0 tx sa 0 pn 1 on \
key 00 0123456789abcdef0123456789abcdef
# TX SA 추가 (AN 1, AES-256 키)
ip macsec add macsec0 tx sa 1 pn 1 on \
key 01 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
# XPN 모드 TX SA (salt와 ssci 지정)
ip macsec add macsec0 tx sa 0 pn 1 on \
key 00 0123456789abcdef0123456789abcdef \
salt 0123456789ab ssci 1
# === RX SC 및 RX SA 설정 ===
# 상대방의 RX SC 추가 (상대방의 SCI)
ip macsec add macsec0 rx 001122334455 port 1
# RX SA 추가 (동일한 SAK)
ip macsec add macsec0 rx 001122334455 port 1 sa 0 pn 1 on \
key 00 0123456789abcdef0123456789abcdef
# === 인터페이스 활성화 ===
ip link set macsec0 up
ip addr add 192.168.100.1/24 dev macsec0
# === 상태 확인 ===
# MACsec 상태 요약
ip macsec show
# 상세 통계
ip -s macsec show
# JSON 출력 (스크립트용)
ip -j macsec show | jq .
# === SA 상태 변경 ===
# TX SA 비활성화
ip macsec set macsec0 tx sa 0 off
# encoding_sa 변경 (키 로테이션)
ip link set macsec0 type macsec encodingsa 1
# === 삭제 ===
# SA 삭제
ip macsec del macsec0 tx sa 0
# RX SC 삭제
ip macsec del macsec0 rx 001122334455 port 1
# MACsec 디바이스 삭제
ip link del macsec0
wpa_supplicant MKA 설정
wpa_supplicant는 MKA 프로토콜의 유저스페이스 구현을 제공하며, MACsec 키 합의를 자동으로 수행합니다. 수동으로 SA를 설정하는 ip macsec과 달리, wpa_supplicant는 MKA를 통해 SAK를 자동 교환하고 로테이션합니다.
# wpa_supplicant 실행 예시
wpa_supplicant -i macsec0 -Dmacsec_linux -c /etc/wpa_supplicant/macsec.conf
# 또는 systemd 서비스로 실행
systemctl start wpa_supplicant-macsec@eth0
Static CAK/CKN 설정 (PSK 모드)
가장 간단한 MKA 설정은 Static CAK(사전 공유 키) 모드입니다. 양측에 동일한 CAK와 CKN을 설정하면 MKA가 자동으로 SAK를 합의합니다.
# /etc/wpa_supplicant/macsec-psk.conf
# --- 호스트 A ---
ctrl_interface=/var/run/wpa_supplicant
eapol_version=3
ap_scan=0
fast_reauth=1
network={
key_mgmt=NONE
eapol_flags=0
macsec_policy=1 # 1 = MACsec 필수
macsec_integ_only=0 # 0 = 암호화+무결성, 1 = 무결성만
macsec_replay_protect=1
macsec_replay_window=0
mka_cak=0123456789abcdef0123456789abcdef
mka_ckn=6162636465666768696a6b6c6d6e6f70
mka_priority=16 # 키 서버 우선순위 (0-255)
}
# --- 호스트 B ---
# 동일한 mka_cak, mka_ckn 사용
# mka_priority를 다르게 하면 키 서버 역할이 결정됨
# 양쪽 호스트에서 실행
# 호스트 A (eth0 = 직결 링크)
wpa_supplicant -i eth0 -Dmacsec_linux -c /etc/wpa_supplicant/macsec-psk.conf &
# MKA가 성공하면 자동으로 macsec0 인터페이스 생성
# IP 주소 할당
ip addr add 10.0.0.1/24 dev macsec0
ip link set macsec0 up
# MKA 상태 확인
wpa_cli -i eth0 status
# ... key_mgmt=NONE
# ... Supplicant PAE state=AUTHENTICATED
# ... MKA status: active
# SAK 교환 확인
ip -s macsec show
600으로 설정하고, 운영 환경에서는 EAP 기반 인증을 권장합니다. CAK가 유출되면 모든 파생 키(ICK, KEK, SAK)가 손상됩니다.
EAP 기반 MACsec (802.1X + MKA)
엔터프라이즈 환경에서는 RADIUS 서버와 802.1X EAP 인증을 결합하여 MACsec을 구성합니다. EAP 인증이 성공하면 MSK(Master Session Key)에서 CAK와 CKN이 자동 파생됩니다.
# /etc/wpa_supplicant/macsec-eap.conf
ctrl_interface=/var/run/wpa_supplicant
eapol_version=3
ap_scan=0
network={
key_mgmt=IEEE8021X
eap=TLS # 또는 PEAP, TTLS 등
eapol_flags=0
# EAP-TLS 인증서
identity="host-a@example.com"
ca_cert="/etc/pki/tls/certs/ca.pem"
client_cert="/etc/pki/tls/certs/host-a.pem"
private_key="/etc/pki/tls/private/host-a.key"
private_key_passwd="secret"
# MACsec 정책
macsec_policy=1
macsec_integ_only=0
macsec_replay_protect=1
macsec_replay_window=32
# EAP에서 CAK/CKN 자동 파생
# mka_cak/mka_ckn은 설정하지 않음!
}
EAP 기반 MACsec의 흐름:
- 802.1X 인증: Supplicant가 Authenticator(스위치)를 통해 RADIUS 서버와 EAP 인증을 수행합니다.
- MSK 파생: EAP 인증 성공 시 양측이 MSK(Master Session Key)를 공유합니다.
- CAK/CKN 파생: MSK에서 CAK와 CKN이 KDF로 파생됩니다.
- MKA 시작: CAK/CKN으로 MKA 프로토콜이 자동 시작되어 SAK를 합의합니다.
- MACsec 보호: SAK 합의 완료 후 데이터 프레임 보호가 시작됩니다.
| 항목 | PSK 모드 | EAP 모드 |
|---|---|---|
| CAK 소스 | 관리자가 수동 설정 | EAP MSK에서 자동 파생 |
| CKN 소스 | 관리자가 수동 설정 | EAP 세션 ID에서 자동 파생 |
| CAK 수명 | 관리자가 변경할 때까지 영구 | EAP 재인증 주기에 따라 갱신 |
| 확장성 | 수동 키 관리로 제한적 | RADIUS 중앙 관리로 대규모 적합 |
| 인프라 요구 | 없음 (호스트 쌍 설정만) | RADIUS 서버, PKI 인증서 필요 |
| 적합 환경 | 소규모, 서버 간 직결 | 엔터프라이즈, 대규모 데이터센터 |
systemd-networkd를 이용한 MACsec 설정
systemd 248+ 버전의 systemd-networkd는 MACsec 디바이스 설정을 기본 지원합니다. wpa_supplicant 없이 정적 키 모드의 MACsec을 구성할 수 있습니다.
# /etc/systemd/network/25-macsec.netdev
[NetDev]
Name=macsec0
Kind=macsec
[MACsec]
Port=1
Encrypt=yes
# /etc/systemd/network/25-macsec.network
[Match]
Name=macsec0
[Network]
Address=10.0.0.1/24
# /etc/systemd/network/25-macsec-key.keyfile
# (별도 키 파일, 권한 600)
[MACsecTransmitAssociation]
Number=0
PacketNumber=1
KeyId=00
Key=0123456789abcdef0123456789abcdef
[MACsecReceiveChannel]
MACAddress=aa:bb:cc:dd:ee:ff
Port=1
[MACsecReceiveAssociation]
Number=0
PacketNumber=1
KeyId=00
Key=0123456789abcdef0123456789abcdef
# 적용
systemctl restart systemd-networkd
networkctl status macsec0
데이터센터 East-West 트래픽 보호 패턴
MACsec의 가장 대표적인 용도는 데이터센터 내부(East-West) 링크 암호화입니다. 서버 간 또는 서버-TOR(Top of Rack) 스위치 간 직결 링크를 MACsec으로 보호하면, 물리적 케이블 도청(wiretapping)이나 중간자 공격(MITM)을 방어할 수 있습니다.
데이터센터 MACsec 배포 패턴
| 패턴 | 구간 | 키 관리 | 장점 |
|---|---|---|---|
| Host-to-TOR | 서버 NIC ↔ TOR 스위치 포트 | 서버별 PSK 또는 802.1X | 서버 측에서 제어 가능, NIC HW offload 활용 |
| Switch-to-Switch | TOR ↔ Spine/Leaf 스위치 | 스위치 쌍별 PSK | 패브릭 전체 암호화, ASIC 가속 |
| End-to-End (희소) | 서버 ↔ 서버 (직결) | 서버 쌍별 PSK | 스위치 불필요, 가장 단순한 구성 |
스위치 연동 (Cisco/Arista/Juniper MACsec 상호운용)
Linux 호스트의 MACsec을 엔터프라이즈 스위치와 연동하려면 양측의 설정을 맞춰야 합니다.
| 스위치 벤더 | MACsec 설정 위치 | 주의사항 |
|---|---|---|
| Cisco (IOS-XE/NX-OS) | mka policy, macsec 인터페이스 명령 |
CKN 길이를 64hex(32B)로 맞춰야 함. should-secure 모드 주의 |
| Arista (EOS) | mac security 프로파일 |
PSK fallback 정책 확인. LLDP와 MACsec 순서 주의 |
| Juniper (Junos) | set security macsec |
connectivity-association 이름과 CKN 매핑(Mapping) 확인 |
# Cisco IOS-XE 스위치와 Linux 호스트 연동 예시
# --- Cisco 스위치 측 (간략) ---
# mka policy my-policy
# key-server-priority 10
# macsec-cipher-suite gcm-aes-128
# interface GigabitEthernet1/0/1
# mka policy my-policy
# mka pre-shared-key key-chain my-keychain
# macsec
# --- Linux 호스트 측 ---
# /etc/wpa_supplicant/macsec-cisco.conf
ctrl_interface=/var/run/wpa_supplicant
eapol_version=3
ap_scan=0
network={
key_mgmt=NONE
eapol_flags=0
macsec_policy=1
macsec_integ_only=0
# Cisco와 동일한 CAK/CKN (CKN은 64 hex 문자 = 32바이트)
mka_cak=0123456789abcdef0123456789abcdef
mka_ckn=6162636465666768696a6b6c6d6e6f706162636465666768696a6b6c6d6e6f70
mka_priority=20
}
# 실행
wpa_supplicant -i eth0 -Dmacsec_linux -c /etc/wpa_supplicant/macsec-cisco.conf
성능 벤치마크 (SW vs HW Offload)
MACsec의 성능은 SW vs HW offload에 따라 극적으로 달라집니다. 소프트웨어 경로에서는 모든 패킷마다 GCM-AES 암복호화를 CPU가 수행해야 하므로, 고속 링크에서는 CPU가 병목(Bottleneck)이 됩니다. HW offload는 NIC 내장 crypto 엔진이 line-rate로 처리하므로 CPU 부담이 사실상 없습니다.
SW MACsec 성능 특성
소프트웨어 MACsec의 성능은 여러 요인에 의해 결정됩니다:
- AES-NI 유무: AES-NI(Intel) 또는 ARMv8-CE(ARM) 없이는 SW MACsec이 사실상 사용할 수 없을 만큼 느립니다. AES-NI가 있으면 단일 코어에서 ~5-8 Gbps, 없으면 ~500 Mbps 수준입니다.
- 패킷 크기: GCM-AES는 패킷당 고정 비용(nonce 설정, 태그 생성)이 있으므로, 작은 패킷일수록 오버헤드(Overhead) 비율이 높아집니다. 64바이트 패킷 대비 1500바이트 패킷에서 약 10배의 처리량(Throughput) 차이가 나타납니다.
- CPU 아키텍처: PCLMULQDQ(캐리 없는 곱셈) 명령어가 GCM의 GHASH 연산을 가속합니다. 최신 CPU일수록 GCM 처리량이 높습니다.
- NUMA 배치: NIC와 같은 NUMA 노드의 CPU가 crypto 처리를 하도록 IRQ affinity를 설정하면 캐시(Cache) 미스가 줄어 성능이 향상됩니다.
프레임 크기별 성능 영향
| 프레임 크기 | SW GCM-AES-128 (Mpps) | SW 처리량 (Gbps) | HW 처리량 (Gbps) | 비고 |
|---|---|---|---|---|
| 64 바이트 | ~1.5 | ~0.8 | line-rate | per-packet 오버헤드 지배적 |
| 256 바이트 | ~1.2 | ~2.5 | line-rate | |
| 512 바이트 | ~0.9 | ~3.7 | line-rate | |
| 1024 바이트 | ~0.7 | ~5.7 | line-rate | |
| 1500 바이트 | ~0.55 | ~6.6 | line-rate | 일반적인 MTU |
| 9000 바이트 (Jumbo) | ~0.18 | ~12.9 | line-rate | 처리량 최적 |
| 구성 | 처리량 (iperf3, TCP) | CPU 사용률 | 지연(Latency) 추가 |
|---|---|---|---|
| MACsec 없음 (baseline) | 25 Gbps | ~15% | - |
| SW MACsec (GCM-AES-128, AES-NI) | ~8-12 Gbps | ~90-100% | ~5-15 µs |
| SW MACsec (GCM-AES-256, AES-NI) | ~6-10 Gbps | ~90-100% | ~8-20 µs |
| HW Offload MACsec (ConnectX-6 Dx) | 25 Gbps (line-rate) | ~15% (baseline 동일) | ~1-2 µs |
| HW Offload MACsec (100G NIC) | 100 Gbps (line-rate) | 최소 | <1 µs |
# 성능 측정 예시
# 1. Baseline (MACsec 없음)
iperf3 -c 10.0.0.2 -t 30 -P 4
# 2. SW MACsec 측정
ip link add link eth0 macsec0 type macsec encrypt on
ip macsec add macsec0 tx sa 0 pn 1 on \
key 00 0123456789abcdef0123456789abcdef
ip macsec add macsec0 rx aabbccddeeff port 1 sa 0 pn 1 on \
key 00 0123456789abcdef0123456789abcdef
ip addr add 10.0.0.1/24 dev macsec0
ip link set macsec0 up
iperf3 -c 10.0.0.2 -t 30 -P 4
# 3. CPU 프로파일링 (SW 경로 병목 확인)
perf top -g -p $(pgrep iperf3)
# gcm_encrypt, aesni_gcm_enc 등이 상위에 나타남
# 4. MTU 영향 측정 (작은 패킷 vs 큰 패킷)
iperf3 -c 10.0.0.2 -t 10 -l 64 # 작은 패킷
iperf3 -c 10.0.0.2 -t 10 -l 1400 # 큰 패킷
# 작은 패킷에서 per-packet GCM 오버헤드가 두드러짐
- SW MACsec에서는 AES-NI가 필수입니다.
lscpu | grep aes로 확인하세요. - 점보 프레임(MTU 9000)을 사용하면 per-packet GCM 오버헤드 비율이 줄어 처리량이 향상됩니다.
- 25G 이상에서는 HW offload 없이는 실용적이지 않습니다.
- NUMA-aware IRQ 배치로 NIC와 동일 NUMA 노드의 CPU가 crypto를 처리하도록 하세요.
지연 분석
MACsec이 추가하는 지연는 주로 GCM-AES 연산 시간입니다:
| 경로 | 추가 지연 | 구성 요소 |
|---|---|---|
| SW MACsec TX | ~3-8 µs | SecTAG 삽입 + GCM encrypt + skb 조작 |
| SW MACsec RX | ~3-10 µs | GCM decrypt + ICV 검증 + replay check + SecTAG 제거 |
| HW Offload TX/RX | ~0.5-2 µs | NIC 파이프라인(Pipeline) 내 처리 (wire delay에 가까움) |
| MKA MKPDU 처리 | 유저스페이스 | wpa_supplicant 처리 시간 (데이터 경로 아님) |
# 레이턴시 측정 (단방향 근사)
# sockperf 사용
sockperf ping-pong -i 10.0.0.2 -t 60 --full-rtt
# 또는 qperf 사용
# 서버: qperf
# 클라이언트: qperf 10.0.0.2 tcp_lat udp_lat
MACsec과 네트워크 네임스페이스(Namespace)
MACsec 디바이스는 네트워크 네임스페이스 간 이동이 가능합니다. 이를 활용하면 컨테이너(Container) 환경에서 MACsec 보호를 적용할 수 있습니다.
# MACsec + 네트워크 네임스페이스 예시
# 1. 기본 네임스페이스에서 MACsec 디바이스 생성
ip link add link eth0 macsec0 type macsec encrypt on
ip macsec add macsec0 tx sa 0 pn 1 on \
key 00 0123456789abcdef0123456789abcdef
ip macsec add macsec0 rx aabbccddeeff port 1 sa 0 pn 1 on \
key 00 0123456789abcdef0123456789abcdef
# 2. 네임스페이스 생성 및 MACsec 이동
ip netns add secure-ns
ip link set macsec0 netns secure-ns
# 3. 네임스페이스 내에서 IP 설정
ip netns exec secure-ns ip addr add 10.0.0.1/24 dev macsec0
ip netns exec secure-ns ip link set macsec0 up
ip netns exec secure-ns ip link set lo up
# 4. 네임스페이스 내에서 통신 테스트
ip netns exec secure-ns ping 10.0.0.2
# 주의: real_dev(eth0)는 원래 네임스페이스에 남아 있어야 합니다.
# MACsec 디바이스만 이동할 수 있습니다.
MACsec과 VLAN/Bridge 환경
MACsec과 VLAN 태깅의 순서는 중요한 설계 결정입니다. IEEE 802.1AE 표준에서는 두 가지 모드를 정의합니다.
| 모드 | 프레임 구조 | 특징 |
|---|---|---|
| VLAN 외부 MACsec (MACsec before VLAN) |
Dst|Src|SecTAG|VLAN|IP...|ICV | VLAN 태그도 암호화/무결성 보호됨. 스위치가 VLAN을 볼 수 없음. |
| VLAN 내부 MACsec (MACsec after VLAN) |
Dst|Src|VLAN|SecTAG|IP...|ICV | VLAN 태그가 평문. 스위치가 VLAN 기반 포워딩 가능. |
# Linux에서 MACsec + VLAN 구성
# 방법 1: MACsec 위에 VLAN (MACsec이 먼저, VLAN 태그 보호됨)
ip link add link eth0 macsec0 type macsec encrypt on
# (SA 설정 생략)
ip link add link macsec0 name macsec0.100 type vlan id 100
ip addr add 10.100.0.1/24 dev macsec0.100
# 방법 2: VLAN 위에 MACsec (VLAN이 먼저, 스위치가 VLAN 볼 수 있음)
ip link add link eth0 name eth0.100 type vlan id 100
ip link add link eth0.100 macsec0 type macsec encrypt on
# (SA 설정 생략)
ip addr add 10.100.0.1/24 dev macsec0
# Bridge 환경
# MACsec 디바이스를 bridge 멤버로 추가 가능
ip link add br0 type bridge
ip link set macsec0 master br0
ip link set br0 up
트러블슈팅과 디버깅(Debugging)
# === 1단계: MACsec 인터페이스 상태 확인 ===
# 인터페이스 존재 및 상태
ip link show type macsec
ip -d link show macsec0
# MACsec 상세 설정 확인
ip macsec show
# cipher suite, encrypt, protect, validate, replay 설정 확인
# === 2단계: SA 상태와 키 매칭 확인 ===
# TX/RX SA가 올바르게 설정되었는지
ip macsec show
# TX SA와 RX SA가 모두 "on" 상태인지
# 양측의 키(key ID)가 일치하는지
# AN 번호가 매칭되는지
# === 3단계: 통계로 문제 진단 ===
ip -s macsec show
# InPktsOK > 0 → 정상 수신 동작
# InPktsNotValid > 0 → ICV 검증 실패 → 키 불일치 또는 프레임 손상
# InPktsNoTag > 0 → MACsec 없는 프레임 수신 (상대가 MACsec 미설정?)
# InPktsLate > 0 → replay 윈도우 밖 → 윈도우 크기 증가 필요
# OutPktsProtected = 0 → TX SA 미설정 또는 비활성
# === 4단계: 실시간 프레임 캡처 ===
# real_dev에서 MACsec 프레임 캡처 (암호화된 상태)
tcpdump -i eth0 ether proto 0x88e5 -c 20 -vv
# macsec_dev에서 복호화된 프레임 캡처
tcpdump -i macsec0 -c 20
# MKA(EAPoL) 프레임 확인
tcpdump -i eth0 ether proto 0x888e -c 10 -vv
# === 5단계: wpa_supplicant MKA 디버깅 ===
# wpa_supplicant를 디버그 모드로 실행
wpa_supplicant -i eth0 -Dmacsec_linux -c /etc/wpa_supplicant/macsec.conf -dd
# wpa_cli로 MKA 상태 실시간 확인
wpa_cli -i eth0 status
wpa_cli -i eth0 mib
# === 6단계: ftrace로 커널 경로 추적 ===
# MACsec 함수 추적
echo 'macsec_*' > /sys/kernel/debug/tracing/set_ftrace_filter
echo function > /sys/kernel/debug/tracing/current_tracer
echo 1 > /sys/kernel/debug/tracing/tracing_on
cat /sys/kernel/debug/tracing/trace_pipe
# === 7단계: 일반적인 문제와 해결 ===
# 문제: 양측 ping 실패, InPktsNotValid 증가
# 원인: 키 불일치 (양측 SAK가 다름)
# 해결: CAK/CKN 또는 수동 설정 키가 양측에서 동일한지 확인
# 문제: MKA 세션이 수립되지 않음
# 원인: EAPoL 프레임이 도달하지 않음
# 해결: 중간 스위치가 EtherType 0x888E를 차단하지 않는지 확인
# 문제: HW offload 실패 ("Operation not supported")
# 원인: NIC가 요청된 cipher suite를 지원하지 않음
# 해결: ethtool -k eth0 | grep macsec 확인, SW 모드 fallback
# 문제: InPktsLate 급증
# 원인: 패킷 순서 역전이 replay 윈도우를 초과
# 해결: replay window 크기 증가 (ip link 재생성 필요)
일반적인 문제 체크리스트
| 증상 | 확인 카운터 | 가능한 원인 | 해결 방법 |
|---|---|---|---|
| 양측 통신 불가 | OutPktsProtected = 0 | TX SA 미설정 또는 비활성 | ip macsec show로 TX SA 상태 확인, on 설정 |
| 단방향만 통신 | 한쪽 InPktsOK=0 | RX SC/SA 미설정 또는 SCI 불일치 | 양측의 SCI와 RX SC 설정 확인 |
| 간헐적 패킷 손실 | InPktsLate 증가 | replay 윈도우 초과 | replay window 크기 증가 (128, 256 등) |
| 모든 패킷 drop | InPktsNotValid 증가 | 키 불일치 (SAK가 다름) | 양측의 key hex 값 동일한지 확인 |
| MKA 세션 미수립 | MACsec 인터페이스 미생성 | EAPoL 프레임 차단, CAK/CKN 불일치 | tcpdump -i eth0 ether proto 0x888e로 MKA 프레임 도달 확인 |
| HW offload 설정 실패 | RTNETLINK: Operation not supported | NIC가 MACsec offload 미지원 | ethtool -k eth0 | grep macsec 확인, SW 모드 사용 |
| MTU 관련 단편화(Fragmentation) | 정상 카운터, 큰 패킷만 실패 | SecTAG+ICV로 인한 MTU 초과 | macsec0 MTU 확인, 점보 프레임 또는 상위 MTU 감소 |
| 성능 저하 | InPktsOK 정상, 처리량 낮음 | SW 경로에서 CPU 병목 | HW offload 활성화, AES-NI 확인, IRQ affinity 조정 |
커널 로그와 동적 디버깅
# 커널 MACsec 관련 메시지 확인
dmesg | grep -i macsec
# 동적 디버그 활성화 (커널에 CONFIG_DYNAMIC_DEBUG 필요)
echo 'module macsec +p' > /sys/kernel/debug/dynamic_debug/control
dmesg -w | grep macsec
# 네트워크 이벤트 모니터링
ip monitor link type macsec
# perf로 SW 경로 병목 분석
perf record -g -a -- sleep 10
perf report --sort=comm,dso,symbol
# gcm_encrypt, aesni_gcm_enc, macsec_encrypt_finish 등 확인
# bpftrace로 MACsec TX/RX 경로 관찰
bpftrace -e 'kprobe:macsec_start_xmit { @tx = count(); }
kprobe:macsec_handle_frame { @rx = count(); }
interval:s:1 { print(@tx); print(@rx); clear(@tx); clear(@rx); }'
커널 빌드 옵션
| Kconfig 옵션 | 기본값 | 설명 |
|---|---|---|
CONFIG_MACSEC |
m (모듈) | MACsec 핵심 모듈 (macsec.ko). 이것 없이는 MACsec 사용 불가. |
CONFIG_CRYPTO_GCM |
y | GCM 모드. MACsec의 암호 스위트에 필수. |
CONFIG_CRYPTO_AES |
y | AES 블록 암호. GCM-AES에 필수. |
CONFIG_CRYPTO_AES_NI_INTEL |
m | AES-NI 하드웨어 가속. SW MACsec 성능에 결정적. |
CONFIG_CRYPTO_SEQIV |
y | 시퀀스 IV 생성. GCM nonce 관리에 필요. |
CONFIG_NET_MACSEC |
- | 일부 커널 버전에서 CONFIG_MACSEC의 별칭. |
# 현재 커널의 MACsec 관련 설정 확인
zcat /proc/config.gz 2>/dev/null | grep -i macsec
# 또는
grep -i macsec /boot/config-$(uname -r)
# MACsec 모듈 로드 확인
lsmod | grep macsec
# 수동 모듈 로드
modprobe macsec
# MACsec 모듈 정보
modinfo macsec
CONFIG_MACSEC=m으로 MACsec 모듈을 제공합니다. ip link add type macsec 시 커널이 자동으로 모듈을 로드합니다.
HW Offload 관련 드라이버 Kconfig
| 드라이버 | Kconfig | 설명 |
|---|---|---|
| mlx5 (Mellanox/NVIDIA) | CONFIG_MLX5_MACSEC |
ConnectX-6 Dx+ MACsec offload. CONFIG_MLX5_CORE 필요. |
| ice (Intel) | CONFIG_ICE |
E810 MACsec은 별도 Kconfig 없이 드라이버에 포함. |
| ocelot/felix (NXP) | CONFIG_MSCC_OCELOT_SWITCH_LIB |
LS1028A 등 NXP 스위치 ASIC의 MACsec. |
| lan966x (Microchip) | CONFIG_LAN966X_SWITCH |
LAN966x 내장 MACsec 엔진. |
유저스페이스 도구 요구사항
| 도구 | 패키지 | 최소 버전 | 용도 |
|---|---|---|---|
ip macsec |
iproute2 | 4.6+ | MACsec 디바이스/SA 수동 관리 |
wpa_supplicant |
wpa_supplicant | 2.6+ (macsec_linux 드라이버) | MKA 프로토콜 (자동 SAK 교환) |
wpa_cli |
wpa_supplicant | 2.6+ | MKA 상태 모니터링 |
ethtool |
ethtool | 5.4+ | HW offload 지원 확인 |
tcpdump |
tcpdump | 4.9+ | MACsec/EAPoL 프레임 캡처 |
# 배포판별 패키지 설치
# RHEL/CentOS/Fedora
dnf install iproute wpa_supplicant ethtool tcpdump
# Ubuntu/Debian
apt install iproute2 wpasupplicant ethtool tcpdump
# SLES/openSUSE
zypper install iproute2 wpa_supplicant ethtool tcpdump
# wpa_supplicant MACsec 드라이버 확인
wpa_supplicant -h 2>&1 | grep macsec
# drivers: ... macsec_linux ...
전체 설정 예제: 두 호스트 간 정적 키 MACsec
가장 기본적인 사용 사례로, 두 Linux 호스트가 직결 이더넷 링크로 연결된 환경에서 ip macsec만으로 MACsec을 구성하는 전체 예제입니다.
# ============================================
# 호스트 A (eth0 MAC: aa:bb:cc:dd:ee:01)
# ============================================
# 1. MACsec 디바이스 생성
ip link add link eth0 macsec0 type macsec \
encrypt on replay on window 64
# 2. TX SA 설정 (AN 0)
ip macsec add macsec0 tx sa 0 pn 1 on \
key 00 ad7a2bd03eac835a6f620fdcb506b345
# 3. RX SC 추가 (호스트 B의 MAC)
ip macsec add macsec0 rx aabbccddeeff port 1
# 4. RX SA 설정 (호스트 B와 동일한 키)
ip macsec add macsec0 rx aabbccddeeff port 1 sa 0 pn 1 on \
key 00 ad7a2bd03eac835a6f620fdcb506b345
# 5. 인터페이스 활성화 및 IP 할당
ip link set macsec0 up
ip addr add 10.0.0.1/24 dev macsec0
# ============================================
# 호스트 B (eth0 MAC: aa:bb:cc:dd:ee:ff)
# ============================================
# 1. MACsec 디바이스 생성
ip link add link eth0 macsec0 type macsec \
encrypt on replay on window 64
# 2. TX SA 설정 (AN 0, 동일 키)
ip macsec add macsec0 tx sa 0 pn 1 on \
key 00 ad7a2bd03eac835a6f620fdcb506b345
# 3. RX SC 추가 (호스트 A의 MAC)
ip macsec add macsec0 rx aabbccddeeff01 port 1
# 4. RX SA 설정
ip macsec add macsec0 rx aabbccddeeff01 port 1 sa 0 pn 1 on \
key 00 ad7a2bd03eac835a6f620fdcb506b345
# 5. 인터페이스 활성화 및 IP 할당
ip link set macsec0 up
ip addr add 10.0.0.2/24 dev macsec0
# ============================================
# 검증
# ============================================
# 호스트 A에서:
ping 10.0.0.2
ip -s macsec show
# 암호화된 프레임 확인 (eth0에서)
tcpdump -i eth0 ether proto 0x88e5 -c 5
# 복호화된 프레임 확인 (macsec0에서)
tcpdump -i macsec0 icmp -c 5
MACsec 프레임 변환 상세
MACsec은 원본 이더넷 프레임을 보호된 프레임으로 변환합니다. 이 과정에서 SecTAG(Security Tag) 삽입, 페이로드 암호화, ICV(Integrity Check Value) 추가가 순차적으로 수행됩니다. 변환 전후의 프레임 구조를 정확히 이해하면 패킷 캡처 분석과 트러블슈팅이 훨씬 수월해집니다.
암호화 모드 변환 (Encrypt + Authenticate)
기본 모드에서는 원본 페이로드 전체가 GCM-AES로 암호화되고, 프레임 끝에 ICV가 추가됩니다.
| 필드 | 원본 프레임 | MACsec 프레임 | 변화 |
|---|---|---|---|
| Dst MAC | 6바이트 | 6바이트 (그대로) | 변경 없음 |
| Src MAC | 6바이트 | 6바이트 (그대로) | 변경 없음 |
| EtherType | 원본 (0x0800 등) | 0x88E5 (MACsec) | SecTAG로 대체 |
| SecTAG | — | 8~16바이트 | 신규 삽입 |
| Payload | 평문 | 암호문 | GCM-AES 암호화 |
| 원본 EtherType | — | 암호화된 페이로드에 포함 | SecTAG 뒤에 매립 |
| ICV | — | 8~16바이트 | 신규 추가 |
| FCS | 4바이트 | 4바이트 (재계산) | 전체 프레임 기반 재계산 |
무결성 전용 모드 변환 (Authenticate Only)
macsec_integ_only=1로 설정하면 페이로드를 암호화하지 않고 무결성 검증만 수행합니다. 디버깅이나 QoS 장비가 페이로드를 검사해야 하는 환경에서 유용합니다.
# 무결성 전용 모드 설정
ip link add link eth0 macsec0 type macsec encrypt off
# encrypt off = 무결성만, encrypt on = 암호화+무결성(기본)
# tcpdump로 확인: 0x88E5이지만 페이로드는 평문
tcpdump -i eth0 -X ether proto 0x88e5 -c 1
# SecTAG의 SC bit 확인: E=0 (암호화 안 함)
GCM AAD(Additional Authenticated Data) 범위
GCM-AES 모드에서 AAD(Additional Authenticated Data, 추가 인증 데이터)에 포함되는 영역과 암호화되는 영역은 명확히 구분됩니다:
| 영역 | AAD (무결성 보호) | 암호화 | 설명 |
|---|---|---|---|
| Dst MAC + Src MAC | O | X | L2 헤더는 평문, 무결성만 보호 |
| SecTAG | O | X | 보안 태그 자체는 평문 |
| Secure Data (페이로드) | O | O (encrypt 모드) | 암호화 + 무결성 동시 보호 |
| ICV | — | — | GCM 인증 태그 출력값 |
MKA 키 교환 프로토콜 상세
MKA(MACsec Key Agreement)는 IEEE 802.1X-2010에서 정의된 키 합의 프로토콜로, EAPoL-MKA 프레임(EtherType 0x888E)을 통해 동작합니다. MKA의 핵심 동작 단계와 타이머(Timer), 상태 머신을 상세히 분석합니다.
MKA 세션 수립 단계
- 피어 발견 (Peer Discovery): 각 참여자가 주기적으로(기본 2초) MKA Hello 메시지를 전송하여 동일 CA(Connectivity Association) 멤버를 발견합니다.
- 라이브 피어 확인 (Live Peer Confirmation): 수신한 MKA PDU에서 자신의 MI(Member Identifier)를 확인하면 해당 피어를 Live Peer List에 등록합니다.
- 키 서버 선출 (Key Server Election): 키 서버 우선순위(0~255, 낮을수록 우선)와 SCI를 비교하여 키 서버를 선출합니다.
- SAK 분배 (SAK Distribution): 키 서버가 랜덤 SAK를 생성하고, KEK로 암호화(key wrap)하여 Distributed SAK 파라미터 세트로 전송합니다.
- SAK 확인 (SAK Confirmation): 수신자가 SAK를 설치하고 MKA PDU에 SAK 사용 시작을 알리면, 양쪽이 동일 SAK로 데이터를 보호합니다.
MKA 타이머와 임계값
| 타이머 | 기본값 | 설정 가능 범위 | 설명 |
|---|---|---|---|
| MKA Hello 주기 | 2초 | 1~10초 | MKA PDU 전송 간격 |
| MKA Life Time | 6초 (Hello × 3) | — | 피어 응답 없으면 삭제 |
| SAK Rekey 주기 | 무한 (PN 소진 시) | 사용자 설정 | SAK 교체 주기 |
| Bounded Hello | 500ms | — | SAK 분배 시 빠른 교환 |
| Suspend-on-Request | 비활성 | — | 키 서버 전환 시 일시 중단 |
MKA PDU 파라미터 세트
MKA PDU 구조 (EAPoL-MKA, EtherType 0x888E):
┌─────────────────────────────────────┐
│ EAPoL 헤더 (4바이트) │
│ Version=3, Type=MKA │
├─────────────────────────────────────┤
│ Basic Parameter Set (필수) │
│ - SCI (8B), MI (12B), MN (4B) │
│ - Key Server Priority, MACsec CI │
├─────────────────────────────────────┤
│ Live Peer List (가변) │
│ - 각 피어: MI (12B) + MN (4B) │
├─────────────────────────────────────┤
│ Potential Peer List (가변) │
│ - 발견했으나 미확인 피어 │
├─────────────────────────────────────┤
│ Distributed SAK (키 서버만 전송) │
│ - KEK로 래핑된 SAK │
│ - AN, Cipher Suite ID │
├─────────────────────────────────────┤
│ ICV Indicator (16바이트) │
│ - ICK로 계산한 MKA PDU 무결성 │
└─────────────────────────────────────┘
SAK 생성과 래핑
/* SAK 생성 흐름 (개념 코드) */
/* 1. 랜덤 SAK 생성 */
get_random_bytes(sak, cipher_suite_key_len); /* 16B 또는 32B */
/* 2. KEK로 SAK 래핑 (AES Key Wrap, RFC 3394) */
aes_key_wrap(kek, sak, sak_len, wrapped_sak);
/* 3. Distributed SAK 파라미터 세트 구성 */
dist_sak.an = next_association_number; /* 0~3 */
dist_sak.cipher_suite = GCM_AES_128;
memcpy(dist_sak.wrapped_sak, wrapped_sak, wrapped_len);
/* 4. MKA PDU에 포함하여 전송 */
mka_send_pdu(participant, &dist_sak);
/* 수신 측: KEK로 SAK 언래핑 후 커널에 설치 */
aes_key_unwrap(kek, wrapped_sak, wrapped_len, sak);
install_sak_to_kernel(macsec_dev, sak, an);
하드웨어 오프로드 드라이버 구현 상세
NIC 드라이버가 MACsec HW offload을 지원하려면 struct macsec_ops의 콜백을 구현하고, netdev->macsec_ops 또는 phydev->macsec_ops에 등록해야 합니다. 이 섹션에서는 드라이버 개발자 관점에서 구현 패턴을 분석합니다.
드라이버 등록(Driver Registration) 패턴
/* NIC 드라이버의 MACsec offload 등록 */
static const struct macsec_ops my_macsec_ops = {
.mdo_dev_open = my_macsec_dev_open,
.mdo_dev_stop = my_macsec_dev_stop,
.mdo_add_secy = my_macsec_add_secy,
.mdo_upd_secy = my_macsec_upd_secy,
.mdo_del_secy = my_macsec_del_secy,
.mdo_add_rxsc = my_macsec_add_rxsc,
.mdo_upd_rxsc = my_macsec_upd_rxsc,
.mdo_del_rxsc = my_macsec_del_rxsc,
.mdo_add_rxsa = my_macsec_add_rxsa,
.mdo_upd_rxsa = my_macsec_upd_rxsa,
.mdo_del_rxsa = my_macsec_del_rxsa,
.mdo_add_txsa = my_macsec_add_txsa,
.mdo_upd_txsa = my_macsec_upd_txsa,
.mdo_del_txsa = my_macsec_del_txsa,
.mdo_get_dev_stats = my_macsec_get_dev_stats,
.mdo_get_tx_sc_stats = my_macsec_get_tx_sc_stats,
.mdo_get_rx_sc_stats = my_macsec_get_rx_sc_stats,
};
/* probe 시 등록 */
static int my_nic_probe(struct pci_dev *pdev, ...)
{
...
netdev->macsec_ops = &my_macsec_ops;
netdev->features |= NETIF_F_HW_MACSEC;
...
}
오프로드 콜백 호출 흐름
| 사용자 명령 | 커널 호출 | 드라이버 콜백 | HW 동작 |
|---|---|---|---|
ip link add macsec0 | macsec_newlink() | mdo_add_secy() | SecY 컨텍스트 생성 |
ip link set macsec0 up | macsec_dev_open() | mdo_dev_open() | MACsec 엔진 활성화 |
ip macsec add tx sa 0 | macsec_add_txsa() | mdo_add_txsa() | TX SA 키 프로그래밍 |
ip macsec add rx sci | macsec_add_rxsc() | mdo_add_rxsc() | RX SC 필터 등록 |
ip macsec add rx sa 0 | macsec_add_rxsa() | mdo_add_rxsa() | RX SA 키 프로그래밍 |
ip link del macsec0 | macsec_dellink() | mdo_del_secy() | 전체 정리 |
SA 키 설치 구현 예
/* TX SA 추가 콜백 구현 예 */
static int my_macsec_add_txsa(struct macsec_context *ctx)
{
struct my_hw_priv *priv = netdev_priv(ctx->netdev);
struct macsec_tx_sa *tx_sa = ctx->sa.tx_sa;
u8 an = ctx->sa.assoc_num;
int ret;
/* 1. HW에 키 프로그래밍 */
ret = my_hw_program_key(priv,
tx_sa->key.id,
tx_sa->key.tfm, /* crypto tfm에서 키 추출 */
an,
true); /* is_tx = true */
if (ret)
return ret;
/* 2. 초기 PN(Packet Number) 설정 */
my_hw_set_pn(priv, an, tx_sa->next_pn, true);
/* 3. SA 활성화 */
if (tx_sa->active)
my_hw_enable_sa(priv, an, true);
return 0;
}
소프트웨어 vs 하드웨어 성능 심층 분석
MACsec의 성능은 소프트웨어(CPU) 처리와 하드웨어(NIC) 오프로드 간에 극적인 차이를 보입니다. AES-NI 명령어가 있는 현대 x86 CPU에서도 25Gbps 이상에서는 SW 처리의 CPU 부담이 급증합니다.
| 측정 항목 | SW MACsec (AES-NI) | HW Offload | 비고 |
|---|---|---|---|
| 1G 처리량 | ~940 Mbps | ~940 Mbps | 1G에서는 차이 미미 |
| 10G 처리량 | ~8.5 Gbps | ~9.9 Gbps | SW 15% 손실 |
| 25G 처리량 | ~16 Gbps | ~24.5 Gbps | SW 36% 손실 |
| 100G 처리량 | ~25 Gbps (병목) | ~98 Gbps | SW에서 100G 불가 |
| CPU 사용률 (10G) | ~200% (2코어) | ~5% | HW offload 40배 절감 |
| 추가 지연 (latency) | ~5~15 us | ~0.5~1 us | HW가 10배 낮음 |
| 소형 패킷(64B) PPS | ~2M pps | ~14.8M pps (10G) | SW는 per-pkt crypto 오버헤드 |
SW 경로 병목 분석
# CPU 프로파일링으로 MACsec SW 병목 확인
perf top -p $(pgrep -f iperf3) -g
# 주요 함수:
# - gcm_hash_crypt_done (GCM 인증 태그 계산)
# - aesni_gcm_enc/dec (AES-NI 암복호화)
# - macsec_encrypt_finish (SecTAG/ICV 조립)
# - skb_copy_bits (데이터 복사)
# iperf3로 MACsec 성능 벤치마크
# 서버 측:
iperf3 -s -B 10.0.0.1
# 클라이언트 측 (macsec0 인터페이스 사용):
iperf3 -c 10.0.0.1 -B 10.0.0.2 -t 30 -P 4
# -P 4: 4개 병렬 스트림으로 멀티코어 활용
# HW offload 전환 후 비교:
ip macsec offload macsec0 mac
iperf3 -c 10.0.0.1 -B 10.0.0.2 -t 30 -P 4
# CPU 사용률과 처리량 비교
XPN (Extended Packet Numbering) 성능 이점
기본 MACsec은 32비트 PN을 사용하여 약 40억 패킷 후 SAK를 교체해야 합니다. 100Gbps 링크에서 64바이트 패킷을 전송하면 약 30초만에 PN이 소진됩니다. GCM-AES-XPN은 64비트 PN을 사용하여 이 문제를 해결합니다.
| 항목 | 표준 PN (32비트) | XPN (64비트) |
|---|---|---|
| 최대 패킷 수 | 232 (~43억) | 264 (~1.8×1019) |
| 100G 64B 소진 | ~29초 | ~39,000년 |
| SAK 교체 빈도 | 매우 빈번 | 실질적으로 불필요 |
| 교체 시 패킷 손실 | 발생 가능 | 해당 없음 |
| SecTAG 크기 | 동일 (하위 32비트만 전송) | 동일 |
| 커널 지원 | 4.6+ | 5.11+ |
멀티홉 MACsec과 WAN 환경
MACsec은 원래 단일 L2 홉(포인트-투-포인트)을 보호하도록 설계되었습니다. 그러나 MPLS/VPLS 등 사업자 네트워크를 통과하는 WAN 환경이나 멀티홉 토폴로지에서도 MACsec을 적용할 수 있습니다.
멀티홉 토폴로지 패턴
| 토폴로지 | MACsec 적용 | 키 관리 | 특징 |
|---|---|---|---|
| 포인트-투-포인트 | 호스트 A ←→ 호스트 B | 단일 CA, PSK 또는 EAP | 가장 단순, 서버 간 직결 |
| 허브-스포크 | 스위치 ←→ 각 서버 | 각 포트별 독립 CA | TOR-서버 간, MACsec 지원 스위치 필수 |
| 체인 (홉-바이-홉) | A ←→ SW1 ←→ SW2 ←→ B | 각 링크별 독립 CA | 스위치에서 복호화→재암호화 |
| WAN 투명 전송 | CE A ←→ PE ←→ PE ←→ CE B | CE 간 단일 CA | 사업자 망에서 MACsec 프레임 투명 전달 |
WAN MACsec 고려사항
# WAN 환경 MACsec 설정 시 고려사항
# 1. MTU 조정: SecTAG(16B) + ICV(16B) = 32B 오버헤드
# WAN 측 MTU가 1500이면 MACsec 디바이스 MTU는 1468
ip link set eth0 mtu 1532 # 또는
ip link set macsec0 mtu 1468 # 페이로드 MTU 축소
# 2. XPN 필수: WAN 고속 링크에서 32비트 PN 소진 방지
ip link add link eth0 macsec0 type macsec \
cipher gcm-aes-xpn-128 \
sci on
# 3. Replay Window 확대: WAN 지터로 패킷 순서 변경 가능
ip link set macsec0 type macsec replay on window 256
# 4. SCI 명시적 포함: 다중 피어 환경
ip link add link eth0 macsec0 type macsec sci on
실전 구성: 포인트-투-포인트 완전 예제
두 Linux 서버 간 MACsec을 처음부터 끝까지 구성하는 완전한 예제입니다. PSK 모드와 MKA 자동 키 교환 모드 두 가지를 모두 포함합니다.
PSK 수동 설정 (MKA 없음)
#!/bin/bash
# ============================================
# MACsec PSK 수동 설정 (MKA 미사용)
# 호스트 A: eth0 = aa:bb:cc:dd:ee:01
# 호스트 B: eth0 = aa:bb:cc:dd:ee:02
# ============================================
# 공통 키 (양측 동일, 보안 채널로 교환)
KEY="0123456789abcdef0123456789abcdef"
# --- 호스트 A ---
# 1. MACsec 디바이스 생성 (GCM-AES-128, 암호화 활성)
ip link add link eth0 macsec0 type macsec \
sci on encrypt on \
cipher gcm-aes-128
# 2. TX SA 설정 (AN=0)
ip macsec add macsec0 tx sa 0 pn 1 on \
key 00 ${KEY}
# 3. RX SC 추가 (상대방 MAC + 포트)
ip macsec add macsec0 rx \
address aa:bb:cc:dd:ee:02 port 1
# 4. RX SA 설정 (상대방과 동일한 키)
ip macsec add macsec0 rx \
address aa:bb:cc:dd:ee:02 port 1 \
sa 0 pn 1 on key 00 ${KEY}
# 5. 인터페이스 활성화 및 IP 할당
ip link set macsec0 up
ip addr add 10.0.0.1/24 dev macsec0
# --- 호스트 B --- (대칭 설정, MAC 주소만 반전)
ip link add link eth0 macsec0 type macsec \
sci on encrypt on cipher gcm-aes-128
ip macsec add macsec0 tx sa 0 pn 1 on key 00 ${KEY}
ip macsec add macsec0 rx address aa:bb:cc:dd:ee:01 port 1
ip macsec add macsec0 rx address aa:bb:cc:dd:ee:01 port 1 \
sa 0 pn 1 on key 00 ${KEY}
ip link set macsec0 up
ip addr add 10.0.0.2/24 dev macsec0
스위치 연동 설정 예 (Cisco/Arista)
! ============================================
! Cisco Nexus 9000 MACsec 설정 (인터페이스 모드)
! ============================================
! 1. MACsec 키체인 설정
key chain macsec-keychain macsec
key 01
key-octet-string 0123456789abcdef0123456789abcdef
cryptographic-algorithm AES_128_CMAC
key-string 6162636465666768696a6b6c6d6e6f70
send-lifetime local 00:00:00 Jan 01 2026 infinite
! 2. MACsec 정책 설정
macsec policy my-policy
cipher-suite GCM-AES-128
key-server-priority 16
replay-protection window-size 64
! 3. 인터페이스에 MACsec 적용
interface Ethernet1/1
macsec keychain macsec-keychain policy my-policy
no shutdown
# ============================================
# Arista EOS MACsec 설정
# ============================================
! 1. MACsec 프로파일
macsec profile my-profile
cipher aes128-gcm
key 01 7 0123456789abcdef0123456789abcdef
mka key-server priority 16
! 2. 인터페이스 적용
interface Ethernet1
macsec profile my-profile
hostapd MACsec Authenticator 설정
스위치가 아닌 Linux 서버가 MACsec Authenticator 역할을 수행할 때, hostapd를 사용하여 802.1X 인증과 MKA를 동시에 처리할 수 있습니다. 이는 소프트웨어 정의 네트워크(SDN) 환경이나 저가형 스위치 없는 직결 구성에서 유용합니다.
# /etc/hostapd/macsec-auth.conf
# hostapd를 MACsec Authenticator로 설정
interface=eth0
driver=macsec_linux
# 802.1X Authenticator 모드
ieee8021x=1
eapol_version=3
eap_reauth_period=3600
# RADIUS 서버 연결
auth_server_addr=10.10.10.1
auth_server_port=1812
auth_server_shared_secret=radius_secret
# MACsec 정책
macsec_policy=1
macsec_integ_only=0
macsec_replay_protect=1
macsec_replay_window=0
# MKA 키 서버 우선순위
mka_priority=0 # 0 = 최우선 키 서버
mka_cak_length=128 # 128 또는 256비트
# hostapd 실행
hostapd -d /etc/hostapd/macsec-auth.conf
# 인증 상태 확인
hostapd_cli sta
# addr=aa:bb:cc:dd:ee:02
# flags=[AUTH][ASSOC][AUTHORIZED]
# dot1xAuthSessionId=xxx
# MKA 세션 상태
hostapd_cli mka_status
# MKA Session: active
# SAK: installed
# Key Server: yes
인증 흐름
| 단계 | 프로토콜 | 동작 |
|---|---|---|
| 1 | EAPoL | Supplicant(클라이언트)가 EAP-Start 전송 |
| 2 | EAP-TLS | hostapd가 RADIUS와 중계하여 상호 인증 |
| 3 | RADIUS | 인증 성공 → MSK(Master Session Key) 수신 |
| 4 | KDF | MSK에서 CAK + CKN 파생 |
| 5 | MKA | hostapd(키 서버)가 SAK 생성 및 분배 |
| 6 | MACsec | 양측 macsec0 인터페이스 활성화, 데이터 보호 시작 |
Session-Timeout 속성으로 재인증 주기를 설정하면 CAK가 주기적으로 갱신됩니다. 일반적으로 3600초(1시간)~86400초(24시간) 사이가 권장됩니다.
흔한 실수와 주의사항
MACsec을 도입할 때 표준 자체보다 운영 절차에서 사고가 더 자주 발생합니다. 키 수명, PN 소진, 검증 모드, 오프로드 폴백 같은 항목은 한 번 잘못 구성하면 외부 모니터링 지표에는 잘 잡히지 않고 트래픽이 조용히 평문으로 흐르거나 멈출 수 있습니다. 아래 표는 현장에서 반복적으로 보고된 6가지 실수입니다.
| 실수 | 증상 | 원인 | 해결 방법 |
|---|---|---|---|
| 32비트 PN으로 고속 링크 운용 | 일정 시간 후 SA가 멈추거나 SAK 강제 로테이션 폭주 | 100GbE 최소 프레임 트래픽에서 약 29초 만에 PN 소진. 표준이 PN wrap을 금지함. | 10GbE 이상은 XPN(64비트) 강제. ip macsec add ... xpn on과 SSCI/salt 함께 설정. |
| SAK 로테이션 주기를 너무 길게 설정 | 긴 시간 동안 같은 키 사용 → PN 소진과 키 노출 위험 증가 | MKA 기본값을 그대로 두거나 mka_cak_lifetime을 일 단위로 설정 |
고속 링크는 시간 단위(예: 1시간), 저속 링크도 24시간 이내로 제한. wpa_supplicant mka_priority·키 서버 설정 검토. |
| validate strict 미설정 | 평문/태그 누락 프레임이 조용히 수신됨 | validate check 또는 disabled로 두면 무결성 실패도 카운터만 증가하고 통과 |
ip link add link eth0 macsec0 type macsec validate strict로 명시. InPktsUntagged·InPktsNotValid를 알람 임계값에 포함. |
| encrypt off로 무결성만 사용 | 스니퍼로 페이로드가 그대로 보임 → 보안 검토에서 지적 | 대역 절감 목적으로 encrypt off 선택. ICV는 붙지만 본문은 평문. |
요구사항이 무결성만이라도 명시되지 않았다면 encrypt on이 기본. 정책 문서에 결정 사유 기록. |
| HW offload 활성화 후 키 관리 누락 | 링크 업이지만 인증 미완료 → 평문 폴백 또는 ICV 실패 폭주 | offload mac 설정만 하고 wpa_supplicant/MKA를 띄우지 않음 → SAK 미생성 |
HW offload는 키 분배 자동화의 대체가 아님. wpa_supplicant 또는 정적 CAK/CKN 설정과 함께 운용. ethtool -k로 macsec-hw-offload: on 확인 후 ip -s macsec show로 SA·키 상태 확인. |
| SCI/SSCI 충돌 | 같은 SAK를 쓰는 두 SC 간 nonce 재사용 → GCM 보안 무너짐(Forbidden) | 다중 인터페이스/멀티홈 환경에서 SCI를 자동 생성으로 두고 정적 CAK 공유 | SC마다 고유 SCI를 명시(sci 0xAABBCCDDEE000001)하고, XPN에서는 SSCI도 SC당 유일하게 부여. |
ip -s macsec show로 OutPktsEncrypted 증가 확인,
② InPktsUntagged·InPktsNotValid가 0인지 확인,
③ wpa_supplicant 로그에서 SAK 설치 메시지 확인.
세 가지가 모두 통과해야 "암호화 운용 중"이라고 판단할 수 있습니다.
공식 문서 기준 최신 커널 메모
최종 점검: stable 6.19.13 (2026-04-18), mainline 7.0 (2026-04-12), docs.kernel.org와 커널 kAPI 문서 기준입니다.
공식 MACsec 개별 문서는 간결하지만, 현재 커널 문서 전반을 보면 MACsec은 net_device 확장 지점과 드라이버별 오프로드 선택 기능으로 자리잡았습니다. 즉 최신 MACsec 운용에서 중요한 질문은 "MACsec을 켰는가"보다 "이 NIC가 어떤 경로로 MACsec을 수행하는가"입니다.
커널은 macsec_ops로 오프로드를 노출합니다
최신 networking kAPI 문서는 struct net_device 내부에 macsec_ops 포인터가 있음을 명시합니다. 이는 MACsec이 상위 추상 API만 존재하는 기능이 아니라, NIC 드라이버가 선택적으로 하드웨어 오프로드 동작을 제공할 수 있는 구조라는 뜻입니다. 다시 말해 동일한 ip macsec 명령을 써도, 실제 데이터 경로는 완전 소프트웨어일 수도 있고 NIC 오프로드일 수도 있습니다.
- 오프로드 가능 여부는 커널 일반 기능이 아니라 드라이버 구현 여부에 달립니다.
- 오프로드 경로를 쓰면 성능은 좋아질 수 있지만, 통계와 실패 지점이 드라이버/NIC 쪽으로 이동합니다.
- 따라서 운영 점검은
ip -s macsec show와 함께 드라이버/펌웨어 지원 여부를 같이 봐야 합니다.
드라이버 지원은 Kconfig부터 확인합니다
공식 mlx5 Kconfig 문서의 최신판은 CONFIG_MLX5_MACSEC 항목을 별도로 문서화합니다. 이는 적어도 mlx5 계열에서는 MACsec 오프로드가 독립 기능으로 유지되고 있음을 보여줍니다. 반대로 이와 같은 Kconfig나 드라이버 문서가 없는 NIC은 같은 사용자 공간(User Space) 설정을 넣어도 소프트웨어 경로로 동작할 가능성이 큽니다. 이 판단은 공식 문서에서 직접 확인 가능한 부분이고, 특정 NIC 세대의 실제 지원 범위는 벤더 문서를 추가 확인해야 합니다.
실무 점검 기준
ip macsec설정 성공만으로 오프로드 여부를 판단하지 않습니다.ethtool기능 목록과 드라이버 문서, 커널 Kconfig 항목을 함께 확인합니다.- 고속 링크에서는 XPN 사용 여부와 SA 로테이션 주기, 오프로드 경로의 카운터 노출 방식을 함께 점검합니다.
- 소프트웨어 경로와 하드웨어 경로를 혼동하면 성능 병목과 장애 위치를 잘못 추적하게 됩니다.
참고자료
- IEEE 802.1AE-2018 — MACsec 표준 규격을 정의하는 IEEE 공식 문서입니다.
- IEEE 802.1X-2020 — 포트 기반 네트워크 접근 제어(Access Control)(PNAC) 표준을 정의합니다.
- Kernel MACsec Documentation — 리눅스 커널 공식 MACsec 문서입니다.
- Linux Networking and Network Devices APIs —
macsec_ops를 포함한 net_device 확장 지점을 설명합니다. - drivers/net/macsec.c — MACsec 커널 드라이버 소스 코드입니다.
- wpa_supplicant — MKA 프로토콜 및 MACsec 키 관리를 지원하는 인증 클라이언트입니다.
- hostapd — 802.1X 인증 서버로 MACsec 환경의 RADIUS 연동을 지원합니다.
- ip-macsec(8) man page —
ip macsec명령어의 사용법을 설명하는 매뉴얼 페이지(Page)입니다. - Open vSwitch MACsec — OVS 환경에서 MACsec을 연동하는 방법을 안내합니다.
- Intel ice 드라이버 문서 — Intel NIC의 MACsec 하드웨어 오프로드 기능을 설명합니다.
- mlx5 Kconfig 문서 —
CONFIG_MLX5_MACSEC와 관련 기능 플래그를 설명합니다. - NVIDIA MACsec Full Offload — ConnectX-7 이상에서 GCM-AES-XPN 풀 오프로드 지원 범위와 펌웨어 요구사항을 설명합니다.
- Intel Community — ixgbe MACsec offload — ixgbe 계열(82599/X540/X550)에 MACsec 오프로드 추가 계획이 없다는 인텔 공식 답변입니다.
- Cisco MACsec Design Guide — 엔터프라이즈 환경에서의 MACsec 배포 설계 가이드입니다.
- RFC 3748 — EAP(Extensible Authentication Protocol) 명세를 정의합니다.
- RFC 5247 — EAP 키 관리 프레임워크를 정의합니다.
- NIST SP 800-120 — EAP 메서드에 대한 NIST 권장 사항입니다.
- NIST SP 800-38D — GCM(Galois/Counter Mode) 인증 암호화 명세입니다.