NetApp solutions for NFS encryption over the wire

NetApp Tech Blog에 갔다가 흥미로운 주제의 글이 보여서 AI 번역(+약간 수정)의 힘을 빌려 읽어보았습니다.
출처: https://community.netapp.com/t5/Tech-ONTAP-Blogs/NetApp-solutions-for-NFS-encryption-over-the-wire/ba-p/458221

개요

NetApp은 세계에서 가장 안전한 스토리지 입니다 . 이를 염두에 두고 NetApp ONTAP을 사용하여 NFS 트래픽을 유선으로 암호화하는 데 사용할 수 있는 기술을 살펴보겠습니다. 옵션에는 Kerberos를 사용한 NFS 사용, IPsec 연결을 통한 NFS 실행, 그리고 TLS를 통한 NFS를 사용하는 초기 접근 방식이 있습니다. Kerberos를 사용한 NFS 설정은 잘 문서화되어 있지만, ONTAP을 사용한 IPsec 및 TLS를 통한 NFS의 종단 간 구성 사례는 찾기가 다소 어렵기 때문에 이 문서에서 자세히 다루겠습니다.

이러한 옵션에 대한 간략한 요약을 원하시면 핵심 사항은 다음과 같습니다.

  • Kerberos를 탑재한 NFS는 유선 암호화 옵션을 포함하여 가장 많은 보안 기능을 제공하지만 가장 복잡하고 성능에 가장 큰 영향을 미칩니다. 
  • IPsec을 통한 NFS는 성숙하고 완벽하게 지원되며, 구성 복잡성 측면에서는 중간적인 위치에 있습니다. NetApp은 성능 저하를 줄이기 위해 새로운 플랫폼에서 IPsec 하드웨어 오프로드 카드(9.16.1 기준)를 이미 지원하고 있습니다.
  • TLS를 통한 NFS는 새롭게 등장한 기술입니다. 구성 복잡도는 가장 낮지만, 2025년 초 현재로서는 프로덕션 환경에 적합하지 않습니다. IPsec과 TLS를 통한 NFS의 성능 저하는 비슷하며, 둘 다 krb5p를 사용한 NFS보다 더 나은 성능을 제공합니다.

NetApp 스토리지에서 이러한 기술을 사용하여 유선 암호화를 구성하는 방법에 대한 자세한 내용을 알고 싶으시다면 계속 읽어보세요!

Kerberos를 사용한 NFS

Kerberos를 이용한 NFS 사용에 대한 간략한 설명부터 시작하겠습니다. 이 옵션은 수년 동안 사용 가능했으며 TR-4616: ONTAP의 NFS Kerberos 에 자세히 설명되어 있습니다 . NFS 클라이언트에서 루트 액세스 권한이 있는 사용자를 신뢰할 수 없는 경우, Kerberos를 이용한 NFS를 사용하면 NFS 클라이언트의 사용자가 본인이 맞는지 확인할 수 있습니다. Kerberos를 이용한 NFS는 krb5p 마운트 옵션을 사용하여 유선 암호화도 제공합니다. TR-4616에서 자세히 설명하고 있으므로 이 블로그에서는 krb5p를 이용한 NFS 구성 단계에 대해서는 다루지 않겠습니다. 이 옵션은 보안 측면에서 매우 유용하지만, 구성이 가장 복잡하고 NFS 유선 암호화 옵션 중 성능 저하가 가장 큽니다. 또한, 하드웨어 오프로드를 통해 krb5p를 이용한 NFS의 성능을 개선하기 위한 로드맵은 없습니다.

IPsec을 통한 NFS

다음은 IPsec 연결을 통한 NFS 실행입니다. ONTAP은 9.8 릴리스 이후 수년간 IPsec을 지원해 왔습니다! ONTAP 9.8부터 사전 공유 키가 지원되었을 뿐만 아니라 9.10.1부터 인증서 인증도 지원해 왔습니다. 최근에는 최신 플랫폼에서 ONTAP 9.16.1을 사용하여 IPsec 하드웨어 오프로드를 지원합니다. 자세한 내용은 ONTAP IPsec 구현의 진화를 참조하세요.

