Infosec403

firewalld_richrules_발표자료.html

32.85 KB · text/html · 업로드 2026-07-24 14:36

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Firewalld & Rich Rules — 상세 정리</title>
<style>
  :root{
    --bg:#f5f5f7;
    --bg-deep:#e8e8ed;
    --ink:#1d1d1f;
    --ink-soft:#6e6e73;
    --blue:#0071e3;
    --blue-deep:#0058b0;
    --card:#ffffff;
    --line:rgba(0,0,0,0.08);
    --code-bg:#1d1d1f;
    --code-line:#2c2c2e;
    --green:#59d499;
    --orange:#f5a623;
    --pink:#ff6482;
    --purple:#bf8cff;
    --cyan:#6fd6ff;
    --radius:22px;
  }

  *{ box-sizing:border-box; }
  html,body{
    margin:0; padding:0; height:100%;
    background:var(--bg);
    color:var(--ink);
    font-family:-apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
      "Helvetica Neue", Arial, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
    overflow:hidden;
    -webkit-font-smoothing:antialiased;
  }

  #deck{ position:relative; width:100vw; height:100vh; }

  .slide{
    position:absolute; inset:0;
    display:flex; flex-direction:column; justify-content:center; align-items:center;
    padding:6vh 8vw;
    opacity:0;
    transform:translateY(24px) scale(0.985);
    transition:opacity .55s cubic-bezier(.2,.8,.2,1), transform .55s cubic-bezier(.2,.8,.2,1);
    pointer-events:none;
  }
  .slide.active{ opacity:1; transform:translateY(0) scale(1); pointer-events:auto; }

  .content{ width:100%; max-width:1020px; }

  .eyebrow{
    font-size:14px; font-weight:600; letter-spacing:.04em;
    text-transform:uppercase; color:var(--blue); margin-bottom:14px;
  }

  h1.big{
    font-size:clamp(38px, 5.6vw, 66px);
    font-weight:700; letter-spacing:-0.02em;
    margin:0 0 10px 0; line-height:1.08;
  }

  h2.title{
    font-size:clamp(25px, 3.4vw, 40px);
    font-weight:700; letter-spacing:-0.015em;
    margin:0 0 22px 0; line-height:1.15;
  }

  p.sub{
    font-size:clamp(15px, 1.8vw, 21px);
    color:var(--ink-soft); font-weight:400; margin:0; line-height:1.55;
  }

  .grid{ display:grid; grid-template-columns:repeat(2, 1fr); gap:16px; margin-top:8px; }
  .grid.cols-3{ grid-template-columns:repeat(3,1fr); }
  .grid.cols-4{ grid-template-columns:repeat(4,1fr); }
  .grid.cols-5{ grid-template-columns:repeat(5,1fr); }
  .grid.cols-1{ grid-template-columns:1fr; }

  .card{
    background:var(--card); border:1px solid var(--line); border-radius:18px;
    padding:20px 22px; box-shadow:0 1px 2px rgba(0,0,0,0.04);
  }
  .card h3{ margin:0 0 8px 0; font-size:18px; font-weight:600; letter-spacing:-0.01em; }
  .card p{ margin:0; font-size:14.5px; color:var(--ink-soft); line-height:1.55; }
  .card .tag{
    display:inline-block; font-size:12px; font-weight:700; color:var(--blue);
    background:rgba(0,113,227,.09); border-radius:20px; padding:3px 10px;
    margin-bottom:10px; letter-spacing:.01em;
  }
  .card.zone{ padding:16px 16px; }
  .card.zone h3{ font-size:15px; }
  .card.zone p{ font-size:12.5px; }
  .card.num .n{ font-size:26px; font-weight:800; color:var(--blue); margin-bottom:6px; }

  table.compare{
    width:100%; border-collapse:separate; border-spacing:0;
    background:var(--card); border-radius:18px; overflow:hidden;
    box-shadow:0 1px 2px rgba(0,0,0,0.04); border:1px solid var(--line);
  }
  table.compare th, table.compare td{
    padding:12px 16px; text-align:left; font-size:14px; border-bottom:1px solid var(--line);
  }
  table.compare th{
    background:var(--bg-deep); font-weight:600; font-size:12px; color:var(--ink-soft);
    text-transform:uppercase; letter-spacing:.03em;
  }
  table.compare tr:last-child td{ border-bottom:none; }
  table.compare td.emph{ font-weight:600; color:var(--ink); }
  table.compare td.accent{ color:var(--blue); font-weight:600; }

  .terminal{
    background:var(--code-bg); border-radius:16px; overflow:hidden;
    box-shadow:0 20px 45px -18px rgba(0,0,0,0.45), 0 1px 0 rgba(255,255,255,0.04) inset;
    margin-top:10px; width:100%;
  }
  .terminal-bar{
    display:flex; align-items:center; gap:8px; padding:10px 14px;
    background:var(--code-line); border-bottom:1px solid rgba(255,255,255,0.06);
  }
  .dot{ width:11px; height:11px; border-radius:50%; }
  .dot.red{ background:#ff5f57; }
  .dot.yellow{ background:#febc2e; }
  .dot.green{ background:#28c840; }
  .terminal-title{
    flex:1; text-align:center; font-size:12px; color:#98989d;
    font-family:ui-monospace, "SF Mono", Menlo, monospace; margin-right:52px;
  }
  pre.code{
    margin:0; padding:16px 20px;
    font-family:ui-monospace, "SF Mono", "Menlo", "Consolas", monospace;
    font-size:14px; line-height:1.6; color:#e6e6e6;
    overflow-x:auto; white-space:pre;
  }
  .c-cmt{ color:#7d7d80; }
  .c-flag{ color:var(--cyan); }
  .c-val{ color:var(--orange); }
  .c-str{ color:var(--green); }
  .c-key{ color:var(--pink); font-weight:600; }
  .c-mod{ color:var(--purple); }

  .caption{ margin-top:12px; font-size:14px; color:var(--ink-soft); }
  .caption b{ color:var(--ink); font-weight:600; }

  ul.clean{ list-style:none; margin:0 0 6px 0; padding:0; }
  ul.clean li{
    position:relative; padding-left:22px; margin-bottom:10px;
    font-size:16.5px; line-height:1.5; color:var(--ink);
  }
  ul.clean li::before{
    content:""; position:absolute; left:0; top:9px;
    width:7px; height:7px; border-radius:50%; background:var(--blue);
  }
  ul.clean li b{ font-weight:600; }
  ul.clean li span.mono{
    font-family:ui-monospace, "SF Mono", monospace; background:rgba(0,0,0,0.06);
    border-radius:6px; padding:1px 7px; font-size:.92em;
  }

  .flow{ display:flex; align-items:center; justify-content:center; gap:14px; margin-top:10px; flex-wrap:wrap; }
  .flow .step{
    background:var(--card); border:1px solid var(--line); border-radius:16px;
    padding:18px 22px; text-align:center; min-width:150px;
    box-shadow:0 1px 2px rgba(0,0,0,0.04);
  }
  .flow .step .k{ font-size:11.5px; font-weight:700; color:var(--blue); text-transform:uppercase; letter-spacing:.04em; margin-bottom:6px; }
  .flow .step .v{ font-size:18px; font-weight:600; }
  .flow .step .d{ font-size:12.5px; color:var(--ink-soft); margin-top:4px; }
  .flow .arrow{ font-size:20px; color:var(--ink-soft); }

  .badge-row{ display:flex; gap:10px; flex-wrap:wrap; margin-top:14px; }
  .badge{
    font-size:13px; font-weight:600; padding:6px 14px; border-radius:20px;
    background:rgba(0,113,227,.09); color:var(--blue);
  }
  .badge.warn{ background:rgba(255,100,130,.12); color:#d63a5a; }
  .badge.ok{ background:rgba(89,212,153,.15); color:#1f9d63; }

  #hud{ position:fixed; left:0; right:0; bottom:26px; display:flex; justify-content:center; align-items:center; gap:8px; z-index:10; flex-wrap:wrap; max-width:80vw; margin:0 auto; }
  .pip{ width:7px; height:7px; border-radius:50%; background:rgba(0,0,0,0.18); transition:all .3s ease; cursor:pointer; }
  .pip.active{ background:var(--blue); width:22px; border-radius:4px; }

  #counter{
    position:fixed; top:26px; right:34px; font-size:13px; color:var(--ink-soft);
    font-weight:600; letter-spacing:.02em; z-index:10; font-family:ui-monospace, "SF Mono", monospace;
  }
  #brand{ position:fixed; top:26px; left:34px; font-size:13px; font-weight:700; color:var(--ink-soft); letter-spacing:.02em; z-index:10; }
  #brand b{ color:var(--ink); }

  .navzone{ position:fixed; top:0; bottom:0; width:14%; z-index:5; cursor:pointer; }
  #zone-prev{ left:0; }
  #zone-next{ right:0; }

  ::-webkit-scrollbar{ display:none; }
</style>
</head>
<body>

<div id="brand"><b>Firewalld</b> · 상세 정리</div>
<div id="counter">01 / 28</div>

<div id="deck">

  <!-- 1. Title -->
  <section class="slide active">
    <div class="content" style="text-align:center;">
      <div class="eyebrow" style="justify-content:center; display:flex;">RED HAT FIREWALL SERVICE</div>
      <h1 class="big">Firewalld & Rich Rules</h1>
      <p class="sub">Netfilter(nftables/iptables)를 쉽게 설정·관리할 수 있게 해주는<br>방화벽 관리 서비스와 그 확장 규칙 언어</p>
      <div class="flow" style="margin-top:52px;">
        <div class="step"><div class="k">대상</div><div class="v">RHEL 계열</div><div class="d">Rocky · CentOS · Fedora</div></div>
        <div class="arrow">→</div>
        <div class="step"><div class="k">핵심</div><div class="v">Zone 기반</div><div class="d">신뢰 수준별 정책</div></div>
        <div class="arrow">→</div>
        <div class="step"><div class="k">확장</div><div class="v">Rich Rules</div><div class="d">세밀한 조건 조합</div></div>
      </div>
    </div>
  </section>

  <!-- 2. Firewalld란? -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">정의</div>
      <h2 class="title">Firewalld란?</h2>
      <ul class="clean">
        <li>Linux에서 사용하는 <b>방화벽 관리 서비스</b></li>
        <li>Linux 커널의 <b>Netfilter</b>(nftables/iptables)를 쉽게 설정하고 관리할 수 있도록 해주는 프로그램</li>
        <li>주로 <b>Red Hat 계열</b> 리눅스 배포판(RHEL, Rocky, CentOS, Fedora)에서 기본 방화벽 관리자로 사용됨</li>
      </ul>
    </div>
  </section>

  <!-- 3. 관계 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">관계 비교</div>
      <h2 class="title">Netfilter · nftables/iptables · Firewalld</h2>
      <div class="grid cols-3">
        <div class="card"><span class="tag">실제 방화벽</span><h3>Netfilter</h3><p>리눅스 커널에 있는 실제 방화벽 기능(패킷 처리)</p></div>
        <div class="card"><span class="tag">제어 도구</span><h3>nftables / iptables</h3><p>Netfilter를 직접 제어하는 도구</p></div>
        <div class="card"><span class="tag">관리 서비스</span><h3>Firewalld</h3><p>nftables/iptables를 더 쉽게 관리하도록 만든 서비스</p></div>
      </div>
    </div>
  </section>

  <!-- 4. 대표 특징 개요 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">개요</div>
      <h2 class="title">Firewalld의 대표적인 특징</h2>
      <div class="grid cols-4">
        <div class="card num"><div class="n">01</div><h3>Zone 기반 관리</h3><p>신뢰 수준별 정책 그룹</p></div>
        <div class="card num"><div class="n">02</div><h3>서비스 단위 허용</h3><p>이름으로 포트 개방</p></div>
        <div class="card num"><div class="n">03</div><h3>Runtime/Permanent</h3><p>임시·영구 설정 구분</p></div>
        <div class="card num"><div class="n">04</div><h3>무중단 규칙 변경</h3><p>재시작 없이 반영</p></div>
      </div>
    </div>
  </section>

  <!-- 5. 특징1: Zone이란? -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">대표 특징 01</div>
      <h2 class="title">Zone(영역)이란?</h2>
      <ul class="clean">
        <li>네트워크의 <b>신뢰 수준</b>에 따라 서로 다른 방화벽 정책을 적용하는 <b>논리적인 그룹</b></li>
        <li>NIC나 연결을 특정 영역(Zone)에 할당하여 관리</li>
        <li>Zone마다 <b>독립적인 방화벽 규칙</b>을 가진다</li>
      </ul>
    </div>
  </section>

  <!-- 6. 특징1: Zone 할당 예시 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">대표 특징 01 · 예시</div>
      <h2 class="title">인터페이스별 Zone 할당</h2>
      <div class="terminal">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">인터페이스 → Zone 매핑</div></div>
        <pre class="code"><span class="c-key">ens160</span> → <span class="c-str">public</span> Zone   <span class="c-cmt"># 외부망</span>
<span class="c-key">ens192</span> → <span class="c-str">trusted</span> Zone  <span class="c-cmt"># 내부망</span></pre>
      </div>
      <p class="caption">같은 서버라도 네트워크 인터페이스마다 <b>다른 방화벽 정책</b>을 적용할 수 있다 → 외부망/내부망 정책을 쉽게 분리.</p>
    </div>
  </section>

  <!-- 7. 특징2: 서비스 단위 허용 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">대표 특징 02</div>
      <h2 class="title">서비스 단위 허용</h2>
      <p class="sub" style="margin-bottom:14px;">포트를 직접 입력할 수도 있지만, <b style="color:var(--ink)">서비스 이름</b>으로도 열 수 있다.</p>
      <div class="terminal">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">bash</div></div>
        <pre class="code"><span class="c-key">firewall-cmd</span> <span class="c-flag">--add-service</span>=<span class="c-str">http</span>   <span class="c-cmt"># 실제로는 TCP 80을 의미</span></pre>
      </div>
    </div>
  </section>

  <!-- 8. 특징3: Runtime vs Permanent -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">대표 특징 03</div>
      <h2 class="title">Runtime / Permanent 구분</h2>
      <div class="terminal">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">Runtime — 재부팅 시 사라짐</div></div>
        <pre class="code"><span class="c-key">firewall-cmd</span> <span class="c-flag">--add-port</span>=<span class="c-val">8080/tcp</span></pre>
      </div>
      <div class="terminal" style="margin-top:12px;">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">Permanent — 재부팅 후에도 유지</div></div>
        <pre class="code"><span class="c-key">firewall-cmd</span> <span class="c-flag">--permanent --add-port</span>=<span class="c-val">8080/tcp</span>
<span class="c-key">firewall-cmd</span> <span class="c-flag">--reload</span></pre>
      </div>
    </div>
  </section>

  <!-- 9. 특징4: 재시작 없이 규칙 변경 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">대표 특징 04</div>
      <h2 class="title">서비스 재시작 없이 규칙 변경</h2>
      <p class="sub" style="margin-bottom:14px;">iptables는 저장·재적용이 번거롭지만, Firewalld는 <b style="color:var(--ink)">기존 연결을 유지하며 동적으로</b> 규칙을 반영한다.</p>
      <div class="terminal">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">bash</div></div>
        <pre class="code"><span class="c-key">firewall-cmd</span> <span class="c-flag">--reload</span></pre>
      </div>
    </div>
  </section>

  <!-- 10. Zone 목록 표 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">Zone 목록</div>
      <h2 class="title">Rocky 기본 제공 Zone</h2>
      <table class="compare">
        <tr><th>Zone</th><th>신뢰 수준</th><th>기본 정책</th><th>사용 예시</th></tr>
        <tr><td class="emph">drop</td><td>매우 낮음</td><td>모든 패킷 폐기(응답 없음)</td><td class="accent">공격자 차단</td></tr>
        <tr><td class="emph">block</td><td>매우 낮음</td><td>모든 연결 거부(응답 있음)</td><td>접근 차단</td></tr>
        <tr><td class="emph">public</td><td>낮음</td><td>필요한 서비스만 허용</td><td class="accent">인터넷</td></tr>
        <tr><td class="emph">external</td><td>낮음</td><td>NAT 환경</td><td>게이트웨이</td></tr>
        <tr><td class="emph">dmz</td><td>중간</td><td>DMZ 서버</td><td>웹 서버</td></tr>
        <tr><td class="emph">work / home / internal</td><td>높음</td><td>내부망 정책</td><td>사내·가정·사설망</td></tr>
        <tr><td class="emph">trusted</td><td>매우 높음</td><td>거의 모든 연결 허용</td><td class="accent">관리망</td></tr>
      </table>
    </div>
  </section>

  <!-- 11. 대표 Zone 01: Public -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">대표 Zone 01</div>
      <h2 class="title">Public Zone</h2>
      <ul class="clean">
        <li>가장 많이 사용하는 Zone</li>
        <li>인터넷에 연결된 서버는 대부분 이 Zone을 사용</li>
        <li><b>필요한 서비스만</b> 열어 놓는 방식</li>
      </ul>
      <div class="terminal">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">bash</div></div>
        <pre class="code"><span class="c-key">firewall-cmd</span> <span class="c-flag">--zone</span>=<span class="c-val">public</span> <span class="c-flag">--add-service</span>=<span class="c-str">http</span>
<span class="c-key">firewall-cmd</span> <span class="c-flag">--zone</span>=<span class="c-val">public</span> <span class="c-flag">--add-service</span>=<span class="c-str">https</span></pre>
      </div>
    </div>
  </section>

  <!-- 12. 대표 Zone 02: Trusted -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">대표 Zone 02</div>
      <h2 class="title">Trusted Zone</h2>
      <ul class="clean">
        <li>가장 <b>신뢰하는 네트워크</b></li>
        <li>거의 모든 연결을 허용</li>
        <li>주로 <b>관리망</b>과 같이 안전이 보장된 네트워크에 사용</li>
      </ul>
      <div class="badge-row"><span class="badge ok">신뢰 수준: 매우 높음</span><span class="badge">사용 예시: 관리망</span></div>
    </div>
  </section>

  <!-- 13. 대표 Zone 03: DMZ -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">대표 Zone 03</div>
      <h2 class="title">DMZ Zone</h2>
      <ul class="clean">
        <li><b>DMZ(DeMilitarized Zone)</b>는 외부에 서비스를 제공해야 하는 서버를 배치하는 네트워크 영역</li>
        <li>내부망과 외부망 사이의 <b>완충 지대</b> 역할</li>
        <li>웹 서버와 같이 외부 노출이 필요한 서버에 사용</li>
      </ul>
      <div class="badge-row"><span class="badge">신뢰 수준: 중간</span><span class="badge">사용 예시: 웹 서버</span></div>
    </div>
  </section>

  <!-- 14. 대표 Zone 04: block -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">대표 Zone 04</div>
      <h2 class="title">block Zone</h2>
      <ul class="clean">
        <li>모든 연결을 <b>거부</b>하지만 상대에게 <b>Response(응답)</b>를 전송한다</li>
        <li>ICMP 응답 등이 가능하여 상대는 "차단되었다"는 사실을 인지할 수 있음</li>
        <li>접근을 명시적으로 차단하고 싶을 때 사용</li>
      </ul>
      <div class="badge-row"><span class="badge warn">신뢰 수준: 매우 낮음</span><span class="badge">사용 예시: 접근 차단</span></div>
    </div>
  </section>

  <!-- 15. 대표 Zone 05: drop -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">대표 Zone 05</div>
      <h2 class="title">drop Zone</h2>
      <ul class="clean">
        <li>가장 <b>강력한 차단</b> — 모든 패킷을 폐기하고 응답을 전혀 보내지 않음</li>
        <li>공격자는 서버가 존재하는지조차 확인하기 어려워짐</li>
        <li>공격자 차단, 스캐닝 방지 등에 사용</li>
      </ul>
      <div class="badge-row"><span class="badge warn">신뢰 수준: 매우 낮음</span><span class="badge">사용 예시: 공격자 차단</span></div>
    </div>
  </section>

  <!-- 16. Zone 정리 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">Zone 정리</div>
      <h2 class="title">Zone 기반 정책의 핵심</h2>
      <p class="sub" style="margin-bottom:18px;">Zone을 기준으로 인터페이스나 네트워크 출처마다 서로 다른 정책을 적용한다.</p>
      <div class="flow">
        <div class="step"><div class="k">인터넷</div><div class="v">public</div><div class="d">필요한 서비스만</div></div>
        <div class="arrow">+</div>
        <div class="step"><div class="k">내부망</div><div class="v">internal</div><div class="d">더 넓은 허용</div></div>
        <div class="arrow">+</div>
        <div class="step"><div class="k">관리망</div><div class="v">trusted</div><div class="d">거의 전체 허용</div></div>
      </div>
      <p class="caption">하나의 서버가 여러 네트워크에 연결되어 있어도 각 네트워크의 신뢰 수준에 맞는 방화벽 정책을 <b>손쉽게 구성</b>할 수 있다.</p>
    </div>
  </section>

  <!-- 17. UFW vs Firewalld -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">비교</div>
      <h2 class="title">UFW vs Firewalld</h2>
      <table class="compare">
        <tr><th>UFW</th><th>Firewalld</th></tr>
        <tr><td>Ubuntu 계열에서 주로 사용</td><td>RHEL·Rocky·CentOS·Fedora 기본 사용</td></tr>
        <tr><td>명령어가 매우 단순</td><td class="accent">Zone 기반으로 더 유연한 관리</td></tr>
        <tr><td>초보자가 배우기 쉬움</td><td>서버 환경에서 많이 사용</td></tr>
        <tr><td>내부적으로 Netfilter 사용</td><td>내부적으로 Netfilter(nftables) 사용</td></tr>
      </table>
    </div>
  </section>

  <!-- 18. Rich Rules란? -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">확장 규칙</div>
      <h2 class="title">Rich Rules란?</h2>
      <ul class="clean">
        <li><b>Rich Language Rules</b> — firewalld에서 제공하는 고급 방화벽 규칙 작성 방식</li>
        <li>기존 firewalld는 Zone(존) 개념을 기반으로 <b>기본 동작이 단순함</b></li>
        <li>firewalld 방화벽의 <b>확장 규칙 언어(문법)</b></li>
        <li>IP, 포트, 프로토콜, 로그, 속도 제한, 동작(허용/차단) 등을 <b>세밀하게 조합</b>해야 할 때 사용</li>
      </ul>
    </div>
  </section>

  <!-- 19. Rich Rules가 필요한 이유 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">필요성</div>
      <h2 class="title">Rich Rules가 필요한 이유</h2>
      <table class="compare">
        <tr><th>구분</th><th>일반 firewalld 규칙</th><th>Rich Rules</th></tr>
        <tr><td class="emph">포트 허용</td><td>가능</td><td>가능</td></tr>
        <tr><td class="emph">서비스 허용</td><td>가능</td><td>가능</td></tr>
        <tr><td class="emph">특정 IP 지정</td><td>제한적</td><td class="accent">가능</td></tr>
        <tr><td class="emph">로그 기록</td><td>어려움</td><td class="accent">가능</td></tr>
        <tr><td class="emph">시간 제한, 조건 조합</td><td>어려움</td><td class="accent">가능</td></tr>
        <tr><td class="emph">세밀한 정책 설정</td><td>제한적</td><td class="accent">가능</td></tr>
      </table>
    </div>
  </section>

  <!-- 20. 일반 규칙 vs Rich Rules 명령 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">문법 비교</div>
      <h2 class="title">일반 규칙 vs Rich Rules 명령</h2>
      <div class="terminal">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">일반적인 firewalld 명령 — 간단한 설정만 가능</div></div>
        <pre class="code"><span class="c-key">firewall-cmd</span> <span class="c-flag">--add-service</span>=<span class="c-str">ssh</span>
<span class="c-key">firewall-cmd</span> <span class="c-flag">--add-port</span>=<span class="c-val">80/tcp</span></pre>
      </div>
      <div class="terminal" style="margin-top:12px;">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">Rich Rules — 세밀한 조건 조합</div></div>
        <pre class="code"><span class="c-key">firewall-cmd</span> <span class="c-flag">--permanent</span> \
<span class="c-flag">--add-rich-rule</span>=<span class="c-str">'rule family="ipv4"
source address="192.168.1.100"
port port="22" protocol="tcp"
accept'</span></pre>
      </div>
    </div>
  </section>

  <!-- 21. Rich Rules 예시 01 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">Rich Rules 예시 01</div>
      <h2 class="title">특정 IP의 SSH만 허용</h2>
      <div class="terminal">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">bash</div></div>
        <pre class="code"><span class="c-key">firewall-cmd</span> <span class="c-flag">--permanent</span> \
<span class="c-flag">--add-rich-rule</span>=<span class="c-str">'rule family="ipv4"
source address="192.168.1.100"
port port="22" protocol="tcp"
accept'</span></pre>
      </div>
      <p class="caption">IPv4만 사용, 출발지 IP <b>192.168.1.100</b>, SSH(22번 포트), <b>accept</b>(허용)</p>
    </div>
  </section>

  <!-- 22. Rich Rules 예시 02 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">Rich Rules 예시 02</div>
      <h2 class="title">특정 IP 전체 차단</h2>
      <div class="terminal">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">bash</div></div>
        <pre class="code"><span class="c-key">firewall-cmd</span> <span class="c-flag">--permanent</span> \
<span class="c-flag">--add-rich-rule</span>=<span class="c-str">'rule family="ipv4"
source address="192.168.1.200"
drop'</span></pre>
      </div>
      <p class="caption">192.168.1.200에서 오는 <b>모든 패킷을 DROP</b>(폐기)한다.</p>
    </div>
  </section>

  <!-- 23. Rich Rules 예시 03 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">Rich Rules 예시 03</div>
      <h2 class="title">SSH 접속 로그 기록 후 허용</h2>
      <div class="terminal">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">bash</div></div>
        <pre class="code"><span class="c-key">firewall-cmd</span> <span class="c-flag">--permanent</span> \
<span class="c-flag">--add-rich-rule</span>=<span class="c-str">'rule
service name="ssh"
log prefix="SSH_ACCESS "
accept'</span></pre>
      </div>
      <p class="caption">SSH 접속을 <b>SSH_ACCESS</b> 접두어로 로그에 기록한 뒤 <b>허용</b>한다.</p>
    </div>
  </section>

  <!-- 24. Rich Rules 예시 04 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">Rich Rules 예시 04</div>
      <h2 class="title">ICMP(Ping) 차단</h2>
      <div class="terminal">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">bash</div></div>
        <pre class="code"><span class="c-key">firewall-cmd</span> <span class="c-flag">--permanent</span> \
<span class="c-flag">--add-rich-rule</span>=<span class="c-str">'rule
protocol value="icmp"
drop'</span></pre>
      </div>
      <p class="caption">ICMP 패킷을 <b>DROP</b>하여 Ping 요청을 차단한다.</p>
    </div>
  </section>


  <!-- 25. Rich Rules와 Zone -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">구조</div>
      <h2 class="title">Rich Rules는 Zone에 소속되는 규칙</h2>
      <ul class="clean">
        <li>Rich Rule은 <b>반드시 특정 Zone 안에 저장</b>된다.</li>
        <li>Firewalld 전체에 적용되는 <b>전역 규칙</b>이 아니다.</li>
        <li>패킷은 <b>먼저 Zone이 결정</b>된 후 <b>해당 Zone의 Rich Rule만 검사</b>한다.</li>
      </ul>
      <p class="caption">예) <b>public Zone</b>의 Rich Rule은 public Zone으로 분류된 패킷에만 적용된다.</p>
    </div>
  </section>

  <!-- 25. iptables vs Rich Rules 문법 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">문법 비교</div>
      <h2 class="title">iptables vs Rich Rules</h2>
      <div class="terminal">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">iptables 규칙</div></div>
        <pre class="code"><span class="c-key">iptables</span> <span class="c-flag">-A</span> INPUT \
-s <span class="c-val">192.168.1.100</span> \
-p tcp \
--dport <span class="c-val">22</span> \
-j ACCEPT</pre>
      </div>
      <div class="terminal" style="margin-top:12px;">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">rich rules 규칙</div></div>
        <pre class="code"><span class="c-key">firewall-cmd</span> <span class="c-flag">--add-rich-rule</span>=<span class="c-str">'rule
source address="192.168.1.100"
port port="22" protocol="tcp"
accept'</span></pre>
      </div>
      <p class="caption">firewalld에서는 조금 더 <b>읽기 쉬운 형태</b>로 작성할 수 있다. Rich Rules는 iptables에서는 사용할 수 없는, <b>firewalld 전용 문법</b>이다.</p>
    </div>
  </section>

  <!-- 26. Rich Rules가 만들어진 이유 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">배경</div>
      <h2 class="title">Rich Rules가 만들어진 이유</h2>
      <p class="sub" style="margin-bottom:14px;">iptables는 강력하지만 문법이 복잡하다 — 처음 배우는 사람은 읽기가 쉽지 않음.</p>
      <div class="terminal">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">iptables — 복잡한 문법</div></div>
        <pre class="code"><span class="c-key">iptables</span> <span class="c-flag">-A</span> INPUT -p tcp -m state --state NEW \
-s <span class="c-val">192.168.1.0/24</span> \
--dport <span class="c-val">22</span> \
-j ACCEPT</pre>
      </div>
      <div class="terminal" style="margin-top:12px;">
        <div class="terminal-bar"><div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div><div class="terminal-title">Rich Rules — 사람이 읽기 쉬운 문법</div></div>
        <pre class="code"><span class="c-key">rule</span>
<span class="c-flag">source</span>=<span class="c-val">192.168.1.0/24</span>
<span class="c-flag">port</span>=<span class="c-val">22</span>
<span class="c-key">accept</span></pre>
      </div>
      <p class="caption">Rich Rules는 <b>정책을 사람이 읽기 쉽게 표현</b>하는 데 초점을 맞춘다.</p>
    </div>
  </section>

  <!-- 27. 최종 정리 -->
  <section class="slide">
    <div class="content">
      <div class="eyebrow">정리</div>
      <h2 class="title">iptables · firewalld 기본 규칙 · Rich Rules</h2>
      <table class="compare">
        <tr><th>iptables</th><th>firewalld 기본 규칙</th><th>Rich Rules</th></tr>
        <tr><td>세밀하지만 문법이 복잡</td><td>단순하지만 세밀한 조합 어려움</td><td class="accent">iptables 수준의 세밀함 + 읽기 쉬운 문법</td></tr>
      </table>
      <p class="caption" style="margin-top:16px;">Rich Rules는 iptables에서 사용할 수 있는 문법이 아니라, <b>firewalld 전용의 고급 규칙 언어</b>다. 대부분의 기능은 iptables로도 구현 가능하지만, 문법과 관리 방식이 다르다.</p>
    </div>
  </section>

</div>

<div id="hud"></div>

<div class="navzone" id="zone-prev"></div>
<div class="navzone" id="zone-next"></div>

<script>
  const slides = document.querySelectorAll('.slide');
  const total = slides.length;
  let idx = 0;

  const hud = document.getElementById('hud');
  slides.forEach((_, i) => {
    const p = document.createElement('div');
    p.className = 'pip' + (i === 0 ? ' active' : '');
    p.addEventListener('click', () => go(i));
    hud.appendChild(p);
  });
  const pips = hud.querySelectorAll('.pip');
  const counter = document.getElementById('counter');

  function pad(n){ return String(n).padStart(2,'0'); }

  function render(){
    slides.forEach((s, i) => s.classList.toggle('active', i === idx));
    pips.forEach((p, i) => p.classList.toggle('active', i === idx));
    counter.textContent = pad(idx+1) + ' / ' + pad(total);
  }

  function go(i){
    idx = Math.max(0, Math.min(total - 1, i));
    render();
  }
  function next(){ go(idx + 1); }
  function prev(){ go(idx - 1); }

  document.getElementById('zone-next').addEventListener('click', next);
  document.getElementById('zone-prev').addEventListener('click', prev);

  window.addEventListener('keydown', (e) => {
    if (['ArrowRight','ArrowDown',' ','PageDown'].includes(e.key)) { next(); e.preventDefault(); }
    if (['ArrowLeft','ArrowUp','PageUp'].includes(e.key)) { prev(); e.preventDefault(); }
    if (e.key === 'Home') go(0);
    if (e.key === 'End') go(total-1);
  });

  let touchX = null;
  window.addEventListener('touchstart', e => touchX = e.touches[0].clientX);
  window.addEventListener('touchend', e => {
    if (touchX === null) return;
    const dx = e.changedTouches[0].clientX - touchX;
    if (dx > 50) prev();
    if (dx < -50) next();
    touchX = null;
  });

  render();
</script>
</body>
</html>