Mengautentikasi pengguna dengan Go


Aplikasi yang berjalan di platform yang dikelola Google Cloud, seperti App Engine, dapat menghindari pengelolaan autentikasi pengguna dan pengelolaan sesi karena menggunakan Identity-Aware Proxy (IAP) untuk mengontrol akses ke aplikasi tersebut. IAP tidak hanya dapat mengontrol akses ke aplikasi, tetapi juga memberikan informasi tentang pengguna yang diautentikasi, termasuk alamat email dan ID persisten untuk aplikasi dalam bentuk header HTTP baru.

Tujuan

  • Wajibkan pengguna aplikasi App Engine Anda untuk mengautentikasi diri mereka sendiri dengan menggunakan IAP.

  • Mengakses identitas pengguna di aplikasi untuk menampilkan alamat email yang diautentikasi milik pengguna saat ini.

Biaya

Dalam dokumen ini, Anda menggunakan komponen Google Cloud yang dapat ditagih berikut:

Untuk membuat perkiraan biaya berdasarkan proyeksi penggunaan Anda, gunakan kalkulator harga. Pengguna baru Google Cloud mungkin memenuhi syarat untuk mendapatkan uji coba gratis.

Setelah menyelesaikan tugas yang dijelaskan dalam dokumen ini, Anda dapat menghindari penagihan berkelanjutan dengan menghapus resource yang Anda buat. Untuk mengetahui informasi selengkapnya, lihat Pembersihan.

Sebelum memulai

  1. Login ke akun Google Cloud Anda. Jika Anda baru menggunakan Google Cloud, buat akun untuk mengevaluasi performa produk kami dalam skenario dunia nyata. Pelanggan baru juga mendapatkan kredit gratis senilai $300 untuk menjalankan, menguji, dan men-deploy workload.
  2. Di konsol Google Cloud, pada halaman pemilih project, pilih atau buat project Google Cloud.

    Buka pemilih project

  3. Menginstal Google Cloud CLI.
  4. Untuk initialize gcloud CLI, jalankan perintah berikut:

    gcloud init
  5. Di konsol Google Cloud, pada halaman pemilih project, pilih atau buat project Google Cloud.

    Buka pemilih project

  6. Menginstal Google Cloud CLI.
  7. Untuk initialize gcloud CLI, jalankan perintah berikut:

    gcloud init
  8. Menyiapkan lingkungan pengembangan Anda.

Menyiapkan project

  1. Di jendela terminal, clone repositori aplikasi contoh ke mesin lokal Anda:

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git
  2. Ubah ke direktori yang berisi kode contoh:

    cd golang-samples/getting-started/authenticating-users

Latar belakang

Tutorial ini menggunakan IAP untuk mengautentikasi pengguna. Ini hanyalah salah satu dari beberapa kemungkinan pendekatan. Untuk mempelajari berbagai metode autentikasi pengguna lebih lanjut, lihat bagian Konsep autentikasi.

Aplikasi Hello user-email-address

Aplikasi untuk tutorial ini adalah aplikasi App Engine Halo dunia minimal, dengan satu fitur non-standar: aplikasi menampilkan "Hello user-email-address", dengan user-email-address adalah alamat email pengguna yang diautentikasi.

Fungsionalitas ini dapat dilakukan dengan memeriksa informasi terautentikasi yang ditambahkan IAP ke setiap permintaan web yang diteruskan ke aplikasi Anda. Ada tiga header permintaan baru yang ditambahkan ke setiap permintaan web yang menjangkau aplikasi Anda. Dua header pertama adalah string teks biasa yang bisa digunakan untuk mengidentifikasi pengguna. Header ketiga adalah objek yang ditandatangani secara kriptografis dengan informasi yang sama tersebut.

  • X-Goog-Authenticated-User-Email: Alamat email pengguna akan mengidentifikasinya. Jangan simpan informasi pribadi jika aplikasi Anda dapat menghindarinya. Aplikasi ini tidak menyimpan data apa pun; tetapi hanya mengirimkan kembali data kepada pengguna.

  • X-Goog-Authenticated-User-Id: User-ID yang ditetapkan oleh Google ini tidak menampilkan informasi tentang pengguna, tetapi memungkinkan aplikasi mengetahui bahwa pengguna yang login sama dengan yang sebelumnya terlihat.

  • X-Goog-Iap-Jwt-Assertion: Anda dapat mengonfigurasi aplikasi Google Cloud untuk menerima permintaan web dari aplikasi cloud lain, dengan mengabaikan IAP, selain permintaan web internet. Jika aplikasi sudah dikonfigurasi, mungkin saja permintaan tersebut memiliki header palsu. Daripada menggunakan salah satu header teks biasa yang disebutkan sebelumnya, Anda dapat menggunakan dan memverifikasi header yang ditandatangani secara kriptografis ini untuk memeriksa apakah informasi telah diberikan oleh Google. Alamat email pengguna dan ID pengguna tetap tersedia sebagai bagian dari header yang ditandatangani ini.

