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 트래픽 보호 패턴, 성능 벤치마크와 트러블슈팅을 실전 운영 관점에서 정리합니다.

전제 조건: 네트워크 스택(Network Stack), Network Device 드라이버(net_device), Linux Crypto Framework (Crypto API) 문서를 먼저 읽으세요. MACsec은 L2 프레임 수준에서 동작하므로 이더넷 프레임 구조와 커널 네트워크 디바이스 개념을 이해한 뒤 보는 편이 정확합니다.
일상 비유: MACsec은 건물 복도의 보안 게이트와 비슷합니다. IPSec이 "목적지까지 봉인된 택배 상자"라면, MACsec은 "건물 각 층 사이의 보안 게이트"입니다. 프레임이 한 홉(스위치 포트, 직결 링크)을 지날 때마다 신원을 확인하고 내용을 봉인합니다. 각 구간마다 독립된 키를 사용하므로, 중간 스위치가 내용을 열어서 QoS 처리 같은 작업을 수행한 뒤 다시 봉인할 수 있습니다.

핵심 요약

  • 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 부담을 제거합니다.

단계별 이해

  1. L2 암호화의 위치를 파악하기
    MACsec은 이더넷 헤더 바로 뒤에서 동작합니다. IP 이상의 계층은 전혀 관여하지 않습니다.
  2. 프레임 구조를 먼저 이해하기
    SecTAG와 ICV가 원래 프레임의 어디에 삽입되는지 그림으로 확인하면 나머지가 쉬워집니다.
  3. 키 합의와 데이터 경로를 분리해서 보기
    MKA는 EAPoL 프레임으로 키를 교환하고, MACsec은 그 키로 데이터를 암호화합니다. 두 경로는 독립적입니다.
  4. SW vs HW offload를 구분하기
    소프트웨어 경로는 커널 crypto API를 사용하고, HW offload는 NIC 펌웨어(Firmware)가 처리합니다. 성능 차이가 극적입니다.
  5. 문제는 통계와 카운터로 확인하기
    ip -s macsec show의 InPktsOK, InPktsInvalid, OutPktsProtected가 첫 번째 진단 지표입니다.
사실 관계: MACsec은 IEEE 802.1AE-2006으로 처음 발표되었고 2018년에 802.1AEcg(GCM-AES-XPN 포함)로 개정되었습니다. Linux 커널에는 4.6에서 소프트웨어 MACsec이 도입되었고(drivers/net/macsec.c), 5.6에서 HW offload 인프라가 추가되었습니다. 2026년 3월 기준 최신 stable 커널에서 CONFIG_MACSEC은 대부분의 배포판에서 모듈로 활성화되어 있습니다.

IEEE 802.1AE 표준 개요

IEEE 802.1AE는 이더넷 LAN에서 데이터 기밀성(confidentiality), 데이터 무결성(integrity), 데이터 원본 인증(origin authentication)을 제공하는 표준입니다. 핵심 특징은 다음과 같습니다.

표준 문서범위핵심 내용
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 분배
PN 소진 문제: 32비트 PN은 약 43억 패킷 후 소진됩니다. 100 Gbps 링크에서 최소 크기 프레임(64바이트)을 보내면 약 29초 만에 소진됩니다. 이것이 고속 링크에서 XPN(64비트)이 필수인 이유입니다.

MACsec vs IPSec vs WireGuard vs kTLS 비교

네트워크 보안은 계층마다 다른 도구가 존재합니다. MACsec은 L2에서 동작하므로 다른 암호화 메커니즘과 경쟁이 아니라 보완 관계입니다.

계층 L7 L4-5 L3 L2 L1 kTLS L4-7 TLS 오프로드 WireGuard L3 VPN 터널 IPSec / xfrm L3 정책 기반 암호화 MACsec L2 홉 단위 암호화 물리 이더넷 / 광섬유 종단 간 종단 간 종단/게이트웨이 홉 단위
항목MACsec (802.1AE)IPSec / xfrmWireGuardkTLS
동작 계층 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 가속
계층 조합: MACsec과 IPSec/WireGuard/kTLS는 서로 다른 계층에서 동작하므로 동시에 사용할 수 있습니다. 예를 들어 데이터센터 내부 링크는 MACsec으로 L2 보호하고, 외부 통신은 WireGuard로 L3 터널을 구성하는 것이 일반적인 심층 방어(defense in depth) 패턴입니다.

