Cloud Service Mesh 예시: mTLS


Cloud Service Mesh 1.5 이상에서는 자동 상호 TLS(자동 mTLS)가 기본적으로 사용 설정됩니다. 자동 mTLS를 사용하면 클라이언트 사이드카 프록시가 서버에 사이드카가 있는지 자동으로 감지합니다. 클라이언트 사이드카는 사이드카가 있는 워크로드에는 mTLS를 전송하고, 사이드카 없는 워크로드에는 일반 텍스트를 전송합니다. 하지만 서비스는 일반 텍스트와 mTLS 트래픽을 모두 수락합니다. 포드에 사이드카 프록시를 삽입할 때에도 mTLS 트래픽만 허용하도록 서비스를 구성하는 것이 좋습니다.

Cloud Service Mesh를 사용하면 단일 YAML 파일을 적용하여 애플리케이션 코드 외부에서 mTLS를 적용할 수 있습니다. Cloud Service Mesh는 전체 서비스 메시, 네임스페이스, 개별 워크로드에 인증 정책을 적용할 수 있는 유연성을 제공합니다.

상호 mTLS

비용

이 문서에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

이 튜토리얼을 마치면 만든 리소스를 삭제하여 비용이 계속 청구되지 않도록 할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

시작하기 전에

  • Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다. 프로젝트에 결제가 사용 설정되어 있는지 확인하는 방법을 알아보세요.

  • GKE 클러스터에 Cloud Service Mesh를 설치하고 인그레스 게이트웨이를 배포합니다. 이 튜토리얼의 클러스터를 설정해야 하는 경우 이를 안내하는 Cloud Service Mesh 빠른 시작을 참조하세요.

    • GKE 클러스터 만들기
    • 관리형 Cloud Service Mesh 프로비저닝
    • 인그레스 게이트웨이 배포
    • microservices-demo 저장소의 원본 매니페스트 집합에서 수정된 anthos-service-mesh-packages 저장소에서 Online Boutique 샘플 애플리케이션 배포 권장사항에 따라 각 서비스는 고유한 서비스 계정을 사용하여 별도의 네임스페이스에 배포됩니다.
  • 테스트용으로 일반 텍스트 트래픽을 전송하는 TestCurl 포드를 만듭니다.

      apiVersion: v1
      kind: Pod
      metadata:
        name: testcurl
        namespace: default
        annotations:
          sidecar.istio.io/inject: "false"
      spec:
        containers:
        - name: curl
          image: curlimages/curl
          command: ["sleep", "600"]
    

Online Boutique 액세스

  1. kubectl의 현재 컨텍스트를, Online Boutique를 배포한 클러스터로 설정합니다.

    gcloud container clusters get-credentials CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  2. frontend 네임스페이스의 서비스를 나열합니다.

    kubectl get services -n frontend
    

    frontend-externalLoadBalancer이며 외부 IP 주소를 포함합니다. 샘플 애플리케이션에는 부하 분산기에 해당하는 서비스가 포함되어 Cloud Service Mesh가 없는 GKE에 배포될 수 있습니다.

  3. frontend-external 서비스의 외부 IP 주소를 사용하여 브라우저에서 애플리케이션을 방문합니다.

    http://FRONTEND_EXTERNAL_IP/
    
  4. Cloud Service Mesh는 인그레스 게이트웨이를 배포하는 기능을 제공합니다. 또한 인그레스 게이트웨이의 외부 IP 주소를 사용하여 Online Boutique에 액세스할 수 있습니다. 게이트웨이의 외부 IP를 가져옵니다. 자리표시자를 다음 정보로 바꿉니다.

    • GATEWAY_SERVICE_NAME: 인그레스 게이트웨이 서비스의 이름입니다. 샘플 게이트웨이를 수정하지 않고 배포한 경우 또는 기본 인그레스 게이트웨이를 배포한 경우 이름은 istio-ingressgateway입니다.
    • GATEWAY_NAMESPACE: 인그레스 게이트웨이를 배포한 네임스페이스입니다. 기본 인그레스 게이트웨이를 배포한 경우 네임스페이스는 istio-system입니다.
    kubectl get service GATEWAY_NAME -n GATEWAY_NAMESPACE
    
  5. 브라우저에서 다른 탭을 열고 인그레스 게이트웨이의 외부 IP 주소를 사용하여 애플리케이션을 방문합니다.

    http://INGRESS_GATEWAY_EXTERNAL_IP/
    
  6. 다음 명령어를 실행하여 다른 포드의 일반 HTTP로 frontend 서비스를 curl합니다. 서비스가 서로 다른 네임스페이스에 있으므로 frontend 서비스의 DNS 이름을 curl해야 합니다.

    kubectl debug --image istio/base --target istio-proxy -it \
      $(kubectl get pod -l app=productcatalogservice -n product-catalog -o jsonpath={.items..metadata.name}) \
      -n product-catalog -- \
      curl http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    기본적으로 TLS 및 일반 텍스트 트래픽이 모두 수락되므로 요청이 200 상태로 성공합니다.

