Memverifikasi identitas VM


Sebelum mengirimkan informasi sensitif ke instance mesin virtual (VM), aplikasi dapat memverifikasi identitas instance tersebut menggunakan token identitas instance yang ditandatangani oleh Google. Setiap instance memiliki Token Web JSON (JWT) unik yang menyertakan detail tentang instance serta tanda tangan RS256 Google. Aplikasi Anda dapat memverifikasi tanda tangan berdasarkan sertifikat Oauth2 publik Google untuk mengonfirmasi identitas instance yang telah terhubung dengannya.

Compute Engine menghasilkan token instance yang ditandatangani hanya jika instance memintanya dari metadata instance. Instance hanya dapat mengakses token uniknya sendiri, bukan token untuk instance lainnya.

Anda mungkin ingin memverifikasi identitas instance dalam skenario berikut:

  • Saat Anda memulai instance untuk pertama kalinya, aplikasi Anda mungkin perlu memastikan bahwa instance yang terhubung memiliki identitas yang valid sebelum mengirimkan informasi sensitif ke instance.
  • Ketika kebijakan mengharuskan Anda menyimpan kredensial di luar lingkungan Compute Engine, dan Anda secara rutin mengirimkan kredensial tersebut ke instance Anda untuk digunakan sementara. Aplikasi Anda dapat mengonfirmasi identitas instance setiap kali perlu mengirimkan kredensial.

Metode autentikasi instance Google memiliki manfaat sebagai berikut:

  • Compute Engine membuat token unik setiap kali instance memintanya, dan setiap token berakhir dalam waktu satu jam. Anda dapat mengonfigurasi aplikasi untuk menerima token identitas instance hanya sekali, sehingga mengurangi risiko token tersebut dapat digunakan kembali oleh sistem yang tidak sah.
  • Token metadata yang ditandatangani menggunakan standar industri terbuka RFC 7519 dan OpenID Connect 1.0, sehingga alat dan library yang sudah ada akan bekerja secara lancar dengan token identitas.

Sebelum memulai

  • Pahami cara mengambil nilai metadata instance.
  • Pahami dasar-dasar Token Web JSON agar Anda mengetahui cara menggunakannya di aplikasi.
  • Pahami cara membuat dan mengaktifkan akun layanan di instance Anda. Instance Anda harus memiliki akun layanan yang terkait agar dapat mengambil token identitasnya. Akun layanan tidak memerlukan izin IAM apa pun untuk mengambil token identitas ini.
  • Siapkan autentikasi, jika Anda belum melakukannya. Autentikasi adalah proses verifikasi identitas Anda untuk akses ke layanan dan API Google Cloud. Untuk menjalankan kode atau contoh dari lingkungan pengembangan lokal, Anda dapat melakukan autentikasi ke Compute Engine sebagai berikut.

    Untuk menggunakan contoh Python di halaman ini dari lingkungan pengembangan lokal, instal dan lakukan inisialisasi gcloud CLI, lalu siapkan Kredensial Default Aplikasi dengan kredensial pengguna Anda.

    1. Menginstal Google Cloud CLI.
    2. Untuk initialize gcloud CLI, jalankan perintah berikut:

      gcloud init
    3. Buat kredensial autentikasi lokal untuk Akun Google Anda:

      gcloud auth application-default login

    Untuk informasi selengkapnya, lihat Siapkan autentikasi untuk lingkungan pengembangan lokal.

Memverifikasi identitas instance

