Episode ini mengamankan otorisasi: kontrol akses level method, enforcement policy yang terpusat, audit logging dan perlindungan metadata sensitif, serta rate limiting, circuit breaking, dan proteksi dari serangan Denial of Service di layanan gRPC.

Autentikasi menjawab "siapa kalian?". Authorization menjawab pertanyaan yang lebih penting: "apa yang boleh kalian lakukan?". Seorang user yang sah belum tentu berhak menghapus produk. Episode 12 membangun lapisan otorisasi, audit, dan pertahanan yang membuat service gRPC benar-benar aman.
Kita membahas kontrol akses level method, enforcement policy yang terpusat, audit logging yang mencatat siapa melakukan apa, perlindungan metadata sensitif, lalu pertahanan terhadap penyalahgunaan: rate limiting, circuit breaking, dan mitigasi DoS.
Pola paling umum: Role-Based Access Control (RBAC). Klaim di dalam JWT (episode 11) dipetakan ke peran, lalu peran dipetakan ke method yang boleh dipanggil:
var accessRules = map[string]string{
"catalog.v1.CatalogService/GetProduct": "user",
"catalog.v1.CatalogService/ListProducts": "user",
"catalog.v1.CatalogService/AddBulk": "admin",
"catalog.v1.CatalogService/UpdatePrice": "admin",
}Dengan peta di atas, GetProduct bisa dipanggil role user, sedangkan AddBulk dan UpdatePrice hanya untuk admin. Method yang tidak terdaftar bisa diatur kebijakan defaultnya — misalnya ditolak.
Enforcement dilakukan di server interceptor agar satu tempat mengontrol seluruh service:
func authorize(ctx context.Context, fullMethod string) error {
role := roleFromClaims(ctx)
required, ok := accessRules[fullMethod]
if !ok {
return status.Error(codes.PermissionDenied, "method tidak dikenali")
}
if role != required && role != "superadmin" {
return status.Error(codes.PermissionDenied, "hak akses tidak cukup")
}
return nil
}Fungsi authorize(ctx, fullMethod) membaca role dari klaim, mencocokkan dengan peta, dan menolak dengan codes.PermissionDenied bila tidak cocok. Panggil fungsi ini sebelum handler di interceptor server.
Policy yang keras-coded sulit diubah dan sulit diaudit. Pindahkan ke konfigurasi eksternal — file YAML yang dibaca saat startup:
methods:
- path: catalog.v1.CatalogService/GetProduct
roles: [user, admin, superadmin]
- path: catalog.v1.CatalogService/AddBulk
roles: [admin, superadmin]
- path: catalog.v1.CatalogService/UpdatePrice
roles: [admin, superadmin]Dengan roles: [admin, superadmin] di file terpisah, perubahan kebijakan cukup deploy konfigurasi baru tanpa mengompilasi ulang server. Pendekatan ini berkembang menjadi Authorization Policy yang dikelola service mesh di episode 18.
Setiap perubahan data penting harus tercatat. Interceptor unary bisa menangkap seluruh konteks panggilan:
func auditInterceptor(ctx context.Context, req any,
info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
identity := identityFromContext(ctx)
res, err := handler(ctx, req)
audit.Log(identity, info.FullMethod, req, err)
return res, err
}audit.Log(identity, info.FullMethod, req, err) menulis baris audit: siapa memanggil, method apa, payload apa, dan hasilnya. Simpan ke storage append-only yang tidak bisa diubah pemanggil — misalnya log terpusat atau object storage.
Jangan pernah menulis token atau kredensial ke dalam log. Token ada di metadata authorization, bukan di payload — pastikan audit logging tidak menyertakan metadata mentah. Jika perlu untuk investigasi, hash dulu atau potong sebagian.
Rate limiting mencegah satu klien membanjiri server. Token bucket memberi jatah request per detik per identitas:
func rateLimit(identity string) error {
limiter, ok := buckets[identity]
if !ok {
limiter = rate.NewLimiter(rate.Limit(20), 40)
buckets[identity] = limiter
}
if !limiter.Allow() {
return status.Error(codes.ResourceExhausted, "terlalu banyak request")
}
return nil
}rate.NewLimiter(rate.Limit(20), 40) mengizinkan 20 request per detik dengan burst 40. Pelanggaran dijawab codes.ResourceExhausted sehingga client tahu harus menunggu, bukan sekadar gagal.
Tiga lapisan pertahanan lain yang wajib:
MaxRecvMsgSize agar pesan raksasa tidak menghabiskan memori.s := grpc.NewServer(
grpc.MaxRecvMsgSize(4*1024*1024),
grpc.MaxSendMsgSize(4*1024*1024),
)Pengaturan MaxRecvMsgSize(4*1024*1024) membatasi pesan masuk sebesar 4 MiB. Kombinasi ini menahan serangan DoS tingkat aplikasi tanpa menunggu jaringan bermasalah.
Inti yang harus dibawa pulang:
ResourceExhausted.Di episode 13 selanjutnya kita membahas performansi dan optimasi gRPC — mengukur latency dan throughput dengan ghz, optimasi lewat compression dan connection reuse, penanganan backpressure, serta menyusun message protobuf yang efisien dengan packed fields dan repeated fields. Keamanan yang solid sekarang diimbangi dengan kecepatan yang terukur.