Men-deploy ke Cloud Run dengan Aman

1. Ringkasan

Anda akan mengubah langkah-langkah default untuk men-deploy layanan ke Cloud Run guna meningkatkan keamanan, lalu melihat cara mengakses aplikasi yang di-deploy dengan cara yang aman. Aplikasi ini adalah "layanan pendaftaran partner" dari aplikasi Cymbal Eats, yang digunakan oleh perusahaan yang bekerja sama dengan Cymbal Eats untuk memproses pesanan makanan.

Yang akan Anda pelajari

Dengan melakukan beberapa perubahan kecil pada langkah-langkah default minimal untuk men-deploy aplikasi ke Cloud Run, Anda dapat meningkatkan keamanannya secara signifikan. Anda akan mengambil aplikasi dan petunjuk deployment yang ada, lalu mengubah langkah-langkah deployment untuk meningkatkan keamanan aplikasi yang di-deploy.

Kemudian, Anda akan melihat cara memberi otorisasi akses ke aplikasi dan membuat permintaan yang diotorisasi.

Ini bukan pembahasan mendalam tentang keamanan deployment aplikasi, tetapi pembahasan tentang perubahan yang dapat Anda lakukan pada semua deployment aplikasi mendatang yang akan meningkatkan keamanannya dengan sedikit upaya.

2. Penyiapan dan Persyaratan

Penyiapan lingkungan mandiri

  1. Login ke Google Cloud Console dan buat project baru atau gunakan kembali project yang sudah ada. Jika belum memiliki akun Gmail atau Google Workspace, Anda harus membuatnya.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • Project name adalah nama tampilan untuk peserta project ini. String ini adalah string karakter yang tidak digunakan oleh Google API. Anda dapat memperbaruinya kapan saja.
  • Project ID bersifat unik di semua project Google Cloud dan tidak dapat diubah (tidak dapat diubah setelah ditetapkan). Cloud Console otomatis membuat string unik; biasanya Anda tidak mementingkan kata-katanya. Di sebagian besar codelab, Anda harus merujuk Project ID-nya (biasanya diidentifikasi sebagai PROJECT_ID). Jika tidak suka dengan ID yang dibuat, Anda dapat membuat ID acak lainnya. Atau, Anda dapat mencobanya sendiri dan melihat apakah ID tersebut tersedia. ID tidak dapat diubah setelah langkah ini dan akan tetap ada selama durasi project.
  • Sebagai informasi, ada nilai ketiga, Project Number yang digunakan oleh beberapa API. Pelajari lebih lanjut ketiga nilai ini di dokumentasi.
  1. Selanjutnya, Anda harus mengaktifkan penagihan di Konsol Cloud untuk menggunakan resource/API Cloud. Menjalankan operasi dalam codelab ini seharusnya tidak memerlukan banyak biaya, bahkan mungkin tidak sama sekali. Guna mematikan resource agar tidak menimbulkan penagihan di luar tutorial ini, Anda dapat menghapus resource yang dibuat atau menghapus seluruh project. Pengguna baru Google Cloud memenuhi syarat untuk mengikuti program Uji Coba Gratis senilai $300 USD.

Mengaktifkan Cloud Shell

  1. Dari Cloud Console, klik Aktifkan Cloud Shell 853e55310c205094.png.

55efc1aaa7a4d3ad.png

Jika belum pernah memulai Cloud Shell, Anda akan melihat layar perantara (di paruh bawah) yang menjelaskan apa itu Cloud Shell. Jika demikian, klik Continue (dan Anda tidak akan pernah melihatnya lagi). Berikut tampilan layar sekali-tampil tersebut:

9c92662c6a846a5c.png

Perlu waktu beberapa saat untuk menyediakan dan terhubung ke Cloud Shell.

9f0e51b578fecce5.png

