본문 바로가기

네트워크

authusrgrp를 쓰면 방화벽 정책의 그룹 매칭이 죽는다 — 문서에 없던 상호작용 (Part 7)

같은 증상으로 검색해 오신 분들께

증상: 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 쪽에 그룹을 만들고 정책에 넣으면 될 것 같았다.

 
bash
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도 할당됐다. 트래픽이 전부 차단됐다.

 
bash
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의 그룹 매칭 설정이 틀렸다.

이걸 확인하는 건 쉬웠다.

 
bash
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가 이 세션의 사용자가 누구라고 알고 있는가?

 
bash
diagnose firewall auth list

출력이 비어 있었다. 인증된 사용자 테이블에 아무것도 없었다.

세션 정보도 봤다.

 
bash
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 쪽 — 주소 객체와 정책

 
bash
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 목적지 제한

파트너사에게는 서버 단위로 제한을 걸었다.

 
bash
config firewall address
    edit "PartnerA-Server-01"
        set subnet 10.20.30.41 255.255.255.255
    next
end

그리고 마지막에 명시적 차단 정책을 둔다.

 
bash
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 로그를 별도로 보관하고, 할당 이력을 검색할 수 있게 해뒀다.

 
bash
# 특정 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에서 절반이 실패하는 현상. 설정으로는 고칠 수 없는 것이었다.

반응형