Melakukan autentikasi menggunakan identitas agen di GKE

Agen Google Kubernetes Engine (GKE) yang memiliki identitas agen dapat menggunakan identitas tersebut untuk melakukan autentikasi ke Google Cloud API dan ke alat serta layanan eksternal. Agen dapat menggunakan identitasnya sendiri atau bertindak atas nama pengguna akhir. Dokumen ini menunjukkan cara developer aplikasi agen mengonfigurasi aplikasi mereka untuk melakukan autentikasi ke berbagai resource. Anda seharusnya sudah memahami cara meminta identitas agen untuk agen GKE.

Bergantung pada resource yang perlu diakses agen, administrator platform Anda mungkin perlu mengonfigurasi vault kredensial pengelola autentikasi untuk menjalankan alur kerja tambahan. Misalnya, agar agen dapat melakukan autentikasi ke GitHub atas nama pengguna akhir, penyedia autentikasi OAuth 3-legged di pengelola autentikasi harus menangani login, otorisasi, dan pengalihan pengguna. Sebagai developer, Anda mengubah agen untuk memanggil penyedia autentikasi yang benar dan menangani kelanjutan percakapan untuk pengguna akhir.

Batasan

  • Lihat batasan Identitas Agen.
  • Anda dapat menggunakan library autentikasi Google untuk mendapatkan token akses dan ID terikat hanya untuk Python. Library autentikasi mungkin tidak mendapatkan token terikat untuk bahasa lain. Jika Anda menggunakan bahasa lain, beralihlah ke token yang tidak terikat dengan menetapkan variabel lingkungan GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN ke false.

Sebelum memulai

Sebelum memulai, pastikan Anda telah melakukan tugas berikut:

  • Aktifkan Google Kubernetes Engine API.
  • Aktifkan Google Kubernetes Engine API
  • Untuk menggunakan Google Cloud CLI untuk tugas ini, instal lalu lakukan inisialisasi gcloud CLI. Jika sebelumnya Anda telah menginstal gcloud CLI, dapatkan versi terbaru dengan menjalankan perintah gcloud components update. Versi gcloud CLI yang lebih lama mungkin tidak mendukung menjalankan perintah dalam dokumen ini.

Peran yang diperlukan

Untuk mendapatkan izin yang diperlukan guna mengonfigurasi agen yang di-deploy di cluster GKE, minta administrator untuk memberi Anda peran IAM Kubernetes Engine Developer (roles/container.developer) di project Anda. Untuk mengetahui informasi selengkapnya tentang cara memberikan peran, lihat Mengelola akses ke project, folder, dan organisasi.

Anda mungkin juga bisa mendapatkan izin yang diperlukan melalui peran khusus atau peran bawaan lainnya.

Melakukan autentikasi ke Google Cloud API

Untuk melakukan autentikasi ke API Google Cloud sebagai identitas agen itu sendiri, agen dapat menggunakan token akses identitas agen dari server metadata di node Anda. Perubahan yang mungkin perlu Anda lakukan pada kode bergantung pada cara Anda memanggil Google Cloud API, sebagai berikut.

Menggunakan Library Klien Cloud

Jika Anda menggunakan Library Klien Cloud versi 2.61.0 atau yang lebih baru dari library google-auth, Kredensial Default Aplikasi (ADC) akan otomatis mendapatkan token akses identitas agen. Anda tidak perlu melakukan perubahan tambahan pada kode. Jika Anda mengaktifkan penyisipan sertifikat untuk Pod dengan menyetel anotasi iam.gke.io/inject-podcertificates: "true", maka token akses akan terikat ke sertifikat X.509 secara default, kecuali jika Anda menonaktifkan token terikat.

Untuk mendapatkan token akses yang tidak terikat saat menggunakan Library Klien Cloud, Anda melakukan salah satu hal berikut:

  • Aktifkan penyisipan sertifikat di Pod Anda dan tetapkan variabel lingkungan GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN ke false.
  • Jangan aktifkan penyisipan sertifikat di Pod Anda.

Menggunakan panggilan langsung ke endpoint Google Cloud API