Virtual machine ini dimuat dengan semua alat pengembangan yang Anda perlukan. Layanan ini menawarkan direktori beranda tetap sebesar 5 GB dan beroperasi di Google Cloud, sehingga sangat meningkatkan performa dan autentikasi jaringan. Sebagian besar pekerjaan Anda dalam codelab ini dapat dilakukan hanya dengan browser atau Chromebook.

Setelah terhubung ke Cloud Shell, Anda akan melihat bahwa Anda sudah diautentikasi dan project sudah ditetapkan ke project ID Anda.

  1. Jalankan perintah berikut di Cloud Shell untuk mengonfirmasi bahwa Anda telah diautentikasi:
gcloud auth list

Output perintah

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Jalankan perintah berikut di Cloud Shell untuk mengonfirmasi bahwa perintah gcloud mengetahui project Anda:
gcloud config list project

Output perintah

[core]
project = <PROJECT_ID>

Jika tidak, Anda dapat menyetelnya dengan perintah ini:

gcloud config set project <PROJECT_ID>

Output perintah

Updated property [core/project].

Penyiapan Lingkungan

Anda akan menjalankan perintah di command line Cloud Shell untuk lab ini. Anda biasanya dapat menyalin perintah dan menempelkannya apa adanya, meskipun dalam beberapa kasus Anda perlu mengubah nilai placeholder menjadi nilai yang benar.

  1. Tetapkan variabel lingkungan ke Project ID untuk digunakan dalam perintah selanjutnya:
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export SERVICE_NAME=partner-registration-service
  1. Aktifkan Cloud Run Service API yang akan menjalankan aplikasi Anda, Firestore API yang akan menyediakan penyimpanan data NoSQL, Cloud Build API yang akan digunakan oleh perintah deployment, dan Artifact Registry yang akan digunakan untuk menyimpan container aplikasi saat dibangun:
gcloud services enable \
  run.googleapis.com \
  firestore.googleapis.com \
  cloudbuild.googleapis.com \
  artifactregistry.googleapis.com
  1. Lakukan inisialisasi database Firestore dalam mode Native. Perintah tersebut menggunakan App Engine API, jadi API tersebut harus diaktifkan terlebih dahulu.

Perintah harus menentukan region untuk App Engine, yang tidak akan kita gunakan tetapi harus dibuat karena alasan historis, dan region untuk database. Kita akan menggunakan us-central untuk App Engine, dan nam5 untuk database. nam5 adalah lokasi multi-region Amerika Serikat. Lokasi multi-region memaksimalkan ketersediaan dan ketahanan database.

gcloud services enable appengine.googleapis.com

gcloud app create --region=us-central
gcloud firestore databases create --region=nam5
  1. Buat clone repositori aplikasi contoh dan buka direktori
git clone https://github.com/GoogleCloudPlatform/cymbal-eats.git

cd cymbal-eats/partner-registration-service

3. Meninjau README

Buka editor dan lihat file yang membentuk aplikasi. Lihat README.md, yang menjelaskan langkah-langkah yang diperlukan untuk men-deploy aplikasi ini. Beberapa langkah ini mungkin melibatkan keputusan keamanan implisit atau eksplisit yang perlu dipertimbangkan. Anda akan mengubah beberapa pilihan ini untuk meningkatkan keamanan aplikasi yang di-deploy, seperti yang dijelaskan di sini:

Langkah 3 - Jalankan npm install

Penting untuk mengetahui asal dan integritas software pihak ketiga yang digunakan dalam aplikasi. Mengelola Keamanan Supply Chain Software relevan untuk membangun software apa pun, bukan hanya aplikasi yang di-deploy ke Cloud Run. Lab ini berfokus pada deployment, sehingga tidak membahas area ini, tetapi Anda dapat meneliti topik ini secara terpisah.

Langkah 4 dan 5 - Edit dan jalankan deploy.sh

