diff --git a/assets/img/news/get-started-microservices-on-kubernetes/simple-microservice-client-part3-1.png b/assets/img/news/get-started-microservices-on-kubernetes/simple-microservice-client-part3-1.png
new file mode 100644
index 00000000..ea84c130
Binary files /dev/null and b/assets/img/news/get-started-microservices-on-kubernetes/simple-microservice-client-part3-1.png differ
diff --git a/guides/get-started-microservices-on-kubernetes.adoc b/guides/get-started-microservices-on-kubernetes.adoc
index e4def41c..e487995a 100644
--- a/guides/get-started-microservices-on-kubernetes.adoc
+++ b/guides/get-started-microservices-on-kubernetes.adoc
@@ -18,14 +18,22 @@ We will start building a link:https://docs.docker.com/[Docker Image, window="_bl
=== Guides in this series
-* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-part1[{simple-microservice-part1}]
-* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-part2[{simple-microservice-part2}]
-* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-database-part1[{simple-microservice-database-part1}]
-* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-database-part2[{simple-microservice-database-part2}]
-* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-infinispan-part1[{simple-microservice-infinispan-part1}]
-* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-infinispan-part2[{simple-microservice-infinispan-part2}]
-* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-jms-part1[{simple-microservice-jms-part1}]
-* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-jms-part2[{simple-microservice-jms-part2}]
+* **{simple-microservice-header}**
+** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-part1[{simple-microservice-part1}]
+** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-part2[{simple-microservice-part2}]
+* **{simple-microservice-database-header}**
+** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-database-part1[{simple-microservice-database-part1}]
+** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-database-part2[{simple-microservice-database-part2}]
+* **{simple-microservice-infinispan-header}**
+** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-infinispan-part1[{simple-microservice-infinispan-part1}]
+** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-infinispan-part2[{simple-microservice-infinispan-part2}]
+* **{simple-microservice-jms-header}**
+** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-jms-part1[{simple-microservice-jms-part1}]
+** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-jms-part2[{simple-microservice-jms-part2}]
+* **{simple-microservice-client-header}**
+** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part1[{simple-microservice-client-part1}]
+** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part2[{simple-microservice-client-part2}]
+** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part3[{simple-microservice-client-part3}]
//* link:get-enterprise-ready[{get-enterprise-ready}]
[[references]]
diff --git a/guides/get-started-microservices-on-kubernetes/_includes/_constants.adoc b/guides/get-started-microservices-on-kubernetes/_includes/_constants.adoc
index 92b883f6..d1da0262 100644
--- a/guides/get-started-microservices-on-kubernetes/_includes/_constants.adoc
+++ b/guides/get-started-microservices-on-kubernetes/_includes/_constants.adoc
@@ -2,14 +2,14 @@
:jaxrs-example-project-groupId: org.wildfly.examples
:jaxrs-example-project-artifactId: jaxrs
:jaxrs-example-project-version: 11.0.0.Final-SNAPSHOT
-:version-bootable-jar: 11.0.0.Beta1
-:version-wildfly-galleon-pack: 32.0.0.Final
+:version-wildfly: 34.0.1.Final
+:version-wildfly-galleon-pack: 34.0.1.Final
:jakarta-jakartaee-api-version: 10.0.0
:version-junit-jupiter-api: 5.10.2
:version-arquillian-junit5-container: 1.8.0.Final
:version-org-wildfly-arquillian-wildfly-arquillian: 5.1.0.Beta1
:version-resteasy-client: 6.2.7.Final
-:version-wildfly-cloud-galleon-pack: 7.0.0.Final
+:version-wildfly-cloud-galleon-pack: 7.0.2.Final
:version-wildfly-maven-plugin: 5.0.0.Final
:my-jaxrs-app-docker-image-name: my-jaxrs-app
:my-jaxrs-app-db-docker-image-name: my-jaxrs-app-db
@@ -46,3 +46,19 @@
:artemis-console-port-name: artemis-console-port
:my-jms-app-docker-image-name: my-jms-app
:podman-network-name: demo-network
+:my-jaxrs-app-docker-image-name-client: my-jaxrs-app-client
+:my-jaxrs-app-docker-image-name-server: my-jaxrs-app-server
+:simple-microservice-client-secured: simple-microservice-client-secured
+:simple-microservice-server-secured: simple-microservice-server-secured
+:keycloak-external: keycloak-external
+:keycloak-internal: keycloak-internal
+:keycloak-realm: keycloak-realm
+:keycloak-data-import: keycloak-data-import
+:keycloak-admin-user: admin
+:keycloak-admin-pws: admin
+:keycloak-user1: alice
+:keycloak-user1-pws: 123
+:keycloak-user2: bob
+:keycloak-user2-pws: 123
+:keycloak-role1: user
+:keycloak-role2: admin
diff --git a/guides/get-started-microservices-on-kubernetes/_includes/_titles.adoc b/guides/get-started-microservices-on-kubernetes/_includes/_titles.adoc
index 5504ff2f..1bab34bc 100644
--- a/guides/get-started-microservices-on-kubernetes/_includes/_titles.adoc
+++ b/guides/get-started-microservices-on-kubernetes/_includes/_titles.adoc
@@ -1,9 +1,17 @@
+:simple-microservice-header: WildFly Java Microservice
:simple-microservice-part1: WildFly Java Microservice - PART 1: Docker Image
:simple-microservice-part2: WildFly Java Microservice - PART 2: Kubernetes
+:simple-microservice-database-header: Connecting to a DB
:simple-microservice-database-part1: Connecting to a DB - PART 1: Docker Image
:simple-microservice-database-part2: Connecting to a DB - PART 2: Kubernetes
+:simple-microservice-jms-header: Using a Message Broker
:simple-microservice-jms-part1: Using a Message Broker - PART 1: Docker Image
:simple-microservice-jms-part2: Using a Message Broker - PART 2: Kubernetes
+:simple-microservice-infinispan-header: Using Infinispan remote cache
:simple-microservice-infinispan-part1: Using Infinispan remote cache - PART 1: Docker Image
:simple-microservice-infinispan-part2: Using Infinispan remote cache - PART 2: Kubernetes
+:simple-microservice-client-header: Invoke one Microservices from another
+:simple-microservice-client-part1: Invoke one Microservices from another - PART 1: Docker Images
+:simple-microservice-client-part2: Invoke one Microservices from another - PART 2: Kubernetes
+:simple-microservice-client-part3: Invoke one Microservices from another - PART 3: Propagate Authentication
:get-enterprise-ready: Get “Enterprise” ready
\ No newline at end of file
diff --git a/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part1.adoc b/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part1.adoc
new file mode 100644
index 00000000..20272a42
--- /dev/null
+++ b/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part1.adoc
@@ -0,0 +1,290 @@
+= {simple-microservice-client-part1}
+:summary: Invoke one microservice from another
+:includedir: ../_includes
+include::{includedir}/_attributes.adoc[]
+include::./_includes/_titles.adoc[]
+include::_includes/_constants.adoc[]
+// you can override any attributes eg to lengthen the
+// time to complete the guide
+:prerequisites-time: 10
+
+In this guide, you will learn HOW-TO invoke one microservice from another;
+
+[[prerequisites]]
+== Prerequisites
+
+To complete this guide, you need:
+
+* Complete link:simple-microservice-part1[{simple-microservice-part1}]
+
+== Introduction
+
+This guide is the first in a series of three:
+
+1. In link:simple-microservice-client-part1[{simple-microservice-client-part1}] (this guide), we explain HOW-TO invoke one microservice from another;
+2. In link:simple-microservice-client-part2[{simple-microservice-client-part2}], as usual, we explain HOW-TO run the whole thing on Kubernetes
+3. In link:simple-microservice-client-part3[{simple-microservice-client-part3}] we explain HOW-TO propagate user authentication and authorization data from the calling microservice to the invoked microservice; this is most useful in a scenario where you have a "chain" of microservices ("**A -> B -> C -> etc.**") and you want the user's authentication and authorization data to be propagated from one microservice to the next;
+
+== This Guide
+
+In these guides, we work with a simple invocation chain composed by +++two+++ microservices:
+
+* **Microservice A**: acting as **client**
+* **Microservice B**: acting as **server**
+
+Our invocation chain is then: "**Microservice A -> Microservice B**": when working with https://microprofile.io/[Microprofile], this is achieved by using the https://github.com/eclipse/microprofile-rest-client[microprofile-rest-client];
+
+Specifically, **Microservice A** will use the https://github.com/eclipse/microprofile-rest-client[microprofile-rest-client] to invoke the Jakarta REST service exposed by **Microservice B**;
+
+For both services, we will start from the microservice we built in link:simple-microservice-part1[{simple-microservice-part1}] (complete code in {source-code-git-repository}/simple-microservice);
+
+== Microservice B - the server
+
+We start from the server because we need the server's API for the client later on;
+
+=== Maven Project
+
+Copy {source-code-git-repository}/simple-microservice into a new folder named *simple-microservice-server* and:
+
+* remove folder *src/test*
+* remove all test scope dependencies
+
+NOTE: we remove tests because, since we are going to introduce service to service invocation, they wouldn't be much useful anymore
+
+==== pom.xml
+
+Update the `artifactId` to `simple-microservice-server`;
+
+NOTE: **Microservice B** is basically unchanged, we will modify it in link:simple-microservice-client-part3[{simple-microservice-client-part3}]
+
+==== Build the application
+
+[source,bash]
+----
+mvn clean package
+----
+
+=== Docker Image
+
+==== Dockerfile
+
+Since you copied {source-code-git-repository}/simple-microservice[simple-microservice], the Dockerfile from link:https://github.com/wildfly/wildfly-s2i/blob/main/examples/docker-build/Dockerfile[examples/docker-build/Dockerfile, window="_blank"] should already be at the root of your project;
+
+==== Build the Docker Image
+
+[source,bash,subs="normal"]
+----
+podman build -t {my-jaxrs-app-docker-image-name-server}:latest .
+----
+
+==== Run the Docker Image
+
+First we create a network for our containers:
+
+[source,bash,subs="normal"]
+----
+podman network create {podman-network-name}
+----
+
+Then we run our container using this network:
+
+[source,bash,subs="normal"]
+----
+podman run --rm -p 8180:8080 -p 10090:9990 \
+ --network={podman-network-name} \
+ --name={my-jaxrs-app-docker-image-name-server} \
+ {my-jaxrs-app-docker-image-name-server}
+----
+
+== Microservice A - the client
+
+=== Maven Project
+
+Copy {source-code-git-repository}/simple-microservice into a new folder named *simple-microservice-client* and:
+
+* remove folder *src/test*
+* remove all test scope dependencies
+
+NOTE: we remove tests because, since we are going to introduce service to service invocation, they wouldn't be much useful anymore
+
+==== pom.xml
+
+Set `simple-microservice-client`;
+
+Add the following to `dependencyManagement`:
+
+[source,xml,subs="normal"]
+----
+
+ org.wildfly.bom
+ wildfly-microprofile
+ ${version.wildfly.bom}
+ pom
+ import
+
+----
+
+Add the following to `dependencies`:
+
+[source,xml,subs="normal"]
+----
+
+ org.eclipse.microprofile.rest.client
+ microprofile-rest-client-api
+ provided
+
+
+ org.eclipse.microprofile.config
+ microprofile-config-api
+ provided
+
+----
+
+Add the following `layers` in the `wildfly-maven-plugin`:
+
+[source,xml,subs="normal"]
+----
+ microprofile-config
+ microprofile-rest-client
+----
+
+Later on, we will use:
+
+* **microprofile-config** to make the URL to **Microservice B** configurable
+* **microprofile-rest-client** to actually invoke **Microservice B**
+
+==== microprofile-config.properties
+
+As anticipated, we use **microprofile-config** to make the URL to **Microservice B** configurable;
+
+Add file `src/main/resources/META-INF/microprofile-config.properties` with the following content:
+
+.microprofile-config.properties:
+[source,properties]
+----
+simple-microservice-server/mp-rest/uri=${simple-microservice-server-uri:http://127.0.0.1:8080}
+simple-microservice-server/mp-rest/connectTimeout=3000
+----
+
+NOTE: `simple-microservice-server-uri` would pick up its value, whenever set, from the environment variable named `SIMPLE_MICROSERVICE_SERVER_URI` (see https://download.eclipse.org/microprofile/microprofile-config-3.0/microprofile-config-spec-3.0.html#default_configsources.env.mapping[env.mapping])
+
+==== Java code
+
+Add the following interface:
+
+.GettingStartedEndpointInterface.java:
+[source,java]
+----
+package org.wildfly.examples;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
+
+@RegisterRestClient(configKey="simple-microservice-server")
+@Path("/hello")
+public interface GettingStartedEndpointInterface {
+ @GET
+ @Path("/{name}")
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response sayHello(final @PathParam("name") String name);
+}
+----
+
+NOTE: this class is used to define the API to be invoked by the Rest Client; the actual URL where the remote service is
+located, comes from the `microprofile-config.properties` file we just added;
+
+Remove the `src/main/java/org/wildfly/examples/GettingStartedService.java` file and replace the content of
+`src/main/java/org/wildfly/examples/GettingStartedEndpoint.java` with the following:
+
+.GettingStartedEndpoint.java:
+[source,java]
+----
+package org.wildfly.examples;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.eclipse.microprofile.rest.client.inject.RestClient;
+
+@Path("/")
+public class GettingStartedEndpoint {
+
+ @Inject
+ @RestClient
+ private GettingStartedEndpointInterface service;
+
+ @GET
+ @Path("/{name}")
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response sayHello(final @PathParam("name") String name) {
+ return service.sayHello(name);
+ }
+}
+----
+
+NOTE: as anticipated, we use **microprofile-rest-client** to actually invoke **Microservice B**
+
+==== Build the application
+
+[source,bash]
+----
+mvn clean package
+----
+
+=== Docker Image
+
+==== Dockerfile
+
+Since you copied {source-code-git-repository}/simple-microservice[simple-microservice], the Dockerfile from link:https://github.com/wildfly/wildfly-s2i/blob/main/examples/docker-build/Dockerfile[examples/docker-build/Dockerfile, window="_blank"] should already be at the root of your project;
+
+==== Build the Docker Image `{my-jaxrs-app-docker-image-name-client}:latest` with the following command:
+
+[source,bash,subs="normal"]
+----
+podman build -t {my-jaxrs-app-docker-image-name-client}:latest .
+----
+
+==== Run the Docker Image
+
+[source,bash,subs="normal"]
+----
+podman run --rm -p 8080:8080 -p 9990:9990 \
+ --network={podman-network-name} \
+ --env "SIMPLE_MICROSERVICE_SERVER_URI=http://{my-jaxrs-app-docker-image-name-server}:8080/hello" \
+ --name={my-jaxrs-app-docker-image-name-client} \
+ {my-jaxrs-app-docker-image-name-client}
+----
+
+NOTE: The **{my-jaxrs-app-docker-image-name-server}** container can be reached, inside the **{podman-network-name}** network, using the DNS name **{my-jaxrs-app-docker-image-name-server}**
+
+== Test
+
+Open http://localhost:8080[http://localhost:8080] in your browser: this web page is served by the **{my-jaxrs-app-docker-image-name-client}** container;
+
+Write something in the "Name" input box and then press "Say Hello": the response you'll see will come from **{my-jaxrs-app-docker-image-name-server}** container!
+
+The complete invocation chain is "**web browser** -> **{my-jaxrs-app-docker-image-name-client}** -> **{my-jaxrs-app-docker-image-name-server}**"
+
+== What's next?
+
+link:simple-microservice-client-part2[{simple-microservice-client-part2}]
+
+[[references]]
+== References
+
+* https://microprofile.io/specifications/microprofile-rest-client[microprofile-rest-client]
+* https://microprofile.io/specifications/microprofile-config[microprofile-config]
+* Source code for this guide:
+** {source-code-git-repository}/simple-microservice-rest-client/simple-microservice-client
+** {source-code-git-repository}/simple-microservice-rest-client/simple-microservice-server
+
+
diff --git a/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part2.adoc b/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part2.adoc
new file mode 100644
index 00000000..b1f713ef
--- /dev/null
+++ b/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part2.adoc
@@ -0,0 +1,293 @@
+= {simple-microservice-client-part2}
+:summary: Invoke one microservice from another on Kubernetes
+:includedir: ../_includes
+include::{includedir}/_attributes.adoc[]
+include::./_includes/_titles.adoc[]
+include::_includes/_constants.adoc[]
+// you can override any attributes eg to lengthen the
+// time to complete the guide
+:prerequisites-time: 10
+
+In this guide, you will learn HOW-TO run the Docker Images you built in link:simple-microservice-client-part1[{simple-microservice-client-part1}] on Kubernetes.
+
+[[prerequisites]]
+== Prerequisites
+
+To complete this guide, you need:
+
+* Complete link:simple-microservice-client-part1[{simple-microservice-client-part1}]
+
+== Introduction
+
+In this guide, we will deploy on Kubernetes the two container images we created in link:simple-microservice-client-part1[{simple-microservice-client-part1}];
+
+== Minikube
+
+You can use whatever Kubernetes cluster you have available; in this guide, and in the following, we will use link:https://minikube.sigs.k8s.io/docs/[minikube, window="_blank"].
+
+== Microservice B - the server
+
+=== Image Registry
+
+To make the `{my-jaxrs-app-docker-image-name-server}:latest` Docker Image available to Kubernetes, you need to push it to some Image Registry that is accessible by the Kubernetes cluster you want to use.
+
+==== Quay.io
+
+There are many Image Registries you can use: in this guide, we will push the `{my-jaxrs-app-docker-image-name-server}:latest` Docker Image, to the link:https://quay.io[quay.io, window="_blank"] Image Registry.
+
+Create a public repository named `{my-jaxrs-app-docker-image-name-server}` on link:https://quay.io[quay.io, window="_blank"] (e.g. link:https://quay.io/repository/{quay-io-account-name}/my-jaxrs-app[https://quay.io/repository/{quay-io-account-name}/{my-jaxrs-app-docker-image-name-server}, window="_blank"]).
+
+NOTE: replace `{quay-io-account-name}` with the name of your account in all the commands that will follow
+
+Tag the Docker image:
+
+[source,bash,subs="normal"]
+----
+podman tag {my-jaxrs-app-docker-image-name-server} quay.io/{quay-io-account-name}/{my-jaxrs-app-docker-image-name-server}
+----
+
+Push the `{my-jaxrs-app-docker-image-name-server}` Docker Image to it:
+
+[source,bash,subs="normal"]
+----
+podman push quay.io/{quay-io-account-name}/{my-jaxrs-app-docker-image-name-server}
+----
+
+At this point, the `{my-jaxrs-app-docker-image-name-server}:latest` Docker Image should be publicly available and free to be consumed by any Kubernetes Cluster;
+
+=== Deploy on Kubernetes
+
+Create a file named `{my-jaxrs-app-docker-image-name-server}-deployment.yaml`:
+
+.{my-jaxrs-app-docker-image-name-server}-deployment.yaml:
+[source,yaml,subs="normal"]
+----
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {my-jaxrs-app-docker-image-name-server}-deployment
+ labels:
+ app: {my-jaxrs-app-docker-image-name-server}
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: {my-jaxrs-app-docker-image-name-server}
+ template:
+ metadata:
+ labels:
+ app: {my-jaxrs-app-docker-image-name-server}
+ spec:
+ containers:
+ - name: {my-jaxrs-app-docker-image-name-server}
+ image: quay.io/tborgato/{my-jaxrs-app-docker-image-name-server}
+ ports:
+ - containerPort: 8080
+ - containerPort: 9990
+ livenessProbe:
+ httpGet:
+ path: /health/live
+ port: 9990
+ readinessProbe:
+ httpGet:
+ path: /health/ready
+ port: 9990
+ startupProbe:
+ httpGet:
+ path: /health/started
+ port: 9990
+----
+
+Deploy to your Kubernetes Cluster:
+
+[source,bash,subs="normal"]
+----
+kubectl apply -f {my-jaxrs-app-docker-image-name-server}-deployment.yaml
+----
+
+=== Create Kubernetes ClusterIP Service
+
+We create a service to consume the services exposed by **{my-jaxrs-app-docker-image-name-server}** from inside Kubernetes;
+
+Create a file named `{my-jaxrs-app-docker-image-name-server}-service.yaml`:
+
+.{my-jaxrs-app-docker-image-name-server}-service.yaml:
+[source,yaml,subs="normal"]
+----
+apiVersion: v1
+kind: Service
+metadata:
+ name: {my-jaxrs-app-docker-image-name-server}-service
+ labels:
+ app: {my-jaxrs-app-docker-image-name-server}
+spec:
+ ports:
+ - name: http
+ protocol: TCP
+ port: 8080
+ targetPort: 8080
+ selector:
+ app: {my-jaxrs-app-docker-image-name-server}
+ type: ClusterIP
+----
+
+Deploy to your Kubernetes Cluster:
+
+[source,bash,subs="normal"]
+----
+kubectl apply -f {my-jaxrs-app-docker-image-name-server}-service.yaml
+----
+
+=== Check Kubernetes Service
+
+[source,bash,subs="normal"]
+----
+kubectl run --rm -it --tty curl-{my-jaxrs-app-docker-image-name-server} --image=curlimages/curl --restart=Never ‐‐ {my-jaxrs-app-docker-image-name-server}-service:8080/hello/pippo
+----
+
+== Microservice A - the client
+
+=== Image Registry
+
+To make the `{my-jaxrs-app-docker-image-name-client}:latest` Docker Image available to Kubernetes, you need to push it to some Image Registry that is accessible by the Kubernetes cluster you want to use.
+
+==== Quay.io
+
+There are many Image Registries you can use: in this guide, we will push the `{my-jaxrs-app-docker-image-name-client}:latest` Docker Image, to the link:https://quay.io[quay.io, window="_blank"] Image Registry.
+
+Create a public repository named `{my-jaxrs-app-docker-image-name-client}` on link:https://quay.io[quay.io, window="_blank"] (e.g. link:https://quay.io/repository/{quay-io-account-name}/my-jaxrs-app[https://quay.io/repository/{quay-io-account-name}/{my-jaxrs-app-docker-image-name-client}, window="_blank"]).
+
+NOTE: replace `{quay-io-account-name}` with the name of your account in all the commands that will follow
+
+Tag the Docker image:
+
+[source,bash,subs="normal"]
+----
+podman tag {my-jaxrs-app-docker-image-name-client} quay.io/{quay-io-account-name}/{my-jaxrs-app-docker-image-name-client}
+----
+
+Push the `{my-jaxrs-app-docker-image-name-client}` Docker Image to it:
+
+[source,bash,subs="normal"]
+----
+podman push quay.io/{quay-io-account-name}/{my-jaxrs-app-docker-image-name-client}
+----
+
+At this point, the `{my-jaxrs-app-docker-image-name-client}:latest` Docker Image should be publicly available and free to be consumed by any Kubernetes Cluster;
+
+=== Deploy on Kubernetes
+
+Create a file named `{my-jaxrs-app-docker-image-name-client}-deployment.yaml`:
+
+.{my-jaxrs-app-docker-image-name-client}-deployment.yaml:
+[source,yaml,subs="normal"]
+----
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {my-jaxrs-app-docker-image-name-client}-deployment
+ labels:
+ app: {my-jaxrs-app-docker-image-name-client}
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: {my-jaxrs-app-docker-image-name-client}
+ template:
+ metadata:
+ labels:
+ app: {my-jaxrs-app-docker-image-name-client}
+ spec:
+ containers:
+ - name: {my-jaxrs-app-docker-image-name-client}
+ image: quay.io/tborgato/{my-jaxrs-app-docker-image-name-client}
+ ports:
+ - containerPort: 8080
+ - containerPort: 9990
+ livenessProbe:
+ httpGet:
+ path: /health/live
+ port: 9990
+ readinessProbe:
+ httpGet:
+ path: /health/ready
+ port: 9990
+ startupProbe:
+ httpGet:
+ path: /health/started
+ port: 9990
+ env:
+ - name: SIMPLE_MICROSERVICE_SERVER_URI
+ value: "http://{my-jaxrs-app-docker-image-name-server}-service:8080"
+----
+
+NOTE: The environment variable `SIMPLE_MICROSERVICE_SERVER_URI` allows **{my-jaxrs-app-docker-image-name-client}** to invoke **{my-jaxrs-app-docker-image-name-server}** through the service **{my-jaxrs-app-docker-image-name-server}-service**
+
+Deploy to your Kubernetes Cluster:
+
+[source,bash,subs="normal"]
+----
+kubectl apply -f {my-jaxrs-app-docker-image-name-client}-deployment.yaml
+----
+
+=== Create Kubernetes NodePort Service
+
+We create a service to consume the services exposed by **{my-jaxrs-app-docker-image-name-client}** from outside Kubernetes;
+
+Create a file named `{my-jaxrs-app-docker-image-name-client}-service.yaml`:
+
+.{my-jaxrs-app-docker-image-name-client}-service.yaml:
+[source,yaml,subs="normal"]
+----
+apiVersion: v1
+kind: Service
+metadata:
+ name: {my-jaxrs-app-docker-image-name-client}-service
+ labels:
+ app: {my-jaxrs-app-docker-image-name-client}
+spec:
+ ports:
+ - name: http
+ protocol: TCP
+ port: 8080
+ targetPort: 8080
+ selector:
+ app: {my-jaxrs-app-docker-image-name-client}
+ type: NodePort
+----
+
+Deploy to your Kubernetes Cluster:
+
+[source,bash,subs="normal"]
+----
+kubectl apply -f {my-jaxrs-app-docker-image-name-client}-service.yaml
+----
+
+=== Check your application
+
+Find out on what IP address/port, link:https://minikube.sigs.k8s.io/docs/[minikube, window="_blank"] is exposing your service:
+
+[source,bash,subs="normal"]
+----
+$ minikube service {my-jaxrs-app-docker-image-name-client}-service --url
+http://192.168.39.143:30347
+----
+
+Verify it's working as expected:
+
+[source,bash,subs="normal"]
+----
+$ curl http://192.168.39.143:30347/hello/pippo
+Hello 'pippo'.
+----
+
+== What's next?
+
+link:simple-microservice-client-part3[{simple-microservice-client-part3}]
+
+[[references]]
+== References
+
+* Source code for this guide:
+** {source-code-git-repository}/simple-microservice-rest-client/simple-microservice-client
+** {source-code-git-repository}/simple-microservice-rest-client/simple-microservice-server
\ No newline at end of file
diff --git a/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part3.adoc b/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part3.adoc
new file mode 100644
index 00000000..94d77c09
--- /dev/null
+++ b/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part3.adoc
@@ -0,0 +1,735 @@
+= {simple-microservice-client-part3}
+:summary: Invoke one microservice from another on Kubernetes propagating users authentication
+:includedir: ../_includes
+include::{includedir}/_attributes.adoc[]
+include::./_includes/_titles.adoc[]
+include::_includes/_constants.adoc[]
+// you can override any attributes eg to lengthen the
+// time to complete the guide
+:prerequisites-time: 10
+
+In this guide, you will learn HOW-TO propagate user authentication and authorization data between two microservices;
+
+[[prerequisites]]
+== Prerequisites
+
+To complete this guide, you need:
+
+* Complete link:simple-microservice-client-part2[{simple-microservice-client-part2}]
+
+== Introduction
+
+The scenario consists of:
+
+* a *Service* deployed on a Kubernetes cluster which is not exposed outside the cluster
+* a *Web Application* deployed on a Kubernetes cluster which is exposed outside the cluster and consumes the *Service*
+
+The user is required to authenticate before using the *Web Application* and, after authentication happens, we want authentication data to be available, not only to the *Web Application*, but also tho the *Service*; authentication is delegated to *Keycloak* using link:https://www.keycloak.org/securing-apps/oidc-layers[OpenID Connect] protocol;
+
+The overall architecture is:
+
+image::get-started-microservices-on-kubernetes/simple-microservice-client-part3-1.png[]
+
+We will start from the two microservices we built in link:simple-microservice-client-part2[{simple-microservice-client-part2}] and:
+
+* *Microservice A* will be the basis for *Web Application*
+* *Microservice B* will be the basis for *Service*
+
+=== How it works
+
+This is how it works:
+
+1. The user tries to access *Web Application* (*Microservice A*) from a web browser
+2. The browser is redirected to *Keycloak* where, by providing username and password, the user authenticates itself
+3. The browser is redirected back to *Web Application*: this time the request contains a *JWT Access Token* (and a few more tokens actually) provided by *Keycloak*, containing authentication and authorization data
+4. *Web Application* validates the *JWT Access Token* and grants access to the user
+5. *Web Application* invokes *Service* (*Microservice B*) forwarding to it the *JWT Access Token* it just received
+6. *Service* validates the *JWT Access Token* and grants access to *Web Application*
+
+== Keycloak
+
+First, we install and configure Keycloak with users, groups etc..
+
+=== Run Keycloak on Kubernetes
+
+Download link:{source-code-git-repository}/simple-microservice-rest-client/simple-microservice-client-secured/kubernetes/keycloak-realm-realm.json[keycloak-realm-realm.json] and create a `configmap` using it as its content:
+
+[source,bash,subs="normal"]
+----
+kubectl create configmap {keycloak-data-import} --from-file=keycloak-realm-realm.json=keycloak-realm-realm.json
+----
+
+Create a file named `keycloak.yaml`:
+
+.keycloak.yaml:
+[source,yaml,subs="normal"]
+----
+apiVersion: v1
+kind: Service
+metadata:
+ name: {keycloak-external}
+ labels:
+ app: keycloak
+spec:
+ ports:
+ - name: http
+ port: 8080
+ targetPort: 8080
+ selector:
+ app: keycloak
+ type: NodePort
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: {keycloak-internal}
+ labels:
+ app: keycloak
+spec:
+ ports:
+ - name: http
+ port: 8080
+ targetPort: 8080
+ selector:
+ app: keycloak
+ type: ClusterIP
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: keycloak
+ labels:
+ app: keycloak
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: keycloak
+ template:
+ metadata:
+ labels:
+ app: keycloak
+ spec:
+ volumes:
+ - name: {keycloak-data-import}-volume
+ configMap:
+ name: {keycloak-data-import}
+ containers:
+ - name: keycloak
+ image: quay.io/keycloak/keycloak:26.0
+ args: [ "start-dev", "--import-realm" ]
+ env:
+ - name: KEYCLOAK_ADMIN
+ value: "{keycloak-admin-user}"
+ - name: KEYCLOAK_ADMIN_PASSWORD
+ value: "{keycloak-admin-pws}"
+ ports:
+ - name: http
+ containerPort: 8080
+ readinessProbe:
+ httpGet:
+ path: /realms/master
+ port: 8080
+ volumeMounts:
+ - name: {keycloak-data-import}-volume
+ mountPath: /opt/keycloak/data/import
+----
+
+Deploy to your Kubernetes Cluster:
+
+[source,bash,subs="normal"]
+----
+kubectl apply -f keycloak.yaml
+----
+
+To access the Keycloak console, find out on what IP address/port, link:https://minikube.sigs.k8s.io/docs/[minikube, window="_blank"] is exposing your **{keycloak-external}** service:
+
+[source,bash,subs="normal"]
+----
+$ minikube service keycloak-external --url
+http://192.168.39.190:31950
+----
+
+Open the link in your web browser and login to Keycloak with username/password "*{keycloak-admin-user}*/*{keycloak-admin-pws}*";
+
+NOTE: since we are using minikube, we expose *Keycloak* outside the cluster with a `NodePort` service (**{keycloak-external}**) and inside the cluster with a `ClusterIP` service (**{keycloak-internal}**)
+
+==== optional alternative: configure Keycloak manually
+
+As an alternative to using *Keycloak* auto import feature (see the "--import-realm" command argument above), you can configure *Keycloak* manually: remove `volumes` and `volumeMounts` and follow these steps:
+
+1. Create a realm called **{keycloak-realm}**
+2. Create a client called **{simple-microservice-client-secured}**; in the Capability config, turn on +++Client authentication+++.
+3. For the **{simple-microservice-client-secured}** client, we also need to set the valid redirect URIs to ***** and set the Web origins to **+** to permit all origins of Valid Redirect URIs.
+4. For the **{simple-microservice-client-secured}** client, note down the +++Client Secret+++ in the +++Credentials+++ tab (e.g. `KqIQIzNHD9LnCRjsCxblDnfEl4rcNoKB`);
+5. Now, click on Realm roles and create two roles, **{keycloak-role1}** and **{keycloak-role2}**.
+6. Create a user called **{keycloak-user1}** and assign her the **{keycloak-role1}** and **{keycloak-role2}** roles; set password **{keycloak-user1-pws}** for **{keycloak-user1}**
+7. Create a user called **{keycloak-user2}** and assign him only the **{keycloak-role1}** role; set password **{keycloak-user2-pws}** for **{keycloak-user2}**
+
+NOTE: in case you want to go deeper, find more information and examples in link:https://wildfly-security.github.io/wildfly-elytron/blog/bearer-only-support-openid-connect/[Setting up your Keycloak OpenID provider]
+
+== Web Application (Microservice A)
+
+=== Maven Project
+
+Copy link:{source-code-git-repository}/simple-microservice-rest-client/simple-microservice-client[simple-microservice-client]
+into a new folder named **{simple-microservice-client-secured}**;
+
+==== pom.xml
+
+Set `{simple-microservice-client-secured}`;
+
+Add the following to `dependencies`:
+
+[source,xml,subs="normal"]
+----
+
+ org.wildfly.security
+ wildfly-elytron-http-oidc
+ provided
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+ provided
+
+----
+
+Add the following `layers` in the `wildfly-maven-plugin`:
+
+[source,xml,subs="normal"]
+----
+ elytron-oidc-client
+----
+
+==== web.xml
+
+Create file `src/main/webapp/WEB-INF/web.xml` with the following content:
+
+.src/main/webapp/WEB-INF/web.xml:
+[source,xml,subs="normal"]
+----
+
+
+
+
+
+ secured
+ /*
+
+
+ {keycloak-role1}
+ {keycloak-role2}
+
+
+
+
+ OIDC
+
+
+
+ {keycloak-role1}
+
+
+ {keycloak-role2}
+
+
+----
+
+==== oidc.json
+
+Create file `src/main/webapp/WEB-INF/oidc.json` with the following content:
+
+.src/main/webapp/WEB-INF/oidc.json:
+[source,json,subs="normal"]
+----
+{
+ "client-id" : "{simple-microservice-client-secured}",
+ "provider-url" : "${env.OIDC_PROVIDER_URL:http://localhost:8080}/realms/{keycloak-realm}",
+ "ssl-required" : "EXTERNAL",
+ "credentials" : {
+ "secret" : "${env.OIDC_CLIENT_SECRET:KqIQIzNHD9LnCRjsCxblDnfEl4rcNoKB}"
+ }
+}
+----
+
+replace `KqIQIzNHD9LnCRjsCxblDnfEl4rcNoKB` with the +++Client Secret+++ you previously noted down;
+
+
+=== Java code
+
+==== GettingStartedEndpointInterface
+
+Add the following interface:
+
+.org.wildfly.examples.GettingStartedEndpointInterface.java:
+[source,java]
+----
+package org.wildfly.examples;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.HeaderParam;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
+import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
+
+@RegisterClientHeaders
+@RegisterRestClient(configKey="simple-microservice-server")
+@Path("/hello")
+public interface GettingStartedEndpointInterface {
+ @GET
+ @Path("/{name}")
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response sayHello(@HeaderParam("Authorization") String authorization, final @PathParam("name") String name);
+}
+----
+
+==== GettingStartedEndpoint
+
+Modify the following class:
+
+.org.wildfly.examples.GettingStartedEndpoint.java:
+[source,java]
+----
+package org.wildfly.examples;
+
+import jakarta.inject.Inject;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.eclipse.microprofile.rest.client.inject.RestClient;
+import org.wildfly.security.http.oidc.OidcSecurityContext;
+
+import java.io.IOException;
+
+@Path("/")
+public class GettingStartedEndpoint {
+
+ @Context
+ private HttpServletRequest httpServletRequest;
+
+ @Inject
+ @RestClient
+ private GettingStartedEndpointInterface service;
+
+ @GET
+ @Path("/{name}")
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response sayHello(final @PathParam("name") String name) throws IOException {
+ Response response;
+ OidcSecurityContext oidcSecurityContext = getOidcSecurityContext(httpServletRequest);
+ if (oidcSecurityContext != null) {
+ String authzHeaderValue = "Bearer " + oidcSecurityContext.getTokenString();
+ System.out.println("\n\n[JWT] service Token: " + authzHeaderValue + "\n\n");
+ return service.sayHello(authzHeaderValue, name);
+ } else {
+ System.out.println("\n\n[JWT] No token :(\n\n");
+ return service.sayHello(null, name);
+ }
+ }
+
+ private OidcSecurityContext getOidcSecurityContext(HttpServletRequest req) {
+ return (OidcSecurityContext) req.getAttribute(OidcSecurityContext.class.getName());
+ }
+}
+----
+
+=== Build and push the image to Quay.io
+
+Build the application:
+
+[source,bash]
+----
+mvn clean package
+----
+
+Build the Docker image:
+
+[source,bash,subs="normal"]
+----
+podman build -t {simple-microservice-client-secured}:latest .
+----
+
+Create a public repository named `{simple-microservice-client-secured}` on link:https://quay.io[quay.io, window="_blank"] (e.g. link:https://quay.io/repository/{quay-io-account-name}/{simple-microservice-client-secured}[https://quay.io/repository/{quay-io-account-name}/{simple-microservice-client-secured}, window="_blank"]).
+
+NOTE: replace `{quay-io-account-name}` with the name of your account in all the commands that will follow
+
+Tag the Docker image:
+
+[source,bash,subs="normal"]
+----
+podman tag {simple-microservice-client-secured} quay.io/{quay-io-account-name}/{simple-microservice-client-secured}
+----
+
+Push the `{simple-microservice-client-secured}` Docker Image:
+
+[source,bash,subs="normal"]
+----
+podman push quay.io/{quay-io-account-name}/{simple-microservice-client-secured}
+----
+
+=== Deploy to Kubernetes
+
+Create file `{simple-microservice-client-secured}-deployment.yaml`:
+
+.{simple-microservice-client-secured}-deployment.yaml:
+[source,yaml,subs="normal"]
+----
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {simple-microservice-client-secured}-deployment
+ labels:
+ app: {simple-microservice-client-secured}
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: {simple-microservice-client-secured}
+ template:
+ metadata:
+ labels:
+ app: {simple-microservice-client-secured}
+ spec:
+ containers:
+ - name: {simple-microservice-client-secured}
+ image: quay.io/{quay-io-account-name}/{simple-microservice-client-secured}
+ ports:
+ - containerPort: 8080
+ - containerPort: 9990
+ livenessProbe:
+ httpGet:
+ path: /health/live
+ port: 9990
+ readinessProbe:
+ httpGet:
+ path: /health/ready
+ port: 9990
+ startupProbe:
+ httpGet:
+ path: /health/started
+ port: 9990
+ env:
+ - name: SIMPLE-MICROSERVICE-SERVER_MP_REST_URI
+ value: "http://{simple-microservice-server-secured}-service:8080"
+ - name: OIDC_PROVIDER_URL
+ # replace with the outcome of "minikube service keycloak-external --url"
+ value: "http://192.168.39.190:31950"
+ - name: OIDC_CLIENT_SECRET
+ value: "KqIQIzNHD9LnCRjsCxblDnfEl4rcNoKB"
+----
+
+Then:
+
+* replace "http://192.168.39.190:31950" with the outcome of command `minikube service keycloak-external --url`
+* replace "{quay-io-account-name}" with your account name on link:quay.io[quay.io]
+* replace `KqIQIzNHD9LnCRjsCxblDnfEl4rcNoKB` with the +++Client Secret+++ you previously noted down;
+
+Deploy to your Kubernetes Cluster:
+
+[source,bash,subs="normal"]
+----
+kubectl apply -f {simple-microservice-client-secured}-deployment.yaml
+----
+
+Create file `{simple-microservice-client-secured}-service.yaml`:
+
+.{simple-microservice-client-secured}-service.yaml:
+[source,yaml,subs="normal"]
+----
+apiVersion: v1
+kind: Service
+metadata:
+ name: {simple-microservice-client-secured}-service
+ labels:
+ app: {simple-microservice-client-secured}
+spec:
+ ports:
+ - name: http
+ protocol: TCP
+ port: 8080
+ targetPort: 8080
+ selector:
+ app: {simple-microservice-client-secured}
+ type: NodePort
+----
+
+Deploy to your Kubernetes Cluster:
+
+[source,bash,subs="normal"]
+----
+kubectl apply -f {simple-microservice-client-secured}-service.yaml
+----
+
+== Service (Microservice B)
+
+=== Maven Project
+
+Copy link:{source-code-git-repository}/simple-microservice-rest-client/simple-microservice-server[simple-microservice-server]
+into a new folder named **simple-microservice-server-secured**;
+
+==== pom.xml
+
+Set `simple-microservice-server-secured`;
+
+Add the following to `dependencyManagement`:
+
+[source,xml,subs="normal"]
+----
+
+ org.wildfly.bom
+ wildfly-microprofile
+ ${version.wildfly.bom}
+ pom
+ import
+
+----
+
+Add the following to `dependencies`:
+
+[source,xml,subs="normal"]
+----
+
+ org.eclipse.microprofile.config
+ microprofile-config-api
+ provided
+
+
+ org.eclipse.microprofile.jwt
+ microprofile-jwt-auth-api
+ provided
+
+----
+
+Add the following `layers` in the `wildfly-maven-plugin`:
+
+[source,xml,subs="normal"]
+----
+ microprofile-config
+ microprofile-jwt
+----
+
+=== microprofile-config.properties
+
+Add file `src/main/resources/META-INF/microprofile-config.properties` with the following content:
+
+.microprofile-config.properties:
+[source,properties]
+----
+mp.jwt.verify.publickey.location=http://localhost:8080/realms/keycloak-realm/protocol/openid-connect/certs
+----
+
+=== Java code
+
+==== GettingStartedApplication
+
+Modify the following class:
+
+.org.wildfly.examples.GettingStartedApplication.java:
+[source,java]
+----
+package org.wildfly.examples;
+
+import jakarta.ws.rs.ApplicationPath;
+import jakarta.ws.rs.core.Application;
+import org.eclipse.microprofile.auth.LoginConfig;
+
+@LoginConfig(authMethod="MP-JWT")
+@ApplicationPath("/hello")
+public class GettingStartedApplication extends Application {
+
+}
+----
+
+==== GettingStartedEndpoint
+
+Modify the following class:
+
+.org.wildfly.examples.GettingStartedEndpoint.java:
+[source,java]
+----
+package org.wildfly.examples;
+
+import jakarta.annotation.security.RolesAllowed;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.eclipse.microprofile.jwt.JsonWebToken;
+
+@Path("/")
+public class GettingStartedEndpoint {
+
+ @Inject
+ @ConfigProperty(name = "mp.jwt.verify.publickey.location")
+ private String publicKeyLocation;
+
+ @Inject
+ JsonWebToken jwt;
+
+ @GET
+ @Path("/{name}")
+ @Produces(MediaType.TEXT_PLAIN)
+ @RolesAllowed({"admin"})
+ public Response sayHello(final @PathParam("name") String name) {
+ System.out.println("mp.jwt.verify.publickey.location=" + publicKeyLocation);
+
+ String response =
+ "Hello " + name
+ + (jwt != null ? (" Subject:" + jwt.getSubject()) : null)
+ + (jwt != null ? (" Issuer: " + jwt.getIssuer()) : null);
+
+ return Response.ok(response).build();
+ }
+}
+----
+
+=== Build and push the image to Quay.io
+
+Create a public repository named `{simple-microservice-server-secured}` on link:https://quay.io[quay.io, window="_blank"] (e.g. link:https://quay.io/repository/{quay-io-account-name}/my-jaxrs-app[https://quay.io/repository/{quay-io-account-name}/{simple-microservice-server-secured}, window="_blank"]).
+
+NOTE: replace `{quay-io-account-name}` with the name of your account in all the commands that will follow
+
+Tag the Docker image:
+
+[source,bash,subs="normal"]
+----
+podman tag {simple-microservice-server-secured} quay.io/{quay-io-account-name}/{simple-microservice-server-secured}
+----
+
+Push the `{simple-microservice-server-secured}` Docker Image:
+
+[source,bash,subs="normal"]
+----
+podman push quay.io/{quay-io-account-name}/{simple-microservice-server-secured}
+----
+
+=== Deploy to Kubernetes
+
+Create file `{simple-microservice-server-secured}-deployment.yaml`:
+
+.{simple-microservice-server-secured}-deployment.yaml:
+[source,yaml,subs="normal"]
+----
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {simple-microservice-server-secured}-deployment
+ labels:
+ app: {simple-microservice-server-secured}
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: {simple-microservice-server-secured}
+ template:
+ metadata:
+ labels:
+ app: {simple-microservice-server-secured}
+ spec:
+ containers:
+ - name: {simple-microservice-server-secured}
+ image: quay.io/tborgato/{simple-microservice-server-secured}
+ ports:
+ - containerPort: 8080
+ - containerPort: 9990
+ livenessProbe:
+ httpGet:
+ path: /health/live
+ port: 9990
+ readinessProbe:
+ httpGet:
+ path: /health/ready
+ port: 9990
+ startupProbe:
+ httpGet:
+ path: /health/started
+ port: 9990
+ env:
+ - name: MP_JWT_VERIFY_PUBLICKEY_LOCATION
+ value: "http://keycloak-internal:8080/realms/{keycloak-realm}/protocol/openid-connect/certs"
+----
+
+Then:
+
+* replace "{quay-io-account-name}" with your account name on link:quay.io[quay.io]
+
+Deploy to your Kubernetes Cluster:
+
+[source,bash,subs="normal"]
+----
+kubectl apply -f {simple-microservice-server-secured}-deployment.yaml
+----
+
+Create file `{simple-microservice-server-secured}-service.yaml`:
+
+.{simple-microservice-server-secured}-service.yaml:
+[source,yaml,subs="normal"]
+----
+apiVersion: v1
+kind: Service
+metadata:
+ name: {simple-microservice-server-secured}-service
+ labels:
+ app: {simple-microservice-server-secured}
+spec:
+ ports:
+ - name: http
+ protocol: TCP
+ port: 8080
+ targetPort: 8080
+ selector:
+ app: {simple-microservice-server-secured}
+ type: ClusterIP
+----
+
+Deploy to your Kubernetes Cluster:
+
+[source,bash,subs="normal"]
+----
+kubectl apply -f {simple-microservice-server-secured}-service.yaml
+----
+
+== Test
+
+[source,bash,subs="normal"]
+----
+$ minikube service {simple-microservice-client-secured}-service --url
+http://192.168.39.190:32225
+----
+
+Open that URL in your browser, log in as *{keycloak-user1}*/*{keycloak-user1-pws}* and try it out!
+
+After pressing the "Say Hello" button, you should see something like:
+
+[source,text]
+----
+Hello ddd Subject:aaef43ee-4005-4d2d-a5f0-0e0d11a1f831 Issuer: http://192.168.39.190:31950/realms/keycloak-realm
+----
+
+
+[[references]]
+== References
+
+* https://wildfly-security.github.io/wildfly-elytron/blog/bearer-only-support-openid-connect/
+* https://github.com/wildfly-security-incubator/elytron-examples/tree/main/oidc-with-bearer
+* https://www.keycloak.org/getting-started/getting-started-kube
+* Source code for this guide:
+** {source-code-git-repository}/simple-microservice-rest-client/simple-microservice-client-secured
+** {source-code-git-repository}/simple-microservice-rest-client/simple-microservice-server-secured
\ No newline at end of file