Jika Anda tidak menggunakan Library Klien Cloud untuk berinteraksi dengan layanan, Anda dapat menggunakan identitas agen untuk melakukan autentikasi ke Google Cloud API dengan melakukan hal berikut:

  1. Mendapatkan token akses dari server metadata di node. Anda bisa mendapatkan token dengan menggunakan salah satu metode berikut:

    • Token akses terikat: gunakan library Python google-auth, yang menemukan sertifikat X.509 Pod dan secara otomatis mendapatkan token akses terikat secara default. Untuk bahasa pemrograman lain, gunakan token yang tidak terikat.

    • Token akses yang tidak terikat: jika Pod tidak memiliki paket kredensial identitas agen, gunakan library autentikasi Google untuk bahasa pemrograman Anda. Library autentikasi secara otomatis mendapatkan token akses yang tidak terikat dan memuat ulang token yang masa berlakunya habis untuk Anda. Untuk aplikasi Python di Pod yang memiliki paket kredensial, tetapkan variabel lingkungan GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN di spesifikasi Pod Anda ke false, seperti pada contoh berikut:

      # Multiple lines are omitted here.
      spec:
        containers:
        - name: example-agent
          image: example-image
          env:
          - name: GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN
            value: "false"
      # Multiple lines are omitted here.
      

      Variabel lingkungan ini mencegah library mendapatkan token akses dan token ID terikat.

  2. Untuk token akses terikat, kirim permintaan ke endpoint mTLS API dan sertakan rantai sertifikat X.509 identitas agen dalam transportasi HTTP. Jika Anda menggunakan library autentikasi Google untuk Python, library tersebut akan menangani konfigurasi transportasi HTTP untuk Anda.

Contoh berikut menunjukkan cara menggunakan library autentikasi Google untuk Python guna mendapatkan token akses terikat dan membuat permintaan ke endpoint mTLS Cloud Storage:

import google.auth
from google.auth.transport.requests import AuthorizedSession


def call_storage_api_mtls(bucket_name: str) -> None:
    # Discover the Pod's X.509 certificate chain by using the auth library
    credentials, project = google.auth.default(
        scopes=["https://www.googleapis.com/auth/cloud-platform"]
    )
    # Configure the mTLS session by using the Pod's certificate chain
    session = AuthorizedSession(credentials)
    session.configure_mtls_channel()
    # Call the Google Cloud mTLS endpoint
    mtls_url = f"https://storage.mtls.googleapis.com/storage/v1/b/{bucket_name}/o"
    response = session.get(mtls_url)
    response.raise_for_status()
    print(response.json())

Mengautentikasi ke alat dan layanan eksternal

Untuk melakukan autentikasi ke alat dan layanan eksternal, Anda dapat mengonfigurasi agen agar mendapatkan kredensial yang diperlukan dari pengelola autentikasi Identitas Agen. Administrator platform mengonfigurasi berbagai penyedia autentikasi di pengelola autentikasi, yang masing-masing mengelola alur kerja dan kredensial autentikasi tertentu. Anda mengubah kode aplikasi untuk memanggil penyedia autentikasi tertentu dan, bergantung pada alur kerja autentikasi, untuk menangani izin pengguna dan kelanjutan percakapan. Perubahan spesifik yang Anda lakukan pada agen bergantung pada apa yang perlu Anda akses, sebagai berikut:

Pengelola autentikasi menangani alur kerja autentikasi yang sesuai dan memberikan akses agen ke kredensial terenkripsi, yang kemudian dapat disertakan dalam permintaan ke layanan eksternal. Untuk mengetahui informasi selengkapnya tentang tindakan yang harus dilakukan administrator platform Anda untuk mengonfigurasi penyedia autentikasi ini dan memberikan akses ke identitas agen Anda, lihat Alur kerja autentikasi untuk agen.

Melakukan autentikasi ke agen lain

Dalam arsitektur multi-agen, agen sering berkolaborasi dengan memanggil langsung agen peer atau layanan hilir. Anda dapat membuat komunikasi langsung antar-workload agen menggunakan token identitas. Anda bisa mendapatkan token ID terikat atau tidak terikat dari server metadata GKE dan menggunakan token tersebut untuk melakukan autentikasi langsung ke agen lain.

Untuk mendapatkan token ID dan menggunakan token dalam permintaan HTTP, gunakan library autentikasi Google untuk Python. Library ini secara otomatis menangani penemuan sertifikat dan perolehan token ID. Jika Anda menggunakan bahasa pemrograman lain, library autentikasi Google mungkin tidak mendapatkan token ID terikat. Beralih ke token ID yang tidak terikat.

