같은 증상으로 검색해 오신 분들께
증상: IPsec dialup + EAP 구성에서 방화벽 정책에 set groups 또는 set users를 넣으면 트래픽이 매칭되지 않고 차단됨. 인증은 정상적으로 성공함. 환경: FortiGate / FortiOS 7.4.11 / Phase1에 set eap enable + set authusrgrp 결론: Phase1에서 EAP를 통해 인증하면 FortiGate가 사용자 신원을 세션에 바인딩하지 않는다. 따라서 정책 수준의 사용자/그룹 매칭이 성립하지 않는다. 우회로: 그룹별로 IP 풀 대역을 분리하고, 정책의 srcaddr에 그 대역 주소 객체를 쓴다. 검색 키워드: authusrgrp policy group match IPsec EAP user identity policy set groups not matching ipsec dialup
1. 하려던 것
그룹별로 접근 범위를 다르게 주려 했다. 요구사항은 단순했다.
| 직원 | 사내 업무 시스템 전체 |
| 유지보수 벤더 | 담당 장비 관리망만 |
| 파트너사 A | 특정 서버 1대 (/32) |
| 파트너사 B | 특정 서버 2대 |
FreeRADIUS 쪽 준비는 끝나 있었다. 사용자별로 Fortinet-Group-Name 벤더 속성을 내려주고 있었다.
partner_a_01 Cleartext-Password := "<REDACTED>"
Fortinet-Group-Name = "partner-a",
Fallthrough = no
FortiGate 쪽에 그룹을 만들고 정책에 넣으면 될 것 같았다.
config user group
edit "partner-a-grp"
set group-type firewall
set member "radius-primary"
config match
edit 1
set server-name "radius-primary"
set group-name "partner-a"
next
end
next
end
config firewall policy
edit 0
set name "PartnerA-to-Server"
set srcintf "ra-ipsec"
set dstintf "internal"
set srcaddr "all"
set dstaddr "PartnerA-Server"
set groups "partner-a-grp" ← 이게 문제
set action accept
set service "HTTPS"
next
end
2. 증상
인증은 성공했다. IP도 할당됐다. 트래픽이 전부 차단됐다.
diagnose debug flow filter addr 10.10.60.160
diagnose debug flow show function-name enable
diagnose debug flow trace start 20
diagnose debug enable
출력:
... find a route: ...
... Denied by forward policy check (policy 0)
Part 5에서 배운 대로 policy 0은 매칭되는 정책이 없다는 뜻이다. 그런데 정책은 만들어져 있었다.
3. 처음 세운 가설과, 그것이 왜 틀렸는가
첫 가설: RADIUS가 Fortinet-Group-Name을 안 내려주고 있거나, FortiGate의 그룹 매칭 설정이 틀렸다.
이걸 확인하는 건 쉬웠다.
diagnose test authserver radius radius-primary pap partner_a_01 '<비밀번호+OTP>'
출력에 그룹 정보가 정상적으로 나왔다.
authenticate 'partner_a_01' against 'pap' succeeded, server=radius-primary
session_timeout=0 idle_timeout=0 ...
group_membership=partner-a
RADIUS는 그룹을 정확히 내려주고 있었고, FortiGate도 그걸 정확히 받고 있었다.
그래서 다음 가설로 갔다.
두 번째 가설: 그룹 매칭 문법이 틀렸다. set match 블록 구성이 잘못됐거나 group-type 설정 문제다.
문법을 여러 형태로 바꿔봤다. 그룹 이름 대소문자, group-type을 firewall/fsso로 바꿔보기, set member에 RADIUS 서버를 넣는 것과 안 넣는 것. 전부 결과가 같았다.
이 지점에서 방향을 바꿨다. 문법 문제라면 어딘가에서 다른 결과가 나와야 한다. 전부 같은 결과라면 문법이 아니라 구조 문제다.
4. 관측 — 세션에 사용자가 없다
핵심 확인은 이거였다. FortiGate가 이 세션의 사용자가 누구라고 알고 있는가?
diagnose firewall auth list
출력이 비어 있었다. 인증된 사용자 테이블에 아무것도 없었다.
세션 정보도 봤다.
diagnose sys session filter src 10.10.60.160
diagnose sys session list
세션은 존재했다. 그런데 사용자 신원 관련 필드가 없었다.
이게 전부였다. 인증은 IKE 단계에서 EAP를 통해 이루어졌고, 그 결과로 터널은 올라왔지만, FortiGate의 방화벽 인증 테이블에는 아무것도 등록되지 않았다.
정책의 set groups는 방화벽 인증 테이블을 참조한다. 테이블이 비어 있으니 매칭될 수 없다. 그러니까 policy 0이 정확한 대답이었다. 정책은 존재하지만 매칭 조건을 만족할 방법이 없었던 것이다.
5. 근본 원인
정리하면 이렇다.
Phase1에서 set eap enable + set authusrgrp <그룹> 방식으로 인증하면, 인증은 IKE 계층에서 완결되고 그 결과가 방화벽 세션의 사용자 신원으로 바인딩되지 않는다.
authusrgrp가 하는 일은 "이 사용자 그룹으로 EAP 인증을 검증하라"까지다. 인증 성공 후 그 신원을 방화벽 정책 엔진에 전달하는 단계가 없다.
이게 버그인지 설계인지는 판단하지 않는다. 관측된 동작은 위와 같고, 문서에서 이 상호작용에 대한 명시적 설명을 찾지 못했다. 이런 종류의 "문서에 없는 계층 간 단절"이 가장 시간을 잡아먹는 종류다.
6. 우회로 — IP 풀이 유일한 수단이 된다
사용자 신원을 정책에서 쓸 수 없다면, 신원을 IP 주소로 표현해야 한다.
Part 3에서 IP 풀을 그룹별로 쪼개 설계해뒀다. 당시엔 "있으면 좋은 것"이었는데, 여기서 유일하게 가능한 접근제어 수단이 됐다.
구조
FreeRADIUS: 사용자별 그룹 판정
└─ rlm_ippool: 그룹에 대응하는 대역에서 IP 할당
└─ FortiGate: 할당된 IP 대역으로 정책 매칭
설정
FreeRADIUS 쪽 — 그룹별 풀 분리
ippool partner_a_pool {
range-start = 10.10.60.160
range-stop = 10.10.60.175
netmask = 255.255.255.0
cache-size = 100
session-db = ${db_dir}/db.ippool.partner_a
ip-index = ${db_dir}/db.ipindex.partner_a
override = no
}
authorize에서 그룹에 따라 해당 풀을 호출한다.
FortiGate 쪽 — 주소 객체와 정책
config firewall address
edit "VPN-PartnerA"
# 왜: Part 3에서 /28 경계에 맞춰 설계했기 때문에 깔끔하게 표현된다
set subnet 10.10.60.160 255.255.255.240
next
end
config firewall policy
edit 0
set name "PartnerA-to-Server"
set srcintf "ra-ipsec"
set dstintf "internal"
# 왜: set groups가 동작하지 않으므로 IP 대역으로 신원을 표현한다
set srcaddr "VPN-PartnerA"
set dstaddr "PartnerA-Server-01"
set action accept
set schedule "always"
set service "HTTPS"
set logtraffic all
next
end
이제 매칭된다.
/32 목적지 제한
파트너사에게는 서버 단위로 제한을 걸었다.
config firewall address
edit "PartnerA-Server-01"
set subnet 10.20.30.41 255.255.255.255
next
end
그리고 마지막에 명시적 차단 정책을 둔다.
config firewall policy
edit 0
set name "VPN-Partner-DenyAll"
set srcintf "ra-ipsec"
set dstintf "any"
set srcaddr "VPN-PartnerA" "VPN-PartnerB"
set dstaddr "all"
set action deny
set logtraffic all
next
end
암묵적 거부에 의존하지 않는다. 로그가 남는 명시적 거부 정책을 두면, 파트너사가 예상 외의 곳에 접근을 시도할 때 그게 보인다. 이건 접근제어가 아니라 관측성 문제다.
7. 이 우회로의 한계
정직하게 적는다. 이건 우회로이고 대가가 있다.
| IP 대역이 곧 권한이다 | 사용자를 다른 그룹으로 옮기려면 재접속이 필요하다 |
| 대역 크기가 그룹 정원이다 | 파트너사 B가 8명을 넘으면 대역 재설계 |
| 로그에 사용자명이 안 남는다 | IP로 사용자를 역추적해야 한다 |
| 풀 고갈 시 진단이 어렵다 | "왜 저 사람만 안 되지" → 풀에 IP가 없어서 |
특히 세 번째가 운영상 불편하다. 방화벽 트래픽 로그에 사용자명이 없으니, 사후 추적할 때 RADIUS 로그와 방화벽 로그를 시각과 IP로 조인해야 한다.
그래서 RADIUS 로그를 별도로 보관하고, 할당 이력을 검색할 수 있게 해뒀다.
# 특정 IP가 언제 누구에게 할당됐는지
grep '10.10.60.163' /var/log/radius/radacct/*/detail-*
8. 여기서 배운 것
- 인증 계층과 정책 계층이 자동으로 연결된다고 가정하지 않는다. 같은 장비 안이라도 두 계층 사이에 신원이 전달되는지는 별개 문제다.
- 문법을 여러 형태로 바꿔봤는데 전부 같은 결과가 나오면 문법 문제가 아니다. 구조를 의심해야 한다. 이 판단 전환이 며칠을 아꼈다.
- diagnose firewall auth list가 비어 있는지 확인하는 건 정책 매칭 문제 진단의 1단계여야 한다. 나는 이걸 3단계쯤에서 했다.
- 초기 설계의 여유가 나중에 우회로가 된다. Part 3에서 IP 대역을 그룹별로 쪼갠 30분이, 여기서 유일한 해결책이었다. 당시엔 필요한지 확신이 없었다.
- 우회로를 채택할 때는 한계를 같이 문서화한다. 6개월 뒤에 "왜 정책에 사용자 그룹을 안 썼지?"라고 생각할 사람은 나 자신이다.
다음 편에서는
Part 8에서 이 시리즈의 가장 어려웠던 문제로 돌아온다. TCP transport에서 절반이 실패하는 현상. 설정으로는 고칠 수 없는 것이었다.
'네트워크' 카테고리의 다른 글
| IKE-over-TCP로 절반이 실패했다 — 설정으로는 고칠 수 없는 것이었다 (Part 8) (0) | 2026.07.26 |
|---|---|
| 다시 한다면 무엇을 바꿀까 — 그리고 아직 끝나지 않은 것들 (Part 12) (0) | 2026.07.25 |
| transport_mode="tcp"는 조용히 무시된다 — 우연히 동작했던 프로파일의 정체 (Part 6) (0) | 2026.07.25 |
| IKE는 붙는데 인증이 안 된다 — 원인이 하나가 아니라 다섯 개였다 (Part 5) (0) | 2026.07.25 |
| EMS 없이 150명에게 FortiClient 프로파일 배포하기 (Part 4) (0) | 2026.07.25 |