게이트웨이 보호


이 페이지에서는 다양한 보안 기능을 사용하여 게이트웨이를 보호하는 방법을 설명합니다.

  • 게이트웨이가 필요한 보안 프로토콜 및 알고리즘을 사용하는지 확인하기 위한 SSL 정책

  • TLS로 클라이언트 및 게이트웨이 간 트래픽과 게이트웨이 및 백엔드 간 트래픽을 보호하는 인증서

  • DDoS 공격으로부터 서비스를 보호하는 Google Cloud Armor 보안 정책

  • 서비스에 대한 액세스를 허용하기 전 인증 및 승인 레이어를 제공하는 IAP(Identity-Aware Proxy)

게이트웨이 보안에 대해 자세히 알아보려면 게이트웨이 보안을 참조하세요.

시작하기 전에

시작하기 전에 다음 태스크를 수행했는지 확인합니다.

  • Google Kubernetes Engine API를 사용 설정합니다.
  • Google Kubernetes Engine API 사용 설정
  • 이 태스크에 Google Cloud CLI를 사용하려면 gcloud CLI를 설치한 후 초기화합니다. 이전에 gcloud CLI를 설치한 경우 gcloud components update를 실행하여 최신 버전을 가져옵니다.

GKE Gateway Controller 요구사항

  • 표준인 경우 GKE 버전 1.24 이상
  • Autopilot의 경우 GKE 버전 1.26 이상
  • Google Cloud CLI 버전 407.0.0 이상
  • Gateway API는 VPC 기반 클러스터에서만 지원됩니다.
  • 내부 GatewayClasses를 사용하는 경우 프록시 전용 서브넷을 사용 설정해야 합니다.
  • 클러스터에 HttpLoadBalancing 부가기능이 사용 설정되어 있어야 합니다.
  • Istio를 사용하는 경우 Istio를 다음 버전 중 하나로 업그레이드해야 합니다.
    • 1.15.2 이상
    • 1.14.5 이상
    • 1.13.9 이상
  • 공유 VPC를 사용하는 경우 호스트 프로젝트에서 서비스 프로젝트의 GKE 서비스 계정에 Compute Network User 역할을 할당해야 합니다.

제한 및 한도

GKE 게이트웨이 컨트롤러 제한 및 한도 외에도 다음 제한사항이 게이트웨이 보안에 적용됩니다.

  • 동일한 게이트웨이 리소스에서 tls.certificateRefs와 함께 networking.gke.io/certmap 주석을 사용할 수 없습니다. 게이트웨이에서 CertificateMap을 참조하는 경우 GKE가 이를 오류로 처리합니다.
  • 인증서 관리자는 자체 관리 및 Google 관리 인증서를 모두 지원하지만 리전 게이트웨이와 호환되지 않습니다.
  • Google 관리 SSL 인증서를 사용하는 경우 게이트웨이에 연결하기 전에 GKE 외부에서 SSL 인증서를 만들어야 합니다.

  • Google 관리 SSL 인증서는 리전 게이트웨이와 호환되지 않습니다. 각 GatewayClass의 TLS 종료 방법에 대한 자세한 내용은 GatewayClass TLS 지원을 참조하세요.

  • 게이트웨이 컨트롤러는 ManagedCertificate 리소스를 지원하지 않습니다.

  • 게이트웨이 컨트롤러는 networking.gke.io/managed-certificates 주석을 지원하지 않습니다.

  • 서비스 구성의 appProtocol 필드는 프로토콜 값(HTTP, HTTPS 또는 HTTP2)으로 대문자만 허용합니다. 소문자를 사용하면 HTTP가 백엔드에 대한 프로토콜로 사용됩니다.

Kubernetes 보안 비밀을 사용하여 게이트웨이 보호

이 예시에서는 Kubernetes 보안 비밀을 사용하여 게이트웨이를 구성합니다.

Kubernetes 보안 비밀에 인증서 저장