Mendapatkan token ID

Untuk meminta token ID dalam kode agen, gunakan library autentikasi Google untuk bahasa pemrograman Anda. Anda dapat menggunakan library untuk meminta token ID terikat atau tidak terikat, sebagai berikut:

  • Token ID terikat: gunakan anotasi iam.gke.io/inject-podcertificates: "true" untuk mengaktifkan penyisipan sertifikat untuk Pod Anda. Library autentikasi untuk Python secara otomatis meminta token ID terikat sertifikat dari server metadata GKE. Gunakan token ID terikat saat Anda melakukan autentikasi antar-agen yang berjalan di Google Cloud dengan menggunakan mTLS.
  • Token ID yang tidak terikat:

    • Aktifkan penyisipan sertifikat untuk Pod Anda dan lakukan salah satu tindakan berikut:
      • Dalam kode aplikasi Anda, di fungsi id_token.fetch_id_token, tetapkan argumen bind_id_token ke nilai False. Argumen ini menyebabkan library autentikasi meminta token ID yang tidak terikat. Permintaan token akses tidak terpengaruh.
      • Dalam spesifikasi Pod, tetapkan variabel lingkungan GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN ke nilai false. Variabel lingkungan ini mencegah library meminta token akses terikat dan token ID.
    • Jangan aktifkan injeksi sertifikat untuk Pod Anda. Library autentikasi mendapatkan token ID yang tidak terikat karena tidak ada paket kredensial di Pod.

    Gunakan token ID yang tidak terikat saat Anda melakukan autentikasi ke Google Cloud API, layanan eksternal, atau agen lain menggunakan koneksi non-mTLS.

Contoh berikut menunjukkan cara meminta token ID terikat atau tidak terikat untuk agen yang mengaktifkan penyisipan kredensial:

  • Meminta token ID terikat:

    import google.auth.transport.requests
    from google.oauth2 import id_token
    
    # Application Default Credentials automatically requests a certificate-bound
    # ID token.
    def get_bound_id_token(target_audience: str) -> str:
        auth_req = google.auth.transport.requests.Request()
        return id_token.fetch_id_token(auth_req, audience=target_audience)
    

    Token identitas terikat mencakup sidik jari sertifikat SHA-256 dari rantai sertifikat X.509 Pod dalam parameter cnf.x5t#S256.

  • Meminta token ID yang tidak terikat:

    import google.auth.transport.requests
    from google.oauth2 import id_token
    
    def get_unbound_id_token(target_audience: str) -> str:
        auth_req = google.auth.transport.requests.Request()
        return id_token.fetch_id_token(
            auth_req,
            audience=target_audience,
            # Always get an unbound ID token, even if the Pod has a credential
            # bundle.
            bind_id_token=False,
        )
    

Menggunakan token ID dalam permintaan ke agen lain

Setelah mendapatkan token ID untuk agen, Anda dapat menggunakan token tersebut untuk mengautentikasi langsung ke agen lain. Cara Anda mengautentikasi koneksi bergantung pada apakah Anda menggunakan token ID terikat atau tidak, sebagai berikut:

  • Untuk token ID terikat, buat koneksi mTLS dengan agen penerima dan autentikasi koneksi menggunakan kedua kredensial berikut dari direktori /var/run/secrets/workload-spiffe-credentials/ di Pod:
    • Paket kredensial identitas agen yang ada di file x509.credential-bundle.private-key.pem, yang berisi rantai sertifikat leaf untuk Pod.
    • Paket kepercayaan cluster yang ada di file TRUST_DOMAIN.spiffe-trust-bundle.pem. File ini berisi sertifikat CA root untuk agen penerima, dan digunakan untuk memvalidasi rantai sertifikat agen penerima selama TLS handshake. Agen yang memanggil dan menerima harus berada di kumpulan identitas agen yang sama.
  • Untuk token ID yang tidak terikat, buat koneksi non-mTLS dengan agen penerima.