Langkah-langkah ini men-deploy aplikasi ke Cloud Run dengan sebagian besar opsi tetap pada nilai defaultnya. Anda akan mengubah langkah ini untuk membuat deployment lebih aman dengan dua cara utama:

  1. Jangan izinkan akses yang tidak diautentikasi. Mengizinkan hal tersebut mungkin praktis untuk mencoba berbagai hal selama eksplorasi, tetapi ini adalah layanan web untuk digunakan oleh partner komersial, dan harus selalu mengautentikasi penggunanya.
  2. Tentukan bahwa aplikasi harus menggunakan akun layanan khusus yang disesuaikan hanya dengan hak istimewa yang diperlukan, bukan akun layanan default yang kemungkinan akan memiliki akses API dan resource lebih banyak daripada yang diperlukan. Hal ini dikenal sebagai prinsip hak istimewa terendah, dan merupakan konsep dasar keamanan aplikasi.

Langkah 6 hingga 11 - Buat permintaan web contoh untuk memverifikasi perilaku yang benar

Karena deployment aplikasi kini memerlukan autentikasi, permintaan ini kini harus menyertakan bukti identitas pemohon. Daripada mengubah file ini, Anda akan membuat permintaan langsung dari command line.

4. Men-deploy layanan secara aman

Ada dua perubahan yang diperlukan dalam skrip deploy.sh: tidak mengizinkan akses yang tidak diautentikasi, dan menggunakan akun layanan khusus dengan hak istimewa minimal.

Anda akan membuat akun layanan baru terlebih dahulu, lalu mengedit skrip deploy.sh untuk mereferensikan akun layanan tersebut dan melarang akses yang tidak diautentikasi, lalu men-deploy layanan dengan menjalankan skrip yang telah diubah sebelum kita dapat menjalankan skrip deploy.sh yang telah diubah.

Buat akun layanan dan beri akun layanan tersebut akses yang diperlukan ke Firestore/Datastore

gcloud iam service-accounts create partner-sa

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:partner-sa@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role=roles/datastore.user

Edit deploy.sh

Ubah file deploy.sh untuk melarang akses yang tidak diautentikasi(–no-allow-unauthenticated), dan untuk menentukan akun layanan baru(–service-account) untuk aplikasi yang di-deploy. Perbaiki GOOGLE_PROJECT_ID agar sesuai dengan ID project Anda sendiri.

Anda akan menghapus dua baris pertama, dan mengubah tiga baris lainnya seperti yang ditunjukkan di bawah.

gcloud run deploy $SERVICE_NAME \
  --source . \
  --platform managed \
  --region ${REGION} \
  --no-allow-unauthenticated \
  --project=$PROJECT_ID \
  --service-account=partner-sa@${PROJECT_ID}.iam.gserviceaccount.com

Men-deploy layanan

Dari command line, jalankan skrip deploy.sh:

./deploy.sh

Setelah deployment selesai, baris terakhir output perintah akan menampilkan URL Layanan aplikasi baru. Simpan URL dalam variabel lingkungan:

export SERVICE_URL=<URL from last line of command output>

Sekarang, coba ambil pesanan dari aplikasi menggunakan alat curl:

curl -i -X GET $SERVICE_URL/partners

Flag -i untuk perintah curl memberi tahu perintah tersebut untuk menyertakan header respons dalam output. Baris pertama output harus berupa:

HTTP/2 403

Aplikasi di-deploy dengan opsi untuk tidak mengizinkan permintaan yang tidak diautentikasi. Perintah curl ini tidak berisi informasi autentikasi, sehingga ditolak oleh Cloud Run. Aplikasi yang sebenarnya di-deploy bahkan tidak berjalan atau menerima data apa pun dari permintaan ini.

5. Membuat Permintaan yang Diautentikasi

Aplikasi yang di-deploy dipanggil dengan membuat permintaan web, yang kini harus diautentikasi agar diizinkan oleh Cloud Run. Permintaan web diautentikasi dengan menyertakan header Authorization dalam bentuk:

Authorization: Bearer identity-token

Token identitas adalah string yang dienkode, ditandatangani secara kriptografis, dan berjangka pendek yang dikeluarkan oleh penyedia autentikasi tepercaya. Dalam hal ini, token identitas yang valid, belum habis masa berlakunya, dan dikeluarkan oleh Google diperlukan.

