GKE에서 모바일 클라이언트용 Pub/Sub 프록시 설정


이 가이드에서는 클라이언트 측 사용자 인증 정보 대신 인증 및 승인 로직을 처리하는 프록시를 사용하여 모바일 또는 클라이언트 측 앱에서 Pub/Sub로 메시지를 게시하는 방법을 보여줍니다.

ID 및 액세스 관리(IAM)를 사용하여 클라이언트에서 Pub/Sub로의 메시지를 인증할 수 있으며, 이러한 장기 실행 사용자 인증 정보는 만료되지 않습니다. 클라이언트 측 앱에서 이러한 사용자 인증 정보는 앱 디컴파일 및 리버스 엔지니어링과 같은 기술을 통해 검색할 수 있습니다.

그 대신 다음 작업을 수행하는 프록시에 인증 및 승인 로직을 오프로드할 수 있습니다.

  • 수신 요청을 인증하여 사용자를 확인합니다.
  • 적절한 IAM 권한과 함께 Pub/Sub에 요청을 전달합니다.

이 가이드에서는 Google Kubernetes Engine(GKE)에서 Pub/Sub 프록시를 구현하는 방법을 보여줍니다. 이 가이드는 모바일 또는 클라이언트 측 애플리케이션의 설계를 정의하고 구현하는 애플리케이션 개발자 및 시스템 설계자를 대상으로 하며, 기본 Kubernetes 개념을 이해하고 Cloud Endpoints에 익숙하다고 가정합니다.

이 가이드의 요청 흐름

Pub/Sub가 스트리밍 파이프라인에 어떻게 적합한지 이해하려면 클릭 스트림 분석을 고려해 보세요. 이 사용 사례에서 사용자가 모바일 앱과 상호작용하는 방식을 이해하는 것이 좋습니다. 이러한 통계를 얻으려면 사용자 활동을 실시간으로 캡처해야 합니다. 다음 다이어그램은 데이터 흐름을 보여줍니다.

Pub/Sub 프록시는 데이터가 집계되기 전에 클라이언트에서 메시지를 수신합니다.

앱에서 캡처한 데이터는 프록시를 통해 Pub/Sub로 푸시됩니다. Pub/Sub는 의미 있는 분석을 수행할 수 있도록 데이터를 집계하는 Dataflow 또는 Dataproc 등의 구독자 다운스트림을 가질 수 있습니다.

다음 다이어그램은 이 가이드에서 따르는 요청 흐름을 자세히 보여줍니다.

파이프라인 구성요소가 사용자 요청에서 상호작용하는 방식

다음 섹션에서는 이 다이어그램의 다양한 구성요소가 어떻게 상호작용하는지 설명합니다.

사용자 인증

모바일 앱은 다양한 방법으로 사용자를 인증할 수 있습니다. 인증 흐름은 앱에 따라 다르며, 이 가이드에서는 사용자 인증을 위한 솔루션 중 하나를 보여줍니다. 이 솔루션의 구현은 이 가이드와 함께 제공됩니다.

클라이언트 앱에서 Pub/Sub 프록시로 보내는 요청

앱 백엔드는 클라이언트가 로컬에 저장하는 단기 인증 토큰을 생성합니다(예: Android Keystore 시스템 또는 iOS 키체인 서비스 사용). 이 가이드에서는 OpenID Connect(OIDC) ID 토큰을 사용하여 클라이언트 앱을 인증합니다. Google에서는 OIDC ID 토큰을 발급하고 서명합니다.

클라이언트 측 앱은 OIDC ID 토큰을 사용하여 Pub/Sub 프록시에 요청을 보냅니다. Pub/Sub 프록시는 토큰을 검증하고 적절한 IAM 사용자 인증 정보와 함께 Pub/Sub에 요청을 전달합니다.

메시지 게시

클라이언트 앱이 성공적으로 인증되면 Pub/Sub 프록시는 Pub/Sub에 게시 요청을 보냅니다. Pub/Sub는 IAM을 사용하여 호출자(Pub/Sub 프록시)가 게시 요청을 보낼 수 있는 적절한 권한이 있는지 확인합니다. 이 가이드에서 Pub/Sub 프록시는 Compute Engine 기본 서비스 계정을 사용하여 Pub/Sub로 인증합니다. Compute Engine 기본 서비스 계정에는 편집자 IAM 역할(roles/editor)이 있어 Pub/Sub 프록시에 대한 게시자 액세스를 제공합니다.