이 블로그의 IPsec 섹션 나머지 부분에서는 ONTAP과 NFS 클라이언트를 사용하여 IPsec을 구성하는 몇 가지 엔드 투 엔드 예시를 제공합니다. IPsec을 구성하는 방법은 여러 가지가 있으며, 널리 사용되는 IPsec 클라이언트 소프트웨어인 strongSwan을 사용하면 다양한 구성 옵션을 사용할 수 있습니다. 모든 트래픽을 암호화하거나 특정 포트만 암호화할 수 있습니다. 특정 IP 주소 간 또는 전체 서브넷 간에 정책을 구성할 수 있습니다. 이 글에서 설명하는 방식은 여러 스토리지 LIF에 대한 동시 연결을 허용하면서도 IPsec 클라이언트 구성을 최대한 일반적으로 유지하는 것입니다.

IPsec의 ONTAP 시행

Kerberos를 사용하거나 TLS를 통해 NFS를 사용할 때, NFS 클라이언트는 필요한 옵션을 사용하여 NFS 내보내기를 마운트하거나 “sec=sys”를 사용하여 표준 마운트를 수행할 수 있습니다. 이 개념은 스토리지 시스템의 LIF에 대해 IPsec 보안 정책이 정의되고 활성화되면 해당 LIF에서는 IPsec 연결을 통해서만 트래픽이 허용된다는 점에서 IPsec과 다릅니다.  

일반 IPsec 저장 정보

다음은 모든 유형의 IPsec 구성에 대해 알아두는 것이 유용한 일부 저장소 측 명령입니다.

# Enable ipsec on your cluster
security ipsec config modify -is-enabled true

# Check for active IPsec connections
security ipsec show-ikesa -node <nodename>

# Check for IPsec related errors
event log show -event ipsec.*

일반 IPsec 클라이언트 구성

ONTAP에서 IPSec을 사용하려면 IKEv2를 지원하는 IPsec 클라이언트 소프트웨어가 필요합니다. Linux 환경에서는 이 요구 사항을 충족하는 두 가지 인기 소프트웨어 패키지인 strongSwan과 Libreswan이 있습니다. 이 예제에서는 strongSwan을 사용하겠습니다. strongSwan을 설치하려면 Red Hat 호환 Linux 배포판에서 다음 명령을 실행하세요.

dnf install epel-release
dnf install strongswan
systemctl enable strongswan
systemctl start strongswan

다음은 이 문서에서 보여주는 모든 IPsec 구성에 적용되는 strongSwan에 대한 몇 가지 참고 사항입니다.

  • strongSwan 클라이언트 구성 파일 경로는  /etc/strongswan/swanctl/swanctl.conf 입니다.
  • IPsec 클라이언트의 디버깅 로깅은 “grep charon /var/log/messages”를

사전 공유 키 인증을 사용한 IPsec

사전 공유 키를 사용한 구성은 간단합니다. 다음 예에서는 SVM의 두 LIF 각각에 대해 스토리지 시스템 정책을 구성하고 IPsec 클라이언트에 서브넷 정의를 사용합니다.

::> security ipsec policy create -vserver svm1 -name lif1_psk -local-ip-subnets 192.168.0.201/32 -remote-ip-subnets 192.168.0.0/24
{Enter your passphrase - I used netapp123netapp123netapp123}
::> security ipsec policy create -vserver svm1 -name lif2_psk -local-ip-subnets 192.168.0.202/32 -remote-ip-subnets 192.168.0.0/24
{Enter your passphrase - I used netapp123netapp123netapp123}

클라이언트에서 각 스토리지 LIF와 사전 공유 키에 대한 연결 정의와 함께 다음 swanctl.conf 구성을 사용합니다.

connections {
    svm1_lif1 {
        children {
            svm1_lif1 {
                esp_proposals = aes256gcm16
                mode = transport
                start_action = trap
                # Disabling replay_window required with ONTAP IPSec HW offload.
                replay_window = 0
                # Connection from local subnet to lif1.
                local_ts = 192.168.0.0/24
                remote_ts = 192.168.0.201/32
            }
        }
        # Connection from local subnet to lif2.
        local_addrs = 192.168.0.0/24
        remote_addrs = 192.168.0.201/32
        proposals = aes256-sha384-ecp384
        local {
            auth = psk
        }
        remote {
            auth = psk
        }
    }
    svm1_lif2 {
        children {
            svm1_lif2 {
                esp_proposals = aes256gcm16
                mode = transport
                start_action = trap
                # Disabling replay_window required with ONTAP IPSec HW offload.
                replay_window = 0
                # Connection from local subnet to lif2.
                local_ts = 192.168.0.0/24
                remote_ts = 192.168.0.202/32
            }
        }
        # Connection from local subnet to lif2.
        local_addrs = 192.168.0.0/24
        remote_addrs = 192.168.0.202/32
        proposals = aes256-sha384-ecp384
        local {
            auth = psk
        }
        remote {
            auth = psk
        }
    }
}
secrets {
    ike-svm1 {
        # This must match the pre-shared key entered for storage policy.
        secret = netapp123netapp123netapp123
        # The ike id must match the storage policy remote-ip-subnets.
        id = 192.168.0.0/24
    }
}