Contoh berikut menunjukkan cara mengirim permintaan ke agen lain menggunakan token ID terikat atau tidak terikat:

  • Token ID terikat: sertakan token identitas terikat di header Authorization: Bearer permintaan yang Anda kirim ke endpoint mTLS agen penerima. Autentikasi koneksi TLS menggunakan sertifikat X.509 dan kunci pribadi Pod:

    import ssl
    import urllib3
    
    BUNDLE_PATH = "/var/run/secrets/workload-spiffe-credentials/x509.credential-bundle.private-key.pem"
    TRUST_BUNDLE_PATH = "/var/run/secrets/workload-spiffe-credentials/TRUST_DOMAIN.spiffe-trust-bundle.pem"
    
    def call_peer_agent_bound_mtls(target_mtls_url: str, target_audience: str) -> None:
    
        # Configure the mTLS context by using the certificate chain and trust
        # bundle from the Pod.
        ctx = ssl.create_default_context(cafile=TRUST_BUNDLE_PATH)
        ctx.load_cert_chain(BUNDLE_PATH)
        http = urllib3.PoolManager(ssl_context=ctx, assert_hostname=False)
    
        # Call a peer agent's mTLS endpoint by using the bound ID token and Pod
        # certificate chain.
        bound_id_token = get_bound_id_token(target_audience)
        response = http.request(
            "POST",
            target_mtls_url,
            headers={"Authorization": f"Bearer {bound_id_token}"},
            json={"task": "analyze_data"},
            timeout=10,
        )
        print(response.json())
    

    Ganti TRUST_DOMAIN dengan domain tepercaya untuk kumpulan identitas agen Anda.

  • Token ID yang tidak terikat: sertakan token di header Authorization: Bearer permintaan Anda ke agen rekanan:

    import requests
    
    def call_peer_agent_unbound(target_url: str, target_audience: str) -> None:
        unbound_id_token = get_unbound_id_token(target_audience)
        # Send the request by using a standard TLS connection or plain HTTP.
        response = requests.post(
            target_url,
            headers={"Authorization": f"Bearer {unbound_id_token}"},
            json={"task": "analyze_data"},
            timeout=10,
        )
        response.raise_for_status()
        print(response.json())
    

Memvalidasi permintaan di agen penerima

Di agen penerima, validasi token ID yang ada dalam permintaan masuk dengan melakukan hal berikut. Anda dapat menggunakan library kriptografi seperti Tink untuk melakukan langkah-langkah verifikasi ini, bukan menulis kode kustom.

  1. Ekstrak token identitas dari header Authorization: Bearer permintaan.
  2. Pastikan bahwa klaim iss (penerbit) dalam token ID adalah kumpulan identitas agen untuk agen yang memanggil. Penerbitnya adalah salah satu dari berikut ini, bergantung pada apakah agen panggilan berada dalam project yang ada di organisasi:
    • Project yang berada dalam organisasi: https://sts.googleapis.com/v1/organizations/ORGANIZATION_ID/locations/global/workloadIdentityPools/agents.global.org-ORGANIZATION_ID.system.id.goog, dengan ORGANIZATION_ID adalah ID organisasi dari organisasi yang berisi project agen panggilan.
    • Project yang tidak berada dalam organisasi: https://sts.googleapis.com/v1/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/agents.global.proj-PROJECT_NUMBER.system.id.goog, dengan PROJECT_NUMBER adalah nomor project cluster GKE agen panggilan.
  3. Temukan URI JSON Web Key Set (JWKS) untuk penerbit dan simpan dalam cache JSON Web Key (JWK) publik. Endpoint untuk JWKS memiliki format ISSUER_URL/openid/jwks, dengan ISSUER_URL adalah URL penerbit.
  4. Validasi tanda tangan token menggunakan informasi berikut dari header JOSE token ID:
    • JWK publik yang cocok dengan parameter header kid.
    • Algoritma kriptografi yang cocok dengan parameter header alg, seperti RS256.
  5. Verifikasi bahwa sidik jari sertifikat SHA-256 yang ada di parameter cnf.x5t#S256 cocok dengan sidik jari sertifikat X.509 yang digunakan agen pemanggil untuk mengautentikasi koneksi mTLS.
  6. Verifikasi klaim berikut dalam token ID:
    • Waktu habis masa berlaku dalam klaim exp ada di masa mendatang.
    • Audiens dalam klaim aud adalah agen penerima.
  7. Otorisasi permintaan berdasarkan ID SPIFFE yang ada di klaim sub (subjek) token.

Langkah berikutnya