목표

  • Pub/Sub 프록시를 실행할 GKE 클러스터를 만듭니다.
  • Pub/Sub 주제를 만듭니다.
  • Pub/Sub 프록시를 배포합니다.
  • Pub/Sub 프록시에 대한 요청을 인증하도록 Endpoints를 구성합니다.
  • 메시지가 Pub/Sub에 게시되었는지 확인합니다.

비용

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

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

이 문서에 설명된 태스크를 완료했으면 만든 리소스를 삭제하여 청구가 계속되는 것을 방지할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

시작하기 전에

  1. In the Google Cloud console, go to the project selector page.

    Go to project selector

  2. Select or create a Google Cloud project.

  3. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

  4. Google Cloud 콘솔에서 Cloud Shell을 활성화합니다.

    Cloud Shell 활성화

    Google Cloud 콘솔 하단에서 Cloud Shell 세션이 시작되고 명령줄 프롬프트가 표시됩니다. Cloud Shell은 Google Cloud CLI가 사전 설치된 셸 환경으로, 현재 프로젝트의 값이 이미 설정되어 있습니다. 세션이 초기화되는 데 몇 초 정도 걸릴 수 있습니다.

  5. 이 가이드에 필요한 환경 변수를 정의합니다.
        export PROJECT=$(gcloud config get-value project)
        export REGION=us-central1
        export ZONE=${REGION}-b
        export CLUSTER=pubsub-proxy
        export TOPIC=proxy-test
        export SERVICE_ACCOUNT=publish-test
        export ENDPOINTS_SERVICE="pubtest.endpoints.${PROJECT}.cloud.goog"
        export GENERATE_TOKEN="https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts"
  6. Cloud Build, Compute Engine, Google Kubernetes Engine, Artifact Analysis, Container Registry, Endpoints, Service Management, Service Control, Pub/Sub용 API를 사용 설정합니다.
        gcloud services enable \
            cloudbuild.googleapis.com \
            compute.googleapis.com \
            container.googleapis.com \
            containeranalysis.googleapis.com \
            containerregistry.googleapis.com \
            endpoints.googleapis.com \
            servicemanagement.googleapis.com \
            servicecontrol.googleapis.com \
            pubsub.googleapis.com

Pub/Sub 주제 만들기

  • Cloud Shell에서 메시지를 게시할 Pub/Sub 주제를 만듭니다.

    gcloud pubsub topics create $TOPIC
    

GKE 클러스터 만들기

  1. Cloud Shell에서 GKE 클러스터를 만듭니다.

    gcloud container clusters create $CLUSTER \
        --zone $ZONE \
        --scopes "https://www.googleapis.com/auth/cloud-platform"
    
  2. 실행 중인 클러스터의 사용자 인증 정보를 가져옵니다.

    gcloud container clusters get-credentials $CLUSTER \
        --zone $ZONE \
        --project $PROJECT
    

컨테이너 이미지 빌드

  1. Cloud Shell에서 코드 저장소를 클론합니다.

    git clone https://github.com/GoogleCloudPlatform/solutions-pubsub-proxy-rest
    
  2. Cloud Build를 사용하여 소스에서 컨테이너 이미지를 빌드한 다음 Container Registry에 저장합니다.

    cd solutions-pubsub-proxy-rest && \
        gcloud builds submit --tag gcr.io/$PROJECT/pubsub-proxy:v1
    

고정 외부 IP 주소 만들기

  1. Cloud Shell에서 나중에 Pub/Sub 프록시 부하 분산기에 할당되는 고정 외부 IP 주소를 만듭니다.

    gcloud compute addresses create service-ip --region $REGION
    
  2. 고정 IP 주소를 환경 변수 PROXY_IP에 저장합니다.

    PROXY_IP=$(gcloud compute addresses describe service-ip \
        --region $REGION --format='value(address)')
    

Endpoints 배포

Pub/Sub 프록시는 Endpoints를 사용하여 사용자의 요청을 인증합니다. Endpoints는 Extensible Service Proxy(ESP)를 사용하여 인증, 모니터링, 추적, API 수명 주기 관리 등의 API 관리 기능을 제공합니다. 이 가이드에서는 Pub/Sub 프록시에 대한 수신 요청을 인증하는 용도로만 Endpoints를 사용합니다.

