블로그 | NGINX

NGINX 튜토리얼: Kubernetes 앱을 SQL 주입으로부터 보호

NGINX-F5-수평-검정-유형-RGB의 일부
다니엘레 폴렌치치 썸네일
다니엘레 폴렌치치
2022년 3월 22일 게시

이 튜토리얼은 Microservices March 2022의 개념을 실제로 적용한 4가지 튜토리얼 중 하나입니다. 쿠버네티스 네트워킹 :

더욱 다양한 Kubernetes 네트워킹 사용 사례에 NGINX를 사용하는 방법에 대한 자세한 지침을 원하시나요? 무료 전자책, NGINX로 Kubernetes 트래픽 관리 다운로드: 실용 가이드

여러분은 베개부터 자전거까지 다양한 상품을 판매하는 인기 있는 지역 매장에서 IT 부문으로 일하고 있습니다. 그들은 첫 번째 온라인 매장을 오픈하려고 하지만, 사이트를 공개하기 전에 보안 전문가에게 펜 테스트를 요청했습니다. 불행히도 보안 전문가가 문제를 발견했습니다! 온라인 상점은 SQL 주입 에 취약합니다. 보안 전문가는 해당 사이트를 악용해 사용자 이름과 비밀번호를 포함한 데이터베이스에서 중요한 정보를 얻을 수 있었습니다.

귀하의 팀, 즉 Kubernetes 엔지니어가 문제를 해결하기 위해 찾아왔습니다. 다행히도 Kubernetes 트래픽 관리 도구를 사용하면 SQL 주입(및 기타 취약점)을 완화할 수 있다는 사실을 알고 계실 겁니다. 앱을 노출하기 위해 Ingress 컨트롤러를 이미 배포했으며 단일 구성으로 취약점이 악용되지 않도록 보장할 수 있습니다. 이제 온라인 매장을 예정대로 오픈할 수 있게 됐습니다. 잘하셨어요!

랩 및 튜토리얼 개요

이 블로그는 2022년 3월 마이크로서비스 단원 3의 랩과 함께 제공되며, Kubernetes의 마이크로서비스 보안 패턴에서는 NGINX와 NGINX Ingress Controller를 사용하여 SQL 주입을 차단하는 방법을 보여줍니다.

튜토리얼을 실행하려면 다음 사양을 갖춘 장비가 필요합니다.

  • 2개 이상의 CPU
  • 2GB의 여유 메모리
  • 20GB의 여유 디스크 공간
  • 인터넷 연결
  • Docker, Hyperkit, Hyper-V, KVM, Parallels, Podman, VirtualBox 또는 VMware Fusion/Workstation과 같은 컨테이너 또는 가상 머신 관리자
  • minikube 설치됨
  • 헬름 설치됨
  • 브라우저 창을 시작할 수 있는 구성입니다. 이것이 가능하지 않다면 브라우저를 통해 관련 서비스에 접속하는 방법을 알아내야 합니다.

랩과 튜토리얼을 최대한 활용하려면 시작하기 전에 다음을 권장합니다.

이 튜토리얼에서는 다음 기술을 사용합니다.

각 과제에 대한 지침에는 앱을 구성하는 데 사용되는 YAML 파일의 전체 텍스트가 포함되어 있습니다. GitHub 저장소 에서 텍스트를 복사할 수도 있습니다. 각 YAML 파일의 텍스트와 함께 GitHub에 대한 링크가 제공됩니다.

이 튜토리얼에는 4가지 과제가 포함되어 있습니다.

  1. 클러스터 및 취약한 앱 배포
  2. 앱 해킹
  3. NGINX 사이드카 컨테이너를 사용하여 특정 요청 차단
  4. NGINX Ingress Controller를 구성하여 요청 필터링

도전 1: 클러스터 및 취약한 앱 배포

이번 챌린지에서는 Minikube 클러스터를 배포 하고 보안 취약점이 있는 Podinfo를 샘플 앱으로 설치합니다 .

Minikube 클러스터 생성

