Identitas Mutual TLS Dapat Hilang di Terminating Proxy

Sebuah layanan dapat mewajibkan sertifikat client pada endpoint publik, hanya menerima sertifikat yang berantai ke certificate authority yang disetujui, tetapi tetap meneruskan request yang pada akhirnya tidak terautentikasi ke aplikasi di belakangnya. Pemeriksaan TLS bisa saja sepenuhnya benar. Celah muncul ketika reverse proxy mengakhiri koneksi TLS tersebut lalu membuka koneksi lain menuju backend.

Mutual TLS mengautentikasi endpoint pada koneksi TLS tertentu. Ia tidak otomatis menempelkan identitas client yang sudah diautentikasi ke request HTTP setelah koneksi itu berakhir, dan koneksi TLS kedua tidak otomatis mewarisi peer dari koneksi pertama. Begitu proxy menjadi TLS server bagi client eksternal, proxy-lah komponen yang memiliki hasil verifikasi sertifikat client. Identitas backend yang diturunkan dari hasil tersebut harus melewati batas kepercayaan baru.

Batas ini mudah tertutupi karena deployment sering disebut secara umum sebagai “dilindungi mTLS”. Secara kriptografis, satu rute dapat terdiri dari dua channel independen dengan peer, credential, dan konsekuensi authorization yang berbeda.

Autentikasi client melekat pada satu koneksi TLS

Pada TLS 1.3, server meminta autentikasi client berbasis sertifikat melalui CertificateRequest. Client kemudian mengirim pesan Certificate dan membuktikan kepemilikan private key dengan CertificateVerify. Transcript handshake dan proses Finished mengikat pertukaran autentikasi tersebut ke sesi TLS itu.

Server lalu melakukan validasi sertifikat dan menerapkan kebijakan lokal. Bergantung pada deployment, pemeriksaan dapat mencakup chain validation, masa berlaku, issuer yang diizinkan, pemeriksaan nama atau extension, kebijakan revocation, serta pemetaan material sertifikat ke principal aplikasi.

Tidak satu pun dari fakta tersebut otomatis membuat objek identitas portabel pada level protokol.

Pertimbangkan layout edge berikut:

client
  |
  | TLS A: client <-> proxy
  | sertifikat client diverifikasi di sini
  v
reverse proxy
  |
  | TLS B: proxy <-> application
  | atau transport lokal tanpa TLS
  v
application

Aplikasi bukan peer pada TLS A. Jika TLS B memakai mutual authentication, sertifikat yang terlihat oleh aplikasi biasanya mengidentifikasi proxy sebagai client TLS B, bukan client eksternal asli. Jika TLS B hanya memakai server-authenticated TLS, aplikasi bahkan tidak menerima sertifikat client TLS.

Artinya, proxy mengubah arsitektur identitas meskipun method, path, dan body HTTP tidak berubah.

Metadata sertifikat yang diteruskan adalah sebuah assertion

Proxy dapat meneruskan informasi sertifikat tertentu ke backend melalui header HTTP atau channel metadata lain. Ini desain yang praktis, tetapi sifat keamanannya berbeda dari client-certificate authentication end-to-end.

Misalnya edge memverifikasi sertifikat eksternal lalu mengirim subject yang sudah dinormalisasi, issuer, serial number, fingerprint sertifikat, atau principal aplikasi yang diturunkan dari sertifikat. Backend tidak lagi memverifikasi bukti TLS client eksternal secara langsung. Backend mempercayai assertion proxy bahwa verifikasi sudah dilakukan dan identitas yang dikirim memang sesuai dengan peer pada koneksi eksternal.

Dengan demikian, proxy menjadi otoritas identitas bagi backend.

Model ini dapat aman jika arsitektur menjadikan peran tersebut eksplisit. Ia menjadi rapuh ketika backend menerima field identitas yang sama dari sumber yang tidak melewati proxy tepercaya. Request eksternal yang dapat mencapai aplikasi secara langsung, atau workload internal yang dapat menyisipkan header yang sama, dapat mengirim metadata yang sulit dibedakan dari assertion proxy.

Menghapus header masuk pada edge berguna, tetapi belum cukup. Backend juga memerlukan dasar tepercaya untuk memastikan request benar-benar datang dari proxy yang berwenang mengassert identitas. Penempatan jaringan dapat membantu, tetapi routability saja sering menjadi sinyal identitas yang lemah pada infrastruktur dinamis atau multi-tenant.

Susunan yang lebih kuat mengautentikasi channel proxy-to-backend dan hanya menerima metadata identitas melalui channel tersebut. Mutual TLS pada hop internal dapat mengautentikasi proxy, sementara nilai yang diteruskan mewakili client eksternal. Keduanya adalah identitas berbeda dengan peran berbeda.

Mutual TLS kedua tidak mempertahankan peer pertama

Menambahkan mutual TLS antara proxy dan aplikasi memang melindungi channel internal, tetapi tidak membuat sertifikat eksternal berlanjut secara kriptografis melintasi dua hop.