이 가이드에서는 Pub/Sub 프록시를 사용하여 ESP를 사이드카로 배포합니다. ESP는 수신 요청을 가로채고 인증한 후 Pub/Sub 프록시로 전달합니다.

  1. Cloud Shell에서 [PROJECT_ID] 자리표시자를 openapi.yaml 파일의 Google Cloud 프로젝트 ID로 바꿉니다.

    sed -i -e "s/\[PROJECT_ID\]/$PROJECT/g" openapi.yaml
    
  2. OpenAPI 매니페스트 파일에서 [IP_ADDRESS] 자리표시자를 PROXY_IP 값으로 바꿉니다.

    sed -i -e "s/\[IP_ADDRESS\]/$PROXY_IP/g" openapi.yaml
    
  3. Endpoints에 OpenAPI 서비스 정의를 배포합니다.

    gcloud endpoints services deploy openapi.yaml
    

    앞의 명령어는 다음을 만듭니다.

    • openapi.yaml 파일(pubtest.endpoints.project-id.cloud.goog)의 호스트 필드에 지정한 이름을 사용하는 관리형 서비스. 여기서 project-id는 Google Cloud 프로젝트의 ID입니다.
    • 서비스 이름과 openapi.yaml 파일의 x-google-endpoints 확장 프로그램에 정의된 Pub/Sub 프록시 부하 분산기의 IP 주소 매핑을 사용하는 DNS A 레코드

    이 가이드는 인증에 API 키 대신 OIDC ID 토큰을 사용하므로 배포 중에 표시되는 경고는 무시해도 됩니다.

    WARNING: openapi.yaml: Operation 'post' in path '/publish': Operation does
    not require an API key; callers may invoke the method without specifying an
    associated API-consuming project. To enable API key all the
    SecurityRequirement Objects
    (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object)
    inside security definition must reference at least one SecurityDefinition
    of type : 'apiKey'.
    
  4. 서비스가 올바르게 배포되었는지 확인합니다.

    gcloud endpoints services describe ${ENDPOINTS_SERVICE}
    

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

    [...]
    producerProjectId: project-id
    serviceConfig:
      documentation:
        summary: Pub/Sub proxy exposed as an Endpoint API
    [...]
      name: pubtest.endpoints.project-id.cloud.goog
      title: PubSub Proxy
      usage: {}
    serviceName: pubtest.endpoints.project-id.cloud.goog
    

    출력에 표시되는 항목의 의미는 다음과 같습니다.

    • project-id: Google Cloud 프로젝트의 ID입니다.