인증 기관(CA)에서 발급되고 검증된 인증서를 사용하거나 자체 서명된 인증서를 만들 수 있습니다. 다음 단계에서는 자체 서명된 인증서를 사용합니다.

  1. 비공개 키를 만듭니다.

    openssl genrsa -out PRIVATE_KEY_FILE 2048
    

    PRIVATE_KEY_FILEprivate-key.pem과 같은 비공개 키 파일 이름으로 바꿉니다. 자세한 내용은 비공개 키 선택 또는 만들기를 참조하세요.

  2. Open SSL 구성 파일을 만듭니다.

    cat <<EOF >CONFIG_FILE
    [req]
    default_bits              = 2048
    req_extensions            = extension_requirements
    distinguished_name        = dn_requirements
    prompt                    = no
    
    [extension_requirements]
    basicConstraints          = CA:FALSE
    keyUsage                  = nonRepudiation, digitalSignature, keyEncipherment
    subjectAltName            = @sans_list
    
    [dn_requirements]
    0.organizationName        = example
    commonName                = store.example.com
    
    [sans_list]
    DNS.1                     = store.example.com
    EOF
    

    CONFIG_FILEconfig-file.cnf와 같은 새 구성 파일의 이름으로 바꿉니다.

  3. 인증서 서명 요청(CSR) 파일을 만듭니다.

    openssl req -new -key PRIVATE_KEY_FILE \
        -out CSR_FILE \
        -config CONFIG_FILE
    

    CSR_FILEcert.pem과 같은 새 CSR 파일의 이름으로 바꿉니다. 자세한 내용은 CSR 만들기를 참조하세요.

  4. CSR에 서명합니다.

    openssl x509 -req \
        -signkey PRIVATE_KEY_FILE \
        -in CSR_FILE \
        -out CERTIFICATE_FILE \
        -extfile CONFIG_FILE \
        -extensions extension_requirements \
        -days 30
    

    CERTIFICATE_FILEcert-file.pem과 같이 명령어가 생성하는 파일의 경로 및 이름으로 바꿉니다. 자세한 내용은 CSR 서명을 참조하세요.

  5. 생성된 키 및 인증서 파일을 사용하여 Kubernetes TLS 보안 비밀을 만듭니다.

    kubectl create secret tls store-example-com \
        --cert=CERTIFICATE_FILE \
        --key=PRIVATE_KEY_FILE
    

    GKE는 인증서 및 키를 게이트웨이에 연결할 수 있는 Kubernetes 리소스로 저장합니다.

게이트웨이 및 HTTPRoute 만들기

  1. 다음 매니페스트를 external-gateway.yaml로 저장합니다.

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
        tls:
          mode: Terminate
          certificateRefs:
          - name: store-example-com
    

    이 매니페스트는 다음 속성을 사용해서 게이트웨이를 기술합니다.

    • gatewayClassName: gke-l7-global-external-managed: 전역 외부 애플리케이션 부하 분산기를 배포합니다.
    • protocol: HTTPSport: 443: TLS를 사용 설정하는 데 필요합니다.
    • tls: 이전 단계에서 만든 Kubernetes 보안 비밀을 참조합니다.
  2. 클러스터에 매니페스트를 적용합니다.

    kubectl apply -f external-gateway.yaml
    
  3. 다음 매니페스트를 store-external-route.yaml로 저장합니다.

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store-external
      labels:
        gateway: external-http
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-v1
          port: 8080
    

    이 매니페스트는 store.example.com에 트래픽을 일치시키고 store-v1 서비스로 전송하는 HTTPRoute를 기술합니다.

  4. 클러스터에 매니페스트를 적용합니다.

    kubectl apply -f store-external-route.yaml
    

게이트웨이 확인

