[Rails] Carrier Wave 및 fog-Google에서 Google Cloud Storage에 연결할 때 기본 인증 정보 사용

TL;DR

  • GCP의 실행 환경(예를 들어 App Engine과 Compute Engine)에서 응용 프로그램은 GCP의 다른 자원을 방문할 때 이 환경과 관련된 서비스 계정의 인증 정보 = 응용 프로그램의 기본 인증 정보(ADC)를 이용할 수 있다.
  • GCP 자원에 접근하는 루비 앱을 이용하면 ADCfog-google 옵션fog-google을 사용할 수 있다.따라서 인증 정보를 수동으로 교환할 필요가 없다.
  • Carrier Wave 백엔드를 Cloud Storagegoogle_application_default로 설정할 때 같은 손도 유효
  • 이때 서비스 계정에 저장 대상 관리자true 역할 부여
  • 배경: Carrier Wave+fog-Google에서 Cloud Storage를 사용하는 Rails 응용 프로그램


    Carrier Wave를 이용해 이미지를 업로드하는 Rails 프로젝트를 만났습니다.
    GCP를 사용하면 애플리케이션이 App Engine에서 실행되고 Carrier Wave의 백엔드는 Cloud Storage입니다.
    Carrier Wave는 Cloud Storagefog-google를 사용하기 위해 인증했습니다.
    roles/storage.ObjectAdmin의 README에 설명된 코드 거의 그대로 사용했다.
    config/initializers/carrierwave.rb
    CarrierWave.configure do |config|
        config.fog_provider = 'fog/google'
        config.fog_credentials = {
            provider: 'Google',
            google_project: Rails.application.secrets.google_cloud_storage_project_name,
            google_json_key_string: Rails.application.secrets.google_cloud_storage_credential_content
            # can optionally use google_json_key_location if using an actual file;
        }
        config.fog_directory = Rails.application.secrets.google_cloud_storage_bucket_name
    end
    
    어쩌면 나도 이 보도를 참고했을지도 모른다.
    https://qiita.com/arthur_foreign/items/43da529ab3beb760ba4b

    서비스 계정의 키를 직접 사용하는 JSON의 문제점


    위 코드를 보면 클라우드 스토어에 대한 액세스 권한이 있는 서비스 계정의 키fog-google가 선택적으로 전달됩니다.
    GCP의 웹 콘솔에서 JSON 형식으로 서비스 계정의 키를 다운로드하고 그 내용을 비밀 관리 기구에 직접 삽입한다[1].
    여기 이미 싫은 냄새 나겠다.fog-google 공식에 상기 샘플이 기재되어 있다
    google_json_key_string 사용하지 않는fog-google Carrier Wave의 클라우드 스토어를 위한 어댑터)도 "How to get the Keyfile?"에서 이미지가 있는↓로 같은 방법을 설명한 것도 사실이다.

    그러나 실제로 이 같은 인증 정보를 관리하는 방법에는'열쇠 JSON을 비밀에 직접 꽂는 것은 역겹다'는 이상의 폐단이 존재한다.
    키 파일의 취득, 보존에 일손이 개입해야 하기 때문에Terraform 등 IaC와는 매우 맞지 않는다.
    예를 들어 Cloud Storage Bucket을 IaC로 간신히 관리하고 있습니다.
  • 액세스용 서비스 계정 설정
  • 서비스 계정의 인증 정보(키 JSON)의 생성/다운로드
  • 인증 정보를 비밀리에 관리
  • IaC의 바깥쪽에서 수작업[2]했습니다.
    어떡하죠?

    응용 프로그램의 기본 인증 정보(ADC) 활용


    Google Cloud의 다양한 실행 환경에서 응용 프로그램의 기본 인증 정보 (ADC) 를 사용할 수 있습니다.
    https://cloud.google.com/docs/authentication/production에서 인용하다.
    프로그램이 Google Cloud 환경에서 실행되고 서비스 계정이 환경에 연결되면 서비스 계정에 대한 인증 정보를 받을 수 있습니다.그런 다음 응용 프로그램에서 이 인증 정보를 사용하여 Google Cloud API를 호출할 수 있습니다.
    Compute Engine, App Engine, Cloud Run, Cloud Function 등 다양한 Google Cloud 서비스 리소스에 서비스 계정을 연결할 수 있습니다.수동으로 인증 정보를 제공하는 것보다 편리하고 안전하기 때문에 이 방법을 추천합니다.
    또한 Google Cloud 클라이언트 라이브러리를 사용하는 것이 좋습니다.Google Cloud 클라이언트 라이브러리에서 응용 프로그램의 기본 인증 정보 (ADC) 라이브러리를 사용하여 서비스 계정의 인증 정보를 자동으로 검색합니다.
    (중략...)
    환경 변수metaware/carrierwave-google-storage를 설정하지 않으면 ADC는 실행 코드의 자원과 연결된 서비스 계정을 사용합니다.
    이 서비스 계정은 Compute Engine, Google Kubernetes Engine, App Engine, Cloud Run, Cloud Function에서 제공될 수 있습니다기본 서비스 계정.또한 사용자가 관리하는 서비스 계정을 만들 수도 있다.
    (...생략)
    이번 예에서는 App Engine에서 실행되는 애플리케이션(Rails 애플리케이션)이 Google Cloud 클라이언트 라이브러리를 이용하여 Google Cloud의 다양한 리소스(e.g.API 호출)에 액세스할 때 인증 정보를 자동으로 부여합니다.
    이 인증 정보는 App Engine자동 승인된 서비스 계정fog-google가 됩니다.
    이 구조를 사용하면 인증 정보(키 JSON)를 수동으로 교환할 필요가 없습니다.그리고 Google도 그걸 추천합니다.
    그럼 GOOGLE_APPLICATION_CREDENTIALS의README를 보세요.
    실제로 위에서 인용한 샘플 코드 앞에는 ADC를 잘 사용할 수 있다고 쓰여 있다.샘플 코드도 있어요.<project-id>@appspot.gserviceaccount.com 옵션fog-google이면 될 것 같아요.
    As of 1.9.0 fog-google supports Google application default credentials (ADC) The auth method uses Google::Auth.get_application_default under the hood.google_application_default따라서 Carrier Wave에서 사용할 때는 이렇게 하면 된다.
    config/initializers/carrierwave.rb
    CarrierWave.configure do |config|
        config.fog_provider = 'fog/google'
        config.fog_credentials = {
            provider: 'Google',
            google_project: Rails.application.secrets.google_cloud_storage_project_name,
            google_application_default: true  # HERE!
        }
        config.fog_directory = Rails.application.secrets.google_cloud_storage_bucket_name
    end
    
    따라서 App Engine을 사용하여 이 Rails 애플리케이션을 이동할 때 Carrier Wave는 App Engine의 기본 서비스 계정true에서 Cloud Storage에 액세스합니다.인증 정보 (키 JSON) 를 은밀히 관리하는 과정에서 해방되었다.

    공인 서비스 계정


    아직 해야 할 일이 하나 더 있다.
    앱 Engine의 기본 서비스 계정connection = Fog::Compute::Google.new(:google_project => "my-project", :google_application_default => true)은 클라우드 스토어 대상을 조작할 권한이 고스란히 없다.
    스토리지 객체 매니저 역할이 필요합니다<project-id>@appspot.gserviceaccount.com.
    ※ 저장 대상 관리자 역할에 대한 모든 권한이 필요한지 알 수 없습니다.권한을 더 축소하고 싶은 사람은 적당히 축소하세요.참고로 Storage 대상 창작자<project-id>@appspot.gserviceaccount.com라면 없다roles/storage.objectAdmin는 틀렸다.
    예를 들어 Terraform의 경우 ↓roles/storage.objectCreator, storage.objects.delete, var.name는 프로젝트 지정에 협조한다).
    # Bucket作成
    resource "google_storage_bucket" "assets" {
      name          = var.name
      location      = var.location
      project       = var.project
    }
    
    # AppEngineのデフォルトサービスアカウントにCloud Storageに関する権限を付与
    resource "google_storage_bucket_iam_member" "appengine_asset_access" {
      bucket = google_storage_bucket.assets.name
      role   = "roles/storage.objectAdmin"
      member = "serviceAccount:${var.project}@appspot.gserviceaccount.com"
    }
    
    에서 알 수 있듯이 상기 키 JSON을 사용하는 문제점(IaC와의 호환성)도 해제되었다.
    ADC의 구조를 이용하여 필요한 정보는 모두 인코딩되었다.

    로컬 개발 시


    다시 인용https://cloud.google.com/docs/authentication/production.
    환경 변수var.location를 설정하면 ADC는 변수와 같은 서비스 계정 키나 프로필을 사용합니다.
    따라서 로컬 개발에서 GCP의 자원(Cloud Storage 등)에 접근해야 하는 경우 로컬 개발을 위해 적절한 서비스 계정을 마련하기 위해 이 키 JSON 파일을 다운로드하고 경로를var.project 환경 변수에 넣으면 된다.
    그나저나 이런 곳의 경계 변수 관리GOOGLE_APPLICATION_CREDENTIALS가 좋겠죠.
    각주
    본문의 주제가 아니기 때문에 비밀 관리 기구 자체의 설명을 생략했다.어떤 적당한 구조를 사용하다.운영 환경이 Google App Engine이면 Berglas 괜찮습니다.↩︎
  • 인코딩도 가능하지만 결과 2, 3은 어렵고 방안은 변하지 않습니다.
  • ↩︎

    좋은 웹페이지 즐겨찾기