I am trying to make a TLS connection to RabbitMQ with authentication provided by self-signed certificates through the SASL EXTERNAL mechanism using the golang implementation provided by https://github.com/apache/qpid-proton. The goal is to be able to connect to RabbitMQ without specifying the username and password in the URI.
RabbitMQ is running with the following configuration:
auth_mechanisms.1 = EXTERNAL
auth_mechanisms.2 = PLAIN
auth_mechanisms.3 = AMQPLAIN
and plugins:
I have confirmed that I am able to connect with SASL EXTERNAL using a Node.js library (https://github.com/amqp/rhea) and I have confirmed that connecting with PLAIN and ANONYMOUS works with Go in the qpid-proton library but have been unable to connect with SASL EXTERNAL with Go.
My client code does not return any errors, but the RabbitMQ error logs tell me that the client closed the TCP connection
2021-06-24 18:57:22.029 [info] <0.16358.106> accepting AMQP connection <0.16358.106> (127.0.0.1:50610 -> 127.0.0.1:5671)
2021-06-24 18:57:23.030 [warning] <0.16358.106> closing AMQP connection <0.16358.106> (127.0.0.1:50610 -> 127.0.0.1:5671):
client unexpectedly closed TCP connection
My client code is as follows:
package main
import (
"fmt"
"github.com/apache/qpid-proton/go/pkg/amqp"
"github.com/apache/qpid-proton/go/pkg/electron"
"os"
"crypto/tls"
"io/ioutil"
"crypto/x509"
"time"
)
func main() {
keyPair, err := tls.LoadX509KeyPair("client.crt", "client.key")
if err != nil {
fmt.Println("Failed to load certificate:", err)
os.Exit(1)
}
rootCa, err := ioutil.ReadFile("rootCA.crt")
if err != nil {
fmt.Println("Failed to read root CA:", err)
os.Exit(1)
}
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM(rootCa)
tlsConfig := &tls.Config{
RootCAs: certPool,
InsecureSkipVerify: true,
Certificates: []tls.Certificate{keyPair},
}
container := electron.NewContainer("myContainer")
tlsConn, err := tls.Dial("tcp", "rabbitmq.default.svc.cluster.local:5671", tlsConfig)
if err != nil {
fmt.Println("Failed to open TLS connection:", err)
os.Exit(1)
}
defer tlsConn.Close()
conn, err := container.Connection(
tlsConn,
electron.SASLEnable(),
electron.SASLAllowedMechs("EXTERNAL"),
)
defer conn.Close(err)
if err != nil {
fmt.Println("Failed to open AMQP connection", err)
os.Exit(1)
}
sess, err := conn.Session()
sender, err := sess.Sender(electron.Target("demo-queue"))
if err != nil {
fmt.Println("Creating sender failed:", err)
os.Exit(1)
}
for i := int64(0); i < 100000 ; i++ {
msg := amqp.NewMessage()
body := fmt.Sprintf("Test message %d", i)
msg.Marshal(body)
sender.SendSync(msg)
time.Sleep(1*time.Second)
}
}
This isn't a solution for using the qpid-proton client library but I ended up using https://github.com/Azure/go-amqp to connect to RabbitMQ through SASL EXTERNAL. This library recently had the functionality added.