Minikube 클러스터를 배포합니다. 몇 초 후에 배포가 성공적이었음을 확인하는 메시지가 나타납니다.

$ minikube start 🏄 완료! kubectl은 이제 기본적으로 "minikube" 클러스터와 "기본" 네임스페이스를 사용하도록 구성되었습니다. 

취약한 앱 설치

여기서는 두 개의 마이크로서비스로 구성된 간단한 전자상거래 앱을 배포합니다.

  • MariaDB 데이터베이스
  • 데이터베이스에 연결하고 데이터를 검색하는 PHP 마이크로서비스

다음 단계를 수행하세요.

  1. 원하는 텍스트 편집기를 사용하여 다음 내용으로 1-app.yaml 이라는 YAML 파일을 만듭니다(또는 GitHub에서 복사합니다 ).

    apiVersion: 앱/v1 종류: 배포 
    메타데이터: 
    이름: 앱 
    사양: 
    선택기: 
    일치 레이블: 
    앱: 앱 
    템플릿: 
    메타데이터: 
    레이블: 
    앱: 앱 
    사양: 
    컨테이너: 
    - 이름: 앱 
    이미지: f5devcentral/microservicesmarch:1.0.3 
    포트: 
    - 컨테이너 포트: 80 
    환경: 
    - 이름: MYSQL_USER 
    값: dan 
    - 이름: MYSQL_PASSWORD 
    값: dan 
    - 이름: MYSQL_DATABASE 
    값: sqlitraining 
    - 이름: DATABASE_HOSTNAME 
    값: db.default.svc.cluster.local 
    --- 
    apiVersion: v1 
    종류: 서비스
    메타데이터: 
    이름: 앱 
    사양: 
    포트: 
    - 포트: 80 
    대상 포트: 80 
    노드포트: 30001 
    선택자: 
    앱: 앱 
    유형: NodePort 
    --- 
    apiVersion: apps/v1 
    종류: 배포 
    메타데이터: 
    이름: db 
    스펙: 
    선택자: 
    매치 레이블: 
    앱: db 
    템플릿: 
    메타데이터: 
    레이블: 
    앱: db 
    스펙: 
    컨테이너: 
    - 이름: db 
    이미지: mariadb:10.3.32-focus 
    포트: 
    - 컨테이너 포트: 3306 
    환경: 
    - 이름: MYSQL_ROOT_PASSWORD 
    값: root 
    - 이름: MYSQL_USER 
    값: dan 
    - 이름: MYSQL_PASSWORD 
    값: dan 
    - 이름: MYSQL_DATABASE 
    값: sqlitraining 
    
    --- 
    apiVersion: v1 
    종류: 서비스
    메타데이터: 
    이름: db 
    스펙: 
    포트: 
    - 포트: 3306 
    대상 포트: 3306 
    선택자: 
    앱: db 
    
  2. 앱과 API 배포:

    $ kubectl apply -f 1-app.yaml deployment.apps/app created service/app created deployment.apps/db created service/db created 
    
  3. STATUS 열의 값이 Running(실행 중)으로 표시된 대로 Podinfo 포드가 배포되었는지 확인합니다. 완전히 배포되려면 30~40초가 걸릴 수 있으므로 두 포드의 상태가 모두 실행 중이 될 때까지 기다린 후 다음 단계(필요한 경우 명령 다시 실행)로 넘어가세요.

    $ kubectl get pods 이름 준비 상태 재시작 나이 app-d65d9b879-b65f2 1/1 실행 중 0 37초 db-7bbcdc75c-q2kt5 1/1 실행 중 0 37초 
    
  4. 브라우저에서 앱을 엽니다.

    $ minikube service app |-----------|------|-------------|-------------|--------------| | NAMESPACE | NAME | TARGET PORT | URL | |-----------|------|-----------------|-------------|-------------| | default | app | | No node port | |-----------|------|-----------------|------------------| 😿 service default/app에 노드 포트가 없습니다. 🏃 서비스 앱을 위한 터널을 시작합니다. |-----------|------|-----------------|------------------| | NAMESPACE | NAME | TARGET PORT | URL | |-----------|------------|-----------------|------------------| | default | app | http://127.0.0.1:55446 | |-----------|-----------------|-----------------|------------------| 🎉 기본 브라우저에서 서비스 default/app을 여는 중... 
    

