List supported Chiper Suits in Kong Gateway using kubectl

Working with data transportation (integration) you sometimes need to check the support for some obscure chiper suit that only works with machines from the 60’s 🙂 Here is one way to do that

# Get the name of a kong gateway pod. Here in the namespace "kong"
> kubectl get pods -n kong

...
kong-gateway-abcdef
...

# List chiper suits supported by the pod
> kubectl -n kong exec -it kong-gateway-abcdef -- openssl ciphers -v

Defaulted container "proxy" out of: proxy, clear-stale-pid (init)
TLS_AES_256_GCM_SHA384         TLSv1.3 Kx=any  Au=any   Enc=AESGCM(256)            Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256   TLSv1.3 Kx=any  Au=any   Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256         TLSv1.3 Kx=any  Au=any   Enc=AESGCM(128)            Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256)            Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384    TLSv1.2 Kx=ECDH Au=RSA   Enc=AESGCM(256)            Mac=AEAD
DHE-RSA-AES256-GCM-SHA384      TLSv1.2 Kx=DH   Au=RSA   Enc=AESGCM(256)            Mac=AEAD
ECDHE-ECDSA-CHACHA20-POLY1305  TLSv1.2 Kx=ECDH Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
...

Tested on Kubernetes v1.29.15, Kubectl v1.27, OpenSSL v3.0.30 and OSX v15.6.1

AMQP with mTLS with AMQPNETLite

Every now and then you are thrown into projects were you might not be the perfect pick from start. I seldom work with .NET and this project was just that 🙂 I was asked to create a small .NET proof-of-concept application in C# that fetches messages from a AMQP broker using mTLS authentication. I post the solution so it might benefit someone else (did not find much about this on Google)
Here is the result:

using Amqp;
using Amqp.Sasl;
using Microsoft.Extensions.Logging;


namespace DotNETApps
{
    class Program
    {
        static async Task Main(string[] args)
        {
            using var loggerFactory = LoggerFactory.Create(builder =>
            {
                builder
                    .AddConsole()
                    .SetMinimumLevel(LogLevel.Debug);
            });

            ILogger logger = loggerFactory.CreateLogger<Program>();

            logger.LogInformation("Application started.");

            Address address = new Address("amqps://mydomain:5671");

            var factory = new ConnectionFactory();
            factory.SSL.ClientCertificates.Add(new 
                  System.Security.Cryptography.X509Certificates
                         .X509Certificate2("c:\\myclientcert.pfx", "secret"));

            factory.SASL.Profile = SaslProfile.Anonymous;

            try {
                logger.LogInformation("Connecting to broker...");
                Connection connection = await factory.CreateAsync(address);
                logger.LogInformation("Connected to broker.");

                Session session = new Session(connection);
                ReceiverLink receiver = 
                         new ReceiverLink(session, "receiver-link", "MYQUEU");

                Console.WriteLine("Receiver connected to broker.");

                Message message = await Task.Run(() => 
                          receiver.Receive(TimeSpan.FromMilliseconds(2000)));

                if (message == null)
                {
                    Console.WriteLine("No message received.");
                    receiver.Close();
                    session.Close();
                    connection.Close();
                    return;
                }

                Console.WriteLine("Received " + message.Body);
                receiver.Accept(message);

                receiver.Close();
                session.Close();
                connection.Close();
            }
            catch (Exception e)
            {
                logger.LogError(e, "An error while processing messages.");
            }

            logger.LogInformation("Application ended.");
        }
    }
}

Tested on Windows 10, AMQPNETLite v2.4.11, .NET 8.0 and Visual Studio Code 1.97.0

Apache Camel OpenAPI Contract-First Example in SpringBoot

Contract-First means what the name implies that we write the contract between client and server first and implement the code for it after. This is a good way to break up the task of creating an API in smaller parts which can be handled over multiple professions. For example, the OpenAPI specification can be created by an IT-architect and the implementation can be done by a programmer, and lastly the API documentation can be carried out by an communications expert.

In this article I’m going to build a simple OpenAPI implementation in Apache Camel and it’s rest-openapi component in a SpringBoot application.

1. We start with the API Specification:

openapi: 3.0.3
info:
  title: Basic API
  version: "1.0"
paths:
  /test:
    get:
      operationId: test
      responses:
        200:
          description: Default response
  /user/{userId}:
    get:
      operationId: getUser
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: string
      responses:
        200:
          description: Default response

A few things to note here:
/test – this is the url that the client will use
operationId for the test endpoint – is the route that will receive the call from url above
/user/{userId} – url with parameter that the client will use
operationId – here the operationId does not match the url, which is fine. The call will go to the route direct:getUser with the userId in a header on the message seen below

2. Implementation of the Camel solution

package com.example.contract_first_example;


import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;


/**
 * A Camel Java DSL Router for Contract First Example
 */
@Component
public class MyApp extends RouteBuilder {
    @Override
    public void configure() throws Exception {
        rest().openApi().specification("hello-rest-service.yaml");

        from("direct://hello")
            .setBody().constant("Hello from Camel!");

        from("direct://getUser")
            .process(exchange -> {
                exchange.getMessage().setBody("Hello from user: " 
                             + exchange.getMessage().getHeader("userId"));
            });
    }
}

3. Now the implementation is done and we move on to testing:

PS C:\Users\niklas> curl -XGET localhost:8080/hello
Hello from Camel!
PS C:\Users\niklas> curl -XGET localhost:8080/user/11
Hello from user: 11

And that is all there is – pretty simple, like most things in the Camel world 😉

Tested on Java 17, OpenAPI 3.0, Apache Camel 4.9.0 and SpringBoot 3.3.4 in a Windows 10 environment