이제  ” swanctl –load-all”을 실행한 다음 ” swanctl –list-conns”를 실행하여 연결이 제대로 로드되었는지 확인하세요. 모든 것이 정상이면 IPsec 클라이언트에서 저장소 LIF에 ping을 성공적으로 보낼 수 있을 것입니다.

인증서 인증을 통한 IPsec

인증서 인증을 사용하는 구성은 저장소 LIF와 IPsec 클라이언트 모두에서 인증서를 생성하고 구성해야 하므로 조금 더 복잡합니다. PKI에 익숙하다면 원하는 방식으로 인증서를 생성하고 관리할 수 있습니다. 이 예에서는 ONTAP에 내장된 인증서 관리 도구를 사용합니다. 공개 키 인증서나 개인 키를 복사할 때는 항상 ” —–BEGIN …”과 ” —–END …” 줄을 포함해야 합니다. 먼저 인증 기관(CA)을 생성하고 해당 CA를 로컬 ONTAP IPsec 구성에 추가한 후, CA 공개 키 인증서를 IPsec 클라이언트 strongSwan 구성 디렉터리에 복사합니다.

security certificate create -vserver svm1 -type root-ca -common-name svm1 -cert-name svm1_ipsec_ca
security ipsec ca-certificate add -vserver svm1 -ca-certs svm1_ipsec_ca
security certificate show -vserver svm1 -cert-name svm1_ipsec_ca -instance
{Copy the public key certificate to a file on the IPsec client at /etc/strongswan/swanctl/x509ca/svm1_ipsec_ca.pem}

다음으로, 저장소 LIF에 사용할 인증서를 생성합니다. IPsec 정책에 포함된 각 저장소 LIF에 대해 다음 단계를 반복합니다. 인증서 서명 요청을 생성할 때 올바른 FQDN과 IP 주소를 사용해야 합니다.

security certificate generate-csr -common-name svm1_lif1.demo.netapp.com -algorithm RSA -hash-function SHA256 -ipaddr 192.168.0.201 -dns-name svm1_lif1.demo.netapp.com
{Save each certificate request and private key}
security certificate sign -vserver svm1 -ca svm1 -ca-serial 1821A2A76A371FFC -expire-days 360
{Enter each certificate to sign and get signed certificate}
security certificate install -type server -vserver svm1
{Enter each signed certificate and private key}

Linux IPsec 클라이언트에 사용할 인증서도 필요합니다. ONTAP 인증서 관리 기능을 다시 사용하여 인증서를 생성한 다음, 공개 키 인증서와 개인 키를 IPsec 클라이언트의 strongSwan에 맞는 올바른 위치에 저장합니다.

security certificate generate-csr -common-name linux1.demo.netapp.com -algorithm RSA -hash-function SHA256 -ipaddr 192.168.0.61
{Save certificate request and private key}
security certificate sign -vserver svm1 -ca svm1 -ca-serial 1821A2A76A371FFC -expire-days 360
{Enter certificate to sign and get signed certificate}
{copy the signed public key certificate to /etc/strongswan/swanctl/x509/linux1.demo.netapp.com.pem}
{copy the private key to /etc/strongswan/swanctl/private/linux1.demo.netapp.com.key}

좋습니다! 모든 인증서가 준비되었으니, SVM의 두 LIF 각각에 대한 스토리지 시스템 정책을 다시 구성하고 IPsec 클라이언트에 대한 서브넷 정의를 사용합니다.

security ipsec policy create -vserver svm1 -name lif1_pki -local-ip-subnets 192.168.0.201/32 -remote-ip-subnets 192.168.0.0/24 -auth-method PKI -cert-name svm1_lif1.demo.netapp.com -local-identity CN=svm1_lif1.demo.netapp.com -remote-identity ANYTHING
security ipsec policy create -vserver svm1 -name lif2_pki -local-ip-subnets 192.168.0.202/32 -remote-ip-subnets 192.168.0.0/24 -auth-method PKI -cert-name svm1_lif2.demo.netapp.com -local-identity CN=svm1_lif2.demo.netapp.com -remote-identity ANYTHING