인터넷으로 요청을 전송하여 게이트웨이가 작동하는지 확인합니다.

  1. 게이트웨이의 IP 주소를 가져옵니다.

    kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"
    

    출력은 다음과 비슷합니다.

    203.0.113.12
    

    이 출력은 공개 IP 주소입니다. 즉, 인터넷 액세스가 가능한 모든 클라이언트가 연결할 수 있습니다.

  2. curl을 사용하여 게이트웨이의 도메인에 액세스합니다.

    curl https://store.example.com --resolve store.example.com:443:GATEWAY_IP_ADDRESS --cacert CERTIFICATE_FILE -v
    

    다음을 바꿉니다.

    • GATEWAY_IP_ADDRESS: 게이트웨이 부하 분산기의 IP 주소입니다.
    • CERTIFICATE_FILE: 생성한 인증서 파일입니다. 게이트웨이에 연결하기 위해 사용 중인 머신에 이 파일을 저장해야 합니다. 게이트웨이에 자체 서명된 인증서가 사용되기 때문에 게이트웨이를 인증하는 데 인증서가 필요합니다.

    --resolve 옵션은 도메인 이름을 게이트웨이의 IP 주소로 확인합니다. 이 주소는 DNS가 이 도메인에 대해 구성되지 않았기 때문에 필요합니다.

    출력은 다음과 비슷합니다.

    ...
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: O=example; CN=store.example.com
    *  start date: Apr 19 15:54:50 2021 GMT
    *  expire date: Apr 19 15:54:50 2022 GMT
    *  common name: store.example.com (matched)
    *  issuer: O=example; CN=store.example.com
    *  SSL certificate verify ok.
    ...
    {
      "cluster_name": "gw",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
      "pod_name": "store-v1-84b47c7f58-tj5mn",
      "pod_name_emoji": "😍",
      "project_id": "agmsb-k8s",
      "timestamp": "2021-04-19T16:30:08"
      # Several lines of output omitted here.
    }
    

    이 출력에는 성공한 TLS 핸드셰이크와 이후 애플리케이션 응답이 포함됩니다. TLS 연결이 게이트웨이에서 종료되고 애플리케이션이 클라이언트에 안전하게 응답합니다.

SSL 인증서를 사용하여 게이트웨이 보호

이 예시에서는 Google 관리 SSL 인증서를 사용하여 게이트웨이를 구성합니다.

SSL 인증서 만들기

  1. Google 관리 전역 SslCertificate 리소스를 만듭니다.

    gcloud compute ssl-certificates create store-example-com \
        --domains=store.example.com \
        --global
    

게이트웨이 및 HTTPRoute 만들기

  1. 다음 매니페스트를 external-gateway.yaml로 저장합니다.

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
        tls:
          mode: Terminate
          options:
            networking.gke.io/pre-shared-certs: store-example-com
    

    이 매니페스트는 다음 속성을 사용해서 게이트웨이를 기술합니다.

    • gatewayClassName: gke-l7-global-external-managed: 전역 외부 애플리케이션 부하 분산기를 배포합니다.
    • protocol:HTTPSport:443: TLS를 사용 설정하는 데 필요합니다.
    • tls.mode:Terminate: SSL 인증서를 사용하여 TLS를 종료합니다.
  2. 매니페스트를 클러스터에 적용합니다.

    kubectl apply -f external-gateway.yaml
    
  3. 다음 HTTPRoute 매니페스트를 store-external-route.yaml로 저장합니다.

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store-external
      labels:
        gateway: external-http
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-v1
          port: 8080
    
  4. 클러스터에 HTTPRoute를 배포합니다.

    kubectl apply -f store-external-route.yaml
    

    GKE가 게이트웨이를 배포하는 데 몇 분 정도 걸릴 수 있습니다.