Dalam beberapa skenario, aplikasi Anda harus memverifikasi identitas instance yang berjalan di Compute Engine sebelum mengirimkan data sensitif ke instance tersebut. Dalam satu contoh umum, ada satu sistem yang berjalan di luar Compute Engine yang disebut "Host1" dan instance Compute Engine bernama "VM1". VM1 dapat terhubung ke Host1 dan memvalidasi identitas instance tersebut dengan proses berikut:

  1. VM1 membuat koneksi yang aman ke Host1 melalui protokol koneksi yang aman pilihan Anda, seperti HTTPS.

  2. VM1 meminta token identitas uniknya dari server metadata dan menentukan audiens token. Dalam contoh ini, nilai audiens adalah URI untuk Host1. Permintaan ke server metadata menyertakan URI audiens sehingga Host1 dapat memeriksa nilai nanti selama langkah verifikasi token.

  3. Google membuat token identitas instance unik baru dalam format JWT dan menyediakannya ke VM1. Payload token mencakup beberapa detail tentang instance dan juga mencakup URI audiens. Baca Konten Token untuk mengetahui deskripsi lengkap tentang konten token.

  4. VM1 mengirimkan token identitas ke Host1 melalui koneksi aman yang ada.

  5. Host1 mendekode token identitas untuk mendapatkan header token dan nilai payload.

  6. Host1 memverifikasi bahwa token ditandatangani oleh Google dengan memeriksa nilai audiens dan memverifikasi tanda tangan sertifikat berdasarkan sertifikat Google publik.

  7. Jika token valid, Host1 akan melanjutkan transmisi dan menutup koneksi setelah selesai. Host1 dan sistem lainnya harus meminta token baru untuk setiap koneksi berikutnya ke VM1.

Mendapatkan token identitas instance

Saat instance mesin virtual Anda menerima permintaan untuk memberikan token identitasnya, instance akan meminta token tersebut dari server metadata menggunakan proses normal untuk mendapatkan metadata instance. Misalnya, Anda dapat menggunakan salah satu metode berikut:

cURL

Buat permintaan curl dan sertakan nilai dalam parameter audience. Secara opsional, Anda dapat menyertakan parameter format untuk menentukan apakah Anda ingin menyertakan detail project dan instance dalam payload atau tidak. Jika menggunakan format full, Anda dapat menyertakan parameter licenses untuk menentukan apakah Anda ingin menyertakan kode lisensi dalam payload atau tidak.

curl -H "Metadata-Flavor: Google" \
'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=AUDIENCE&format=FORMAT&licenses=LICENSES'

Ganti kode berikut:

  • AUDIENCE: URI unik yang disepakati oleh instance dan sistem yang memverifikasi identitas instance. Misalnya, audiens dapat berupa URL untuk koneksi antara dua sistem.
  • FORMAT: parameter opsional yang menentukan apakah detail project dan instance disertakan dalam payload atau tidak. Tentukan full untuk menyertakan informasi ini dalam payload atau standard untuk menghapus informasi dari payload. Nilai defaultnya adalah standard. Untuk mengetahui informasi selengkapnya, lihat Format token identitas.
  • LICENSES: parameter opsional yang menentukan apakah kode lisensi untuk image yang terkait dengan instance ini disertakan dalam payload. Tentukan TRUE untuk menyertakan informasi ini atau FALSE untuk menghapus informasi ini dari payload. Nilai defaultnya adalah FALSE. Tidak berpengaruh kecuali jika format adalah full

Server metadata merespons permintaan ini dengan Token Web JSON yang ditandatangani menggunakan algoritma RS256. Token ini mencakup tanda tangan Google dan informasi tambahan dalam payload. Anda dapat mengirim token ini ke sistem dan aplikasi lain agar dapat memverifikasi token dan mengonfirmasi bahwa itu adalah identitas instance Anda.

Python

Anda dapat mengirimkan permintaan sederhana dari instance ke server metadata menggunakan metode di library requests Python. Contoh permintaan berikut, lalu mencetak token identitas instance. Token tersebut bersifat unik untuk instance yang membuat permintaan ini.

import requests

AUDIENCE_URL = "http://www.example.com"
METADATA_HEADERS = {"Metadata-Flavor": "Google"}
METADATA_VM_IDENTITY_URL = (
    "http://metadata.google.internal/computeMetadata/v1/"
    "instance/service-accounts/default/identity?"
    "audience={audience}&format={format}&licenses={licenses}"
)
FORMAT = "full"
LICENSES = "TRUE"