네임스페이스당 상호 TLS 사용 설정

kubectl을 사용해 PeerAuthentication 정책을 적용하여 mTLS를 적용합니다.

  1. 다음 인증 정책을 mtls-namespace.yaml로 저장합니다.

    cat <<EOF > mtls-namespace.yaml
    apiVersion: "security.istio.io/v1beta1"
    kind: "PeerAuthentication"
    metadata:
      name: "namespace-policy"
    spec:
      mtls:
        mode: STRICT
    EOF
    

    YAML의 mode: STRICT 줄에서 mTLS만 허용하도록 서비스를 구성합니다. 기본적으로 modePERMISSIVE이며 일반 텍스트와 mTLS를 모두 허용하도록 서비스를 구성합니다.

  2. 인증 정책을 적용하여 모든 Online Boutique 서비스에서 mTLS만 수락하도록 구성합니다.

    for ns in ad cart checkout currency email frontend loadgenerator \
         payment product-catalog recommendation shipping; do
    kubectl apply -n $ns -f mtls-namespace.yaml
    done
    

    예상 출력:

    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created

  3. 브라우저에서 frontend-external 서비스의 외부 IP 주소를 사용하여 Online Boutique에 액세스하는 탭으로 이동합니다.

    http://FRONTEND_EXTERNAL_IP/
    
  4. 페이지를 새로고침합니다. 브라우저에 다음 오류가 표시됩니다.

    사이트에 연결할 수 없습니다.

    페이지를 새로고침하면 일반 텍스트가 frontend 서비스로 전송됩니다. STRICT 인증 정책으로 인해 사이드카 프록시는 서비스에 대한 요청을 차단합니다.

  5. 브라우저에서 istio-ingressgateway의 외부 IP 주소를 사용하여 Online Boutique에 액세스하는 탭으로 이동하고 정상적으로 표시되는 페이지를 새로고침합니다. 인그레스 게이트웨이를 사용하여 Online Boutique에 액세스하면 요청은 다음 경로를 사용합니다.

    상호 mTLS

    mTLS 인증 흐름은 다음과 같습니다.

    1. 브라우저에서 서버로 일반 텍스트 HTTP 요청을 보냅니다.
    2. 인그레스 게이트웨이 프록시 컨테이너가 요청을 가로챕니다.
    3. 인그레스 게이트웨이 프록시는 서버 측 프록시(이 예시에서는 프런트엔드 서비스)와 TLS 핸드셰이크를 수행합니다. 이 핸드셰이크에는 인증서 교환이 포함됩니다. 이러한 인증서는 Cloud Service Mesh를 통해 프록시 컨테이너에 사전 로드됩니다.
    4. 인그레스 게이트웨이 프록시는 서버 인증서의 보안 이름 확인을 실행하여 승인된 ID가 서버를 실행 중인지 확인합니다.
    5. 인그레스 게이트웨이와 서버 프록시는 상호 TLS 연결을 설정하며, 서버 프록시는 요청을 서버 애플리케이션 컨테이너(프런트엔드 서비스)로 전달합니다.
  6. 다음 명령어를 실행하여 다른 포드의 일반 HTTP로 frontend 서비스를 curl합니다.

    kubectl exec testcurl -n default -- curl \
      http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    STRICT peerAuthentication 정책이 적용된 사이드카 없는 워크로드에서 일반 텍스트 트래픽을 전송하므로 요청이 실패합니다.