게이트웨이 확인

  1. 게이트웨이의 IP 주소를 가져옵니다.

    kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"
    

    출력은 다음과 비슷합니다.

    203.0.113.12
    

    이 출력은 공개 IP 주소입니다. 즉, 인터넷 액세스가 가능한 모든 클라이언트가 연결할 수 있습니다.

  2. A 또는 AAAA 레코드를 업데이트하여 도메인을 게이트웨이의 IP 주소로 전달합니다.

    이 단계는 Google 관리 SSL 인증서를 구성하는 경우에만 필요합니다. 자체 관리 인증서를 구성하는 경우 이 단계를 건너뛸 수 있습니다.

    DNS 레코드가 업데이트된 후 부하 분산기가 Google 관리 인증서를 사용할 때까지 최대 10분 정도가 걸릴 수 있습니다.

  3. curl을 사용하여 인터넷으로 요청을 전송하여 게이트웨이가 작동하는지 확인합니다.

    curl https://store.example.com -v
    

    출력은 다음과 비슷합니다.

    ...
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: O=example; CN=store.example.com
    *  start date: Apr 19 15:54:50 2021 GMT
    *  expire date: Apr 19 15:54:50 2022 GMT
    *  common name: store.example.com (matched)
    *  issuer: O=example; CN=store.example.com
    *  SSL certificate verify ok.
    ...
    {
      "cluster_name": "gw",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
      "pod_name": "store-v1-84b47c7f58-tj5mn",
      "pod_name_emoji": "😍",
      "project_id": "agmsb-k8s",
      "timestamp": "2021-04-19T16:30:08",
      "zone": "us-west1-a"
    }
    

    이 출력에는 성공한 TLS 핸드셰이크와 애플리케이션 응답이 포함됩니다. TLS가 게이트웨이에서 올바르게 종료되고 애플리케이션이 클라이언트에 안전하게 응답합니다.

인증서 관리자를 사용하여 게이트웨이 보호

이 예시에서는 인증서 관리자를 사용하여 게이트웨이를 구성합니다.

CertificateMap 만들기

  1. CertificateMap을 만듭니다.

    gcloud certificate-manager maps create store-example-com-map
    
  2. 자체 관리형 인증서 및 키를 Certificate에 로드합니다.

    gcloud certificate-manager certificates create store-example-com-cert \
        --certificate-file="cert.pem" \
        --private-key-file="PRIVATE_KEY_FILE"
    
  3. 인증서를 CertificateMap에 할당하는 CertificateMapEntry를 만듭니다.

    gcloud certificate-manager maps entries create store-example-com-map-entry \
        --map=store-example-com-map \
        --hostname=store.example.com \
        --certificates=store-example-com-cert
    

게이트웨이 및 HTTPRoute 만들기

  1. 다음 매니페스트를 cert-map-gateway.yaml로 저장합니다.

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
      annotations:
        networking.gke.io/certmap: store-example-com-map
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
    

    이 매니페스트는 다음 속성을 사용해서 게이트웨이를 기술합니다.

    • gatewayClassName: gke-l7-global-external-managed: 전역 외부 애플리케이션 부하 분산기를 배포합니다.
    • protocol: HTTPSport: 443: TLS를 사용 설정하는 데 필요합니다.

    인증서 관리자에서 networking.gke.io/certmap 주석을 사용하여 TLS가 구성되므로 TLS 섹션이 없습니다.

  2. 클러스터에 매니페스트를 적용합니다.

    kubectl apply -f cert-map-gateway.yaml
    

    GKE가 게이트웨이를 배포하는 데 몇 분 정도 걸릴 수 있습니다.

  3. 다음 매니페스트를 cert-map-http-route.yaml로 저장합니다.

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: foo
      namespace: default
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - foo.example.com
      rules:
      - matches:
        - path:
            value: /
        backendRefs:
        - name: foo-v1
          port: 8080
    
  4. 클러스터에 매니페스트를 적용합니다.

    kubectl apply -f cert-map-http-route.yaml
    

