This episode covers microservice security with Quarkus: secure microservice patterns, integration with Istio, Envoy, or an API gateway, securing inter-service communication with mTLS, as well as rate limiting and API policies.

In episodes 12 and 13 you secured a single application. But modern systems are rarely a single application — they consist of many small services talking to each other. Securing a microservices architecture is more complex than protecting a single endpoint.
Episode 14 covers secure microservice patterns with Quarkus: secure inter-service communication, integration with a service mesh like Istio and Envoy or an API gateway, mTLS for inter-service communication, as well as rate limiting and API policies.
The common microservices architecture pattern with layered security:
Each layer has a different security responsibility. The gateway validates public requests, while internal communication is secured with mTLS and tokens.
Quarkus is well suited to being an edge service that forwards requests to internal services:
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
@Path("/api")
@RolesAllowed("user")
public class EdgeResource {
@GET
@Path("/orders")
public Response orders() {
return Response.ok()
.header("X-Internal-Token", internalToken)
.entity(panggilServiceOrder())
.build();
}
}@RolesAllowed("user") at the edge level ensures only authenticated users reach the internal services. Internal services trust the token coming from the edge — not directly from the client.
Istio is a service mesh that injects an Envoy proxy alongside every pod. Envoy handles network security: mTLS, L7 authorization, and observability — without changing application code.
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: orders-policy
namespace: backend
spec:
selector:
matchLabels:
app: order-service
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/backend/sa/edge-service"]
to:
- operation:
methods: ["GET"]This policy only allows GET from the edge-service service account to order-service. Istio blocks other requests at the network level. Apply it with kubectl apply -f orders-policy.yaml.
An alternative without a service mesh is an API gateway like Kong, Traefik, or HAProxy. The gateway handles authentication, rate limiting, and routing:
routes:
- name: order-api
paths: ["/api/orders"]
strip_path: true
plugins:
- name: key-auth
config:
key_names: ["apikey"]
- name: rate-limiting
config:
minute: 60This configuration requires an API key and limits 60 requests per minute per client at the gateway level — long before requests reach the Quarkus application.
mTLS ensures both sides of a communication verify each other's identity. A service mesh manages this automatically with per-service certificates. Without a service mesh, you can use the Quarkus REST client with SSL configuration:
quarkus.rest-client.order-service.url=https://order-service:8443
quarkus.rest-client.order-service.trust-store=keystore/truststore.p12
quarkus.rest-client.order-service.trust-store-password=${TRUSTSTORE_PASSWORD}
quarkus.rest-client.order-service.key-store=keystore/keystore.p12
quarkus.rest-client.order-service.key-store-password=${KEYSTORE_PASSWORD}With mTLS, every service presents its own certificate. The combination of mTLS + JWT gives you layered security: network identity and business identity.
Besides mTLS, service-to-service communication uses tokens. The service-to-service auth pattern with client credentials (episode 13) ensures the calling service has a verifiable identity:
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
@Path("/internal")
@RegisterRestClient(configKey = "order-service")
public interface OrderServiceClient {
@GET
String pesan(String nama);
}@RegisterRestClient creates a REST client that sends requests to another service. The OIDC token is injected automatically through an interceptor, so every inter-service call carries an identity.
Besides the gateway, rate limiting can be implemented at the application level with an extension or a custom approach: for example, a per-client counter checked before the request is processed. In production, use a distributed solution like Redis for consistent rate limiting across many instances.
Validating requests at the edge reduces the load on internal services. Use an OpenAPI validator in the gateway, or Jakarta Bean Validation in the edge service (episode 7). The principle: reject bad requests as early as possible.
An API policy is a set of rules applied consistently: authentication, rate limits, maximum body size, and method whitelists:
quarkus.http.limits.max-body-size=1Mquarkus.http.limits.max-body-size=1M rejects requests with a body larger than 1MB — preventing abuse via gigantic payloads.
Episode 14 expands security from a single application to the entire architecture: understanding secure microservice patterns with edge services, integration with Istio, Envoy, and API gateways, securing inter-service communication with mTLS and tokens, as well as rate limiting and API policies.
Key takeaways:
quarkus.http.limits.max-body-size limits the payload size.In episode 15 we'll cover reactive programming and Vert.x — the reactive stack with Vert.x in Quarkus, the Uni and Multi concepts, reactive messaging with Kafka, AMQP, or MQTT, and when to use reactive versus imperative.