마지막으로 IPsec 클라이언트에 swanctl.conf가 있습니다.

connections {
    svm1_lif1 {
        children {
            svm1_lif1 {
                esp_proposals = aes256gcm16
                mode = transport
                start_action = trap
                # Disabling replay_window required with ONTAP IPSec HW offload.
                replay_window = 0
                # Connection from local subnet to lif1.
                local_ts = 192.168.0.0/24
                remote_ts = 192.168.0.201/32
            }
        }
        # Connection from local subnet to lif1.
        local_addrs = 192.168.0.0/24
        remote_addrs = 192.168.0.201/32
        proposals = aes256-sha384-ecp384
        local {
          auth = pubkey
          id = "CN=linux1.demo.netapp.com"
          certs = linux1.demo.netapp.com.pem
        }
        remote {
          auth = pubkey
          id = "CN=svm1_lif1.demo.netapp.com"
        }
    }
    svm1_lif2 {
        children {
            svm1_lif2 {
                esp_proposals = aes256gcm16
                mode = transport
                start_action = trap
                # Disabling replay_window required with ONTAP IPSec HW offload.
                replay_window = 0
                # Connection from local subnet to lif2.
                local_ts = 192.168.0.0/24
                remote_ts = 192.168.0.202/32
            }
        }
        # Connection from local subnet to lif2.
        local_addrs = 192.168.0.0/24
        remote_addrs = 192.168.0.202/32
        proposals = aes256-sha384-ecp384
        local {
          auth = pubkey
          id = "CN=linux1.demo.netapp.com"
          certs = linux1.demo.netapp.com.pem
        }
        remote {
          auth = pubkey
          id = "CN=svm1_lif2.demo.netapp.com"
        }
    }
}

이제  “swanctl –load-all”을 실행한 다음 “swanctl –list-conns”를 실행하여 연결이 제대로 로드되었는지 확인하세요. 모든 것이 정상이면 IPsec 클라이언트에서 저장소 LIF에 ping을 성공적으로 보낼 수 있을 것입니다.

IPv6에 대한 IPsec 구성 참고 사항

IPv6에서 IPsec을 테스트해 보았는데, 이 기능을 구현하기 위해 몇 가지 strongSwan 구성 요구 사항에 부딪혔습니다. 첫 번째 문제는 swanctl.conf에서 IPv6 NDP NS 및 NA 트래픽을 우회해야 한다는 것입니다. 구성 파일의 다음 스니펫에 나와 있습니다.

{Add this at the start of the connections block}
    # Bypass IPv6 NDP NS and NA traffic.
    # As per https://docs.strongswan.org/docs/5.9/config/IPv6Ndp.html
    ndp {
        children {
            ns {
                mode = pass
                start_action = trap
                local_ts = ::/0[ipv6-icmp/135]
                remote_ts = ::/0[ipv6-icmp/135]
            }
            na {
                mode = pass
                start_action = trap
                local_ts = ::/0[ipv6-icmp/136]
                remote_ts = ::/0[ipv6-icmp/136]
            }
        }
    }

IPv6에서 테스트하면서 발견한 또 다른 변경 사항은 간단한 IP 주소 엔드포인트(서브넷 표기 없음)는 다음 스니펫에서 볼 수 있듯이 swanctl.conf의 local_addrs 및 remote_addrs 파일에 지정해야 한다는 것입니다.

        local_addrs = fd12:1234:5678:1::2
        remote_addrs = fd12:1234:5678:1::4

마지막으로, ONTAP IPsec HW 오프로드는 현재 IPv6에서 지원되지 않습니다.

TLS를 통한 NFS

마지막으로, TLS를 통한 NFS 활용법을 소개해 드리겠습니다. TLS를 통한 NFS 기능은 ONTAP 9.15.1에서 기술 프리뷰로 소개되었습니다. 즉, 아직 정식 출시 준비가 되지 않았으며, ONTAP에서 이 기능에 대한 완전한 GA 지원은 향후 릴리스에서 제공될 예정입니다. 또한, 이 기능은 Linux NFS 클라이언트 측에서도 매우 새로운 기능이라는 점을 알아두셔야 합니다. RHEL 9.4에서 기술 프리뷰 로 처음 선보였기 때문입니다 .

