워크로드 아이덴티티 제휴의 인증서 기반 액세스 구성

이 문서에서는 X.509 인증서를 사용하여 워크로드 아이덴티티 제휴의 인증서 기반 액세스를 구성하는 방법을 설명합니다.

인증서 기반 액세스는 TLS 핸드셰이크 중에 상호 TLS (mTLS)를 사용하여 클라이언트와 서버를 모두 인증합니다. 이 프로세스에서 mTLS 바인딩은 전송 컨텍스트를 기반으로 정책을 통합하고 TLS 세션 내 클라이언트 인증서의 상태를 사용하여 승인 결정을 내립니다.

X.509 워크로드 아이덴티티 제휴의 경우 mTLS 바인딩을 통해 전체 인증 흐름이 신뢰할 수 있는 워크로드에 안전하게 연결됩니다. 이렇게 하면 인증이 신뢰할 수 있는 특정 엔드포인트에 바인딩되므로 사용자 인증 정보 도용 위험이 완화됩니다.

워크로드 아이덴티티 제휴 구성의 인증서 기반 액세스 개요

다음은 워크로드 아이덴티티 제휴의 인증서 기반 액세스를 구성하는 프로세스를 간략하게 설명합니다.

  1. X.509 인증서의 신뢰 앵커를 사용하여 신뢰를 구성하여 워크로드 아이덴티티 제휴를 설정합니다.

  2. 인증서 기반 액세스의 액세스 수준을 만듭니다.

  3. mTLS 바인딩을 적용하는 컨텍스트 인식 액세스 정책에 액세스 수준을 추가합니다.

시작하기 전에

다음 기본 요건이 충족되었는지 확인합니다.

  • 최신 버전의 Google Cloud CLI

    Google Cloud CLI를 최신 버전으로 업데이트하려면 다음 명령어를 실행합니다.

    gcloud components update
    

    Google Cloud CLI를 설치해야 하는 경우 Google Cloud CLI 설치를 참고하세요.

  • X.509 인증서 신뢰 앵커를 사용하는 워크로드 아이덴티티 제휴 구성

  • 이 기능을 사용하려면 다음 양식을 작성하여 허용 목록에 추가하세요. 허용 목록 요청 양식 허용 목록에 추가되면 연락을 드립니다.

인증서의 액세스 수준 만들기

  1. mTLS 액세스 수준을 만듭니다. mTLS 액세스 수준은 리소스에 대한 액세스를 결정할 때 인증서를 검증합니다.

    콘솔

    Access Context Manager에서 맞춤 액세스 수준을 만들고 CEL 표현식 필드에 request.auth.matchesMtlsTokens(origin) == true 표현식을 입력합니다.

    gcloud

    커스텀 액세스 수준을 만들려면 다음 명령어를 실행합니다.

       gcloud access-context-manager levels create ACCESS_LEVEL_NAME 
    --title=TITLE
    --custom-level-spec=FILE
    --description=DESCRIPTION
    --policy=POLICY_NAME

    다음을 바꿉니다.

    • ACCESS_LEVEL_NAME: 액세스 수준의 이름입니다.
    • TITLE: 액세스 수준의 제목입니다.
    • FILE: 다음 콘텐츠가 포함된 YAML 파일: request.auth.matchesMtlsTokens(origin) == true
    • DESCRIPTION: 액세스 수준에 대한 설명입니다.
    • POLICY_NAME: 액세스 정책의 이름입니다.
  2. 만든 액세스 수준을 환경 변수로 내보냅니다. 이 변수는 후속 단계에서 사용됩니다.

      export ACCESS_LEVEL_ID=ACCESS_LEVEL_ID
      

    ACCESS_LEVEL_ID을 액세스 수준 이름으로 바꿉니다(예: accessPolicies/12345/accessLevels/acl_1).

