Ad Code

Ticker

6/recent/ticker-posts

Quarkus - Implement Basic Authentication using Kubernetes (K8s) secrets for Rest APIs running as Docker Container inside Kubernetes PODs

This example explains how to implement Basic Authentication using Filter for Rest APIs in Quarkus application. Here we will store the Basic Auth credentials in Kubernetes (K8s) secret object.

Prerequisites To complete this example:

  • An IDE
  • JDK 11+ installed with JAVA_HOME configured appropriately
  • Apache Maven 3.8.1+
  • Docker Desktop
  • Kubectl
  • WSL Windows Subsystem for Linux
  • Windows PowerShell

In this Example we have two sections, 

In the First Section we will use the Basic Auth details from our local application.properties configuration file and validate the same with Basic Auth credential provided in the request header

And in the Second Section we will create the Docker Image of our greetings Application, run the image as a Container within POD of our Local Kubernetes (K8s) Cluster and use Kubernetes secret object for validating our Basic Auth details with Basic Auth credential provided in the request header.

Here we will Use Windows Docker Desktop as Docker Engine which has embedded Kubernetes (K8s) Cluster.

Section 1: With Local application.properties configuration file:

Here are the Steps:

1. Create a maven project using Quarkus and add the below Dependencies in pom.xml.

2.  Create Rest End point the needs to be secured using Basic Authentication.

@Path("/hello")
public class GreetingResource {

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello RESTEasy";
}
}

3. Create ConfigProperties for getting userName and password from external configuration

@ConfigMapping(prefix = "teachlea", namingStrategy = ConfigMapping.NamingStrategy.VERBATIM)
public interface ConfigProperties {

Authentication Authentication();

interface Authentication{
String userName();
String password();
}
}

4. Configure properties in application.properties file:

AUTH_USER = teachlea
AUTH_PASSWORD = dGVhY2hsZWE=

teachlea.Authentication.userName = ${AUTH_USER}
teachlea.Authentication.password = ${AUTH_PASSWORD}

5. Create a filter class which implements ContainerRequestFilter. This class will filter each and every Rest End Point and validate with the Basic Auth provided in request header:

@Inject
ConfigProperties configProperties;

@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
final MultivaluedMap<String, String> headers = requestContext.getHeaders();
final List<String> authorization = headers.get(AUTHORIZATION_PROPERTY);
validateAuthHeader(authorization);
checkAuthentication(authorization, configProperties);

}

private void validateAuthHeader(final List<String> authorization) throws AuthenticationException {
if (authorization == null || authorization.isEmpty()) {
throw new AuthenticationException();
}
}

private void checkAuthentication(final List<String> authorization, ConfigProperties configProperties) throws AuthenticationException {

final String encodedUserPassword = authorization.get(0).replaceFirst(AUTHENTICATION_SCHEME + " ", "");
String usernameAndPassword = null;
usernameAndPassword = new String(Base64.getDecoder().decode(encodedUserPassword));
final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, COLON);
log.debug("tokenizer count in checkAuthentication is: {}",tokenizer.countTokens());
if (tokenizer.countTokens() == tokenCount) {
final String username = tokenizer.nextToken();
final String password = tokenizer.nextToken();
if (!isAuthAllowed(username, password, configProperties)) {
throw new AuthenticationException();
}
} else {
throw new AuthenticationException();
}

}

private boolean isAuthAllowed(final String username, final String password, ConfigProperties configProperties) {
boolean isAllowed = false;
String userName = configProperties.Authentication().userName();
//String passWord = new String(Base64.getDecoder().decode(configProperties.Authentication().password().getBytes()));
String passWord = configProperties.Authentication().password();
isAllowed = userName.equalsIgnoreCase(username) && passWord.equalsIgnoreCase(password);
return isAllowed;
}

6. run Quarkus application in dev using below command

7. Quarkus Application will be started with below logs:


8. Now its time to Test our implementation, for this we will use postman tool :

   Case 1:  Send the Get Request [localhost:8080/hello] with No Auth details in the Request Header, You will get the Response as 401 Unauthorized as Response Code and Status with response message "Authentication information is missing or invalid".


  Case 2:  Send the Get Request [localhost:8080/hello] with Wrong Basic Auth details in the Request Header, You will get the Response as 401 Unauthorized as Response Code and Status with response message "Authentication information is missing or invalid".


Case 3:  Send the Get Request [localhost:8080/hello] with Correct Basic Auth details in the Request Header that  matched with the Auth Details Configured in our application.properties, You will get the Success Response as 200 OK as Response Code and Status with response message "Hello RESTEasy".



Section 2: Create the Docker Image of our greetings Application, run the image as a Container within POD of our Local Kubernetes (K8s) Cluster and use Kubernetes secret object for validating our Basic Auth details.

Note:  For this we will remove the Basic Auth userName and password details from our application.properties file in the code base:

teachlea.Authentication.userName = ${AUTH_USER}
teachlea.Authentication.password = ${AUTH_PASSWORD}

Here are the Steps:

1. Now create a docker file here we will use Quarkus provided [Dockerfile.jvm] file:

2.  Package the greetings application as jar using the command [./mvnw package].

3. Start Windows Docker Desktop. After Some time both Docker Desktop and Kubernetes will started as show below: 


4. Create the Docker Image using Docker File using the below command:

5. A docker image will be created for our greetings Application and we can validate the same in Our IntelliJ Idea Service Section.


6. Go to the Docker Desktop Dashboard there also you will be able to see docker image of our greetings Application.


7. Now its time to create the Kubernetes Deployment and Secret objects. And for this we will create Deployment.yaml and secret.yaml file

Deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: teachlea
labels:
app: my-app
spec:
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- image: "quarkus/quarkus-basic-auth-jvm:v1"
name: my-app
imagePullPolicy: Never
ports:
- name: web
containerPort: 8080
envFrom:
- secretRef:
name: my-secret
secret.yaml

Kubernetes secret file takes user credentials in Base64 Encoded form as shown below:
apiVersion: v1
kind: Secret
metadata:
name: my-secret
namespace: teachlea
type: Opaque
data:
AUTH_USER: dGVhY2hsZWE=
AUTH_PASSWORD: dGVhY2hsZWE=
8.  Open WSL and create a namespace using kubectl create command as shown below:


9. Open Window Power Shell and create secret and deployment object using kubectl commands as shown bellow:






10. Login to Kubernetes Dashboard using token and select the namespace "teachlea" you will able to see the Deployment and POD details there as shown below:

11. Expose the Deployment as a Kubernetes service object using command:

       kubectl expose deployment my-app --port=80 --target-port=8080

12. Now its time to Test our implementation, for this we will use postman tool :

   Case 1:  Send the Get Request [localhost:8080/hello] with No Auth details in the Request Header, You will get the Response as 401 Unauthorized as Response Code and Status with response message "Authentication information is missing or invalid".


  Case 2:  Send the Get Request [localhost:8080/hello] with Wrong Basic Auth details in the Request Header, You will get the Response as 401 Unauthorized as Response Code and Status with response message "Authentication information is missing or invalid".


Case 3:  Send the Get Request [localhost:8080/hello] with Correct Basic Auth details in the Request Header that  matched with the Auth Details Configured in our application.properties, You will get the Success Response as 200 OK as Response Code and Status with response message "Hello RESTEasy".


Summary:

So In this example we have implemented Basic Authentication with Kubernetes (K8s) secrets using Filter for Rest APIs running as Docker Container inside Kubernetes PODs. 

GitHub Link : rajivksingh13/teachlea

Please feel free to provide your valuable comments, Thanks.

Post a Comment

3 Comments

  1. check the readme file at git hub for more details

    ReplyDelete
  2. Are there other ways to implement authentication without using a Filter/Interceptor

    ReplyDelete
    Replies
    1. Yes, just with yaml configuration also we can implement basic authentication

      Delete

Ad Code