def acquire_token(
    audience: str = AUDIENCE_URL, format: str = "standard", licenses: bool = True
) -> str:
    """
    Requests identity information from the metadata server.

    Args:
        audience: the unique URI agreed upon by both the instance and the
            system verifying the instance's identity. For example, the audience
            could be a URL for the connection between the two systems.
        format: the optional parameter that specifies whether the project and
            instance details are included in the payload. Specify `full` to
            include this information in the payload or standard to omit the
            information from the payload. The default value is `standard`.
        licenses: an optional parameter that specifies whether license
            codes for images associated with this instance are included in the
            payload. Specify TRUE to include this information or FALSE to omit
            this information from the payload. The default value is FALSE.
            Has no effect unless format is `full`.

    Returns:
        A JSON Web Token signed using the RS256 algorithm. The token includes a
        Google signature and additional information in the payload. You can send
        this token to other systems and applications so that they can verify the
        token and confirm that the identity of your instance.
    """
    # Construct a URL with the audience and format.
    url = METADATA_VM_IDENTITY_URL.format(
        audience=audience, format=format, licenses=licenses
    )

    # Request a token from the metadata server.
    r = requests.get(url, headers=METADATA_HEADERS)
    # Extract and return the token from the response.
    r.raise_for_status()
    return r.text

Server metadata merespons permintaan ini dengan Token Web JSON yang ditandatangani menggunakan algoritma RS256. Token ini mencakup tanda tangan Google dan informasi tambahan dalam payload. Anda dapat mengirim token ini ke sistem dan aplikasi lain agar dapat memverifikasi token dan mengonfirmasi bahwa itu adalah identitas instance Anda.

Memverifikasi token

Setelah aplikasi Anda menerima token identitas instance dari instance Compute Engine, aplikasi tersebut dapat memverifikasi token menggunakan proses berikut.

  1. Terima token dari instance mesin virtual, dekode token menggunakan dekoder JWT RS256, dan baca konten header untuk mendapatkan nilai kid.

  2. Pastikan token ditandatangani dengan membandingkan token dengan sertifikat Google publik. Setiap sertifikat publik memiliki nilai kid yang sesuai dengan nilai kid di header token.

  3. Jika token valid, bandingkan konten payload dengan nilai yang diharapkan. Jika payload token menyertakan detail tentang instance dan project, aplikasi Anda dapat memeriksa nilai instance_id, project_id, dan zone. Nilai tersebut adalah tuple unik secara global yang mengonfirmasi bahwa aplikasi Anda berkomunikasi dengan instance yang benar dalam project yang diinginkan.

Anda dapat mendekode dan memverifikasi token menggunakan alat apa pun yang diinginkan, tetapi metode yang umum adalah menggunakan library untuk bahasa pilihan Anda. Misalnya, Anda dapat menggunakan metode verify_token dari library Google OAuth 2.0 untuk Python. Metode verify_token mencocokkan nilai kid dengan sertifikat yang sesuai, memverifikasi tanda tangan, memeriksa klaim audiens, dan menampilkan konten payload dari token.

import google.auth.transport.requests
from google.oauth2 import id_token

def verify_token(token: str, audience: str) -> dict:
    """
    Verify token signature and return the token payload.

    Args:
        token: the JSON Web Token received from the metadata server to
            be verified.
        audience: the unique URI agreed upon by both the instance and the
            system verifying the instance's identity.

    Returns:
        Dictionary containing the token payload.
    """
    request = google.auth.transport.requests.Request()
    payload = id_token.verify_token(token, request=request, audience=audience)
    return payload

Setelah memverifikasi token dan kontennya, aplikasi Anda dapat melanjutkan komunikasi dengan instance tersebut melalui koneksi yang aman, lalu menutup koneksi setelah selesai. Untuk koneksi berikutnya, minta token baru dari instance dan verifikasi ulang identitas instance tersebut.

Konten token

Token identitas instance berisi tiga bagian utama:

Header menyertakan nilai kid untuk mengidentifikasi sertifikat Oauth2 publik yang harus Anda gunakan untuk memverifikasi tanda tangan. Header juga menyertakan nilai alg untuk mengonfirmasi bahwa tanda tangan dibuat menggunakan algoritma RS256.

{
  "alg": "RS256",
  "kid": "511a3e85d2452aee960ed557e2666a8c5cedd8ae",
}

Payload

