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 신규 사용자는 무료 체험판을 사용할 수 있습니다.

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

시작하기 전에

인그레스 게이트웨이 배포

  1. kubectl의 현재 컨텍스트를 클러스터로 설정합니다.

    gcloud container clusters get-credentials CLUSTER_NAME  \
    --project=PROJECT_ID \
    --zone=CLUSTER_LOCATION 
    
  2. 인그레스 게이트웨이에 대해 네임스페이스를 만듭니다.

    kubectl create namespace asm-ingress
    
  3. 네임스페이스의 삽입을 사용 설정합니다. 이 단계는 컨트롤 플레인 구현에 따라 다릅니다.

    관리형(TD)

    기본 삽입 라벨을 네임스페이스에 적용합니다.

    kubectl label namespace asm-ingress \
        istio.io/rev- istio-injection=enabled --overwrite
    

    관리형(Istiod)

    권장: 다음 명령어를 실행하여 네임스페이스에 기본 삽입 라벨을 적용합니다.

      kubectl label namespace asm-ingress \
          istio.io/rev- istio-injection=enabled --overwrite
    

    관리형 Istiod 컨트롤 플레인이 있는 기존 사용자: 기본 삽입을 사용하는 것이 좋지만 버전 기반 삽입은 지원됩니다. 다음 안내를 따르세요.

    1. 다음 명령어를 실행하여 사용 가능한 출시 채널을 찾습니다.

      kubectl -n istio-system get controlplanerevision
      

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

      NAME                AGE
      asm-managed-rapid   6d7h
      

      출력에서 NAME 열 아래의 값은 Cloud Service Mesh 버전에 사용 가능한 출시 채널에 해당하는 버전 라벨입니다.

    2. 네임스페이스에 버전 라벨을 적용합니다.

      kubectl label namespace asm-ingress \
          istio-injection- istio.io/rev=REVISION_LABEL --overwrite
      
  4. anthos-service-mesh-samples 저장소에 게이트웨이 예시를 배포합니다.

    kubectl apply -n asm-ingress \
    -f docs/shared/asm-ingress-gateway
    

    예상 출력:

    serviceaccount/asm-ingressgateway configured
    service/asm-ingressgateway configured
    deployment.apps/asm-ingressgateway configured
    gateway.networking.istio.io/asm-ingressgateway configured
    

Online Boutique 샘플 애플리케이션 배포

  1. 아직 설정하지 않은 경우 kubectl의 현재 컨텍스트를 클러스터로 설정합니다.

      gcloud container clusters get-credentials CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  2. 샘플 애플리케이션의 네임스페이스를 만듭니다.

      kubectl create namespace onlineboutique
    
  3. Envoy 프록시를 자동으로 주입하도록 onlineboutique 네임스페이스에 라벨을 지정합니다. 자동 사이드카 주입 사용 설정 단계를 따릅니다.

  4. 샘플 앱, 프런트엔드용 VirtualService, 워크로드의 서비스 계정을 배포합니다. 이 튜토리얼에서는 마이크로서비스 데모 앱인 Online Boutique를 배포합니다.

      kubectl apply \
      -n onlineboutique \
      -f docs/shared/online-boutique/virtual-service.yaml
      kubectl apply \
      -n onlineboutique \
      -f docs/shared/online-boutique/service-accounts
    

서비스 보기

  1. onlineboutique 네임스페이스의 포드를 확인합니다.

    kubectl get pods -n onlineboutique
    

    예상 출력:

    NAME                                     READY   STATUS    RESTARTS   AGE
    adservice-85598d856b-m84m6               2/2     Running   0          2m7s
    cartservice-c77f6b866-m67vd              2/2     Running   0          2m8s
    checkoutservice-654c47f4b6-hqtqr         2/2     Running   0          2m10s
    currencyservice-59bc889674-jhk8z         2/2     Running   0          2m8s
    emailservice-5b9fff7cb8-8nqwz            2/2     Running   0          2m10s
    frontend-77b88cc7cb-mr4rp                2/2     Running   0          2m9s
    loadgenerator-6958f5bc8b-55q7w           2/2     Running   0          2m8s
    paymentservice-68dd9755bb-2jmb7          2/2     Running   0          2m9s
    productcatalogservice-84f95c95ff-c5kl6   2/2     Running   0          114s
    recommendationservice-64dc9dfbc8-xfs2t   2/2     Running   0          2m9s
    redis-cart-5b569cd47-cc2qd               2/2     Running   0          2m7s
    shippingservice-5488d5b6cb-lfhtt         2/2     Running   0          2m7s
    

    애플리케이션의 모든 포드가 작동되고 READY 열의 2/2를 사용해서 실행됩니다. 이것은 포드에 Envoy 사이드카 프록시가 성공적으로 주입된 것을 나타냅니다. 몇 분 후에도 2/2가 표시되지 않는다면 문제 해결 가이드를 방문하세요.

  2. 외부 IP를 가져오고 이를 변수로 설정합니다.

    kubectl get services -n asm-ingress
    export FRONTEND_IP=$(kubectl --namespace asm-ingress \
    get service --output jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}' \
    )
    

    다음과 비슷한 출력이 표시됩니다.

    NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                                      AGE
    asm-ingressgateway   LoadBalancer   10.19.247.233   35.239.7.64   80:31380/TCP,443:31390/TCP,31400:31400/TCP   27m
    
    
  3. 웹브라우저에서 EXTERNAL-IP 주소를 방문합니다. 브라우저에 Online Boutique 매장이 표시될 것으로 예상됩니다.

    Online Boutique 프런트엔드

TestCurl 포드 만들기

테스트용으로 일반 텍스트 트래픽을 전송하는 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 정책 구성에 대한 일반적인 가이드는 전송 보안 구성을 참조하기