인증 정책 찾기 및 삭제하기

  1. 서비스 메시의 모든 PeerAuthentication 정책 목록을 보려면 다음을 실행하세요.

    kubectl get peerauthentication --all-namespaces
    

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

    NAMESPACE         NAME               MODE     AGE
    ad                namespace-policy   STRICT   17m
    cart              namespace-policy   STRICT   17m
    checkout          namespace-policy   STRICT   17m
    currency          namespace-policy   STRICT   17m
    email             namespace-policy   STRICT   17m
    frontend          namespace-policy   STRICT   17m
    loadgenerator     namespace-policy   STRICT   17m
    payment           namespace-policy   STRICT   17m
    product-catalog   namespace-policy   STRICT   17m
    recommendation    namespace-policy   STRICT   17m
    shipping          namespace-policy   STRICT   17m
    
  2. 모든 Online Boutique 네임스페이스에서 인증 정책을 삭제합니다.

    for ns in ad cart checkout currency email frontend loadgenerator payment \
      product-catalog recommendation shipping; do
        kubectl delete peerauthentication -n $ns namespace-policy
    done;
    

    예상 출력:

    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    
  3. frontend-external 서비스의 외부 IP 주소를 사용하여 Online Boutique에 액세스하고 페이지를 새로 고칩니다. 페이지가 예상한 대로 표시됩니다.

  4. 다음 명령어를 실행하여 다른 포드의 일반 HTTP로 frontend 서비스를 curl합니다.

    kubectl debug --image istio/base --target istio-proxy -it \
      $(kubectl get pod -l app=productcatalogservice -n product-catalog -o jsonpath={.items..metadata.name}) \
      -n product-catalog -- \
      curl http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    기본적으로 TLS 및 일반 텍스트 트래픽이 모두 수락되므로 요청이 200 상태로 성공합니다.

Google Cloud 콘솔에서 워크로드 목록을 표시하는 페이지를 새로 고치면 mTLS 상태가 Permissive로 표시됩니다.

워크로드당 상호 TLS 사용 설정

특정 워크로드의 PeerAuthentication 정책을 설정하려면 selector 섹션을 구성하고 원하는 워크로드와 일치하는 라벨을 지정해야 합니다. 하지만 Cloud Service Mesh는 아웃바운드 mTLS 트래픽에 대한 워크로드 수준 정책을 서비스로 집계할 수 없습니다. 이 동작을 관리하려면 대상 규칙을 구성해야 합니다.

  1. 특정 워크로드에 인증 정책을 적용합니다. 다음 정책에서 어떻게 라벨 및 선택기를 사용하여 특정 frontend 배포를 타겟팅하는지 확인하세요.

    cat <<EOF | kubectl apply -n frontend -f -
    apiVersion: "security.istio.io/v1beta1"
    kind: "PeerAuthentication"
    metadata:
      name: "frontend"
      namespace: "frontend"
    spec:
      selector:
        matchLabels:
          app: frontend
      mtls:
        mode: STRICT
    EOF
    

    예상 출력:

    peerauthentication.security.istio.io/frontend created
  2. 일치하는 대상 규칙을 구성합니다.

    cat <<EOF | kubectl apply -n frontend -f -
    apiVersion: "networking.istio.io/v1alpha3"
    kind: "DestinationRule"
    metadata:
      name: "frontend"
    spec:
      host: "frontend.demo.svc.cluster.local"
      trafficPolicy:
        tls:
          mode: ISTIO_MUTUAL
    EOF
    

    예상 출력:

    destinationrule.networking.istio.io/frontend created
  3. frontend-external 서비스의 외부 IP 주소를 사용하여 Online Boutique에 액세스하고 페이지를 새로 고칩니다. frontend serviceSTRICT mTLS로 설정되어 있고 사이드카 프록시가 요청을 차단하기 때문에 페이지가 표시되지 않습니다.

  4. 다음 명령어를 실행하여 다른 포드의 일반 HTTP로 frontend 서비스를 curl합니다.

    kubectl exec testcurl -n default -- curl \
      http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    STRICT peerAuthentication 정책이 적용된 사이드카 없는 워크로드에서 일반 텍스트 트래픽을 전송하므로 요청이 실패합니다.

  5. 인증 정책을 삭제합니다.

    kubectl delete peerauthentication -n frontend frontend
    

    예상 출력:

    peerauthentication.security.istio.io "frontend" deleted
    
  6. 대상 규칙을 삭제합니다.

    kubectl delete destinationrule -n frontend frontend
    

    예상 출력:

    destinationrule.networking.istio.io "frontend" deleted
    