SecTAG와 ICV 프레임 형식

MACsec은 원래 이더넷 프레임에 두 가지 요소를 추가합니다: 헤더 쪽의 SecTAG(Security Tag)와 꼬리 쪽의 ICV(Integrity Check Value)입니다.

일반 이더넷 프레임 Dst MAC (6B) Src MAC (6B) EtherType (2B) Payload (46-1500B) FCS MACsec 적용 MACsec 프레임 Dst MAC Src MAC SecTAG EtherType 0x88E5 + SCI + PN 원본 EtherType Secure Data (암호화된 Payload) 또는 평문 (무결성 전용 모드) ICV 8 / 16 바이트 FCS SecTAG 상세 구조 (8 또는 16바이트) MACsec EtherType 0x88E5 (2B) TCI/AN (1B) SL (1B) Packet Number (4B) SCI (선택) MAC(6B) + Port ID(2B)
필드크기설명
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바이트)은 보안성이 낮아 권장되지 않습니다.
MTU 영향: SecTAG(8~16B) + ICV(8~16B) = 최대 32바이트가 추가되므로, 1500B MTU 이더넷에서 MACsec을 사용하면 실효 페이로드(Payload)는 최대 1468바이트로 줄어듭니다. Baby Giant Frame(1522B 이상) 또는 점보 프레임 지원이 권장됩니다.

GCM-AES-128/256, GCM-AES-XPN 암호 스위트

MACsec은 AES-GCM (Galois/Counter Mode)만을 암호 스위트로 사용합니다. IPSec처럼 다양한 알고리즘을 협상하지 않으며, 표준에 정의된 4가지 스위트 중 하나를 선택합니다.

Cipher SuiteCipher 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] */
};
XPN과 SSCI: XPN 모드에서는 64비트 PN 중 상위 32비트가 프레임에 직접 포함되지 않습니다. 대신 양측이 동기화된 PN 윈도우를 유지하고, SSCI(Short Secure Channel Identifier)를 nonce에 혼합하여 동일 SAK를 쓰는 여러 SC 간 nonce 충돌을 방지합니다.

MKA (MACsec Key Agreement) 프로토콜

MKA는 IEEE 802.1X-2010에 정의된 키 합의 프로토콜로, MACsec이 사용할 SAK를 안전하게 분배합니다. MKA는 EAPoL(Extensible Authentication Protocol over LAN) 프레임, 구체적으로 EAPoL-MKA (EtherType 0x888E)를 사용합니다.

참여자 A 참여자 B 1단계 MKPDU: Basic Parameter Set (CKN, MI, MN, 우선순위) MKPDU: Basic Parameter Set (CKN, MI, MN, 우선순위) 2단계 양측 ICK로 MKPDU ICV 검증 → 상호 인증 (Live Peer List 교환) 3단계 우선순위 비교 → 키 서버(Key Server) 선출 (낮은 값 = 높은 우선순위) 4단계 SAK 분배: Distributed SAK Parameter Set (KEK로 래핑) 5단계 MKPDU에 SAK Use Parameter Set 포함 → SAK 수락 확인 6단계 MACsec 데이터 보호 시작 (SecTAG + 암호화 + ICV) 계속 주기적 MKPDU (기본 2초 간격) — liveness 확인 + SAK 로테이션

MKA의 핵심 개념들:

CAK → ICK → KEK → SAK 키 계층 구조

MACsec의 키 계층은 단일 루트 키(CAK)에서 모든 운영 키를 파생하는 구조입니다.