도전 2: 앱 해킹

샘플 신청서는 다소 기본적입니다. 여기에는 품목 목록(예: 베개)이 있는 홈페이지와 설명 및 가격 등의 세부 정보가 있는 제품 페이지가 포함됩니다. 데이터는 MariaDB 데이터베이스에 저장됩니다. 페이지가 요청될 때마다 데이터베이스에 대한 SQL 쿼리가 실행됩니다.

  • 홈페이지의 경우, 데이터베이스의 모든 항목이 검색됩니다.
  • 제품 페이지의 경우 ID로 항목을 가져옵니다.

베개 제품 페이지를 열면 URL이 /product/1 로 끝나는 것을 볼 수 있습니다. 그만큼1 는 제품 ID입니다. SQL 쿼리에 악성 코드를 직접 삽입하는 것을 방지하려면 백엔드 서비스에 요청을 전달하기 전에 사용자 입력을 정리하는 것이 가장 좋습니다. 하지만 앱이 제대로 구성되지 않았고, 데이터베이스에 대한 SQL 쿼리에 삽입되기 전에 입력이 이스케이프 되지 않았다면 어떻게 될까요?

익스플로잇 1

앱이 입력을 제대로 이스케이프하는지 알아보려면 데이터베이스에 없는 ID로 변경하여 간단한 실험을 실행해 보세요.

URL의 마지막 요소를 수동으로 변경합니다.1 에게-1 . 오류 메시지 " 잘못된 제품 ID "-1은 제품 ID가 이스케이프되지 않고 대신 문자열이 쿼리에 직접 삽입된다는 것을 나타냅니다. 해커가 아니라면 이건 안 좋은 일이네요!

데이터베이스 쿼리가 다음과 같다고 가정해 보겠습니다.

SELECT * FROM some_table WHERE id = "1"