메시 전체 mTLS 적용

메시의 모든 서비스에서 일반 텍스트 트래픽을 허용하지 않도록 하려면 mTLS 모드를 STRICT로 설정하여 메시 전체 PeerAuthentication 정책을 설정합니다. 메시 전체 PeerAuthentication 정책에 선택기가 없어야 하며 정책이 루트 네임스페이스 istio-system에 적용되어야 합니다. 정책을 배포하면 워크로드가 서로 인증할 수 있도록 컨트롤 플레인이 TLS 인증서를 자동으로 프로비저닝합니다.

  1. 메시 전체 mTLS를 적용합니다.

    kubectl apply -f - <<EOF
    apiVersion: "security.istio.io/v1beta1"
    kind: "PeerAuthentication"
    metadata:
      name: "mesh-wide"
      namespace: "istio-system"
    spec:
      mtls:
        mode: STRICT
    EOF
    

    예상 출력:

    peerauthentication.security.istio.io/mesh-wide created

  2. frontend-external 서비스의 외부 IP 주소를 사용하여 Online Boutique에 액세스하고 페이지를 새로 고칩니다. 페이지가 표시되지 않습니다.

  3. 다음 명령어를 실행하여 다른 포드의 일반 HTTP로 frontend 서비스를 curl합니다.

    kubectl exec testcurl -n default -- curl \
      http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    STRICT peerAuthentication 정책이 적용된 사이드카 없는 워크로드에서 일반 텍스트 트래픽을 전송하므로 요청이 실패합니다.

  4. mesh-wide 정책을 삭제합니다.

    kubectl delete peerauthentication -n istio-system mesh-wide
    

    예상 출력:

    peerauthentication.security.istio.io "mesh-wide" deleted
    

삭제

이 튜토리얼에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 리소스가 포함된 프로젝트를 삭제하거나 프로젝트를 유지하고 개별 리소스를 삭제하세요.

  • 추가 요금이 청구되지 않도록 하려면 클러스터를 삭제하세요.

    gcloud container clusters delete  CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  • 클러스터를 유지하고 Online Boutique를 삭제하려면 다음 안내를 따르세요.

    1. 애플리케이션 네임스페이스를 삭제합니다.
    kubectl delete -f online-boutique/kubernetes-manifests/namespaces
    

    예상 출력:

    namespace "ad" deleted
    namespace "cart" deleted
    namespace "checkout" deleted
    namespace "currency" deleted
    namespace "email" deleted
    namespace "frontend" deleted
    namespace "loadgenerator" deleted
    namespace "payment" deleted
    namespace "product-catalog" deleted
    namespace "recommendation" deleted
    namespace "shipping" deleted
    
    1. 서비스 항목을 삭제합니다.
    kubectl delete -f online-boutique/istio-manifests/allow-egress-googleapis.yaml
    

    예상 출력:

    serviceentry.networking.istio.io "allow-egress-googleapis" deleted
    serviceentry.networking.istio.io "allow-egress-google-metadata" deleted
    

다음 단계

  • PeerAuthentication 정책 구성에 대한 일반적인 가이드는 전송 보안 구성을 참조하기