프록시 배포

  1. Cloud Shell에서 자체 서명 SSL 인증서를 생성하여 프록시에 대한 HTTPS 연결을 허용합니다.

    openssl req -x509 -nodes -days 365 \
        -newkey rsa:2048 -keyout ./nginx.key \
        -out ./nginx.crt \
        -subj "/CN=${ENDPOINTS_SERVICE}"
    
  2. SSL 인증서와 비공개 키를 사용하여 Kubernetes 보안 비밀을 만듭니다.

    kubectl create secret generic nginx-ssl \
        --from-file=./nginx.crt \
        --from-file=./nginx.key
    
  3. 배포 매니페스트 파일의 [PROJECT_ID] 자리표시자를 Google Cloud 프로젝트 ID로 바꿉니다.

    sed -i -e "s/\[PROJECT_ID\]/$PROJECT/g" kube/deployment.yaml
    
  4. 서비스 매니페스트 파일의 [IP_ADDRESS] 자리표시자를 PROXY_IP 값으로 바꿉니다.

    sed -i -e "s/\[IP_ADDRESS\]/$PROXY_IP/g" kube/service.yaml
    
  5. 프록시를 배포합니다.

    kubectl apply -f kube/
    
  6. 배포가 성공했는지 확인합니다.

    kubectl rollout status deployment/pubsub-proxy
    

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

    [...]
    deployment "pubsub-proxy" successfully rolled out
    
  7. 두 컨테이너(ESP 및 Pub/Sub 프록시)가 Pod에서 실행 중인지 확인합니다.

    kubectl get pods $(kubectl get pod \
        -l app=pubsub-proxy \
        -o jsonpath="{.items[0].metadata.name}") \
        -o jsonpath={.spec.containers[*].name}
    

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

    esp  pubsub-proxy
    
  8. EXTERNAL-IP의 값이 <pending>에서 이전에 만든 고정 외부 IP 주소로 변경되는지 감시합니다.

    kubectl get svc pubsub-proxy -w
    

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

    NAME          TYPE          CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
    pubsub-proxy  LoadBalancer  10.7.247.212  <pending>     443:31104/TCP  6m32s
    pubsub-proxy  LoadBalancer  10.7.247.212  <PROXY_IP>    443:31104/TCP  6m5s
    

    감시를 중지하려면 CTRL+C를 누릅니다.

    Pub/Sub 프록시가 성공적으로 배포되면 https://${ENDPOINTS_SERVICE}/publish에 노출됩니다. 새 DNS 구성이 전파되는 데 몇 분 정도 걸릴 수 있습니다.

  9. DNS 구성을 확인합니다.

    watch nslookup ${ENDPOINTS_SERVICE}
    

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

    Server:   169.254.169.254
    Address:  169.254.169.254#53
    
    Non-authoritative answer:
    Name: pubtest.endpoints.project-id.cloud.goog
    Address: gke-load-balancer-ip
    

    출력에 표시되는 항목의 의미는 다음과 같습니다.

    • gke-load-balancer-ip: GKE 부하 분산기(프록시 IP)의 IP 주소입니다.

    감시를 중지하려면 CTRL+C를 누릅니다.

위 단계 중 어느 단계에서든 오류가 발생하는 경우 문제해결 단계를 참조하세요.

인증 토큰 생성

인증 토큰을 생성하기 위한 다음 절차는 예시로 만들어졌습니다. 프로덕션 환경의 경우 사용자가 자신의 인증 토큰을 생성할 수 있는 방법이 필요합니다. 예를 들어 프로그래매틱 방식으로 OIDC ID 토큰을 가져오기 위한 샘플 코드는 IAP(Identity-Aware Proxy) 문서에서 찾을 수 있습니다.

인증 토큰을 생성하려면 다음 단계를 따르세요.

  1. OIDC ID 토큰을 생성할 Google Cloud 서비스 계정을 만듭니다.

    gcloud iam service-accounts create \
        $SERVICE_ACCOUNT \
        --display-name $SERVICE_ACCOUNT
    
  2. 서비스 계정의 이메일 ID를 가져옵니다.

    SA_EMAIL=${SERVICE_ACCOUNT}@${PROJECT}.iam.gserviceaccount.com
    
  3. 서비스 계정에 서비스 계정 토큰 생성자 IAM 역할(roles/iam.serviceAccountTokenCreator)을 부여합니다.

    gcloud iam service-accounts add-iam-policy-binding $SA_EMAIL \
        --member user:$(gcloud config get-value account) \
        --role roles/iam.serviceAccountTokenCreator
    
  4. IAM 사용자 인증 정보 API를 사용하여 OIDC ID 토큰을 생성합니다.

    TOKEN=$(curl -s ${GENERATE_TOKEN}/${SA_EMAIL}:generateIdToken \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -d '{"audience": "'${ENDPOINTS_SERVICE}'", "includeEmail": "true"}' | jq -r ".token")
    

    Endpoints 서비스 이름은 audience 필드에 지정됩니다. audience 클레임은 토큰이 대상인 수신자를 식별합니다.

  5. 토큰이 성공적으로 생성되었는지 확인합니다.

    echo $TOKEN
    

    JSON 웹 토큰(JWT)은 다음과 비슷합니다.

    eyJhbGciOiJSUzI1NiIsImtpZCI6IjY4NjQyODlm[...].eyJhdWQiOiJwdWJ0ZXN0LmVuZHBvaW50cy52aXR
    hbC1vY3RhZ29uLTEwOTYxMi5jbG91ZC5nb[...].SjBI4TZjZAlYo6lFKkrvfAcVUp_AJzFKoSsjNbmD_n[...]
    