Jika Anda yakin bahwa aplikasi telah dikonfigurasi sehingga hanya permintaan web internet yang dapat menjangkaunya, dan tidak ada yang dapat menonaktifkan layanan IAP untuk aplikasi, mengambil ID pengguna unik hanya memerlukan satu baris kode:

userID := r.Header.Get("X-Goog-Authenticated-User-ID")

Namun, aplikasi yang tangguh akan mendeteksi berbagai kesalahan, termasuk masalah konfigurasi atau lingkungan yang tidak terduga. Oleh karena itu, sebaiknya buat fungsi yang menggunakan dan memverifikasi header yang ditandatangani secara kriptografis. Tanda tangan header tersebut tidak dapat dipalsukan, dan jika diverifikasi, dapat digunakan untuk menampilkan identifikasi.

Memahami kode

Bagian ini menjelaskan cara kerja kode. Jika ingin menjalankan aplikasi, Anda dapat langsung membuka bagian Men-deploy aplikasi.

  • File go.mod menentukan modul Go dan modul yang menjadi tempatnya bergantung.

    module github.com/GoogleCloudPlatform/golang-samples/getting-started/authenticating-users
    
    go 1.19
    
    require (
    	cloud.google.com/go/compute/metadata v0.2.3
    	github.com/golang-jwt/jwt v3.2.2+incompatible
    )
    
    require cloud.google.com/go/compute v1.19.1 // indirect
    
  • File app.yaml memberi tahu App Engine lingkungan bahasa yang diperlukan kode Anda.

    runtime: go112
  • Aplikasi dimulai dengan mengimpor paket dan menentukan fungsi main. Fungsi main mendaftarkan pengendali indeks dan memulai server HTTP.

    
    // The authenticating-users program is a sample web server application that
    // extracts and verifies user identity data passed to it via Identity-Aware
    // Proxy.
    package main
    
    import (
    	"encoding/json"
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    	"time"
    
    	"cloud.google.com/go/compute/metadata"
    	"github.com/golang-jwt/jwt"
    )
    
    // app holds the Cloud IAP certificates and audience field for this app, which
    // are needed to verify authentication headers set by Cloud IAP.
    type app struct {
    	certs map[string]string
    	aud   string
    }
    
    func main() {
    	a, err := newApp()
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	http.HandleFunc("/", a.index)
    
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    		log.Printf("Defaulting to port %s", port)
    	}
    
    	log.Printf("Listening on port %s", port)
    	if err := http.ListenAndServe(":"+port, nil); err != nil {
    		log.Fatal(err)
    	}
    }
    
    // newApp creates a new app, returning an error if either the Cloud IAP
    // certificates or the app's audience field cannot be obtained.
    func newApp() (*app, error) {
    	certs, err := certificates()
    	if err != nil {
    		return nil, err
    	}
    
    	aud, err := audience()
    	if err != nil {
    		return nil, err
    	}
    
    	a := &app{
    		certs: certs,
    		aud:   aud,
    	}
    	return a, nil
    }
    
  • Fungsi index mendapatkan nilai header pernyataan JWT yang ditambahkan IAP dari permintaan masuk dan memanggil fungsi validateAssertion untuk memvalidasi nilai yang ditandatangani secara kriptografis. Alamat email tersebut kemudian digunakan dalam respons web minimal.

    
    // index responds to requests with our greeting.
    func (a *app) index(w http.ResponseWriter, r *http.Request) {
    	if r.URL.Path != "/" {
    		http.NotFound(w, r)
    		return
    	}
    
    	assertion := r.Header.Get("X-Goog-IAP-JWT-Assertion")
    	if assertion == "" {
    		fmt.Fprintln(w, "No Cloud IAP header found.")
    		return
    	}
    	email, _, err := validateAssertion(assertion, a.certs, a.aud)
    	if err != nil {
    		log.Println(err)
    		fmt.Fprintln(w, "Could not validate assertion. Check app logs.")
    		return
    	}
    
    	fmt.Fprintf(w, "Hello %s\n", email)
    }
    
  • Fungsi validateAssertion memvalidasi bahwa pernyataan ditandatangani dengan benar dan menampilkan alamat email dan ID pengguna terkait.

    Untuk memvalidasi pernyataan JWT, Anda perlu mengetahui sertifikat kunci publik entity yang menandatangani pernyataan (dalam hal ini Google), dan audiens yang menjadi tujuan pernyataan tersebut. Untuk aplikasi App Engine, audience adalah string yang berisi informasi identifikasi project Google Cloud di dalamnya. Fungsi validateAssertion mendapatkan sertifikat tersebut dari fungsi certs dan string audiens dari fungsi audience.

    
    // validateAssertion validates assertion was signed by Google and returns the
    // associated email and userID.
    func validateAssertion(assertion string, certs map[string]string, aud string) (email string, userID string, err error) {
    	token, err := jwt.Parse(assertion, func(token *jwt.Token) (interface{}, error) {
    		keyID := token.Header["kid"].(string)
    
    		_, ok := token.Method.(*jwt.SigningMethodECDSA)
    		if !ok {
    			return nil, fmt.Errorf("unexpected signing method: %q", token.Header["alg"])
    		}
    
    		cert := certs[keyID]
    		return jwt.ParseECPublicKeyFromPEM([]byte(cert))
    	})
    
    	if err != nil {
    		return "", "", err
    	}
    
    	claims, ok := token.Claims.(jwt.MapClaims)
    	if !ok {
    		return "", "", fmt.Errorf("could not extract claims (%T): %+v", token.Claims, token.Claims)
    	}
    
    	if claims["aud"].(string) != aud {
    		return "", "", fmt.Errorf("mismatched audience. aud field %q does not match %q", claims["aud"], aud)
    	}
    	return claims["email"].(string), claims["sub"].(string), nil
    }
    
  • Anda dapat mencari ID numerik dan nama project Google Cloud serta memasukkannya sendiri ke dalam kode sumber, tetapi fungsi audience melakukannya untuk Anda dengan membuat kueri layanan metadata standar yang tersedia untuk setiap aplikasi App Engine. Karena layanan metadata berada di luar kode aplikasi, hasil tersebut disimpan dalam variabel global yang ditampilkan tanpa harus mencari metadata dalam panggilan berikutnya.

    Layanan metadata App Engine (dan layanan metadata serupa untuk layanan Google Cloud computing lainnya) terlihat seperti situs web dan dikueri oleh kueri web standar. Namun, layanan metadata sebenarnya bukan situs eksternal, melainkan fitur internal yang menampilkan informasi yang diminta tentang aplikasi yang sedang berjalan, sehingga aman untuk menggunakan permintaan http, bukan permintaan https. Layanan metadata digunakan untuk mendapatkan ID Google Cloud saat ini yang diperlukan untuk menentukan audiens yang dituju dalam pernyataan JWT.

    
    // audience returns the expected audience value for this service.
    func audience() (string, error) {
    	projectNumber, err := metadata.NumericProjectID()
    	if err != nil {
    		return "", fmt.Errorf("metadata.NumericProjectID: %w", err)
    	}
    
    	projectID, err := metadata.ProjectID()
    	if err != nil {
    		return "", fmt.Errorf("metadata.ProjectID: %w", err)
    	}
    
    	return "/projects/" + projectNumber + "/apps/" + projectID, nil
    }
    
  • Verifikasi tanda tangan digital memerlukan sertifikat kunci publik dari penanda tangan. Google menyediakan situs yang menampilkan semua sertifikat kunci publik yang digunakan saat ini. Hasil ini akan disimpan dalam cache jika diperlukan lagi dalam instance aplikasi yang sama.

    
    // certificates returns Cloud IAP's cryptographic public keys.
    func certificates() (map[string]string, error) {
    	const url = "https://www.gstatic.com/iap/verify/public_key"
    	client := http.Client{
    		Timeout: 5 * time.Second,
    	}
    	resp, err := client.Get(url)
    	if err != nil {
    		return nil, fmt.Errorf("Get: %w", err)
    	}
    
    	var certs map[string]string
    	dec := json.NewDecoder(resp.Body)
    	if err := dec.Decode(&certs); err != nil {
    		return nil, fmt.Errorf("Decode: %w", err)
    	}
    
    	return certs, nil
    }
    