Pada TLS A, proxy memverifikasi kepemilikan private key client eksternal. Pada TLS B, aplikasi memverifikasi kepemilikan private key proxy. Aplikasi dapat memastikan request dikirim oleh proxy yang disetujui, tetapi dari TLS B saja aplikasi tidak dapat mengetahui client mana yang diautentikasi pada TLS A.

Perbedaan ini penting untuk authorization dan audit. Backend mungkin memerlukan dua fakta sekaligus:

transport peer: edge-proxy-17
asserted external principal: payments-worker-42

Menyatukannya menjadi satu field “client identity” menghilangkan provenance. Jika insiden kemudian melibatkan mapping rule yang salah, proxy yang dikompromikan, atau routing bypass, log yang menyimpan kedua identitas akan jauh lebih berguna untuk menelusuri rantai kepercayaan.

Perbedaan ini juga membatasi klaim non-repudiation. Catatan backend bahwa proxy mengassert principal tertentu bukan hal yang sama dengan backend ikut berpartisipasi dalam bukti sertifikat client eksternal.

Certificate forwarding memiliki risiko representasi

Meneruskan seluruh sertifikat client ke aplikasi dapat mempertahankan lebih banyak input untuk kebijakan downstream, tetapi juga membawa masalah parsing dan canonicalization. Field HTTP bersifat tekstual, sedangkan sertifikat X.509 adalah objek DER biner yang biasanya direpresentasikan dalam PEM atau encoding lain. Produk proxy juga berbeda dalam cara melakukan escaping, delimiter handling, representasi chain, dan penyertaan hasil verifikasi.

Backend yang mem-parsing ulang sertifikat yang diteruskan tidak boleh menganggap parsing yang berhasil sebagai bukti bahwa edge sudah memvalidasinya. Parsing hanya membuktikan struktur. Authentication membutuhkan statement tepercaya tentang hasil verifikasi edge, atau validasi sertifikat independen dengan kebijakan yang sesuai.

Meneruskan hanya subject distinguished name menghindari parsing sertifikat penuh, tetapi dapat menimbulkan ambiguitas lain. Distinguished name memiliki aturan perbandingan terstruktur dan banyak representasi tekstual. String tampilan mentah adalah principal key yang buruk kecuali proxy dan backend memiliki kontrak normalisasi yang persis sama.

Fingerprint memberi referensi stabil terhadap byte sertifikat tertentu, tetapi rotasi sertifikat akan mengubah fingerprint meskipun principal operasional tetap sama. Mapping berbasis subject atau SAN dapat bertahan terhadap reissue, namun keamanan kemudian bergantung pada kebijakan issuance dan keunikan identifier. CA yang dipercaya untuk banyak populasi mungkin terlalu luas untuk satu aplikasi tanpa constraint atau mapping eksplisit.

Karena itu, format metadata sebenarnya ikut menentukan model identitas, bukan sekadar format serialisasi.

Connection reuse memisahkan event handshake dari request

HTTP connection reuse menambah detail penting. Client authentication terjadi di layer TLS, sedangkan authorization biasanya diputuskan per request HTTP.

Jika beberapa request berjalan pada satu koneksi TLS yang sudah diautentikasi, peer certificate adalah state koneksi. Proxy dapat mengaitkan setiap request dengan peer tersebut selama implementasinya mempertahankan asosiasi dengan benar. Koneksi backend dapat di-pool dan digunakan ulang secara independen, bahkan untuk request dari banyak client eksternal.

Ini normal bagi terminating proxy, sekaligus menunjukkan bahwa backend tidak boleh menyamakan koneksi TLS internal dengan satu client eksternal. Satu koneksi proxy terautentikasi dapat membawa identity assertion untuk banyak caller.

Hal ini sangat penting pada sistem yang menyimpan authorization context pada scope koneksi. Backend yang melihat internal mTLS lalu menyimpan satu external principal pada pooled connection dapat tanpa sengaja menerapkan principal itu ke request berikutnya milik client lain. Identitas eksternal yang diteruskan proxy harus tetap bersifat request-scoped kecuali arsitektur transport benar-benar menjamin hubungan satu koneksi satu client.

TLS 1.3 juga memiliki post-handshake client authentication ketika dinegosiasikan, tetapi dukungan dan integrasinya bervariasi. Hal itu tidak mengubah batas dasarnya: autentikasi yang terjadi pada koneksi client-to-proxy tetap menjadi state koneksi tersebut sampai proxy meneruskan hasil yang dapat dipercaya.

Authorization harus jelas menyebut aktor yang dinilai

Backend di belakang identity-aware proxy dapat membuat beberapa keputusan authorization berbeda. Ia dapat mengotorisasi proxy sebagai infrastructure caller, mengotorisasi external principal yang diassert proxy, atau mensyaratkan keduanya.

Pemeriksaan ini menjawab pertanyaan keamanan yang berbeda. Autentikasi proxy mengontrol intermediary mana yang boleh membuat assertion identitas. Authorization external principal menentukan client asli mana yang boleh menjalankan aksi aplikasi. Menganggap salah satunya sebagai pengganti yang lain dapat menghasilkan privilege yang terlalu luas.