워크로드 아이덴티티 풀의 컨텍스트 인식 액세스 바인딩 만들기

  1. 다음 환경 변수를 설정합니다.

    export ORG_ID=ORG_ID
    export CALLER_PROJECT_ID=CALLER_PROJECT_ID
    export FEDERATED_PRINCIPAL=FEDERATED_PRINCIPAL
    

    다음을 바꿉니다.

    • ORG_ID: 조직의 ID입니다.
    • CALLER_PROJECT_ID: API를 호출하는 데 사용할 프로젝트의 ID입니다.
    • FEDERATED_PRINCIPAL: 컨텍스트 인식 액세스 정책을 준수하는 워크로드 아이덴티티 풀의 ID 주 구성원 이름입니다. 다음 옵션 중 하나를 사용할 수 있습니다.

      principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT_ATTRIBUTE_VALUE 형식의 단일 ID

      또는

      풀의 모든 ID(형식: principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/*)

    gcloud

    gcloud alpha access-context-manager cloud-bindings create \
    --organization=ORG_ID \
    --federated-principal=FEDERATED_PRINCIPAL \
    --level=ACCESS_LEVEL_ID
    --dry-run-level=DRY_RUN_ACCESS_LEVEL_ID
    

    다음을 바꿉니다.

    • ACCESS_LEVEL_ID: 액세스 수준 이름입니다.
    • DRY_RUN_ACCESS_LEVEL_ID: 드라이런 액세스 수준 이름입니다. 기존 트래픽에 미칠 수 있는 영향을 파악하려면 먼저 테스트 실행 정책 바인딩을 사용 설정하는 것이 좋습니다.

    curl

    1. 상황 인식 액세스 바인딩이 포함된 JSON 파일을 만듭니다.

      필드가 반복되더라도 요청에 하나의 액세스 수준만 제공할 수 있습니다. 다음 유형의 통합 주 구성원을 사용할 수 있습니다.

      • 단일 ID: principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT_ATTRIBUTE_VALUE
      • 풀의 모든 ID: principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/*
      echo { \
        \"principal\": { \
          \"federatedPrincipal\": \"${FEDERATED_PRINCIPAL:?}\" \
        },\
        \"accessLevels\": [\"${ACCESS_LEVEL_ID:?}\"] \
      } \
      >> request.json
      
    2. curl를 사용하여 다음 HTTP 요청을 보냅니다.

      curl -H "X-Goog-User-Project: ${CALLER_PROJECT_ID:?}" -X POST \
         -H "Authorization: Bearer $(gcloud auth print-access-token)" \
         -H "Content-Type: application/json; charset=utf-8" \
         -d @request.json \
       "https://accesscontextmanager.googleapis.com/v1alpha/organizations/${ORG_ID:?}/gcpUserAccessBindings"
      

Google Cloud 클라이언트 라이브러리를 사용하여 승인

Google Cloud 클라이언트 라이브러리를 사용하여 직원 ID 제휴 워크로드를 승인하려면 다음 단계를 완료하세요.

  1. 직원 ID 제휴 인증용으로 구성된 애플리케이션 기본 사용자 인증 정보 (ADC) 파일을 만듭니다.

    gcloud iam workload-identity-pools create-cred-config IDENTITY_POOL_ID \
    --credential-cert-path WORKLOAD_CERTIFICATE_PATH \
    --credential-cert-private-key-path WORKLOAD_KEY_PATH \
    --output-file ADC_FILE_OUTPUT_PATH
    

    다음을 바꿉니다.

    • IDENTITY_POOL_ID: 워크로드 아이덴티티 풀의 ID입니다.
    • WORKLOAD_CERTIFICATE_PATH: 워크로드의 인증서 파일 경로입니다.
    • WORKLOAD_KEY_PATH: 워크로드의 비공개 키 파일 경로입니다.
    • ADC_FILE_OUTPUT_PATH: ADC 파일의 출력 경로입니다.

    이 명령어는 gcloud CLI 기본 구성 디렉터리에 인증서 구성 파일도 생성합니다. 인증서 구성 파일은 초기 인증을 지원하고 Google Cloud 리소스에 대한 후속 요청을 위해 mTLS 핸드셰이크를 설정합니다.

  2. ADC 파일을 가리키도록 환경 변수를 설정합니다. 이렇게 하면 Google 클라이언트 라이브러리에서 사용자 인증 정보를 검색할 수 있습니다.

    export GOOGLE_APPLICATION_CREDENTIALS=${application_default_credentials.json}
    

    ADC 파일을 생성할 때 --output-file 인수를 생략하면 이 단계는 선택사항입니다. 인수를 생략하면 ADC 파일이 gcloud CLI 기본 구성 디렉터리에서 생성되고 읽힙니다.

  3. Google Cloud API에 대한 액세스를 설정하고 테스트하려면 다음 단계를 완료하세요. Go 또는 Python을 사용할 수 있습니다.

    Go

    1. 다음 예시를 사용하여 golang_test.go와 같은 Go 파일을 만듭니다.

      package golang_test
      
      import (
           "io"
           "log"
           "testing"
      
           "cloud.google.com/go/auth/credentials"
           "cloud.google.com/go/auth/httptransport"
      )
      
      func TestGoExample(t *testing.T) {
      
           scopes := []string{
                   "https://www.googleapis.com/auth/pubsub", // Scope for Pub/Sub access
                   // Add other scopes as needed
           }
      
           dopts := credentials.DetectOptions{
                   Scopes: scopes,
           }
      
           // Create httptransport.Options with the scopes
           opts := &httptransport.Options{
                   DetectOpts: &dopts,
           }
           hc, err := httptransport.NewClient(opts)
           if err != nil {
                   t.Fatalf("NewHTTPClient: %v", err)
           }
      
           resp, err := hc.Get("https://pubsub.mtls.googleapis.com/v1/projects/PROJECT_ID/topics")
           if err != nil {
                   t.Fatalf("Get: %v", err)
           }
           t.Logf("Status: %s", resp.Status)
      
           t.Cleanup(func() {
                  resp.Body.Close()
           })
      
           b, err := io.ReadAll(resp.Body)
           if err != nil {
                  t.Fatal(err)
           }
           log.Println(string(b))
      }
      

      PROJECT_ID를 gcloud CLI 프로젝트 ID로 바꿉니다.

    2. Compute Engine VM에서 테스트를 실행하려면 다음 명령어를 사용하세요.

    go mod init example.com
    go mod tidy
    go test -v golang_test.go --count=1
    

    Python

    1. 다음 예시를 사용하여 python_test.py와 같은 테스트 파일을 만듭니다.

      import google.auth
      import google.auth.transport.requests
      import requests
      
      def test_go_example():
      # Define the required scopes for your application
      scopes = [
         "https://www.googleapis.com/auth/pubsub",  # Scope for Pub/Sub access
         # Add other scopes as needed
      ]
      
      # Obtain Application Default Credentials (ADC) with the specified scopes
      credentials, _ = google.auth.default(scopes=scopes)
      
      # Create an authorized HTTP session using the ADC credentials
      authed_session = google.auth.transport.requests.AuthorizedSession(credentials)
      
      try:
      # Make a GET request to the Pub/Sub API endpoint
      response = authed_session.get(
          "https://pubsub.mtls.googleapis.com/v1/projects/PROJECT_ID/topics"
      )
      
      # Check if the request was successful
      response.raise_for_status()  # Raise an exception for error statuses
      
      # Log the response status and content
      print(f"Status: {response.status_code}")
      print(response.text)
      
      except requests.exceptions.RequestException as e:
      print(f"Error making the request: {e}")
      
      if __name__ == "__main__":
      test_go_example()
      

      PROJECT_ID를 gcloud CLI 프로젝트 ID로 바꿉니다.

    2. Compute Engine VM에서 테스트를 실행하려면 다음 단계를 완료하세요.

      1. Python 가상 환경을 설정합니다.
      2. 필수 라이브러리를 설치합니다.

        pip install google-auth google-auth-httplib2 requests
        
      3. 테스트를 실행합니다.

        python3 python_test.py
        

일반 HTTP 요청을 사용하여 승인

일반 HTTP 요청을 사용하여 직원 ID 제휴 워크로드를 승인하려면 다음 단계를 완료하세요.

  1. 표준 mTLS 핸드셰이크를 통해 Google Cloud 보안 토큰 서비스에서 인증서 바인딩 액세스 토큰을 가져옵니다.

  2. 보안 토큰 서비스에서 가져온 액세스 토큰으로 Google Cloud 서비스를 호출합니다. 이 예에서는 Cloud Storage를 쿼리합니다.

    $ curl --key ${workload_key.pem} --cert ${workload_cert.pem} -X GET 'https://storage.mtls.googleapis.com/{replace_with_your_resources}' -H "Authorization: Bearer $ACCESS_TOKEN"
    
  3. mTLS 바인딩은 mTLS 사용을 강제합니다. 다음 명령어를 실행하여 비 mTLS 연결이 승인되지 않음 오류로 실패하는지 확인합니다.

    $ curl -X GET 'https://storage.googleapis.com/{replace_with_your_resources}' -H "Authorization: Bearer $ACCESS_TOKEN"
    

정책 바인딩 나열

워크로드 아이덴티티 제휴의 정책 바인딩을 나열하려면 다음 명령어를 실행합니다.

gcloud

다음 명령어는 지정된 조직 내의 특정 바인딩을 나열하여 제휴 주 구성원에 적용되는 바인딩을 필터링합니다.

gcloud alpha access-context-manager cloud-bindings list \
--organization=ORG_ID \
--filter='principal:federatedPrincipal'

curl

curl -H "X-Goog-User-Project: ${CALLER_PROJECT_ID:?}" -X GET \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://accesscontextmanager.googleapis.com/v1alpha/organizations/${ORG_ID:?}/gcpUserAccessBindings?filter=principal%3Afederated_principal"

정책 바인딩 업데이트

정책 바인딩을 업데이트하려면 JSON 파일에 새 액세스 수준을 추가하고 다음 명령어를 실행합니다.

gcloud

gcloud alpha access-context-manager cloud-bindings update \
--binding=BINDING_ID \
--level=NEW_ACCESS_LEVEL_ID

curl

curl -H "X-Goog-User-Project: ${CALLER_PROJECT_ID:?}" -X PATCH \
 -H "Authorization: Bearer $(gcloud auth print-access-token)" \
 -H "Content-Type: application/json; charset=utf-8" \
 -d @request.json \
"https://accesscontextmanager.googleapis.com/v1alpha/organizations/${ORG_ID:?}/gcpUserAccessBindings/${BINDING_ID:?}?updateMask=access_levels"

정책 바인딩 삭제

정책 바인딩을 삭제하려면 다음 명령어를 실행합니다.

gcloud

gcloud alpha access-context-manager cloud-bindings delete \
--binding=BINDING_ID

curl

curl -H "X-Goog-User-Project: ${CALLER_PROJECT_ID:?}" -X DELETE \
   -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://accesscontextmanager.googleapis.com/v1alpha/organizations/${ORG_ID:?}/gcpUserAccessBindings/${BINDING_ID:?}"

문제 해결

다음은 몇 가지 일반적인 문제와 이를 해결하기 위한 제안된 조치입니다.

  • 오류: 403 Forbidden, user does not have permission.

    작업: IAM 정책을 확인하여 워크로드 ID 풀이 Google Cloud 리소스에 액세스할 수 있는지 확인합니다.

  • 오류: Unauthorized_client: Could not obtain a value for google.subject from the given credential.

    작업: 백엔드에서 속성 매핑을 기반으로 클라이언트 인증서에서 google.subject 값을 추출할 수 없습니다. 클라이언트 인증서를 확인하여 매핑에 사용하는 필드에 값이 있는지 확인합니다.

  • 컨텍스트 인식 액세스를 사용 설정한 후 예기치 않은 액세스 거부가 발생하면 다음 명령어를 사용하여 컨텍스트 인식 액세스 바인딩을 삭제하여 트래픽을 빠르게 차단 해제할 수 있습니다.

    gcloud alpha access-context-manager cloud-bindings delete
    

    액세스가 복원된 후 감사 로그를 검토하여 요청이 거부된 이유를 확인합니다.