프록시를 사용하여 Pub/Sub 호출

  1. Cloud Shell에서 테스트 메시지를 게시합니다.

    curl -i -k -X POST https://${ENDPOINTS_SERVICE}/publish \
        -H "Authorization: Bearer $TOKEN" \
        -H "Content-Type: application/json" \
        -d '{"topic": "'$TOPIC'", "messages": [ {"attributes": {"key1": "value1", "key2" : "value2"}, "data": "test data"}]}'
    

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

    HTTP/2 200
    server: nginx
    date: Sun, 02 Jun 2019 03:53:46 GMT
    ...
    
  2. 메시지가 Pub/Sub 주제에 성공적으로 게시되었는지 확인합니다.

    kubectl logs -f --tail=5 deployment/pubsub-proxy -c pubsub-proxy
    

    Pub/Sub 프록시 배포 로그에 Successfully published 메시지가 표시됩니다.

    2019-06-02 03:49:39.723:INFO:oejs.Server:main: Started @2554ms
    Jun 02, 2019 3:53:44 AM com.google.pubsub.proxy.publish.PublishMessage
    getPublisher
    INFO: Creating new publisher for: proxy-test
    Jun 02, 2019 3:53:47 AM
    com.google.pubsub.proxy.publish.PublishMessage$1 onSuccess
    INFO: Successfully published: 569006136173844
    

문제해결

  1. Cloud Shell에서 Pub/Sub 프록시 Pod의 두 컨테이너 상태를 확인합니다.

    kubectl describe pods $(kubectl get pod -l app=pubsub-proxy \
        -o jsonpath="{.items[0].metadata.name}")
    

    로그 출력에서 컨테이너의 상태는 Running입니다.

    [...]
    Containers:
      esp:
    [...]
      State:  Running
        Started:  Fri, 21 Jun 2019 16:41:30 +0530
      Ready:  True
      Restart Count:  0
    [...]
      pubsub-proxy:
        State:  Running
          Started:  Fri, 21 Jun 2019 16:41:42 +0530
        Ready:  True
        Restart Count:  0
    [...]
    
  2. (선택사항) 컨테이너 로그를 확인하여 다른 오류가 있는지 확인합니다. 예를 들어 Pub/Sub 프록시 로그를 확인하려면 다음 명령어를 실행합니다.

    kubectl logs -f --tail=10 deployment/pubsub-proxy -c pubsub-proxy
    

문제해결과 관련하여 도움이 필요한 경우 다음 문서를 참조하세요.

삭제

이 가이드에서 사용한 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 이 가이드에서 만든 Google Cloud 프로젝트를 삭제하거나 이 가이드와 연결된 리소스를 삭제하면 됩니다.

Google Cloud 프로젝트 삭제

비용이 청구되지 않도록 하는 가장 쉬운 방법은 가이드에서 만든 프로젝트를 삭제하는 것입니다.

  1. Google Cloud 콘솔에서 리소스 관리 페이지로 이동합니다.

    리소스 관리로 이동

  2. 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
  3. 대화상자에서 프로젝트 ID를 입력한 후 종료를 클릭하여 프로젝트를 삭제합니다.

리소스 삭제

이 튜토리얼에서 사용된 Google Cloud 프로젝트를 유지하려면 개별 리소스를 삭제합니다.

  1. Cloud Shell에서 GKE 클러스터를 삭제합니다.

    gcloud container clusters delete $CLUSTER --zone $ZONE --async
    
  2. 다운로드한 코드, 아티팩트, 기타 종속 항목을 삭제합니다.

    cd .. && rm -rf solutions-pubsub-proxy-rest
    
  3. Container Registry에 있는 이미지를 삭제합니다.

    gcloud container images list-tags \
        gcr.io/$PROJECT/pubsub-proxy \
        --format 'value(digest)' | \
        xargs -I {} gcloud container images delete \
        --force-delete-tags --quiet \
        gcr.io/${PROJECT}/pubsub-proxy@sha256:{}
    
  4. Pub/Sub 주제를 삭제합니다.

    gcloud pubsub topics delete $TOPIC
    
  5. 서비스 계정을 삭제합니다.

    gcloud iam service-accounts delete $SA_EMAIL
    
  6. Endpoints를 삭제합니다.

    gcloud endpoints services delete ${ENDPOINTS_SERVICE}
    
  7. 고정 IP 주소를 삭제합니다.

    gcloud compute addresses delete service-ip --region $REGION
    

다음 단계