게이트웨이 확인

  1. 게이트웨이의 IP 주소를 가져옵니다.

    kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"
    

    출력은 다음과 비슷합니다.

    203.0.113.12
    

    이 출력은 공개 IP 주소입니다. 즉, 인터넷 액세스가 가능한 모든 클라이언트가 연결할 수 있습니다.

  2. A 또는 AAAA 레코드를 업데이트하여 도메인을 게이트웨이의 IP 주소로 전달합니다.

    이 단계는 Google 관리 SSL 인증서를 구성하는 경우에만 필요합니다. 자체 관리 인증서를 구성하는 경우 이 단계를 건너뛸 수 있습니다.

    DNS 레코드가 업데이트된 후 부하 분산기가 Google 관리 인증서를 사용할 때까지 최대 10분 정도가 걸릴 수 있습니다.

  3. curl을 사용하여 게이트웨이의 도메인에 액세스합니다.

    curl https://store.example.com -v
    

    출력은 다음과 비슷합니다.

    ...
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: O=example; CN=store.example.com
    *  start date: Apr 19 15:54:50 2021 GMT
    *  expire date: Apr 19 15:54:50 2022 GMT
    *  common name: store.example.com (matched)
    *  issuer: O=example; CN=store.example.com
    *  SSL certificate verify ok.
    ...
    {
      "cluster_name": "gw",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
      "pod_name": "store-v1-84b47c7f58-tj5mn",
      "pod_name_emoji": "😍",
      "project_id": "agmsb-k8s",
      "timestamp": "2021-04-19T16:30:08",
      "zone": "us-west1-a"
    }
    

    이 출력에는 성공한 TLS 핸드셰이크와 애플리케이션 응답이 포함됩니다. TLS가 게이트웨이에서 올바르게 종료되고 애플리케이션이 클라이언트에 안전하게 응답합니다.

TLS를 사용하여 애플리케이션 트래픽에 대한 부하 분산기 보호

ports[].appProtocol 필드를 사용하여 부하 분산기에서 백엔드 포드로 이동하는 트래픽을 암호화할 수 있습니다. appProtocol에 지원되는 필드는 HTTP, HTTPS, HTTP2입니다.

다음 매니페스트는 백엔드 포드와 통신하려면 HTTPS 트래픽을 사용해야 하는 부하 분산기를 지정하는 서비스를 설명합니다.

apiVersion: v1
kind: Service
metadata:
  name: store-v2
spec:
  selector:
    app: store
    version: v2
  ports:
  - port: 8080
    targetPort: 8080
    appProtocol: HTTPS

부하 분산기는 백엔드 포드에서 사용하는 인증서를 확인하지 않습니다. 개발자가 백엔드 포드에 사용되는 인증서가 유효한지 확인해야 합니다.

SSL 정책을 사용하여 부하 분산기 트래픽에 대한 클라이언트 보호

애플리케이션이 HTTPS를 사용하는 외부 게이트웨이를 통해 노출되는 경우 최신 프로토콜을 사용하거나 최소 SSL 또는 TLS 버전을 지정하는 것이 중요합니다. SSL 정책을 사용하여 부하 분산기 트래픽에 대한 클라이언트를 보호할 수 있습니다.

게이트웨이에 연결할 수 있는 SSL 정책과 이를 만드는 방법에 대한 자세한 내용은 클라이언트 및 부하 분산기 간 트래픽 보호를 위한 SSL 정책 구성을 참조하세요.

Google Cloud Armor를 사용하여 백엔드 보호

Google Cloud Armor 보안 정책을 사용하면 웹 기반 공격으로부터 부하 분산 애플리케이션을 보호할 수 있습니다. Google Cloud Armor 보안 정책을 구성한 후에는 Kubernetes 서비스에 적용된 GCPBackendPolicy에서 이를 참조할 수 있습니다.

게이트웨이에 Google Cloud Armor 정책을 구성하려면 백엔드 서비스를 보호하도록 Google Cloud Armor 보안 정책 구성을 참조하세요.

IAP(Identity-Aware Proxy)를 사용하여 백엔드에 대한 요청 인증

IAP(Identity-Aware Proxy)는 애플리케이션에 요청을 보내는 클라이언트를 인증하고 역할 기반 트래픽 승인을 적용하여 원치 않는 트래픽으로부터 백엔드를 보호하는 데 도움이 됩니다. GKE용 IAP(Identity-Aware Proxy)를 사용 설정하면 Kubernetes 서비스에 적용되는 GCPBackendPolicy에서 OAuth 사용자 인증 정보를 참조할 수 있습니다.

게이트웨이에 IAP(Identity-Aware Proxy)를 구성하려면 IAP(Identity-Aware Proxy) 구성을 참조하세요.

다음 단계