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 dengan Cymbal Eats untuk memproses pesanan makanan.

Yang akan Anda pelajari

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

Anda kemudian akan melihat cara mengizinkan akses ke aplikasi dan membuat permintaan yang sah.

Ini bukanlah tinjauan menyeluruh mengenai keamanan deployment aplikasi, melainkan perubahan yang dapat Anda lakukan pada semua deployment aplikasi mendatang yang akan meningkatkan keamanannya dengan sangat 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 peduli tentang apa itu. Di sebagian besar codelab, Anda harus mereferensikan Project ID (biasanya diidentifikasi sebagai PROJECT_ID). Jika Anda tidak menyukai ID yang dihasilkan, Anda dapat membuat ID acak lainnya. Atau, Anda dapat mencobanya sendiri dan lihat 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. Untuk 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.pngS.

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 Lanjutkan (dan Anda tidak akan pernah melihatnya lagi). Berikut tampilan layar sekali-tampil tersebut:

9c92662c6a846a5c.pngS

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

9f0e51b578fecce5.pngS

Mesin virtual ini dimuat dengan semua alat pengembangan yang Anda butuhkan. 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. Biasanya Anda dapat menyalin perintah dan menempelkannya sebagaimana 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 berikutnya:
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export SERVICE_NAME=partner-registration-service
  1. Aktifkan API layanan Cloud Run 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. Melakukan inisialisasi database Firestore dalam mode Native. Perintah tersebut menggunakan App Engine API, jadi harus diaktifkan terlebih dahulu.

Perintah tersebut 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 di 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. Clone repositori aplikasi sampel dan buka direktorinya
git clone https://github.com/GoogleCloudPlatform/cymbal-eats.git

cd cymbal-eats/partner-registration-service

3. Tinjau README

Buka editor dan lihat file yang menyusun 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 dengan membangun software apa pun, bukan hanya aplikasi yang di-deploy ke Cloud Run. Lab ini berfokus pada deployment, jadi tidak membahas area ini, tetapi Anda mungkin ingin meneliti topik tersebut secara terpisah.

Langkah 4 dan 5 - Edit dan jalankan deploy.sh

Langkah-langkah ini men-deploy aplikasi ke Cloud Run dan membiarkan sebagian besar opsi tetap dalam setelan default. Anda akan memodifikasi langkah ini untuk membuat deployment menjadi lebih aman dengan dua cara utama:

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

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

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

4. Men-deploy layanan dengan aman

Ada dua perubahan yang diidentifikasi diperlukan dalam skrip deploy.sh: tidak mengizinkan akses yang tidak diautentikasi, dan penggunaan 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 untuk melarang akses yang tidak diautentikasi, lalu men-deploy layanan dengan menjalankan skrip yang telah diubah sebelum kita dapat menjalankan skrip deploy.sh yang dimodifikasi.

Membuat akun layanan dan memberinya 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 tidak mengizinkan akses yang tidak diautentikasi(–no-allow-unauthenticated), dan untuk menentukan akun layanan baru(–service-account) untuk aplikasi yang di-deploy. Koreksi GOOGLE_PROJECT_ID menjadi ID project Anda.

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

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 tahunya agar menyertakan header respons dalam output. Baris pertama output harus berupa:

HTTP/2 403

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

5. Membuat Permintaan yang Diautentikasi

Aplikasi yang di-deploy dipanggil dengan membuat permintaan web, yang sekarang harus diautentikasi agar Cloud Run dapat mengizinkannya. Permintaan web diautentikasi dengan menyertakan header Authorization dalam formulir:

Authorization: Bearer identity-token

Token identitas adalah string berenkode jangka pendek yang ditandatangani secara kriptografis dan diterbitkan oleh penyedia autentikasi tepercaya. Dalam hal ini, diperlukan token identitas yang masih berlaku, valid, dan diterbitkan Google.

Membuat permintaan sebagai akun pengguna

Alat Google Cloud CLI dapat menyediakan token untuk pengguna terautentikasi secara default. Jalankan perintah ini guna mendapatkan token identitas untuk akun Anda sendiri dan simpan di variabel lingkungan ID_TOKEN:

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

Secara default, token identitas yang diterbitkan Google berlaku selama satu jam. Jalankan perintah curl berikut untuk membuat permintaan yang ditolak sebelumnya 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 dipenuhi. (Jika Anda menunggu satu jam dan mencoba lagi permintaan ini, permintaan itu akan gagal karena masa berlaku token telah berakhir.) Isi respons ada di akhir output, setelah baris kosong:

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

Belum ada partner.

Daftarkan partner menggunakan contoh data JSON 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 yang terdaftar sekarang:

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

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

Membuat permintaan sebagai akun yang tidak sah