CAK Connectivity Association Key CKN (Key Name, 식별자) KDF (AES-CMAC) KDF (AES-CMAC) KDF (AES-CMAC) ICK Integrity Check Key KEK Key Encrypting Key KCK Key Confirmation Key (256비트 CAK용) MKPDU ICV 생성/검증 피어 상호 인증 AES Key Wrap SAK Secure Association Key (데이터 암복호화) TX: GCM-AES 암호화 RX: GCM-AES 복호화/검증 + Salt (XPN nonce 구성)
파생 원본용도수명
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 로테이션 메커니즘은 다음과 같습니다.

키 서버 선출 규칙

  1. 모든 참여자는 MKPDU에 Key Server Priority 값을 포함합니다 (0-255, 기본값 일반적으로 16).
  2. 낮은 우선순위 값이 더 높은 우선순위를 가집니다.
  3. 우선순위가 동일하면 낮은 SCI(MAC 주소 기반)가 키 서버가 됩니다.
  4. 키 서버만이 SAK를 생성하고 KEK로 래핑하여 분배할 수 있습니다.

SAK 로테이션 트리거

무중단 키 로테이션: MACsec은 최대 4개의 SA(AN 0-3)를 동시에 유지할 수 있으므로, 새 SAK가 모든 참여자에게 분배·확인된 후에야 이전 SA가 비활성화됩니다. 이 과정에서 패킷 손실이 발생하지 않습니다.

Linux 커널 MACsec 아키텍처

Linux MACsec은 drivers/net/macsec.c에 구현된 가상 네트워크 디바이스입니다. 실제 물리 NIC(real_dev) 위에 MACsec 가상 디바이스(macsec_dev)를 얹는 구조로, VLAN 디바이스와 유사한 패턴입니다.

유저스페이스 ip macsec (iproute2) wpa_supplicant Netlink (RTNL) 커널: drivers/net/macsec.c macsec_dev (net_device) macsec0, macsec1, ... ndo_start_xmit = macsec_start_xmit struct macsec_secy tx_sc, rx_sc[], sci, validate key_len, icv_len, xpn, encrypt Crypto API (GCM-AES) aead_request, scatterlist gcm(aes) / AES-NI 가속 rx_handler: macsec_handle_frame() real_dev에 등록된 수신 핸들러 macsec_ops (HW offload) mdo_add_secy, mdo_upd_txsa, ... MACsec 통계 (per-SA/SC) InPkts*, OutPkts*, InOctets*, ... 물리 NIC (real_dev): eth0 일반 이더넷 프레임 송수신 HW offload 지원 시: NIC 내 암복호화 EtherType 0x88E5 프레임은 macsec rx_handler로 전달

커널 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 디바이스의 특징:

송신 경로: macsec_start_xmit() → SecTAG 삽입 → GCM 암호화

상위 스택이 MACsec 디바이스로 패킷을 보내면 macsec_start_xmit()이 호출됩니다. 이 함수는 원본 프레임에 SecTAG를 삽입하고 GCM-AES로 암호화한 뒤 real_dev를 통해 전송합니다.