Men-deploy aplikasi

Sekarang Anda dapat men-deploy aplikasi, lalu mengaktifkan IAP untuk mewajibkan pengguna melakukan autentikasi sebelum mereka dapat mengakses aplikasi.

  1. Di jendela terminal, buka direktori yang berisi file app.yaml, lalu deploy aplikasi ke App Engine:

    gcloud app deploy
    
  2. Jika diminta, pilih wilayah di sekitar.

  3. Ketika ditanya apakah Anda ingin melanjutkan operasi deployment, masukkan Y.

    Dalam beberapa menit, aplikasi Anda sudah tayang di internet.

  4. Lihat aplikasi:

    gcloud app browse
    

    Di output, salin web-site-url, alamat web untuk aplikasi.

  5. Di jendela browser, tempel web-site-url untuk membuka aplikasi.

    Tidak ada email yang ditampilkan karena Anda belum menggunakan IAP, sehingga tidak ada informasi pengguna yang dikirim ke aplikasi.

Aktifkan IAP

Setelah instance App Engine ada, Anda dapat melindunginya dengan IAP:

  1. Di konsol Google Cloud, buka halaman Identity-Aware Proxy.

    Buka halaman Identity-Aware Proxy

  2. Karena ini adalah pertama kalinya Anda mengaktifkan opsi autentikasi untuk project ini, Anda akan melihat pesan bahwa Anda harus mengonfigurasi layar izin OAuth sebelum dapat menggunakan IAP.

    Klik Konfigurasi Layar Persetujuan.

  3. Pada tab OAuth Consent Screen di halaman Credentials, lengkapi kolom berikut:

    • Jika akun Anda berada di organisasi Google Workspace, pilih External, lalu klik Create. Untuk memulai, aplikasi hanya akan tersedia untuk pengguna yang secara eksplisit Anda izinkan.

    • Di kolom Application name, masukkan IAP Example.

    • Di kolom Email dukungan, masukkan alamat email Anda.

    • Di kolom Authorized domain, masukkan bagian nama host dari URL aplikasi, misalnya, iap-example-999999.uc.r.appspot.com. Tekan tombol Enter setelah memasukkan nama host di kolom.

    • Di kolom Link halaman beranda aplikasi, masukkan URL untuk aplikasi Anda, misalnya https://iap-example-999999.uc.r.appspot.com/.

    • Di kolom Baris kebijakan privasi aplikasi, gunakan URL yang sama dengan link halaman beranda untuk tujuan pengujian.

  4. Klik Save. Saat diminta membuat kredensial, Anda dapat menutup jendela.

  5. Di konsol Google Cloud, buka halaman Identity-Aware Proxy.

    Buka halaman Identity-Aware Proxy

  6. Untuk memuat ulang halaman, klik Refresh . Halaman ini menampilkan daftar resource yang dapat Anda lindungi.

  7. Di kolom IAP, klik untuk mengaktifkan IAP untuk aplikasi.

  8. Di browser Anda, buka web-site-url lagi.

  9. Sebagai ganti halaman web, terdapat layar login untuk mengautentikasi diri Anda sendiri. Saat login, akses Anda ditolak karena IAP tidak memiliki daftar pengguna yang diizinkan untuk masuk ke aplikasi.