입력을 이스케이프하지 않음으로써 발생하는 취약점을 악용하려면 다음을 바꾸세요. 1 와 함께 -1" <악성적인 쿼리> -- // 다음과 같은 것:

  • 따옴표( " ) 뒤에-1 첫 번째 쿼리가 완료되었습니다.
  • 따옴표 뒤에 악의적인 쿼리를 직접 추가할 수 있습니다.
  • -- // 시퀀스는 나머지 쿼리를 삭제합니다.

예를 들어 URL의 마지막 요소를 ‑1" 로 변경하는 경우 1-- // , 쿼리는 다음으로 컴파일됩니다.

SELECT * FROM some_table WHERE id = "-1" OR 1 -- //" -------------- ^ 주입됨 ^ 

이렇게 하면 데이터베이스에서 모든 행을 선택할 수 있어 해킹에 유용합니다. 이것이 사실인지 알아보려면 URL 끝 부분을 ‑1" 로 변경하세요. 결과 오류 메시지는 데이터베이스에 대한 더 유용한 정보를 제공합니다.

치명적인 오류: 포착되지 않은 mysqli_sql_exception: SQL 구문에 오류가 있습니다. MariaDB 서버 버전에 해당하는 매뉴얼을 확인하여 /var/www/html/product.php:23의 1번째 줄에서 '"-1""' 근처에 사용할 올바른 구문을 확인하세요. 스택 추적: #0 /var/www/html/product.php(23): mysqli->query('SELECT * FROM p...') #1 {main}이 /var/www/html/product.php의 23번째 줄에서 throw되었습니다.

이제 데이터베이스 결과를 ID별로 정렬하기 위해 삽입된 코드를 조작할 수 있습니다.

-1" 또는 1 ID DESC로 정렬 -- //

결과는 데이터베이스의 마지막 항목에 대한 제품 페이지입니다.

익스플로잇 2

데이터베이스에서 결과를 정렬하도록 강제하는 것은 흥미롭지만, 해킹이 목표인 경우에는 그다지 유용하지 않습니다. 데이터베이스에서 사용자 이름과 비밀번호를 추출해 보는 것이 훨씬 더 가치 있는 일입니다.

데이터베이스에 사용자 이름과 비밀번호가 포함된 테이블이 있다고 가정하는 것이 안전합니다. 하지만 products 테이블에서 users 테이블로 액세스를 확장하려면 어떻게 해야 할까요?

답은 다음과 같은 코드를 삽입하는 것입니다.

-1" UNION SELECT * FROM 사용자 -- //

어디

  • ‑1"은 첫 번째 쿼리에서 빈 집합을 반환하도록 합니다.
  • UNION은 두 개의 데이터베이스 테이블(이 경우에는 productsusers )을 강제로 결합합니다. 이를 통해 원래( products ) 테이블에 없는 정보(암호)를 얻을 수 있습니다.
  • SELECT * FROM users는 users 테이블의 모든 행을 선택합니다.
  • -- // 시퀀스는 악의적인 쿼리 다음의 모든 것을 삭제합니다.

삽입된 코드로 끝나도록 URL을 수정하면 새로운 오류 메시지가 표시됩니다.

치명적인 오류: 포착되지 않은 mysqli_sql_exception: 사용된 SELECT 문은 /var/www/html/product.php:23에서 열 수가 다릅니다. 스택 추적: #0 /var/www/html/product.php(23): mysqli->query('SELECT * FROM p...') #1 {main}이 /var/www/html/product.php의 23번째 줄에서 throw되었습니다.

이 메시지는 products 테이블과 users 테이블의 열 수가 동일하지 않아 UNION 명령을 실행할 수 없음을 보여줍니다. 하지만 SELECT 명령에 매개변수로 열(필드 이름)을 하나씩 추가하여 시행착오를 거쳐 열의 개수를 알아낼 수 있습니다. users 테이블의 필드 이름을 추측하는 좋은 방법은 password 입니다. 다음을 시도해 보세요.

# 1개 열 선택 -1" UNION SELECT password FROM users; -- // # 2개 열 선택 -1" UNION SELECT password,password FROM users; -- // # 3개 열 선택 -1" UNION SELECT password,password,password FROM users; -- / # 4개 열 선택 -1" UNION SELECT password,password,password,password FROM users; -- // # 5개 열 선택 -1" UNION SELECT password,password,password,password,password FROM users; -- //

마지막 쿼리가 성공하면( users 테이블에 5개의 열이 있음을 알려줌) 사용자 비밀번호가 표시됩니다.

이 시점에서는 이 비밀번호에 해당하는 사용자 이름을 알 수 없습니다. 하지만 users 테이블의 열 수를 안다면 이전과 같은 유형의 쿼리를 사용하여 해당 정보를 얻을 수 있습니다. 관련 필드 이름이 username 이라고 가정합니다. 그리고 그 결과는 맞습니다. 다음 쿼리는 users 테이블에서 사용자 이름과 비밀번호를 모두 노출합니다. 좋습니다. 하지만 이 앱이 귀하의 인프라에 호스팅되지 않았다면 말입니다!

-1" UNION SELECT username,username,password,password,username FROM users where id=1 -- //

도전 3: NGINX 사이드카 컨테이너를 사용하여 특정 요청 차단

온라인 스토어 앱 개발자는 분명히 사용자 입력(매개변수화된 쿼리 사용 등)을 살균하는 데 더 많은 주의를 기울여야 하지만, Kubernetes 엔지니어로서 앱에 공격이 도달하지 못하도록 차단하여 SQL 주입을 방지하는 데 도움을 줄 수도 있습니다. 그렇게 하면 앱이 취약하다는 것이 그렇게 중요하지 않습니다.

앱을 보호하는 방법은 여러 가지가 있습니다. 이 랩의 나머지 부분에서는 다음 두 가지에 초점을 맞춥니다.

NGINX 오픈 소스를 사이드카로 배포

  1. 다음 내용으로 2-app-sidecar.yaml 이라는 YAML 파일을 만듭니다(또는 GitHub에서 복사합니다 ). 구성의 중요한 측면은 다음과 같습니다.

    • NGINX 오픈 소스를 실행하는 사이드카 컨테이너가 포트 8080에서 시작됩니다.
    • NGINX는 모든 트래픽을 앱으로 전달합니다.
    • SELECT 또는 UNION (다른 문자열 포함)을 포함하는 모든 요청은 거부됩니다( ConfigMap 섹션의 첫 번째 위치 블록 참조).
    • 해당 앱 서비스는 모든 트래픽을 먼저 NGINX 컨테이너로 라우팅합니다.
    apiVersion: apps/v1 
    종류: 배포 
    메타데이터: 
    이름: 앱 
    사양: 
    선택기: 
    일치 레이블: 
    앱: 앱 
    템플릿: 
    메타데이터: 
    레이블: 
    앱: 앱 
    사양: 
    컨테이너: 
    - 이름: 앱 
    이미지: f5devcentral/microservicesmarch:1.0.3 
    포트: 
    - 컨테이너 포트: 80 
    환경: 
    - 이름: MYSQL_USER 
    값: dan 
    - 이름: MYSQL_PASSWORD 
    값: dan 
    - 이름: MYSQL_DATABASE 
    값: sqlitraining 
    - 이름: DATABASE_HOSTNAME 
    값: db.default.svc.cluster.local 
    - 이름: 프록시 # <-- 사이드카 
    이미지: "nginx" 
    포트: 
    - 컨테이너 포트: 8080 
    볼륨 마운트: 
    - 마운트 경로: /etc/nginx 
    이름: nginx-config 
    볼륨: 
    - 이름: nginx-config 
    구성 맵: 
    이름: 사이드카 
    --- 
    api 버전: v1 
    종류: 서비스
    메타데이터: 
    이름: 앱 
    사양: 
    포트: 
    - 포트: 80 
    대상 포트: 8080 # <-- 트래픽이 프록시로 라우팅됩니다. 
    nodePort: 30001 
    선택자: 
    앱: 앱 
    유형: 노드포트 
    --- 
    apiVersion: v1 
    종류: ConfigMap 
    메타데이터: 
    이름: 사이드카 
    데이터: 
    nginx.conf: |- 
    이벤트 {} 
    http { 
    서버 { 
    수신 8080 기본 서버; 
    수신 [::]:8080 기본 서버; 
    
    위치 ~* "(\'|\")(.*)(drop|insert|md5|select|union)" { 
    모두 거부; 
    } 
    
    위치 / { 
    프록시 패스 http://localhost:80/; 
    } 
    } 
    } 
    --- 
    api 버전: apps/v1 
    종류: 배포 
    메타데이터: 
    이름: db 
    스펙: 
    선택자: 
    매치 레이블: 
    앱: db 
    템플릿: 
    메타데이터: 
    레이블: 
    앱: db 
    스펙: 
    컨테이너: 
    - 이름: db 
    이미지: mariadb:10.3.32-focus 
    포트: 
    - 컨테이너 포트: 3306 
    환경: 
    - 이름: MYSQL_ROOT_PASSWORD 
    값: root 
    - 이름: MYSQL_USER 
    값: dan 
    - 이름: MYSQL_PASSWORD 
    값: dan 
    - 이름: MYSQL_DATABASE 
    값: sqlitraining 
    
    --- 
    apiVersion: v1 
    종류: 서비스
    메타데이터: 
    이름: db 
    스펙: 
    포트: 
    - 포트: 3306 
    대상 포트: 3306 
    선택자: 
    앱: db
    
  2. 사이드카 배치:

    $ kubectl apply -f 2-app-sidecar.yaml deployment.apps/app 구성됨 service/app 구성됨 configmap/sidecar 생성됨 deployment.apps/db 변경되지 않음 service/db 변경되지 않음 
    

사이드카를 필터로 테스트

앱으로 돌아가서 SQL 주입을 다시 시도하여 사이드카가 트래픽을 필터링하는지 테스트합니다. NGINX는 요청이 앱에 도달하기 전에 해당 요청을 차단합니다!

-1" UNION SELECT username,username,password,password,username FROM users where id=1 -- //

도전 4: NGINX Ingress Controller를 구성하여 요청 필터링

3번째 과제 에서와 같이 앱을 보호하는 것은 교육적 경험으로는 흥미롭지만 다음과 같은 이유로 프로덕션에는 권장하지 않습니다.

  • 이는 완전한 보안 솔루션이 아닙니다.
  • 확장성이 없습니다(여러 앱에 이 보호 기능을 쉽게 적용할 수 없음).
  • 업데이트는 복잡하고 비효율적입니다.

훨씬 더 나은 솔루션은 NGINX Ingress Controller를 사용하여 모든 앱에 동일한 보호 기능을 확장하는 것입니다! Ingress 컨트롤러는 웹 애플리케이션 방화벽(WAF)에서처럼 요청 차단부터 인증 및 권한 부여까지 모든 종류의 보안 기능을 중앙에서 관리하는 데 사용할 수 있습니다.

이번 챌린지에서는 NGINX Ingress Controller를 배포하고 , 트래픽 라우팅을 구성하고 , 필터가 SQL 주입을 차단하는지 확인합니다 .

NGINX Ingress Controller 배포 

NGINX Ingress Controller를 설치하는 가장 빠른 방법은 Helm을 사용하는 것입니다.  

  1. Helm에 NGINX 저장소를 추가합니다. 

    $ helm repo nginx-stable 추가 https://helm.nginx.com/stable  
    
  2. F5 NGINX에서 유지 관리하는 NGINX 오픈 소스 기반 NGINX Ingress Controller를 다운로드하여 설치합니다. enableSnippets=true 매개변수에 주의하세요. 스니펫은 SQL 주입을 차단하도록 NGINX를 구성하는 데 사용됩니다. 마지막 출력 줄은 설치가 성공적으로 완료되었음을 확인합니다.

    $ helm install main nginx-stable/nginx-ingress \ --set controller.watchIngressWithoutClass=true --set controller.service.type=NodePort \ --set controller.service.httpPort.nodePort=30005 \ --set controller.enableSnippets=true 이름: main 마지막 배포: 요일 월 DD hh:mm:ss YYYY 네임스페이스: 기본 상태: 배포됨 개정: 1 테스트 모음: 없음 참고사항: NGINX Ingress Controller가 설치되었습니다.  
    
  3. STATUS 열에 Running 값이 표시된 대로 NGINX Ingress Controller Pod가 배포되었는지 확인합니다. 

    $ kubectl get pods 이름 준비 상태 ... main-nginx-ingress-779b74bb8b-mtdkr 1/1 실행 중 ... ... RESTARTS AGE ... 0 18초
    

앱으로 트래픽 라우팅

  1. 다음 내용으로 3-ingress.yaml 이라는 YAML 파일을 만듭니다(또는 GitHub에서 복사합니다 ). 앱으로의 트래픽을 라우팅하는 데 필요한 Ingress 매니페스트를 정의합니다(이번에는 사이드카 프록시를 통하지 않음). 주석을 주목하세요: NGINX Ingress Controller 구성을 사용자 정의하는 데 스니펫이 사용된 블록은 3번째 과제의 ConfigMap 정의와 동일한 위치 블록입니다. 이 블록은 SELECT 또는 UNION을 포함한(다른 문자열 포함) 모든 요청을 거부합니다.

    apiVersion: v1 종류: 서비스
    메타데이터: 
    이름: 사이드카 없는 앱 
    사양: 
    포트: 
    - 포트: 80 
    대상 포트: 80 
    선택자: 
    앱: 앱 
    --- 
    api 버전: networking.k8s.io/v1 
    종류: Ingress 
    메타데이터: 
    이름: 항목 
    주석: 
    nginx.org/server-snippets: | 
    위치 ~* "(\'|\")(.*)(drop|insert|md5|select|union)" { 
    모두 거부; 
    } 
    spec: 
    ingressClassName: nginx 
    규칙: 
    - 호스트: "example.com" 
    http: 
    경로: 
    - 백엔드: 
    서비스: 
    이름: app-without-sidecar 
    포트: 
    번호: 80 
    경로: / 
    경로 유형: 접두사 
    
  2. Ingress 리소스 배포: 
  3. $ kubectl apply -f 3-ingress.yaml service/app-without-sidecar가 생성됨 ingress.networking.k8s.io/entry가 생성됨 
    

필터 작동 확인

  1. 올바른 호스트 이름으로 NGINX Ingress Controller Pod에 요청을 발행하려면 일회용 BusyBox 컨테이너를 실행하세요.

    $ kubectl run -ti --rm=true busybox --image=busybox $ wget --header="호스트: example.com" -qO- main-nginx-ingress    # ...
    
  2. SQL 주입을 시도하세요. 그만큼403 금지 상태 코드는 NGINX가 공격을 차단한다는 것을 확인합니다!

     

    $ wget --header="호스트: example.com" -qO- 'main-nginx-ingress/product/-1"%20UNION%20SELECT%20username,username,password,password,username%20FROM%20users%20where%2 0id=1%20--%20//' wget: 서버에서 오류가 반환되었습니다: HTTP/1.1 403 금지됨 
    

다음 단계

쿠버네티스는 기본적으로 안전하지 않습니다. Ingress 컨트롤러는 SQL 주입(및 기타 여러) 취약점을 완화할 수 있습니다. 하지만 NGINX Ingress Controller로 구현한 WAF 유사 기능은 실제 WAF를 대체하는 것이 아니며, 앱을 안전하게 설계하는 것을 대체하는 것도 아니라는 점을 명심하세요. 능숙한 해커는 코드를 약간만 변경해도 UNION 해킹을 성공시킬 수 있습니다. 이 주제에 대한 자세한 내용은 SQL 주입(SQLi)에 대한 펜테스터 가이드를 참조하세요.

그럼에도 불구하고 Ingress 컨트롤러는 여전히 대부분의 보안을 중앙 집중화하여 중앙 집중화된 인증 및 권한 부여 사용 사례(mTLS, Single Sign‑On) 및 F5 NGINX App Protect WAF 와 같은 강력한 WAF를 포함하여 더 높은 효율성과 보안으로 이어지는 강력한 도구입니다.

앱과 아키텍처가 복잡할수록 보다 세부적인 제어가 필요할 수 있습니다. 조직에 Zero Trust와 종단 간 암호화가 필요한 경우 Kubernetes 클러스터의 서비스 간 통신(동서 트래픽)을 제어하기 위해 항상 무료인 F5 NGINX Service Mesh 와 같은 서비스 메시를 고려하세요. 4장 ' 고급 Kubernetes 배포 전략' 에서 서비스 메시를 살펴보겠습니다.

NGINX 오픈 소스를 확보하고 배포하는 방법에 대한 자세한 내용은 nginx.org를 방문하세요.

NGINX App Protect가 탑재된 NGINX Plus 기반 NGINX Ingress Controller를 사용해 보려면 오늘 무료 30일 평가판을 시작하거나 당사에 문의하여 사용 사례에 대해 논의해 보세요 . 

NGINX 오픈 소스 기반 NGINX Ingress Controller를 사용해 보려면 GitHub 저장소에서 NGINX Ingress Controller 릴리스를 참조하거나 DockerHub 에서 미리 빌드된 컨테이너를 다운로드하세요. 


"이 블로그 게시물에는 더 이상 사용할 수 없거나 더 이상 지원되지 않는 제품이 참조될 수 있습니다. 사용 가능한 F5 NGINX 제품과 솔루션에 대한 최신 정보를 보려면 NGINX 제품군을 살펴보세요. NGINX는 이제 F5의 일부가 되었습니다. 이전의 모든 NGINX.com 링크는 F5.com의 유사한 NGINX 콘텐츠로 리디렉션됩니다."