Permintaan terautentikasi yang dibuat pada langkah terakhir berhasil tidak hanya karena pengguna tersebut telah diautentikasi, tetapi juga karena pengguna yang diautentikasi (akun Anda) telah diberi otorisasi. Artinya, akun memiliki izin untuk memanggil aplikasi. Tidak semua akun yang diautentikasi akan diberi otorisasi untuk melakukan tindakan tersebut.

Akun default yang digunakan dalam permintaan sebelumnya telah diberi otorisasi karena merupakan akun yang membuat project yang berisi aplikasi, dan secara default yang memberinya izin untuk memanggil aplikasi Cloud Run di akun. Izin tersebut dapat dicabut jika diperlukan, yang 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 sama seperti saat Anda mendapatkan token identitas untuk akun default Anda sebelumnya. Namun, hal ini mengharuskan akun default Anda memiliki izin untuk meniru identitas akun layanan. Berikan izin ini ke akun Anda.
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 di variabel lingkungan TEST_IDENTITY. Jika perintah menampilkan pesan error, tunggu satu atau dua menit dan coba lagi.
export TEST_TOKEN=$( \
  gcloud auth print-identity-token \
    --impersonate-service-account \
    "tester@$PROJECT_ID.iam.gserviceaccount.com" \
)
  1. Buat permintaan web yang diautentikasi 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 tersebut, meskipun diautentikasi, tidak diotorisasi. Akun layanan yang baru tidak memiliki izin untuk memanggil aplikasi ini.

Memberikan otorisasi pada akun

Akun pengguna atau layanan harus memiliki peran Cloud Run Invoker di layanan Cloud Run agar dapat membuat permintaan ke akun 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 sampai peran baru diperbarui, ulangi permintaan yang telah 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 sekarang 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 terautentikasi yang telah Anda buat hingga saat ini telah 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 pengguna akhir.

Catatan:

Cloud Run dapat menghosting aplikasi web yang ditampilkan kepada pengguna, tetapi jenis aplikasi tersebut harus menetapkan Cloud Run agar mengizinkan permintaan yang tidak diautentikasi dari pengguna web browser web. Jika aplikasi memerlukan autentikasi pengguna, aplikasi harus menanganinya, bukan meminta Cloud Run untuk melakukannya. Aplikasi tersebut 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 permintaan contoh hingga saat ini adalah objek JSON, bukan halaman web. Itu karena layanan pendaftaran partner ini ditujukan untuk penggunaan oleh program, dan JSON adalah bentuk yang mudah digunakan untuk mereka. Selanjutnya, Anda akan menulis dan menjalankan program untuk memakai data ini.

Permintaan yang diautentikasi dari program Python

Program dapat membuat permintaan yang diautentikasi dari aplikasi Cloud Run yang aman melalui permintaan web HTTP standar, tetapi termasuk header Authorization. Satu-satunya tantangan baru bagi 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 diterbitkan dan ditandatangani oleh otoritas yang dikenali oleh IAM. Ada library klien yang tersedia dalam banyak bahasa yang dapat digunakan oleh program untuk meminta penerbitan token tersebut. Library klien yang akan digunakan contoh ini adalah Python google.auth. Ada beberapa library Python untuk membuat permintaan web secara umum; contoh ini menggunakan modul requests yang populer.

Langkah pertama adalah menginstal kedua 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-nya adalah pengguna yang telah melakukan otentikasi di dalam shell tersebut. Di Cloud Shell, biasanya pengguna login ke Google. Dalam kasus lain, ini adalah pengguna yang diautentikasi dengan gcloud auth login atau perintah gcloud lainnya. Jika pengguna belum pernah login, tidak akan ada pengguna default dan kode ini akan gagal.

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

Kode Python untuk membuat permintaan dengan header Otorisasi tambahan adalah:

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

Program Python lengkap berikut akan membuat permintaan terautentikasi ke layanan Cloud Run untuk mengambil semua partner terdaftar, lalu mencetak nama dan ID mereka 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 otentikasi sebagai pengguna {i>default<i} terlebih dahulu, sehingga program dapat menggunakan kredensial tersebut. Jalankan perintah gcloud auth di bawah ini:

gcloud auth application-default login

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

python print_partners.py

Output-nya akan terlihat seperti berikut:

10102: Zippy food delivery
67292: Foodful

Permintaan program mencapai layanan Cloud Run karena telah diautentikasi dengan identitas Anda, dan Anda adalah pemilik project ini sehingga diberi otorisasi untuk menjalankannya secara default. Program ini akan lebih umum dijalankan dengan identitas akun layanan. Saat dijalankan di sebagian besar produk Google Cloud, seperti Cloud Run atau App Engine, identitas default-nya 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, atau simpan project dan hapus resource satu per satu.

Menghapus project

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