Membuat permintaan sebagai akun pengguna Anda

Alat Google Cloud CLI dapat memberikan token untuk pengguna yang diautentikasi secara default. Jalankan perintah ini untuk mendapatkan token identitas untuk akun Anda sendiri dan menyimpannya dalam variabel lingkungan ID_TOKEN:

export ID_TOKEN=$(gcloud auth print-identity-token)

Secara default, token identitas yang dikeluarkan Google berlaku selama satu jam. Jalankan perintah curl berikut untuk membuat permintaan yang sebelumnya ditolak karena tidak diizinkan. Perintah ini akan menyertakan header yang diperlukan:

curl -i -X GET $SERVICE_URL/partners \
  -H "Authorization: Bearer $ID_TOKEN"

Output perintah harus dimulai dengan HTTP/2 200, yang menunjukkan bahwa permintaan dapat diterima dan sedang diproses. (Jika Anda menunggu selama satu jam dan mencoba permintaan ini lagi, permintaan akan gagal karena masa berlaku token akan habis.) Isi respons berada di akhir output, setelah baris kosong:

{"status":"success","data":[]}

Belum ada partner.

Daftarkan partner menggunakan data JSON contoh di direktori dengan dua perintah curl:

curl -X POST \
  -H "Authorization: Bearer $ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d "@example-partner.json" \
  $SERVICE_URL/partner

dan

curl -X POST \
  -H "Authorization: Bearer $ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d "@example-partner2.json" \
  $SERVICE_URL/partner

Ulangi permintaan GET sebelumnya untuk melihat semua partner terdaftar sekarang:

curl -i -X GET $SERVICE_URL/partners \
  -H "Authorization: Bearer $ID_TOKEN"

Anda akan melihat data JSON dengan lebih banyak konten, yang memberikan informasi tentang dua partner terdaftar.

Membuat permintaan sebagai akun yang tidak sah

Permintaan yang diautentikasi yang dibuat pada langkah terakhir berhasil bukan hanya karena diautentikasi, tetapi juga karena pengguna yang diautentikasi (akun Anda) diotorisasi. Artinya, akun tersebut memiliki izin untuk memanggil aplikasi. Tidak semua akun terautentikasi akan diizinkan untuk melakukannya.

Akun default yang digunakan dalam permintaan sebelumnya telah diberi otorisasi karena merupakan akun yang membuat project yang berisi aplikasi, dan secara default, akun tersebut diberi izin untuk memanggil aplikasi Cloud Run apa pun di akun tersebut. Izin tersebut dapat dicabut jika diperlukan, yang akan diinginkan dalam aplikasi produksi. Daripada melakukannya sekarang, Anda akan membuat akun layanan baru tanpa hak istimewa atau peran yang ditetapkan dan menggunakannya untuk mencoba mengakses aplikasi yang di-deploy.

  1. Buat akun layanan bernama tester.
gcloud iam service-accounts create tester
  1. Anda akan mendapatkan token identitas untuk akun baru ini dengan cara yang hampir sama seperti saat Anda mendapatkan token untuk akun default Anda sebelumnya. Namun, hal ini mengharuskan akun default Anda memiliki izin untuk meniru identitas akun layanan. Beri akun Anda izin ini.
export USER_EMAIL=$(gcloud config list account --format "value(core.account)")

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="user:$USER_EMAIL" \
  --role=roles/iam.serviceAccountTokenCreator
  1. Sekarang, jalankan perintah berikut untuk menyimpan token identitas untuk akun baru ini dalam variabel lingkungan TEST_IDENTITY. Jika perintah menampilkan pesan error, tunggu sebentar, lalu coba lagi.
export TEST_TOKEN=$( \
  gcloud auth print-identity-token \
    --impersonate-service-account \
    "tester@$PROJECT_ID.iam.gserviceaccount.com" \
)
  1. Buat permintaan web terautentikasi seperti sebelumnya, tetapi menggunakan token identitas ini:
curl -i -X GET $SERVICE_URL/partners \
  -H "Authorization: Bearer $TEST_TOKEN"

Output perintah akan dimulai lagi dengan HTTP/2 403 karena permintaan, meskipun diautentikasi, tidak diizinkan. Akun layanan baru tidak memiliki izin untuk memanggil aplikasi ini.

Memberi otorisasi akun

Akun pengguna atau layanan harus memiliki peran Cloud Run Invoker di layanan Cloud Run agar dapat membuat permintaan ke layanan tersebut. Berikan peran tersebut kepada akun layanan penguji dengan perintah:

export REGION=us-central1
gcloud run services add-iam-policy-binding ${SERVICE_NAME} \
  --member="serviceAccount:tester@$PROJECT_ID.iam.gserviceaccount.com" \
  --role=roles/run.invoker \
  --region=${REGION}

Setelah menunggu satu atau dua menit agar peran baru diperbarui, ulangi permintaan yang diautentikasi. Simpan TEST_TOKEN baru jika sudah satu jam atau lebih sejak pertama kali disimpan.

curl -i -X GET $SERVICE_URL/partners \
  -H "Authorization: Bearer $TEST_TOKEN"

Output perintah kini dimulai dengan HTTP/1.1 200 OK dan baris terakhir berisi respons JSON. Permintaan ini diterima oleh Cloud Run dan diproses oleh aplikasi.

6. Mengautentikasi program versus mengautentikasi pengguna

Permintaan yang diautentikasi yang telah Anda buat hingga saat ini menggunakan alat command line curl. Ada alat dan bahasa pemrograman lain yang dapat digunakan sebagai gantinya. Namun, permintaan Cloud Run yang diautentikasi tidak dapat dilakukan menggunakan browser web dengan halaman web biasa. Jika pengguna mengklik link atau mengklik tombol untuk mengirimkan formulir di halaman web, browser tidak akan menambahkan header Authorization yang diperlukan oleh Cloud Run untuk permintaan yang diautentikasi.

Mekanisme autentikasi bawaan Cloud Run ditujukan untuk digunakan oleh program, bukan oleh pengguna akhir.

Catatan:

Cloud Run dapat menghosting aplikasi web yang berinteraksi dengan pengguna, tetapi jenis aplikasi tersebut harus menyetel Cloud Run untuk mengizinkan permintaan yang tidak terautentikasi dari browser web pengguna. Jika aplikasi memerlukan autentikasi pengguna, aplikasi harus menanganinya, bukan meminta Cloud Run untuk melakukannya. Aplikasi dapat melakukannya dengan cara yang sama seperti aplikasi web di luar Cloud Run. Cara melakukannya berada di luar cakupan codelab ini.

Anda mungkin telah memperhatikan bahwa respons terhadap contoh permintaan hingga saat ini adalah objek JSON, bukan halaman web. Hal ini karena layanan pendaftaran partner ini ditujukan untuk digunakan oleh program, dan JSON adalah bentuk yang mudah digunakan oleh program. Selanjutnya, Anda akan menulis dan menjalankan program untuk menggunakan data ini.

Permintaan terautentikasi dari program Python

Program dapat membuat permintaan yang diautentikasi dari aplikasi Cloud Run yang diamankan melalui permintaan web HTTP standar, tetapi menyertakan header Authorization. Satu-satunya tantangan baru untuk program tersebut adalah mendapatkan token identitas yang valid dan belum habis masa berlakunya untuk ditempatkan di header tersebut. Token tersebut akan divalidasi oleh Cloud Run menggunakan Google Cloud Identity and Access Management (IAM), sehingga token harus dikeluarkan dan ditandatangani oleh otoritas yang diakui oleh IAM. Ada library klien yang tersedia dalam banyak bahasa yang dapat digunakan program untuk meminta penerbitan token tersebut. Library klien yang akan digunakan dalam contoh ini adalah google.auth Python. Ada beberapa library Python untuk membuat permintaan web secara umum; contoh ini menggunakan modul requests yang populer.