Sebagai contoh, memberikan privilege aplikasi hanya karena TLS B mengautentikasi edge proxy berarti identitas proxy secara efektif memiliki seluruh izin yang dapat dicapai melalui backend. Itu mungkin memang desain yang diinginkan bila seluruh enforcement berada di edge, tetapi harus dianggap sebagai keputusan trust yang eksplisit.

Sebaliknya, hanya memeriksa external principal yang diteruskan tanpa memeriksa provenance assertion berarti caller tak tepercaya dapat menjadi identity provider bagi dirinya sendiri jika ia bisa mencapai backend.

Kontrak aman biasanya terdiri dari dua tahap: pastikan intermediary yang mengassert identitas memang berwenang, lalu evaluasi principal yang diassert berdasarkan kebijakan aplikasi.

Perilaku failure menentukan batas efektif

Kebijakan sertifikat yang kuat dapat runtuh jika failure path melewati enforcement tersebut.

Proxy yang gagal memvalidasi sertifikat client tidak boleh mengisi field identitas seolah autentikasi berhasil. Backend yang mengharapkan asserted identity perlu mendefinisikan perilaku ketika field hilang, malformed, duplikat, atau tidak konsisten dengan metadata verifikasi. Fallback ke anonymous access mungkin valid untuk layanan campuran, tetapi route yang membutuhkan autentikasi harus memiliki kondisi terpisah yang fail closed.

Eksposur backend secara langsung merupakan failure mode lain. Firewall, service-mesh policy, private addressing, workload identity, atau authenticated internal TLS dapat membatasinya. Invarian pentingnya adalah request yang membawa proxy-asserted identity tidak boleh mencapai authorization logic melalui jalur tidak terautentikasi yang membiarkan sender mengontrol field assertion yang sama.

Perubahan operasional dapat merusak invarian ini tanpa mengubah kode aplikasi. Load balancer baru, health-check path, debugging ingress, sidecar configuration, atau migrasi antarlayer proxy dapat mengubah komponen mana yang mengakhiri TLS dan komponen mana yang menghapus atau membuat metadata identitas.

Karena itu, lokasi termination dan provenance assertion harus dianggap sebagai konfigurasi yang memiliki dampak keamanan, bukan detail jaringan transparan.

Certificate-bound token memperlihatkan batas koneksi yang sama

OAuth mutual-TLS certificate-bound access token membuat batas ini semakin jelas. RFC 8705 mengikat access token ke client certificate, biasanya melalui SHA-256 certificate thumbprint. Pada protected resource, sertifikat yang digunakan untuk mutual TLS harus cocok dengan sertifikat yang diasosiasikan dengan token.

Terminating proxy generik dapat mengganggu sifat ini. Jika protected resource hanya melihat TLS dari proxy, layer TLS-nya melihat sertifikat proxy, bukan sertifikat yang private key-nya dibuktikan oleh client eksternal. Meneruskan header yang berisi sertifikat eksternal saja tidak otomatis menciptakan ulang bukti possession yang diminta desain certificate-bound token.

Deployment dapat menempatkan verifikasi token binding pada komponen yang benar-benar mengakhiri koneksi mutual TLS eksternal, lalu meneruskan hasil yang sudah diautentikasi ke downstream service melalui trust model terpisah. Arsitektur lain dapat mempertahankan TLS termination langsung pada resource yang melakukan binding check.

Intinya, komponen yang mengklaim bukti possession harus memiliki akses ke sertifikat dari koneksi TLS tempat proof tersebut benar-benar terjadi.

Persyaratan ini lebih ketat daripada identity forwarding biasa karena sertifikat bukan sekadar identifier; ia merupakan bagian dari syarat proof-of-possession token.

Lokasi termination adalah bagian dari security model

Mutual TLS dapat memberikan autentikasi client yang kuat, tetapi cakupannya presisi: peer diautentikasi terhadap server endpoint pada koneksi TLS tertentu. Pada terminating proxy, proxy-lah endpoint itu. Semua yang terjadi setelah termination adalah hubungan keamanan terpisah.

Hal ini tidak membuat proxy termination secara inheren tidak aman. Namun proxy menjadi security principal dengan tugas yang konkret: memvalidasi sertifikat eksternal sesuai kebijakan, menurunkan identitas tanpa mapping ambigu, mencegah injection metadata identitas, mengautentikasi dirinya ke downstream service bila diperlukan, mempertahankan provenance per request, dan gagal secara aman ketika kontrak assertion tidak terpenuhi.

Arsitektur lebih mudah dianalisis ketika kedua sisi setiap batas disebut secara eksplisit. Client eksternal mengautentikasi dirinya ke edge. Edge mengautentikasi dirinya ke backend. Backend mempercayai edge tertentu untuk mengassert external principal. Authorization kemudian bekerja terhadap aktor yang memang dimaksud, bukan terhadap sertifikat apa pun yang kebetulan terlihat pada koneksi TLS terdekat.