Quarkus Security - TLS mutual antara dua aplikasi Quarkus
Kita akan membahas cara untuk secara manual mengatur enkripsi TLS mutual antara dua aplikasi Quarkus, baik di bare metal maupun di Kubernetes.
Apa itu Autentikasi TLS Mutual?
Autentikasi TLS mutual, atau autentikasi dua arah, adalah perpanjangan dari Transport Layer Security (TLS). Ini memastikan bahwa lalu lintas antara klien dan server aman dan tepercaya dalam kedua arah.
Mengapa TLS Mutual?
TLS mutual memberikan lapisan keamanan tambahan yang memverifikasi tidak hanya identitas server tetapi juga identitas klien.
Bagaimana Cara Mengimplementasikannya?
Pendekatan terbaik untuk mengimplementasikan Mutual TLS antara dua layanan adalah dengan mendelegasikannya ke infrastruktur, misalnya, Service Mesh. Ini mencapai cara komunikasi yang standar dan aman serta menghindari setiap aplikasi mengimplementasikan solusinya sendiri. Namun, adakalanya kita tidak selalu bekerja di lingkungan yang ideal.
Mari kita lihat bagaimana mengimplementasikan mTLS dengan Quarkus jika kita tidak memiliki lingkungan service mesh seperti Istio.
Penyiapan Awal
Mari kita buat kedua aplikasi server dan klien yang akan kita amankan.1. Buat quarkus-server-mtls
mvn io.quarkus:quarkus-maven-plugin:1.4.1.Final:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=quarkus-server-mtls \
-DclassName="org.acme.server.mtls.GreetingResource" \
-Dextensions="rest-client, resteasy-jsonb, kubernetes-client" \
-Dpath="/hello-server"
Berikut adalah penjelasan tentang perintah Maven yang kita berikan dalam konteks pengaturan aplikasi server Quarkus untuk mTLS:
Perintah Maven ini digunakan untuk membuat proyek baru Quarkus untuk aplikasi sisi server dengan konfigurasi mTLS. Berikut adalah penjelasan dari setiap parameter yang digunakan:
mvn io.quarkus:quarkus-maven-plugin:1.4.1.Final:create
- Menggunakan plugin Maven Quarkus untuk membuat proyek baru.-DprojectGroupId=org.acme
- Menetapkan ID grup proyek.-DprojectArtifactId=quarkus-server-mtls
- Menamai artefak proyek khusus untuk server mTLS.-DclassName="org.acme.server.mtls.GreetingResource"
- Membuat kelas sumber daya REST di paket yang ditentukan.-Dextensions="rest-client, resteasy-jsonb, kubernetes-client"
- Menambahkan ekstensi penting:rest-client
untuk melakukan permintaan HTTP.resteasy-jsonb
untuk pemrosesan JSON.kubernetes-client
untuk integrasi dengan Kubernetes.
-Dpath="/hello-server"
- Menetapkan jalur dasar untuk endpoint REST.
Catatan: Kita mungkin ingin mempertimbangkan untuk menggunakan versi yang lebih baru dari plugin Maven Quarkus, kecuali jika kita secara khusus memerlukan versi 1.4.1.Final untuk alasan kompatibilitas.
2. Buat quarkus-client-mtls
mvn io.quarkus:quarkus-maven-plugin:1.4.1.Final:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=quarkus-client-mtls \
-DclassName="org.acme.client.mtls.GreetingResource" \
-Dextensions="rest-client, resteasy-jsonb, kubernetes-client" \
-Dpath="/hello-client"
Berikut adalah penjelasan tentang perintah Maven untuk aplikasi klien:
Perintah Maven ini digunakan untuk membuat aplikasi klien yang akan berkomunikasi dengan aplikasi server menggunakan mTLS. Berikut penjelasan detailnya:
mvn io.quarkus:quarkus-maven-plugin:1.4.1.Final:create
- Menggunakan plugin Maven Quarkus yang sama untuk membuat proyek-DprojectGroupId=org.acme
- ID grup yang sama dengan server untuk konsistensi-DprojectArtifactId=quarkus-client-mtls
- Nama artefak khusus untuk klien mTLS (berbeda dengan server)-DclassName="org.acme.client.mtls.GreetingResource"
- Membuat kelas di paket client.mtls (membedakan dari server)-Dextensions="rest-client, resteasy-jsonb, kubernetes-client"
- Ekstensi yang sama:rest-client
untuk membuat permintaan HTTP ke serverresteasy-jsonb
untuk pemrosesan JSONkubernetes-client
untuk integrasi Kubernetes
-Dpath="/hello-client"
- Jalur endpoint untuk klien (berbeda dari server yang menggunakan "/hello-server")
Perbedaan utama dari aplikasi server:
- Artefak ID:
quarkus-client-mtls
vsquarkus-server-mtls
- Package:
org.acme.client.mtls
vsorg.acme.server.mtls
- Path endpoint:
/hello-client
vs/hello-server
Mengapa diperlukan kedua aplikasi?
Untuk mTLS, kedua pihak (server dan klien) perlu saling mengautentikasi. Server akan memverifikasi sertifikat klien, dan klien akan memverifikasi sertifikat server.
3. Pembuatan Sertifikat dan Truststore
Tentu saja memerlukan sertifikat untuk server dan klien, serta truststore :
3.1 Membuat Sertifikat untuk Server:
Perintah berikut digunakan untuk menghasilkan pasangan kunci (key pair) untuk sertifikat server:
$ keytool -genkeypair -storepass password -keyalg RSA -keysize 2048 -dname "CN=server" -alias server -ext "SAN:c=DNS:localhost,IP:127.0.0.1" -keystore quarkus-server-mtls/src/main/resources/META-INF/resources/server.keystore
Penjelasan:
- storepass password: Menetapkan kata sandi untuk keystore.
- keyalg RSA: Menggunakan algoritma RSA untuk kunci.
- keysize 2048: Ukuran kunci 2048 bit.
- dname "CN=server": Menetapkan nama subjek untuk sertifikat.
- alias server: Menetapkan alias untuk sertifikat.
- ext "SAN:c=DNS:localhost,IP:127.0.0.1": Menetapkan Subject Alternative Name (SAN) untuk sertifikat.
- keystore : Menentukan lokasi keystore untuk menyimpan sertifikat.
3.2 Membuat Sertifikat untuk Client:
Perintah berikut digunakan untuk menghasilkan pasangan kunci untuk sertifikat klien:
$ keytool -genkeypair -storepass password -keyalg RSA -keysize 2048 -dname "CN=client" -alias client -ext "SAN:c=DNS:localhost,IP:127.0.0.1" -keystore quarkus-client-mtls/src/main/resources/META-INF/resources/client.keystore
Penjelasan:
Pembuatan Sertifikat Dengan Keytool |
Parameter yang digunakan sama dengan yang di atas, tetapi dengan nama subjek dan alias yang berbeda.
Membuat Truststore:
Untuk contoh ini, kita akan mensimulasikan truststore menggunakan:
client.keystore
sebagai truststore untuk aplikasi server.server.keystore
sebagai truststore untuk aplikasi klien.
Kita dapat menyalin keystore ke truststore dengan perintah berikut (bila anda buat tidak dalam project sebelumnya, pada case saya ini semua sudah pada project masing masing, lihat gambar):
$ cp quarkus-server-mtls/src/main/resources/META-INF/resources/server.keystore quarkus-client-mtls/src/main/resources/META-INF/resources/client.truststore$ cp quarkus-client-mtls/src/main/resources/META-INF/resources/client.keystore quarkus-server-mtls/src/main/resources/META-INF/resources/server.truststore
Membuat Truststore |
Dengan langkah-langkah ini, kita telah berhasil membuat sertifikat dan truststore yang diperlukan untuk mengatur mTLS antara aplikasi server dan klien. Selanjutnya mari kita melanjutkan dengan langkah-langkah konfigurasi lebih lanjut
Aplikasi Server Hello
Mari kita buka dan konfigurasi aplikasi server quarkus-server-mtls
.
Mengaktifkan SSL pada Aplikasi Hello Server
Tambahkan properti berikut untuk mengaktifkan SSL di file src/main/resources/application.properties
:
quarkus.ssl.native=true
quarkus.http.ssl-port=8443
quarkus.http.ssl.certificate.key-store-file=META-INF/resources/server.keystore
quarkus.http.ssl.certificate.key-store-password=password
quarkus.http.port=0
quarkus.http.test-port=0
Anda dapat melihat panduan Using SSL with Native untuk menjelajahi lebih dalam tentang cara kerja SSL di Quarkus.
Mengaktifkan Autentikasi Klien
Tambahkan properti berikut ke file application.properties
untuk mengaktifkan autentikasi klien:
quarkus.http.ssl.client-auth=required
quarkus.http.ssl.certificate.trust-store-file=META-INF/resources/server.truststore
quarkus.http.ssl.certificate.trust-store-password=password
Penjelasan:
- quarkus.http.ssl.client-auth=required: Mengharuskan autentikasi
- klien.quarkus.http.ssl.certificate.trust-store-file: Menentukan lokasi truststore untuk sertifikat klien.
- quarkus.http.ssl.certificate.trust-store-password: Menetapkan kata sandi untuk truststore.
Memperbaru GreetingResource di Applikasi Server
Untuk lebih jelas bahwa respons berasal dari aplikasi server, kita akan memperbarui kelas org.acme.server.mtls.GreetingResource
:
package org.acme.server.mtls;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/hello-server")
public class GreetingResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello from server";
}
}
Memperbarui Kelas Uji
Perbarui kelas uji org.acme.server.mtls.GreetingResourceTest
:
package org.acme.server.mtls;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
public class GreetingResourceTest {
@Test
public void testHelloEndpoint() {
given()
.when().get("/hello-server")
.then()
.statusCode(200)
.body(is("hello from server"));
}
}
Gantilah pencocokan (matcher) dengan "hello from server".
Jalankan Project Server
Dengan Maven CLI
mvn quarkus:dev
Atau langsung dari GUI IntelliJ IDEA.
Server Berjalan |
Server Berjalan 2 |
Curl ke server dengan -k |
Perintah curl Anda berfungsi karena:
- Endpoint /hello-server diekspos oleh kelas GreetingResource.
- Server berjalan dengan SSL diaktifkan pada port 8443, seperti yang dikonfigurasi dalam application.properties.
- Flag -k dalam curl memungkinkan koneksi SSL yang tidak aman (ia melewati verifikasi sertifikat).
- Endpoint mengembalikan teks biasa "hello from server" seperti yang diharapkan.
- Semuanya berfungsi sesuai dengan konfigurasi.
Anda tidak akan mendapatkan kesalahan curl: (35) ... sslv3 alert bad certificate karena server Anda dikonfigurasi untuk SSL (HTTPS) tetapi tidak untuk mutual TLS (mTLS). Konfigurasi saat ini dalam application.properties hanya mengharuskan server untuk menyajikan sertifikatnya kepada klien. Klien (curl) tidak diharuskan untuk menyajikan sertifikat, sehingga koneksi berhasil.
Memaksa MTLS Dari Client
Jika Anda ingin menerapkan mTLS (mengharuskan klien untuk menyajikan sertifikat yang valid), Anda perlu mengonfigurasi server untuk mengharuskan dan memvalidasi sertifikat klien. Ini biasanya melibatkan pengaturan properti seperti pada application.properties:
# Enforce client certificate authentication
quarkus.http.ssl.client-auth=required
Sekarang mengharuskan klien untuk menyajikan sertifikat yang valid |
Aplikasi Client Hello
Buka Aplikasi Client MTLS |
Pada titik ini, aplikasi server sudah siap untuk melaksanakan Mutual TLS. Mari kita buka dan konfigurasi klien quarkus-client-mtls.
Update application.properties milik Client
Buka src/main/resources/application.properties pada project quarkus-client-mtls.Untuk mengonfigurasi klien REST MicroProfile untuk Mutual TLS, tambahkan properti berikut:org.acme.client.mtls.GreetingService/mp-rest/url=https://localhost:8443
org.acme.client.mtls.GreetingService/mp-rest/trustStore=classpath:/META-INF/resources/client.truststore
org.acme.client.mtls.GreetingService/mp-rest/trustStorePassword=password
org.acme.client.mtls.GreetingService/mp-rest/keyStore=classpath:/META-INF/resources/client.keystore
org.acme.client.mtls.GreetingService/mp-rest/keyStorePassword=password
quarkus.ssl.native=true
Tambahkan Mockito pada Client
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-mockito</artifactId>
</dependency>
Update Unit Test MIlik Client
package org.acme.client.mtls;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
public class GreetingResourceTest {
@Test
public void testHelloEndpoint() {
given()
.when().get("/hello-client")
.then()
.statusCode(200)
.body(is("hello from server"));
}
}
Buat GreetingService Interface
package org.acme.client.mtls;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/")
@ApplicationScoped
@RegisterRestClient
public interface GreetingService {
@GET
@Path("/hello-server")
@Produces(MediaType.TEXT_PLAIN)
String hello();
}
Update GreetingResource
package org.acme.client.mtls;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/hello-client")
public class GreetingResource {
@Inject
@RestClient
GreetingService greetingService;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return greetingService.hello();
}
}
Error Saat Akses Di Browser
Ada beberapa hal diatas tidak langsung saya perbaiki karena error akan memberi kita pelajaran berharga.
akses http://localhost:8080/hello-clientError di http://localhost:8080/hello-client |
"Internal Server Error Error handling 88ca9a86-338d-4c8a-a12c-18f6745394d2-2, org.jboss.resteasy.spi.UnhandledException: javax.ws.rs.ProcessingException: RESTEASY004655: Unable to invoke request: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate."
Kesalahan ini menunjukkan kegagalan handshake SSL karena sertifikat klien yang buruk atau hilang. Dalam klien REST Quarkus atau Java yang menggunakan mutual TLS (mTLS), ini biasanya berarti:
- Klien tidak menyajikan sertifikat yang valid.
- Server menolak sertifikat (kedaluwarsa, tidak tepercaya, atau CN yang salah).
- Keystore/truststore klien dikonfigurasi dengan salah.
Cara Memperbaiki:
- Pastikan klien dikonfigurasi untuk mengirim sertifikat yang valid.
- Periksa bahwa jalur keystore dan truststore, kata sandi, dan tipe sudah benar dalam konfigurasi aplikasi Anda (misalnya, application.properties).
- Pastikan server mempercayai sertifikat klien (CA atau sertifikat yang ditandatangani sendiri).
- Verifikasi keabsahan sertifikat (tidak kedaluwarsa, subjek yang benar, dll.).
Aktifkan Debug Mode
-Djavax.net.debug=ssl:handshake |
Ulangi Pembuatan Keystore diatas
$ keytool -genkeypair -storepass password -keyalg RSA -keysize 2048 -dname "CN=server" -alias server -ext "SAN:c=DNS:localhost,IP:127.0.0.1" -keystore quarkus-server-mtls/src/main/resources/META-INF/resources/server.keystore $ keytool -genkeypair -storepass password -keyalg RSA -keysize 2048 -dname "CN=client" -alias client -ext "SAN:c=DNS:localhost,IP:127.0.0.1" -keystore quarkus-client-mtls/src/main/resources/META-INF/resources/client.keystore
$ cp quarkus-server-mtls/src/main/resources/META-INF/resources/server.keystore quarkus-client-mtls/src/main/resources/META-INF/resources/client.truststore$ cp quarkus-client-mtls/src/main/resources/META-INF/resources/client.keystore quarkus-server-mtls/src/main/resources/META-INF/resources/server.truststore
Update application.properties server seperti ini (cek bedanya dengan diatas)
quarkus.ssl.native=true
quarkus.http.ssl-port=8443
# Server keystore (server identity)
quarkus.http.ssl.certificate.key-store-file=META-INF/resources/server.keystore
quarkus.http.ssl.certificate.key-store-password=password
# Server truststore (CA untuk client certificates)
quarkus.http.ssl.certificate.trust-store-file=META-INF/resources/server.truststore
quarkus.http.ssl.certificate.trust-store-password=password
quarkus.http.port=0
quarkus.http.test-port=0
# Enforce client certificate authentication
quarkus.http.ssl.client-auth=required
Update application.properties client seperti ini (cek bedanya dengan diatas)
org.acme.client.mtls.GreetingService/mp-rest/url=https://localhost:8443
org.acme.client.mtls.GreetingService/mp-rest/trustStore=classpath:/META-INF/resources/client.truststore
org.acme.client.mtls.GreetingService/mp-rest/trustStorePassword=password
org.acme.client.mtls.GreetingService/mp-rest/keyStore=classpath:/META-INF/resources/client.keystore
org.acme.client.mtls.GreetingService/mp-rest/keyStorePassword=password
quarkus.ssl.native=true
Hasilnya
Dengan curl dari terminal.
Dari Terminal |
Dengan akses dari browser.
Dari Browser |
Dengan Unit Test
Kata Penutup
Dalam tutorial ini, kita telah membahas
langkah-langkah penting untuk mengonfigurasi klien REST MicroProfile
dengan Mutual TLS (mTLS) dalam aplikasi Quarkus. Kita telah menjelaskan
pengaturan yang diperlukan dalam file application.properties
, serta langkah-langkah untuk memecahkan masalah yang mungkin muncul selama proses handshake SSL.
Dengan memahami dan menerapkan konfigurasi yang tepat, kita dapat memastikan bahwa komunikasi antara klien dan server berlangsung dengan aman dan terjamin. mTLS adalah metode yang efektif untuk meningkatkan keamanan aplikasi kita, terutama dalam lingkungan yang memerlukan otentikasi yang kuat.
Kami berharap tutorial ini bermanfaat dan membantu dalam mengimplementasikan mTLS dalam proyek Anda. Jika Anda memiliki pertanyaan lebih lanjut atau mengalami kesulitan, jangan ragu untuk mencari bantuan dari komunitas atau dokumentasi resmi Quarkus. Selamat berkarya dan semoga sukses dalam pengembangan aplikasi Anda!
- https://quarkus.io/blog/quarkus-mutual-tls/
Comments
Post a Comment