Menambahkan pengguna yang diberi otorisasi ke aplikasi

  1. Di konsol Google Cloud, buka halaman Identity-Aware Proxy.

    Buka halaman Identity-Aware Proxy

  2. Centang kotak untuk aplikasi App Engine, lalu klik Add Principal.

  3. Masukkan allAuthenticatedUsers, lalu pilih peran Cloud IAP/IAP-Secured Web App User.

  4. Klik Save.

Kini, semua pengguna yang dapat diautentikasi oleh Google dapat mengakses aplikasi. Jika mau, Anda dapat membatasi akses lebih lanjut dengan hanya menambahkan satu atau beberapa orang atau grup sebagai akun utama:

  • Semua alamat email Gmail atau Google Workspace

  • Alamat email Google Grup

  • Nama domain Google Workspace

Mengakses aplikasi

  1. Di browser, buka web-site-url.

  2. Untuk memuat ulang halaman, klik Refresh .

  3. Di layar login, login dengan kredensial Google Anda.

    Halaman tersebut menampilkan halaman "Hello user-email-address" dengan alamat email Anda.

    Jika Anda masih melihat halaman yang sama seperti sebelumnya, mungkin ada masalah dengan browser tidak memperbarui permintaan baru sepenuhnya setelah Anda mengaktifkan IAP. Tutup semua jendela browser, buka kembali, dan coba lagi.