Langkah pertama adalah menginstal dua library klien:

pip install google-auth
pip install requests

Kode Python untuk meminta token identitas bagi pengguna default adalah:

credentials, _ = google.auth.default()
credentials.refresh(google.auth.transport.requests.Request())
identity_token = credentials.id_token

Jika Anda menggunakan shell perintah seperti Cloud Shell atau shell terminal standar di komputer Anda sendiri, pengguna default adalah pengguna yang telah diautentikasi di dalam shell tersebut. Di Cloud Shell, biasanya pengguna yang login ke Google. Dalam kasus lain, pengguna yang diautentikasi dengan perintah gcloud auth login atau gcloud lainnya. Jika pengguna belum pernah login, tidak akan ada pengguna default dan kode ini akan gagal.

Untuk program yang membuat permintaan program lain, Anda umumnya tidak ingin menggunakan identitas seseorang, melainkan identitas program yang meminta. Di sinilah akun layanan berfungsi. Anda men-deploy layanan Cloud Run dengan akun layanan khusus yang menyediakan identitas yang digunakan saat membuat permintaan API, seperti ke Cloud Firestore. Saat program berjalan di platform Google Cloud, library klien akan otomatis menggunakan akun layanan yang ditetapkan sebagai identitas defaultnya, sehingga kode program yang sama dapat berfungsi dalam kedua situasi.

Kode Python untuk membuat permintaan dengan header Otorisasi yang ditambahkan adalah:

auth_header = {"Authorization": "Bearer " + identity_token}
response = requests.get(url, headers=auth_header)

Program Python lengkap berikut akan membuat permintaan yang diautentikasi ke layanan Cloud Run untuk mengambil semua partner terdaftar, lalu mencetak nama dan ID yang ditetapkan. Salin dan jalankan perintah di bawah untuk menyimpan kode ini ke file print_partners.py.

cat > ./print_partners.py << EOF
def print_partners():
    import google.auth
    import google.auth.transport.requests
    import requests

    credentials, _ = google.auth.default()
    credentials.refresh(google.auth.transport.requests.Request())
    identity_token = credentials.id_token

    auth_header = {"Authorization": "Bearer " + identity_token}
    response = requests.get("${SERVICE_URL}/partners", headers=auth_header)

    parsed_response = response.json()
    partners = parsed_response["data"]

    for partner in partners:
        print(f"{partner['partnerId']}: {partner['name']}")


print_partners()
EOF

Anda akan menjalankan program ini dengan perintah shell. Anda harus melakukan autentikasi sebagai pengguna default terlebih dahulu, sehingga program dapat menggunakan kredensial tersebut. Jalankan perintah gcloud auth di bawah:

gcloud auth application-default login

Ikuti petunjuk untuk menyelesaikan login. Kemudian, jalankan program dari command line:

python print_partners.py

Outputnya akan terlihat seperti berikut:

10102: Zippy food delivery
67292: Foodful

Permintaan program mencapai layanan Cloud Run karena diautentikasi dengan identitas Anda, dan Anda adalah pemilik project ini sehingga secara default diizinkan untuk menjalankannya. Program ini lebih sering dijalankan dengan identitas akun layanan. Saat dijalankan di sebagian besar produk Google Cloud, seperti Cloud Run atau App Engine, identitas defaultnya adalah akun layanan dan akan digunakan, bukan akun pribadi.

7. Selamat!

Selamat, Anda telah menyelesaikan codelab!

Langkah berikutnya:

Pelajari codelab Cymbal Eats lainnya:

Pembersihan

Agar tidak menimbulkan biaya pada akun Google Cloud Anda untuk resource yang digunakan dalam tutorial ini, hapus project yang berisi resource tersebut, atau simpan project dan hapus setiap resource.

Menghapus project

Cara termudah untuk menghilangkan penagihan adalah dengan menghapus project yang Anda buat untuk tutorial.