Studi Kasus: Mengamankan API gRPC Internal
Dalam era modern pengembangan perangkat lunak, API gRPC semakin populer berkat performa, efisiensi serialisasi data, serta dukungan multi bahasa. gRPC banyak digunakan untuk service-to-service communication dalam arsitektur microservices, baik pada aplikasi cloud-native maupun enterprise. Namun, mengamankan API gRPC, terutama untuk konsumsi internal, sering kali dianggap remeh. Banyak tim development yang berasumsi bahwa API internal aman dari ancaman eksternal karena berada di dalam trusted network. Nyatanya, ada beragam skenario yang dapat mengekspos API internal pada risiko serius.
Artikel ini akan membahas studi kasus penerapan keamanan pada API gRPC internal. Kita akan mengeksplorasi ancaman utama, strategi mitigasinya, serta contoh kode dan arsitektur real-world yang bisa langsung diadopsi untuk mengamankan ekosistem gRPC-mu.
Ancaman pada API Internal
Banyak insiden keamanan besar dalam dua dekade terakhir karena kepercayaan berlebihan pada internal perimeter. Berikut ancaman umum pada API internal:
| Ancaman | Penjelasan |
|---|---|
| Lateral Movement | Penyerang yang berhasil masuk ke salah satu service/VM dapat berpindah ke service lain. |
| Data Leakage | Tanpa enkripsi, data sensitif dapat di-sniff di jaringan internal. |
| Unauthorized Access | Tidak ada otentikasi/authorization sehingga service manapun bisa mengakses API internal. |
| Privilege Escalation | Service dengan hak akses terlalu luas bisa digunakan sebagai pintu masuk penyerang. |
| Service Impersonation | Penyerang menyamar sebagai service internal menggunakan custom client. |
Studi Kasus: Payroll Service
Mari asumsikan sebuah arsitektur microservices sederhana di internal perusahaan fintech. Salah satu service penting adalah PayrollService, bertugas memproses gaji karyawan. Service ini hanya boleh diakses oleh HRService dan FinanceService.
Diagram Arsitektur
flowchart LR
subgraph Internal Network
HRService
FinanceService
PayrollService
end
HRService -- gRPC call --> PayrollService
FinanceService -- gRPC call --> PayrollService
1. Mengaktifkan TLS pada gRPC
Secara default, gRPC menggunakan HTTP/2 tanpa harus TLS aktif (plaintext), namun ini rawan sniffing di internal LAN. Wajib hukumnya mengaktifkan TLS pada semua komunikasi gRPC, bahkan di internal.
Contoh Implementasi TLS di Go
Generate certificate:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=payroll.internal"
PayrollServer.go
import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
func main() {
creds, err := credentials.NewServerTLSFromFile("cert.pem", "key.pem")
if err != nil { log.Fatalf("failed to load cert: %v", err) }
grpcServer := grpc.NewServer(grpc.Creds(creds))
// register your service implementation...
}
Client dengan TLS:
conn, err := grpc.Dial(
"payroll.internal:50051",
grpc.WithTransportCredentials(credentials.NewClientTLSFromFile("cert.pem", "")),
)
Jangan pernah deploy service gRPC, bahkan di internal, tanpa TLS!
2. Service Authentication dan Mutual TLS (mTLS)
TLS melindungi data in-transit, namun tidak memastikan siapa klien atau server. Dengan mutual TLS, kedua pihak harus memperlihatkan digital certificate valid yang diterbitkan CA terpercaya.
Implementasi mTLS: PayrollService hanya menerima permintaan dari service yang sudah di-whitelist.
Generate CA, server dan client certificate
# Generate CA
openssl genrsa -out ca.key 4096
openssl req -x509 -new -key ca.key -sha256 -out ca.crt -subj "/CN=companyCA"
# Server key dan CSR
openssl genrsa -out payroll.key 4096
openssl req -new -key payroll.key -out payroll.csr -subj "/CN=payroll.internal"
openssl x509 -req -in payroll.csr -CA ca.crt -CAkey ca.key -out payroll.crt -CAcreateserial
# Client (misal HRService)
openssl genrsa -out hr.key 4096
openssl req -new -key hr.key -out hr.csr -subj "/CN=hr.internal"
openssl x509 -req -in hr.csr -CA ca.crt -CAkey ca.key -out hr.crt -CAcreateserial
Server (Go):
creds, _ := credentials.NewTLS(&tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert,
Certificates: []tls.Certificate{serverCert},
ClientCAs: caCertPool, // berisi ca.crt
})
grpcServer := grpc.NewServer(grpc.Creds(creds))
Client (Go):
creds, _ := credentials.NewTLS(&tls.Config{
Certificates: []tls.Certificate{clientCert}, // hr.crt & hr.key
RootCAs: caCertPool, // ca.crt
})
conn, _ := grpc.Dial(serverAddr, grpc.WithTransportCredentials(creds))
Dengan skema ini, payroll service yakin yang terkoneksi adalah client terpercaya. Bila ada service lain mencoba connect tanpa sertifikat CA, request akan otomatis ditolak.
3. Authorization Layer: Membatasi Service yang Boleh Akses
Meskipun service sudah terautentikasi via mTLS, perlu juga authorization agar service hanya mengakses resource yang berhak.
Kita dapat menerapkan interceptors pada server untuk memeriksa CN (Common Name) dari sertifikat client.
Contoh Interceptor di Go:
import (
"google.golang.org/grpc"
"google.golang.org/grpc/peer"
)
func authorizeInterceptor(
ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (interface{}, error) {
p, ok := peer.FromContext(ctx)
if !ok { return nil, status.Errorf(codes.PermissionDenied, "No peer found") }
tlsInfo, ok := p.AuthInfo.(credentials.TLSInfo)
if !ok { return nil, status.Errorf(codes.PermissionDenied, "No TLS auth info") }
cn := tlsInfo.State.PeerCertificates[0].Subject.CommonName
if cn != "hr.internal" && cn != "finance.internal" {
return nil, status.Errorf(codes.PermissionDenied, "Unauthorized service: %s", cn)
}
return handler(ctx, req)
}
grpcServer := grpc.NewServer(grpc.Creds(creds), grpc.UnaryInterceptor(authorizeInterceptor))
4. Audit dan Rate Limit
Kombinasi audit log dan rate limit dapat membatasi peluang abuse, terutama pada API payroll yang sangat sensitif.
- Implementasi rate limiter sisi server misal dengan ratelimit library.
- Simpan audit log setiap request beserta client CN agar traceable jika terjadi insiden.
5. Summary Best Practices
| Praktik | Rekomendasi |
|---|---|
| Transport security | Selalu gunakan TLS, meski di “trusted” network |
| Service identity | Terapkan mTLS dan PKI internal |
| Authorization | Validasi CN di setiap request, whitelist service tertentu |
| Rate Limit | Batasi frekuensi call ke API sensitif |
| Audit Log | Catat semua call beserta identitas ke dalam log terproteksi |
| Cert management | Otomatiskan rotasi dan distribusi certificate, misal via cert-manager |
Flow Data Protection PayrollService
sequenceDiagram
participant HR as HRService (Client)
participant PS as PayrollService (Server)
Note left of HR: Hold mTLS Cert (CN=hr.internal)
Note right of PS: Hold mTLS Cert (CN=payroll.internal)
HR->>PS: Initiate gRPC TLS handshake
HR-->>PS: Present client cert
PS-->>HR: Present server cert
PS->>PS: Verify client CN == Whitelist
HR->>PS: PayrollRequest (berhasil jika mTLS & CN OK)
PS-->>HR: PayrollResponse
Note over HR,PS: Semua data terenkripsi & terotorisasi end-to-end
Kesimpulan
Meskipun gRPC biasanya diterapkan pada internal service, menganggap API internal aman bagaikan menganggap rumah tanpa pintu cukup karena berada di lingkungan “aman”. Nyatanya, ancaman siber berkembang; peluang lateral movement, sniffing, hingga eksfiltrasi data bisa terjadi kapan saja. Penerapan TLS, mTLS, authorization per service, serta audit log sudah menjadi minimum viable security pada ekosistem gRPC internal.
Mulailah dengan mengaktifkan TLS hari ini. Lanjutkan ke mTLS dan selanjutnya, otomasikan deployment sertifikat via proper secret management. Budayakan zero trust – waspadai serangan dari dalam dan luar perimeter. Saat insiden terjadi, audit log adalah penyelamat. Semoga dengan studi kasus PayrollService ini, Anda lebih siap membangun gRPC internal yang secure by design.
Referensi:
- gRPC Security Best Practices
- Google BeyondCorp: Zero Trust Model
- Zero Trust Microservices Architecture Patterns