Konsep otentikasi

Ada beberapa cara agar aplikasi dapat mengautentikasi penggunanya dan membatasi akses hanya untuk pengguna yang diotorisasi. Metode autentikasi umum, dengan mengurangi tingkat upaya untuk aplikasi, tercantum di bagian berikut.

Opsi Kelebihan Kekurangan
Autentikasi aplikasi
  • Aplikasi dapat berjalan di platform apa pun, dengan atau tanpa koneksi internet
  • Pengguna tidak perlu menggunakan layanan lain untuk mengelola autentikasi
  • Aplikasi harus mengelola kredensial pengguna dengan aman dan mencegah pengungkapan
  • Aplikasi harus menyimpan data sesi untuk pengguna yang login
  • Aplikasi harus menyediakan pendaftaran pengguna, perubahan sandi, pemulihan sandi
OAuth2
  • Aplikasi dapat berjalan di platform mana pun yang terhubung ke internet, termasuk workstation developer
  • Aplikasi tidak memerlukan pendaftaran pengguna, perubahan sandi, atau fungsi pemulihan sandi.
  • Pengungkapan risiko informasi pengguna didelegasikan ke layanan lain
  • Tindakan keamanan login baru yang ditangani di luar aplikasi
  • Pengguna harus mendaftar ke layanan identitas
  • Aplikasi harus menyimpan data sesi untuk pengguna yang login
IAP
  • Aplikasi tidak perlu memiliki kode untuk mengelola pengguna, autentikasi, atau status sesi
  • Aplikasi tidak memiliki kredensial pengguna yang mungkin telah diretas
  • Aplikasi hanya dapat berjalan di platform yang didukung oleh layanan. Secara khusus, layanan Google Cloud tertentu yang mendukung IAP, seperti App Engine.

Autentikasi yang dikelola aplikasi

Dengan metode ini, aplikasi akan mengelola sendiri setiap aspek autentikasi pengguna. Aplikasi harus mengelola database kredensial penggunanya sendiri dan mengelola sesi pengguna, serta harus menyediakan fungsi untuk mengelola akun dan sandi pengguna, memeriksa kredensial pengguna, serta mengeluarkan, memeriksa, dan memperbarui sesi pengguna dengan setiap login yang diautentikasi. Diagram berikut mengilustrasikan metode autentikasi yang dikelola aplikasi.

Alur pengelolaan aplikasi

Seperti yang ditunjukkan dalam diagram, setelah pengguna login, aplikasi akan membuat dan menyimpan informasi tentang sesi pengguna. Saat pengguna membuat permintaan ke aplikasi, permintaan tersebut harus menyertakan informasi sesi yang harus diverifikasi oleh aplikasi.