Payload berisi klaim audiens aud. Jika instance menentukan format=full saat meminta token, payload juga menyertakan klaim tentang instance mesin virtual dan project-nya. Saat meminta token format lengkap, menentukan licenses=TRUE juga akan menyertakan klaim tentang lisensi yang terkait dengan instance.

{
   "iss": "[TOKEN_ISSUER]",
   "iat": [ISSUED_TIME],
   "exp": [EXPIRED_TIME],
   "aud": "[AUDIENCE]",
   "sub": "[SUBJECT]",
   "azp": "[AUTHORIZED_PARTY]",
   "google": {
    "compute_engine": {
      "project_id": "[PROJECT_ID]",
      "project_number": [PROJECT_NUMBER],
      "zone": "[ZONE]",
      "instance_id": "[INSTANCE_ID]",
      "instance_name": "[INSTANCE_NAME]",
      "instance_creation_timestamp": [CREATION_TIMESTAMP],
      "instance_confidentiality": [INSTANCE_CONFIDENTIALITY],
      "license_id": [
        "[LICENSE_1]",
          ...
        "[LICENSE_N]"
      ]
    }
  }
}

Dengan keterangan:

  • [TOKEN_ISSUER]: URL yang mengidentifikasi siapa yang menerbitkan token. Untuk Compute Engine, nilai ini adalah https://accounts.google.com.
  • [ISSUED_TIME]: stempel waktu unix yang menunjukkan kapan token dikeluarkan. Nilai ini diupdate setiap kali instance meminta token dari server metadata.
  • [EXPIRED_TIME]: stempel waktu unix yang menunjukkan kapan token berakhir.
  • [AUDIENCE]: URI unik yang disepakati oleh instance dan sistem yang memverifikasi identitas instance. Misalnya, audiens dapat berupa URL untuk koneksi antara dua sistem.
  • [SUBJECT]: subjek token, yang merupakan ID unik untuk akun layanan yang Anda kaitkan dengan instance.
  • [AUTHORIZED_PARTY]: pihak yang dikirimi Token ID yang merupakan ID unik untuk akun layanan yang terkait dengan instance Anda.
  • [PROJECT_ID]: ID untuk project tempat Anda membuat instance.
  • [PROJECT_NUMBER]: nomor unik untuk project tempat Anda membuat instance.
  • [ZONE]: zona tempat instance berada.
  • [INSTANCE_ID]: ID unik untuk instance yang memiliki token ini. ID ini bersifat unik dalam project dan zona.
  • [INSTANCE_NAME]: nama instance tempat token ini berada. Jika project Anda menggunakan DNS zona, nama ini dapat digunakan kembali di seluruh zona. Jadi, gunakan kombinasi project_id, zone, dan instance_id nilai untuk mengidentifikasi ID instance yang unik. Project dengan DNS global aktif memiliki nama instance unik di seluruh project.
  • [CREATION_TIMESTAMP]: stempel waktu Unix yang menunjukkan kapan Anda membuat instance.
  • [INSTANCE_CONFIDENTIALITY]: 1 jika instance adalah confidential VM.
  • [LICENSE_1] hingga [LICENSE_N]: kode lisensi untuk image yang terkait dengan instance ini.

Payload Anda mungkin terlihat mirip dengan contoh berikut:

{
  "iss": "https://accounts.google.com",
  "iat": 1496953245,
  "exp": 1496956845,
  "aud": "https://www.example.com",
  "sub": "107517467455664443765",
  "azp": "107517467455664443765",
  "google": {
    "compute_engine": {
      "project_id": "my-project",
      "project_number": 739419398126,
      "zone": "us-west1-a",
      "instance_id": "152986662232938449",
      "instance_name": "example",
      "instance_creation_timestamp": 1496952205,
      "instance_confidentiality": 1,
      "license_id": [
        "1000204"
      ]
    }
  }
}

Tanda Tangan

Google menghasilkan tanda tangan dengan mengenkode base64url pada header dan payload, serta menggabungkan kedua nilai tersebut. Anda dapat memeriksa nilai ini terhadap sertifikat Oauth2 publik untuk memverifikasi token.

Langkah selanjutnya