TLS를 통한 NFS 스토리지 구성

TLS를 통한 NFS를 실행하기 위한 구성 단계를 살펴보겠습니다. TLS를 통한 NFS는 인증서를 사용하므로, SVM의 각 LIF에 대해 TLS를 통한 NFS 트래픽을 처리할 고유한 인증서를 구성해야 합니다. PKI에 익숙하다면 원하는 방식으로 인증서를 생성하고 관리할 수 있습니다. 이 예에서는 ONTAP에 내장된 인증서 관리 도구를 사용하여 설정을 간소화하겠습니다. 먼저 SVM에 인증 기관(CA)을 생성하고 나중에 NFS 클라이언트에서 사용할 CA의 공개 키 인증서를 표시합니다. 공개 키 인증서나 개인 키를 복사할 때는 항상 ” —–BEGIN …” 및 ” —–END …” 줄을 포함해야 합니다.

security certificate create -vserver svm1 -type root-ca -common-name svm1_ca
security certificate show -vserver svm1 -common-name svm1_ca -type root-ca -instance

다음으로, SVM LIF 중 하나에 대한 인증서를 만들고 TLS를 통한 NFS에 이 인증서를 사용하도록 LIF를 구성합니다.

security certificate generate-csr -common-name svm1_lif1.demo.netapp.com -algorithm RSA -hash-function SHA256 -ipaddr 192.168.0.61 -dns-name svm1_lif1.demo.netapp.com,svm1_lif1,svm1
{Save certificate request and private key}
security certificate sign -ca svm1_ca -vserver svm1 -ca-serial 181F8F545154B6BA -expire-days 364
{Enter certificate to sign and get signed certificate}
security certificate install -vserver svm1 -type server -cert-name svm1_lif1.demo.netapp.com
{Enter signed certificate and private key}
nfs tls interface enable -vserver svm1 -lif svm1_lif1 -certificate-name svm1_lif1.demo.netapp.com

위 명령은 TLS를 통한 NFS 트래픽을 실행하려는 각 LIF에 필요합니다. 또한, 위의 security certificate generate-csr 명령에 대해 몇 가지 참고 사항이 있습니다.

  • -common-name 인수는 LIF IP 주소의 FQDN이어야 합니다.
  • -ipaddr 인수에 올바른 LIF IP 주소를 사용해야 합니다.
  • 클라이언트에서 NFS 마운트에 사용될 수 있는 모든 호스트 이름을 포함하도록 -dns-name 인수를 구성해야 합니다. 여기에는 단일 호스트 이름에 대해 여러 개의 LIF IP 주소가 반환되도록 멀티홈 DNS 항목을 사용하는 구성도 포함됩니다.

TLS를 통한 NFS 클라이언트 구성

이제 Linux NFS 클라이언트에서 먼저 ktls 패키지를 설치해야 합니다. 제 예시에서는 Red Hat 9.4 호환 클라이언트를 사용합니다.

dnf install ktls-utils
systemctl enable tlshd
systemctl start tlshd

다음으로, “security certificate show -vserver svm1 -common-name svm1_ca -type root-ca -instance” 명령 출력에서 ​​복사하라고 말씀드렸던 CA 공개 키 인증서 기억하시나요? 이 인증서를 Linux 클라이언트에 저장하고 다음과 같이 명령을 실행해야 합니다.

vi /etc/pki/ca-trust/source/anchors/svm1_ca.pem
{Paste the CA public certificate that was used to sign LIF certificates on storage side}
update-ca-trust extract

이제 TLS를 사용하여 NFS 내보내기를 마운트할 수 있습니다! TLS를 통해 NFSv3로 마운트하는 구문은 다음과 같습니다.

mount -o nfsvers=3,xprtsec=tls svm1_lif1:/vol1 /vol1

끝입니다! IPv6를 사용하는 경우 TLS를 통한 NFS 절차는 동일합니다. 인증서를 생성할 때 필요에 따라 IPv6 IP 주소를 대체하면 됩니다. 

이 모든 정보가 도움이 되셨기를 바랍니다! 이러한 기술이나 구성 방식에 대해 궁금한 점이 있으면 댓글로 알려주세요.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

You May Also Like
Read More

What is NVMe?

NVMe, NVMe-oF, NVMe/FC 및 NVMe/TCP 정의 NVMe(NonVolatile Memory Express)는 모든 유형의 기업 워크로드에 대해 최고의 처리량과 가장 빠른…