Keuntungan utama dari pendekatan ini adalah bahwa pendekatan ini bersifat mandiri dan berada di bawah kontrol aplikasi. Aplikasi ini bahkan tidak harus tersedia di internet. Kelemahan utamanya adalah aplikasi kini bertanggung jawab untuk menyediakan semua fungsi pengelolaan akun dan melindungi semua data kredensial yang sensitif.

Autentikasi eksternal dengan OAuth2

Alternatif yang baik untuk menangani semua hal dalam aplikasi adalah dengan menggunakan layanan identitas eksternal, seperti Google, yang menangani semua informasi dan fungsi akun pengguna dan bertanggung jawab untuk mengamankan kredensial yang sensitif. Saat pengguna mencoba login ke aplikasi, permintaan akan dialihkan ke layanan identitas, yang mengautentikasi pengguna, lalu mengalihkan permintaan kembali ke aplikasi dengan menyediakan informasi autentikasi yang diperlukan. Untuk informasi selengkapnya, lihat Menggunakan OAuth 2.0 untuk Aplikasi Server Web.

Diagram berikut mengilustrasikan autentikasi eksternal dengan metode OAuth2.

Alur OAuth2

Alur dalam diagram dimulai saat pengguna mengirim permintaan untuk mengakses aplikasi. Aplikasi tidak mengalihkan browser pengguna ke platform identitas Google yang menampilkan halaman untuk login ke Google. Setelah berhasil login, browser pengguna akan diarahkan kembali ke aplikasi. Permintaan ini mencakup informasi yang dapat digunakan aplikasi untuk mencari informasi tentang pengguna yang telah diautentikasi, dan aplikasi kini merespons pengguna.

Metode ini memiliki banyak manfaat bagi aplikasi. Metode ini mendelegasikan semua fungsi dan risiko pengelolaan akun ke layanan eksternal, yang dapat meningkatkan keamanan login dan akun tanpa harus mengubah aplikasi. Namun, seperti yang ditunjukkan dalam diagram sebelumnya, aplikasi harus memiliki akses ke internet untuk menggunakan metode ini. Aplikasi juga bertanggung jawab untuk mengelola sesi setelah pengguna diautentikasi.

Identity-Aware Proxy

Pendekatan ketiga, yang dibahas dalam tutorial ini, adalah menggunakan IAP untuk menangani semua autentikasi dan pengelolaan sesi dengan perubahan apa pun pada aplikasi. IAP mencegat semua permintaan web ke aplikasi Anda, memblokir permintaan apa pun yang belum diautentikasi, dan meneruskan permintaan lainnya dengan data identitas pengguna yang ditambahkan ke setiap permintaan.

Penanganan permintaan ditampilkan dalam diagram berikut.

Alur IAP

Permintaan dari pengguna dicegat oleh IAP, yang memblokir permintaan yang tidak diautentikasi. Permintaan yang diautentikasi diteruskan ke aplikasi, asalkan pengguna yang diautentikasi tercantum dalam daftar pengguna yang diizinkan. Permintaan yang diteruskan melalui IAP memiliki header yang ditambahkan pada permintaan tersebut, yang mengidentifikasi pengguna yang membuat permintaan.

Aplikasi tidak perlu lagi menangani informasi akun atau sesi pengguna. Setiap operasi yang perlu mengetahui ID unik untuk pengguna bisa mendapatkannya secara langsung dari setiap permintaan web yang masuk. Namun, metode ini hanya dapat digunakan untuk layanan komputasi yang mendukung IAP, seperti App Engine dan load balancer. Anda tidak dapat menggunakan IAP di mesin pengembangan lokal.

Pembersihan

Agar akun Google Cloud Anda tidak ditagih atas resource yang digunakan dalam tutorial ini, hapus project yang berisi resource tersebut, atau simpan project dan hapus masing-masing resource.

  1. Di konsol Google Cloud, buka halaman Manage resource.

    Buka Manage resource

  2. Pada daftar project, pilih project yang ingin Anda hapus, lalu klik Delete.
  3. Pada dialog, ketik project ID, lalu klik Shut down untuk menghapus project.