네트워크 스택 dev_queue_xmit() macsec_start_xmit() 1. TX SA 선택 (active AN) 2. PN 할당 (atomic 증가) 3. PN 소진 체크 SecTAG 삽입 skb_push() + SecTAG 헤더 구성 GCM-AES 암호화 macsec_encrypt_finish() AEAD encrypt: payload → ciphertext AAD: SecTAG | ICV 생성 후 추가 skb->dev = real_dev dev_queue_xmit(skb) Wire 0x88E5 프레임 HW offload 활성 시: SW 암호화 건너뜀 → NIC 처리 ※ 비동기 crypto의 경우 콜백(macsec_encrypt_done)에서 전송이 완료됩니다.
/* 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_handlermacsec_handle_frame()으로 전달됩니다.

Wire 0x88E5 프레임 real_dev NIC rx_handler 호출 macsec_handle_frame() SecTAG 파싱 1. EtherType 0x88E5 확인 2. SCI로 RX SC 검색 3. AN으로 RX SA 선택 GCM-AES 복호화 + ICV 검증 macsec_decrypt() AEAD decrypt: ICV 불일치 시 drop Replay Protection PN 윈도우 검사 → 중복/재전송 차단 SecTAG/ICV 제거 → 네트워크 스택 전달 상위 프로토콜 (IP, ARP, ...) validate 모드: Strict: 검증 실패 시 즉시 drop Check: 검증하되 통과 허용 Disabled: 검증 안 함

수신 경로의 주요 검증 단계:

  1. SecTAG 유효성: EtherType, 버전 비트, TCI 플래그 조합이 유효한지 확인합니다.
  2. SCI 매칭: SecTAG의 SCI(또는 추론된 SCI)로 해당 RX SC를 검색합니다. 매칭되는 SC가 없으면 drop됩니다.
  3. SA 선택: AN 필드로 RX SA를 선택합니다. 해당 SA가 비활성이면 drop됩니다.
  4. GCM-AES 복호화: SA의 키로 페이로드를 복호화하고 ICV를 검증합니다. ICV 불일치는 즉시 drop + InPktsNotValid 증가.
  5. Replay check: PN이 윈도우 내에 있고 중복이 아닌지 확인합니다.
  6. 프레임 복원: 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 (엄격 순서, 역전 불허)
윈도우 크기 설정: 기본값 0은 패킷 순서가 완벽히 보장되는 직결 링크에 적합합니다. 스위치를 통과하면서 순서가 바뀔 수 있는 환경에서는 적절한 윈도우 크기(예: 128, 256)를 설정해야 합니다. 윈도우가 너무 크면 replay 공격 방어가 약해집니다.

SCI (Secure Channel Identifier)와 SA (Secure Association)

SCI와 SA의 관계는 MACsec 보안 모델의 핵심입니다.

SecY (Security Entity) SCI = MAC 주소 (6B) + Port ID (2B) = 고유 식별자 TX Secure Channel (1개) SCI = 자신의 MAC + Port ID TX SA 0 SAK₀, PN counter, 활성 TX SA 1 SAK₁ (대기) TX SA 2 (비어 있음) TX SA 3 (비어 있음) encoding_sa = 0 (현재 송신에 사용 중인 SA) RX Secure Channel(s) (복수 가능) 각 SC의 SCI = 상대방 MAC + Port ID RX SA 0 SAK₀, PN window, lowest_pn RX SA 1 SAK₁ (준비) RX SA 2 RX SA 3 수신 프레임의 AN 필드로 SA 선택
개념방향수량설명
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 보호: RX SC 목록과 SA 배열은 RCU로 보호됩니다. 데이터 경로(hot path)에서 읽기는 rcu_dereference()로, 구조체 변경은 rtnl_lock 아래에서 수행됩니다. 이는 MACsec이 고속 데이터 경로에서 락 없이 동작할 수 있게 합니다.

MACsec HW Offload 아키텍처

Linux 5.6부터 MACsec은 NIC 하드웨어에 암복호화를 위임할 수 있는 offload 인프라를 제공합니다. HW offload가 활성화되면 CPU는 SecTAG 삽입/제거와 GCM 연산을 수행하지 않으며, NIC가 line-rate로 처리합니다.

SW MACsec (기본) 네트워크 스택 (IP, TCP, ...) macsec_dev SW 암복호화 (Crypto API) real_dev 드라이버 (일반 전송) NIC HW 암호화된 0x88E5 프레임 송출 HW Offload MACsec 네트워크 스택 (IP, TCP, ...) macsec_dev 암호화 건너뜀 → 평문 전달 real_dev 드라이버 (macsec_ops 등록) NIC HW (MACsec 엔진) SecTAG 삽입 + GCM 암호화 → 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);
};

드라이버 구현 시 핵심 사항:

HW Offload 지원 NIC

벤더 / 드라이버offload 모드특이사항
Mellanox (NVIDIA) / mlx5 ConnectX-6 Dx 이상 MAC offload GCM-AES-128/256, XPN 지원. 가장 완성도 높은 구현.
Intel / ice E810 시리즈 MAC offload GCM-AES-128/256 지원. 6.x 커널에서 점진적으로 확장.
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: 암호화된 송신 패킷
offload 확인: ip macsec show 출력에 offload mac 또는 offload phy가 표시되면 HW offload가 활성화된 상태입니다. SW 모드에서는 이 필드가 나타나지 않습니다.

ip macsec 명령어 완전 가이드

iproute2ip 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
CAK/CKN 보안: PSK 모드에서 CAK/CKN은 양측 설정 파일에 평문으로 저장됩니다. 파일 권한을 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의 흐름:

  1. 802.1X 인증: Supplicant가 Authenticator(스위치)를 통해 RADIUS 서버와 EAP 인증을 수행합니다.
  2. MSK 파생: EAP 인증 성공 시 양측이 MSK(Master Session Key)를 공유합니다.
  3. CAK/CKN 파생: MSK에서 CAK와 CKN이 KDF로 파생됩니다.
  4. MKA 시작: CAK/CKN으로 MKA 프로토콜이 자동 시작되어 SAK를 합의합니다.
  5. MACsec 보호: SAK 합의 완료 후 데이터 프레임 보호가 시작됩니다.
항목PSK 모드EAP 모드
CAK 소스 관리자가 수동 설정 EAP MSK에서 자동 파생
CKN 소스 관리자가 수동 설정 EAP 세션 ID에서 자동 파생
CAK 수명 관리자가 변경할 때까지 영구 EAP 재인증 주기에 따라 갱신
확장성 수동 키 관리로 제한적 RADIUS 중앙 관리로 대규모 적합
인프라 요구 없음 (호스트 쌍 설정만) RADIUS 서버, PKI 인증서 필요
적합 환경 소규모, 서버 간 직결 엔터프라이즈, 대규모 데이터센터
EAP 재인증과 키 갱신: EAP 모드에서 RADIUS 서버의 Session-Timeout 속성으로 재인증 주기를 설정하면, 주기적으로 새 MSK가 파생되고 이로부터 새 CAK/CKN이 생성됩니다. 이는 PSK 모드에서는 불가능한 자동 키 갱신(key rotation at the CAK level)을 제공합니다.

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)을 방어할 수 있습니다.

Spine Switch TOR Switch A TOR Switch B MACsec MACsec Server A1 Server A2 Server B1 Server B2 MACsec MACsec MACsec MACsec 각 물리 링크마다 독립된 MACsec 세션 (독립된 CAK/SAK) 스위치는 중간에서 복호화 → QoS/ACL 처리 → 재암호화

데이터센터 MACsec 배포 패턴

패턴구간키 관리장점
Host-to-TOR 서버 NIC ↔ TOR 스위치 포트 서버별 PSK 또는 802.1X 서버 측에서 제어 가능, NIC HW offload 활용
Switch-to-Switch TOR ↔ Spine/Leaf 스위치 스위치 쌍별 PSK 패브릭 전체 암호화, ASIC 가속
End-to-End (희소) 서버 ↔ 서버 (직결) 서버 쌍별 PSK 스위치 불필요, 가장 단순한 구성
홉 단위의 의미: MACsec은 종단 간 보호가 아니므로 Server A1에서 Server B1으로 보내는 패킷은 A1→TOR-A(복호화→재암호화)→Spine(복호화→재암호화)→TOR-B(복호화→재암호화)→B1 경로를 거칩니다. 각 홉에서 스위치가 L2/L3 헤더를 검사할 수 있어 QoS, ACL, 모니터링이 가능합니다.

스위치 연동 (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
CKN 길이 호환성: 일부 스위치(특히 Cisco)는 CKN이 정확히 64 hex 문자(32바이트)여야 합니다. Linux wpa_supplicant는 가변 길이를 허용하지만, 스위치와 연동 시에는 길이를 정확히 맞춰야 합니다. CKN이 32바이트보다 짧으면 0으로 패딩(Padding)합니다.

성능 벤치마크 (SW vs HW Offload)

MACsec의 성능은 SW vs HW offload에 따라 극적으로 달라집니다. 소프트웨어 경로에서는 모든 패킷마다 GCM-AES 암복호화를 CPU가 수행해야 하므로, 고속 링크에서는 CPU가 병목(Bottleneck)이 됩니다. HW offload는 NIC 내장 crypto 엔진이 line-rate로 처리하므로 CPU 부담이 사실상 없습니다.

SW MACsec 성능 특성

소프트웨어 MACsec의 성능은 여러 요인에 의해 결정됩니다:

프레임 크기별 성능 영향

프레임 크기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 사용률레이턴시 추가
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 디바이스만 이동할 수 있습니다.
컨테이너 환경: Docker/Podman에서 MACsec을 사용하려면 호스트에서 MACsec 디바이스를 생성한 뒤 컨테이너의 네트워크 네임스페이스로 이동하는 방식을 사용합니다. 또는 macvlan 위에 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
QinQ 주의: MACsec SecTAG의 EtherType(0x88E5)은 VLAN 태그(0x8100/0x88A8)과 다르므로, QinQ 환경에서 태깅 순서에 따라 중간 스위치가 프레임을 올바르게 포워딩하지 못할 수 있습니다. MACsec과 VLAN의 스택 순서를 네트워크 토폴로지(Topology)에 맞게 신중히 결정하세요.

트러블슈팅과 디버깅(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
배포판 지원: 대부분의 주요 Linux 배포판(RHEL 8+, Ubuntu 20.04+, SLES 15+, Fedora 32+)은 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 MAC6바이트6바이트 (그대로)변경 없음
Src MAC6바이트6바이트 (그대로)변경 없음
EtherType원본 (0x0800 등)0x88E5 (MACsec)SecTAG로 대체
SecTAG8~16바이트신규 삽입
Payload평문암호문GCM-AES 암호화
원본 EtherType암호화된 페이로드에 포함SecTAG 뒤에 매립
ICV8~16바이트신규 추가
FCS4바이트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 MACOXL2 헤더는 평문, 무결성만 보호
SecTAGOX보안 태그 자체는 평문
Secure Data (페이로드)OO (encrypt 모드)암호화 + 무결성 동시 보호
ICVGCM 인증 태그 출력값
MACsec 프레임 변환 과정 원본 이더넷 프레임 Dst MAC (6B) Src MAC (6B) EtherType Payload (평문) FCS (4B) SecTAG 삽입 + GCM-AES 암호화 + ICV 추가 MACsec 보호 프레임 Dst MAC Src MAC 0x88E5 SecTAG (8-16B) 암호화된 Secure Data ICV FCS AAD (Additional Authenticated Data) 암호화 범위 SecTAG 내부 구조 TCI/AN (1B) SL (Short Length 1B) PN (Packet Number) (4B) SCI (선택적, SC=1일 때) (8B: MAC 6B + Port 2B) TCI 비트필드 V=1 ES SC SCB E C AN (2비트)
원본 프레임에서 MACsec 프레임으로의 변환 과정: SecTAG 삽입, 페이로드 암호화, ICV 추가

MKA 키 교환 프로토콜 상세

MKA(MACsec Key Agreement)는 IEEE 802.1X-2010에서 정의된 키 합의 프로토콜로, EAPoL-MKA 프레임(EtherType 0x888E)을 통해 동작합니다. MKA의 핵심 동작 단계와 타이머, 상태 머신을 상세히 분석합니다.

MKA 세션 수립 단계

  1. 피어 발견 (Peer Discovery): 각 참여자가 주기적으로(기본 2초) MKA Hello 메시지를 전송하여 동일 CA(Connectivity Association) 멤버를 발견합니다.
  2. 라이브 피어 확인 (Live Peer Confirmation): 수신한 MKA PDU에서 자신의 MI(Member Identifier)를 확인하면 해당 피어를 Live Peer List에 등록합니다.
  3. 키 서버 선출 (Key Server Election): 키 서버 우선순위(0~255, 낮을수록 우선)와 SCI를 비교하여 키 서버를 선출합니다.
  4. SAK 분배 (SAK Distribution): 키 서버가 랜덤 SAK를 생성하고, KEK로 암호화(key wrap)하여 Distributed SAK 파라미터 세트로 전송합니다.
  5. SAK 확인 (SAK Confirmation): 수신자가 SAK를 설치하고 MKA PDU에 SAK 사용 시작을 알리면, 양쪽이 동일 SAK로 데이터를 보호합니다.

MKA 타이머와 임계값

타이머기본값설정 가능 범위설명
MKA Hello 주기2초1~10초MKA PDU 전송 간격
MKA Life Time6초 (Hello × 3)피어 응답 없으면 삭제
SAK Rekey 주기무한 (PN 소진 시)사용자 설정SAK 교체 주기
Bounded Hello500msSAK 분배 시 빠른 교환
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에 등록해야 합니다. 이 섹션에서는 드라이버 개발자 관점에서 구현 패턴을 분석합니다.

드라이버 등록 패턴

/* 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 macsec0macsec_newlink()mdo_add_secy()SecY 컨텍스트 생성
ip link set macsec0 upmacsec_dev_open()mdo_dev_open()MACsec 엔진 활성화
ip macsec add tx sa 0macsec_add_txsa()mdo_add_txsa()TX SA 키 프로그래밍
ip macsec add rx scimacsec_add_rxsc()mdo_add_rxsc()RX SC 필터 등록
ip macsec add rx sa 0macsec_add_rxsa()mdo_add_rxsa()RX SA 키 프로그래밍
ip link del macsec0macsec_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 Mbps1G에서는 차이 미미
10G 처리량~8.5 Gbps~9.9 GbpsSW 15% 손실
25G 처리량~16 Gbps~24.5 GbpsSW 36% 손실
100G 처리량~25 Gbps (병목)~98 GbpsSW에서 100G 불가
CPU 사용률 (10G)~200% (2코어)~5%HW offload 40배 절감
추가 지연 (latency)~5~15 us~0.5~1 usHW가 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
MACsec 홉-바이-홉 토폴로지 서버 A MACsec macsec0 CA1 TOR 스위치 1 복호화→QoS→재암호화 CA2 Spine 스위치 복호화→라우팅→재암호화 CA3 TOR 스위치 2 복호화→전달 CA4 서버 B MACsec macsec0 각 링크(CA)는 독립된 CAK/SAK 쌍을 사용 — 중간 스위치에서 평문 접근 후 재암호화 CA1: 서버A↔TOR1, CA2: TOR1↔Spine, CA3: Spine↔TOR2, CA4: TOR2↔서버B
홉-바이-홉 MACsec: 각 링크는 독립된 CA(Connectivity Association)로 보호되며, 중간 스위치에서 복호화→처리→재암호화
보안 한계: 홉-바이-홉 MACsec에서는 중간 스위치가 평문 데이터에 접근할 수 있습니다. 엔드-투-엔드 암호화가 필요하면 MACsec 위에 IPSec이나 kTLS를 추가로 적용하세요. MACsec은 물리 링크 보호, 상위 프로토콜은 엔드-투-엔드 보호로 역할을 분담합니다.

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

인증 흐름

단계프로토콜동작
1EAPoLSupplicant(클라이언트)가 EAP-Start 전송
2EAP-TLShostapd가 RADIUS와 중계하여 상호 인증
3RADIUS인증 성공 → MSK(Master Session Key) 수신
4KDFMSK에서 CAK + CKN 파생
5MKAhostapd(키 서버)가 SAK 생성 및 분배
6MACsec양측 macsec0 인터페이스 활성화, 데이터 보호 시작
FreeRADIUS 설정 팁: FreeRADIUS에서 MACsec용 EAP-TLS를 설정할 때, Session-Timeout 속성으로 재인증 주기를 설정하면 CAK가 주기적으로 갱신됩니다. 일반적으로 3600초(1시간)~86400초(24시간) 사이가 권장됩니다.

참고자료