feat: makes mutual TLS optional for postgres, mysql/mariadb and grpc (#244)
* feat: makes mutual TLS optional for postgres and mysql * feat: makes mutual TLS optional for gRPC * refactor: replaces deprecated grpc.WithInsecure() * docs: changes meaning of grpc tls option to client cert * chore: updates test go version to same as project version (1.18) * test: adds TLS and mutual TLS support to db and grpc test environments * chore: adds generated test certificates to .gitignore * chore: reduces test certificates to minimum key usage * chore: adds second client certificate which acts as unauthorized * test: adds mysql tls and mutual tls tests * refactor: postgres ssl config check * refactor: change connectTries to 0 for postgres to only have 1 retry by default like mysql * refactor: postgres sslmode and sslrootcert code * test: adds postgres tls and mutual tls tests * fix: treat grpc authOpts grpc_ca_cert, grpc_tls_cert, grpc_tls_key as file paths instead of actual file contents refactor: improves error logging * test: adds grpc tls and mutual tls tests * Fix postgres ssl modes `require`, ``verify-ca` and `verify-full` to work without explicit root certificate. * refactor: adds warning for unknown pg_sslmode style: removes empty lines * style: compress switch case Co-authored-by: Martin Abbrent <martin.abbrent@ufz.de>
This commit is contained in:
parent
a5ca115287
commit
92a9e105cc
|
@ -22,6 +22,9 @@ vendor
|
|||
.idea/
|
||||
.vscode/
|
||||
|
||||
# generated test certificates, keys and CSRs
|
||||
test-files/certificates/**/*.csr
|
||||
test-files/certificates/**/*.pem
|
||||
|
||||
# todo
|
||||
TODO
|
||||
|
|
|
@ -6,7 +6,10 @@ FROM debian:stable-slim as builder
|
|||
#Change them for your needs.
|
||||
ENV MOSQUITTO_VERSION=1.6.10
|
||||
ENV PLUGIN_VERSION=0.6.1
|
||||
ENV GO_VERSION=1.13.8
|
||||
ENV GO_VERSION=1.18
|
||||
# Used in run-test-in-docker.sh to check if the script
|
||||
# is actually run in a container
|
||||
ENV MOSQUITTO_GO_AUTH_TEST_RUNNING_IN_A_CONTAINER=true
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
@ -68,5 +71,9 @@ RUN wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | apt-key add -
|
|||
apt-get install -y mongodb-org && \
|
||||
rm -f /usr/bin/systemctl
|
||||
|
||||
# Install CFSSL to generate test certificates required for tests
|
||||
RUN export PATH=$PATH:/usr/local/go/bin && go install github.com/cloudflare/cfssl/cmd/cfssl@v1.6.2 && cp ~/go/bin/cfssl /usr/local/bin
|
||||
RUN export PATH=$PATH:/usr/local/go/bin && go install github.com/cloudflare/cfssl/cmd/cfssljson@v1.6.2 && cp ~/go/bin/cfssljson /usr/local/bin
|
||||
|
||||
# Pre-compilation of test for speed-up latest re-run
|
||||
RUN export PATH=$PATH:/usr/local/go/bin && go test -c ./backends -o /dev/null
|
|
@ -1409,8 +1409,8 @@ The following `auth_opt_` options are supported:
|
|||
| grpc_host | | Y | gRPC server hostname |
|
||||
| grpc_port | | Y | gRPC server port number |
|
||||
| grpc_ca_cert | | N | gRPC server CA cert path |
|
||||
| grpc_tls_cert | | N | gRPC server TLS cert path |
|
||||
| grpc_tls_key | | N | gRPC server TLS key path |
|
||||
| grpc_tls_cert | | N | gRPC client TLS cert path |
|
||||
| grpc_tls_key | | N | gRPC client TLS key path |
|
||||
| grpc_disable_superuser | false | N | disable superuser checks |
|
||||
| grpc_fail_on_dial_error | false | N | fail to init on dial error |
|
||||
| grpc_dial_timeout_ms | 500 | N | dial timeout in ms |
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -53,9 +55,9 @@ func NewGRPC(authOpts map[string]string, logLevel log.Level) (*GRPC, error) {
|
|||
}
|
||||
}
|
||||
|
||||
caCert := []byte(authOpts["grpc_ca_cert"])
|
||||
tlsCert := []byte(authOpts["grpc_tls_cert"])
|
||||
tlsKey := []byte(authOpts["grpc_tls_key"])
|
||||
caCert := authOpts["grpc_ca_cert"]
|
||||
tlsCert := authOpts["grpc_tls_cert"]
|
||||
tlsKey := authOpts["grpc_tls_key"]
|
||||
addr := fmt.Sprintf("%s:%s", authOpts["grpc_host"], authOpts["grpc_port"])
|
||||
withBlock := authOpts["grpc_fail_on_dial_error"] == "true"
|
||||
|
||||
|
@ -156,7 +158,7 @@ func (o *GRPC) Halt() {
|
|||
}
|
||||
}
|
||||
|
||||
func setup(hostname string, caCert, tlsCert, tlsKey []byte, withBlock bool) ([]grpc.DialOption, error) {
|
||||
func setup(hostname string, caCert string, tlsCert string, tlsKey string, withBlock bool) ([]grpc.DialOption, error) {
|
||||
logrusEntry := log.NewEntry(log.StandardLogger())
|
||||
logrusOpts := []grpc_logrus.Option{
|
||||
grpc_logrus.WithLevels(grpc_logrus.DefaultCodeToLevel),
|
||||
|
@ -172,25 +174,36 @@ func setup(hostname string, caCert, tlsCert, tlsKey []byte, withBlock bool) ([]g
|
|||
nsOpts = append(nsOpts, grpc.WithBlock())
|
||||
}
|
||||
|
||||
if len(caCert) == 0 && len(tlsCert) == 0 && len(tlsKey) == 0 {
|
||||
nsOpts = append(nsOpts, grpc.WithInsecure())
|
||||
if len(caCert) == 0 {
|
||||
nsOpts = append(nsOpts, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
log.WithField("server", hostname).Warning("creating insecure grpc client")
|
||||
} else {
|
||||
log.WithField("server", hostname).Info("creating grpc client")
|
||||
cert, err := tls.X509KeyPair(tlsCert, tlsKey)
|
||||
|
||||
caCertBytes, err := ioutil.ReadFile(caCert)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "load x509 keypair error")
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("could not load grpc ca certificate (grpc_ca_cert) from file (%s)", caCert))
|
||||
}
|
||||
|
||||
caCertPool := x509.NewCertPool()
|
||||
if !caCertPool.AppendCertsFromPEM(caCert) {
|
||||
return nil, errors.Wrap(err, "append ca cert to pool error")
|
||||
if !caCertPool.AppendCertsFromPEM(caCertBytes) {
|
||||
return nil, errors.New("append ca cert to pool error. Maybe the ca file (grpc_ca_cert) does not contain a valid x509 certificate")
|
||||
}
|
||||
tlsConfig := &tls.Config{
|
||||
RootCAs: caCertPool,
|
||||
}
|
||||
|
||||
nsOpts = append(nsOpts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
RootCAs: caCertPool,
|
||||
})))
|
||||
if len(tlsCert) != 0 && len(tlsKey) != 0 {
|
||||
cert, err := tls.LoadX509KeyPair(tlsCert, tlsKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "load x509 keypair error")
|
||||
}
|
||||
certificates := []tls.Certificate{cert}
|
||||
tlsConfig.Certificates = certificates
|
||||
} else if len(tlsCert) != 0 || len(tlsKey) != 0 {
|
||||
log.Warn("gRPC backend warning: mutual TLS was disabled due to missing client certificate (grpc_tls_cert) or client key (grpc_tls_key)")
|
||||
}
|
||||
|
||||
nsOpts = append(nsOpts, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)))
|
||||
}
|
||||
|
||||
return nsOpts, nil
|
||||
|
|
|
@ -2,14 +2,17 @@ package backends
|
|||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
gs "github.com/iegomez/mosquitto-go-auth/grpc"
|
||||
log "github.com/sirupsen/logrus"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -184,3 +187,122 @@ func TestGRPC(t *testing.T) {
|
|||
})
|
||||
|
||||
}
|
||||
|
||||
func TestGRPCTls(t *testing.T) {
|
||||
Convey("Given a mock grpc server with TLS", t, func(c C) {
|
||||
serverCert, err := tls.LoadX509KeyPair("/test-files/certificates/grpc/fullchain-server.pem",
|
||||
"/test-files/certificates/grpc/server-key.pem")
|
||||
c.So(err, ShouldBeNil)
|
||||
|
||||
config := &tls.Config{
|
||||
Certificates: []tls.Certificate{serverCert},
|
||||
ClientAuth: tls.NoClientCert,
|
||||
}
|
||||
grpcServer := grpc.NewServer(grpc.Creds(credentials.NewTLS(config)))
|
||||
gs.RegisterAuthServiceServer(grpcServer, NewAuthServiceAPI())
|
||||
|
||||
listen, err := net.Listen("tcp", ":3123")
|
||||
c.So(err, ShouldBeNil)
|
||||
|
||||
go grpcServer.Serve(listen)
|
||||
defer grpcServer.Stop()
|
||||
|
||||
authOpts := make(map[string]string)
|
||||
authOpts["grpc_host"] = "localhost"
|
||||
authOpts["grpc_port"] = "3123"
|
||||
authOpts["grpc_dial_timeout_ms"] = "100"
|
||||
authOpts["grpc_fail_on_dial_error"] = "true"
|
||||
|
||||
Convey("Given client connects without TLS, it should fail", func() {
|
||||
g, err := NewGRPC(authOpts, log.DebugLevel)
|
||||
c.So(err, ShouldBeError)
|
||||
c.So(err.Error(), ShouldEqual, "context deadline exceeded")
|
||||
c.So(g, ShouldBeNil)
|
||||
})
|
||||
|
||||
authOpts["grpc_ca_cert"] = "/test-files/certificates/db/ca.pem"
|
||||
|
||||
Convey("Given client connects with TLS but with wrong CA, it should fail", func() {
|
||||
g, err := NewGRPC(authOpts, log.DebugLevel)
|
||||
c.So(err, ShouldBeError)
|
||||
c.So(err.Error(), ShouldEqual, "context deadline exceeded")
|
||||
c.So(g, ShouldBeNil)
|
||||
})
|
||||
|
||||
authOpts["grpc_ca_cert"] = "/test-files/certificates/ca.pem"
|
||||
|
||||
Convey("Given client connects with TLS, it should work", func() {
|
||||
g, err := NewGRPC(authOpts, log.DebugLevel)
|
||||
c.So(err, ShouldBeNil)
|
||||
c.So(g, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestGRPCMutualTls(t *testing.T) {
|
||||
Convey("Given a mock grpc server with TLS", t, func(c C) {
|
||||
serverCert, err := tls.LoadX509KeyPair("/test-files/certificates/grpc/fullchain-server.pem",
|
||||
"/test-files/certificates/grpc/server-key.pem")
|
||||
c.So(err, ShouldBeNil)
|
||||
|
||||
clientCaBytes, err := ioutil.ReadFile("/test-files/certificates/grpc/ca.pem")
|
||||
c.So(err, ShouldBeNil)
|
||||
clientCaCertPool := x509.NewCertPool()
|
||||
c.So(clientCaCertPool.AppendCertsFromPEM(clientCaBytes), ShouldBeTrue)
|
||||
|
||||
config := &tls.Config{
|
||||
Certificates: []tls.Certificate{serverCert},
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
ClientCAs: clientCaCertPool,
|
||||
}
|
||||
grpcServer := grpc.NewServer(grpc.Creds(credentials.NewTLS(config)))
|
||||
gs.RegisterAuthServiceServer(grpcServer, NewAuthServiceAPI())
|
||||
|
||||
listen, err := net.Listen("tcp", ":3123")
|
||||
c.So(err, ShouldBeNil)
|
||||
|
||||
go grpcServer.Serve(listen)
|
||||
defer grpcServer.Stop()
|
||||
|
||||
authOpts := make(map[string]string)
|
||||
authOpts["grpc_host"] = "localhost"
|
||||
authOpts["grpc_port"] = "3123"
|
||||
authOpts["grpc_dial_timeout_ms"] = "100"
|
||||
authOpts["grpc_fail_on_dial_error"] = "true"
|
||||
|
||||
Convey("Given client connects without TLS, it should fail", func() {
|
||||
g, err := NewGRPC(authOpts, log.DebugLevel)
|
||||
c.So(err, ShouldBeError)
|
||||
c.So(err.Error(), ShouldEqual, "context deadline exceeded")
|
||||
c.So(g, ShouldBeNil)
|
||||
})
|
||||
|
||||
authOpts["grpc_ca_cert"] = "/test-files/certificates/ca.pem"
|
||||
|
||||
Convey("Given client connects with TLS but without a client certificate, it should fail", func() {
|
||||
g, err := NewGRPC(authOpts, log.DebugLevel)
|
||||
c.So(err, ShouldBeError)
|
||||
c.So(err.Error(), ShouldEqual, "context deadline exceeded")
|
||||
c.So(g, ShouldBeNil)
|
||||
})
|
||||
|
||||
authOpts["grpc_tls_cert"] = "/test-files/certificates/db/client.pem"
|
||||
authOpts["grpc_tls_key"] = "/test-files/certificates/db/client-key.pem"
|
||||
|
||||
Convey("Given client connects with mTLS but with client cert from wrong CA, it should fail", func() {
|
||||
g, err := NewGRPC(authOpts, log.DebugLevel)
|
||||
c.So(err, ShouldBeError)
|
||||
c.So(err.Error(), ShouldEqual, "context deadline exceeded")
|
||||
c.So(g, ShouldBeNil)
|
||||
})
|
||||
|
||||
authOpts["grpc_tls_cert"] = "/test-files/certificates/grpc/client.pem"
|
||||
authOpts["grpc_tls_key"] = "/test-files/certificates/grpc/client-key.pem"
|
||||
|
||||
Convey("Given client connects with mTLS, it should work", func() {
|
||||
g, err := NewGRPC(authOpts, log.DebugLevel)
|
||||
c.So(err, ShouldBeNil)
|
||||
c.So(g, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -117,6 +117,7 @@ func NewMysql(authOpts map[string]string, logLevel log.Level, hasher hashing.Has
|
|||
}
|
||||
|
||||
customSSL := false
|
||||
useSslClientCertificate := false
|
||||
|
||||
if sslmode, ok := authOpts["mysql_sslmode"]; ok {
|
||||
if sslmode == "custom" {
|
||||
|
@ -127,20 +128,21 @@ func NewMysql(authOpts map[string]string, logLevel log.Level, hasher hashing.Has
|
|||
|
||||
if sslCert, ok := authOpts["mysql_sslcert"]; ok {
|
||||
mysql.SSLCert = sslCert
|
||||
} else {
|
||||
customSSL = false
|
||||
useSslClientCertificate = true
|
||||
}
|
||||
|
||||
if sslKey, ok := authOpts["mysql_sslkey"]; ok {
|
||||
mysql.SSLKey = sslKey
|
||||
} else {
|
||||
customSSL = false
|
||||
useSslClientCertificate = true
|
||||
}
|
||||
|
||||
if sslRootCert, ok := authOpts["mysql_sslrootcert"]; ok {
|
||||
mysql.SSLRootCert = sslRootCert
|
||||
} else {
|
||||
customSSL = false
|
||||
if customSSL {
|
||||
log.Warn("MySQL backend warning: TLS was disabled due to missing root certificate (mysql_sslrootcert)")
|
||||
customSSL = false
|
||||
}
|
||||
}
|
||||
|
||||
//If the protocol is a unix socket, we need to set the address as the socket path. If it's tcp, then set the address using host and port.
|
||||
|
@ -179,17 +181,26 @@ func NewMysql(authOpts map[string]string, logLevel log.Level, hasher hashing.Has
|
|||
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
|
||||
return mysql, errors.Errorf("Mysql failed to append root CA pem error: %s", err)
|
||||
}
|
||||
clientCert := make([]tls.Certificate, 0, 1)
|
||||
certs, err := tls.LoadX509KeyPair(mysql.SSLCert, mysql.SSLKey)
|
||||
if err != nil {
|
||||
return mysql, errors.Errorf("Mysql load key and cert error: %s", err)
|
||||
}
|
||||
clientCert = append(clientCert, certs)
|
||||
|
||||
err = mq.RegisterTLSConfig("custom", &tls.Config{
|
||||
RootCAs: rootCertPool,
|
||||
Certificates: clientCert,
|
||||
})
|
||||
tlsConfig := &tls.Config{
|
||||
RootCAs: rootCertPool,
|
||||
}
|
||||
|
||||
if useSslClientCertificate {
|
||||
if mysql.SSLCert != "" && mysql.SSLKey != "" {
|
||||
clientCert := make([]tls.Certificate, 0, 1)
|
||||
certs, err := tls.LoadX509KeyPair(mysql.SSLCert, mysql.SSLKey)
|
||||
if err != nil {
|
||||
return mysql, errors.Errorf("Mysql load key and cert error: %s", err)
|
||||
}
|
||||
clientCert = append(clientCert, certs)
|
||||
tlsConfig.Certificates = clientCert
|
||||
} else {
|
||||
log.Warn("MySQL backend warning: mutual TLS was disabled due to missing client certificate (mysql_sslcert) or client key (mysql_sslkey)")
|
||||
}
|
||||
}
|
||||
|
||||
err = mq.RegisterTLSConfig("custom", tlsConfig)
|
||||
if err != nil {
|
||||
return mysql, errors.Errorf("Mysql register TLS config error: %s", err)
|
||||
}
|
||||
|
|
|
@ -208,3 +208,110 @@ func TestMysql(t *testing.T) {
|
|||
})
|
||||
|
||||
}
|
||||
|
||||
func TestMysqlTls(t *testing.T) {
|
||||
authOpts := make(map[string]string)
|
||||
authOpts["mysql_host"] = "localhost"
|
||||
authOpts["mysql_port"] = "3306"
|
||||
authOpts["mysql_protocol"] = "tcp"
|
||||
authOpts["mysql_allow_native_passwords"] = "true"
|
||||
authOpts["mysql_dbname"] = "go_auth_test"
|
||||
authOpts["mysql_user"] = "go_auth_test_tls"
|
||||
authOpts["mysql_password"] = "go_auth_test_tls"
|
||||
|
||||
authOpts["mysql_userquery"] = "SELECT password_hash FROM test_user WHERE username = ? limit 1"
|
||||
authOpts["mysql_superquery"] = "select count(*) from test_user where username = ? and is_admin = true"
|
||||
authOpts["mysql_aclquery"] = "SELECT test_acl.topic FROM test_acl, test_user WHERE test_user.username = ? AND test_acl.test_user_id = test_user.id AND (rw >= ? or rw = 3)"
|
||||
|
||||
Convey("Given custom ssl disabled, it should fail", t, func() {
|
||||
mysql, err := NewMysql(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, "mysql"))
|
||||
So(err, ShouldBeError)
|
||||
So(err.Error(), ShouldContainSubstring, "Error 1045: Access denied for user")
|
||||
So(mysql.DB, ShouldBeNil)
|
||||
})
|
||||
|
||||
authOpts["mysql_sslmode"] = "custom"
|
||||
authOpts["mysql_sslrootcert"] = "/test-files/certificates/ca.pem"
|
||||
|
||||
Convey("Given custom ssl enabled, it should work without a client certificate", t, func() {
|
||||
mysql, err := NewMysql(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, "mysql"))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
rows, err := mysql.DB.Query("SHOW status like 'Ssl_cipher';")
|
||||
So(err, ShouldBeNil)
|
||||
So(rows.Next(), ShouldBeTrue)
|
||||
|
||||
var variableName string
|
||||
var variableValue string
|
||||
err = rows.Scan(&variableName, &variableValue)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(variableName, ShouldEqual, "Ssl_cipher")
|
||||
So(variableValue, ShouldNotBeBlank)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMysqlMutualTls(t *testing.T) {
|
||||
authOpts := make(map[string]string)
|
||||
authOpts["mysql_host"] = "localhost"
|
||||
authOpts["mysql_port"] = "3306"
|
||||
authOpts["mysql_protocol"] = "tcp"
|
||||
authOpts["mysql_allow_native_passwords"] = "true"
|
||||
authOpts["mysql_dbname"] = "go_auth_test"
|
||||
authOpts["mysql_user"] = "go_auth_test_mutual_tls"
|
||||
authOpts["mysql_password"] = "go_auth_test_mutual_tls"
|
||||
|
||||
authOpts["mysql_userquery"] = "SELECT password_hash FROM test_user WHERE username = ? limit 1"
|
||||
authOpts["mysql_superquery"] = "select count(*) from test_user where username = ? and is_admin = true"
|
||||
authOpts["mysql_aclquery"] = "SELECT test_acl.topic FROM test_acl, test_user WHERE test_user.username = ? AND test_acl.test_user_id = test_user.id AND (rw >= ? or rw = 3)"
|
||||
|
||||
authOpts["mysql_sslmode"] = "custom"
|
||||
authOpts["mysql_sslrootcert"] = "/test-files/certificates/ca.pem"
|
||||
|
||||
Convey("Given custom ssl enabled and no client certificate is given, it should fail", t, func() {
|
||||
mysql, err := NewMysql(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, "mysql"))
|
||||
So(err, ShouldBeError)
|
||||
So(err.Error(), ShouldContainSubstring, "Error 1045: Access denied for user")
|
||||
So(mysql.DB, ShouldBeNil)
|
||||
})
|
||||
|
||||
authOpts["mysql_sslcert"] = "/test-files/certificates/db/unauthorized-second-client.pem"
|
||||
authOpts["mysql_sslkey"] = "/test-files/certificates/db/unauthorized-second-client-key.pem"
|
||||
|
||||
Convey("Given custom ssl enabled and unauthorized client certificate is given, it should fail", t, func() {
|
||||
mysql, err := NewMysql(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, "mysql"))
|
||||
So(err, ShouldBeError)
|
||||
So(err.Error(), ShouldContainSubstring, "Error 1045: Access denied for user")
|
||||
So(mysql.DB, ShouldBeNil)
|
||||
})
|
||||
|
||||
authOpts["mysql_sslcert"] = "/test-files/certificates/grpc/client.pem"
|
||||
authOpts["mysql_sslkey"] = "/test-files/certificates/grpc/client-key.pem"
|
||||
|
||||
Convey("Given custom ssl enabled and invalid client certificate is given, it should fail", t, func() {
|
||||
mysql, err := NewMysql(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, "mysql"))
|
||||
So(err, ShouldBeError)
|
||||
So(err.Error(), ShouldContainSubstring, "invalid connection")
|
||||
So(mysql.DB, ShouldBeNil)
|
||||
})
|
||||
|
||||
authOpts["mysql_sslcert"] = "/test-files/certificates/db/client.pem"
|
||||
authOpts["mysql_sslkey"] = "/test-files/certificates/db/client-key.pem"
|
||||
|
||||
Convey("Given custom ssl enabled and client certificate is given, it should work", t, func() {
|
||||
mysql, err := NewMysql(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, "mysql"))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
rows, err := mysql.DB.Query("SHOW status like 'Ssl_cipher';")
|
||||
So(err, ShouldBeNil)
|
||||
So(rows.Next(), ShouldBeTrue)
|
||||
|
||||
var variableName string
|
||||
var variableValue string
|
||||
err = rows.Scan(&variableName, &variableValue)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(variableName, ShouldEqual, "Ssl_cipher")
|
||||
So(variableValue, ShouldNotBeBlank)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -51,7 +51,6 @@ func NewPostgres(authOpts map[string]string, logLevel log.Level, hasher hashing.
|
|||
SuperuserQuery: "",
|
||||
AclQuery: "",
|
||||
hasher: hasher,
|
||||
connectTries: -1,
|
||||
}
|
||||
|
||||
if host, ok := authOpts["pg_host"]; ok {
|
||||
|
@ -98,9 +97,12 @@ func NewPostgres(authOpts map[string]string, logLevel log.Level, hasher hashing.
|
|||
postgres.AclQuery = aclQuery
|
||||
}
|
||||
|
||||
checkSSL := true
|
||||
|
||||
if sslmode, ok := authOpts["pg_sslmode"]; ok {
|
||||
switch sslmode {
|
||||
case "verify-full", "verify-ca", "require", "disable":
|
||||
default:
|
||||
log.Warnf("PG backend warning: using unknown pg_sslmode: '%s'", sslmode)
|
||||
}
|
||||
postgres.SSLMode = sslmode
|
||||
} else {
|
||||
postgres.SSLMode = "disable"
|
||||
|
@ -108,20 +110,14 @@ func NewPostgres(authOpts map[string]string, logLevel log.Level, hasher hashing.
|
|||
|
||||
if sslCert, ok := authOpts["pg_sslcert"]; ok {
|
||||
postgres.SSLCert = sslCert
|
||||
} else {
|
||||
checkSSL = false
|
||||
}
|
||||
|
||||
if sslKey, ok := authOpts["pg_sslkey"]; ok {
|
||||
postgres.SSLKey = sslKey
|
||||
} else {
|
||||
checkSSL = false
|
||||
}
|
||||
|
||||
if sslCert, ok := authOpts["pg_sslrootcert"]; ok {
|
||||
postgres.SSLCert = sslCert
|
||||
} else {
|
||||
checkSSL = false
|
||||
if sslRootCert, ok := authOpts["pg_sslrootcert"]; ok {
|
||||
postgres.SSLRootCert = sslRootCert
|
||||
}
|
||||
|
||||
//Exit if any mandatory option is missing.
|
||||
|
@ -132,14 +128,31 @@ func NewPostgres(authOpts map[string]string, logLevel log.Level, hasher hashing.
|
|||
//Build the dsn string and try to connect to the db.
|
||||
connStr := fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%s", postgres.User, postgres.Password, postgres.DBName, postgres.Host, postgres.Port)
|
||||
|
||||
if (postgres.SSLMode == "verify-ca" || postgres.SSLMode == "verify-full") && checkSSL {
|
||||
connStr = fmt.Sprintf("%s sslmode=verify-ca sslcert=%s sslkey=%s sslrootcert=%s", connStr, postgres.SSLCert, postgres.SSLKey, postgres.SSLRootCert)
|
||||
} else if postgres.SSLMode == "require" {
|
||||
switch postgres.SSLMode {
|
||||
case "require":
|
||||
connStr = fmt.Sprintf("%s sslmode=require", connStr)
|
||||
} else {
|
||||
case "verify-ca":
|
||||
connStr = fmt.Sprintf("%s sslmode=verify-ca", connStr)
|
||||
case "verify-full":
|
||||
connStr = fmt.Sprintf("%s sslmode=verify-full", connStr)
|
||||
case "disable":
|
||||
fallthrough
|
||||
default:
|
||||
connStr = fmt.Sprintf("%s sslmode=disable", connStr)
|
||||
}
|
||||
|
||||
if postgres.SSLRootCert != "" {
|
||||
connStr = fmt.Sprintf("%s sslrootcert=%s", connStr, postgres.SSLRootCert)
|
||||
}
|
||||
|
||||
if postgres.SSLKey != "" {
|
||||
connStr = fmt.Sprintf("%s sslkey=%s", connStr, postgres.SSLKey)
|
||||
}
|
||||
|
||||
if postgres.SSLCert != "" {
|
||||
connStr = fmt.Sprintf("%s sslcert=%s", connStr, postgres.SSLCert)
|
||||
}
|
||||
|
||||
if tries, ok := authOpts["pg_connect_tries"]; ok {
|
||||
connectTries, err := strconv.Atoi(tries)
|
||||
|
||||
|
|
|
@ -199,3 +199,88 @@ func TestPostgres(t *testing.T) {
|
|||
})
|
||||
|
||||
}
|
||||
|
||||
func TestPostgresTls(t *testing.T) {
|
||||
authOpts := make(map[string]string)
|
||||
authOpts["pg_host"] = "localhost"
|
||||
authOpts["pg_port"] = "5432"
|
||||
authOpts["pg_dbname"] = "go_auth_test"
|
||||
authOpts["pg_user"] = "go_auth_test_tls"
|
||||
authOpts["pg_password"] = "go_auth_test_tls"
|
||||
authOpts["pg_userquery"] = "SELECT password_hash FROM test_user WHERE username = $1 limit 1"
|
||||
authOpts["pg_superquery"] = "select count(*) from test_user where username = $1 and is_admin = true"
|
||||
authOpts["pg_aclquery"] = "SELECT test_acl.topic FROM test_acl, test_user WHERE test_user.username = $1 AND test_acl.test_user_id = test_user.id AND (rw = $2 or rw = 3)"
|
||||
|
||||
Convey("Given custom ssl disabled, it should fail", t, func() {
|
||||
postgres, err := NewPostgres(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, "postgres"))
|
||||
So(err, ShouldBeError)
|
||||
So(err.Error(), ShouldContainSubstring, "pg_hba.conf rejects connection")
|
||||
So(postgres.DB, ShouldBeNil)
|
||||
})
|
||||
|
||||
authOpts["pg_sslmode"] = "verify-full"
|
||||
authOpts["pg_sslrootcert"] = "/test-files/certificates/ca.pem"
|
||||
|
||||
Convey("Given custom ssl enabled, it should work without a client certificate", t, func() {
|
||||
postgres, err := NewPostgres(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, "postgres"))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
rows, err := postgres.DB.Query("SELECT cipher FROM pg_stat_activity JOIN pg_stat_ssl USING(pid);")
|
||||
So(err, ShouldBeNil)
|
||||
So(rows.Next(), ShouldBeTrue)
|
||||
|
||||
var sslCipher string
|
||||
err = rows.Scan(&sslCipher)
|
||||
So(err, ShouldBeNil)
|
||||
So(sslCipher, ShouldNotBeBlank)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPostgresMutualTls(t *testing.T) {
|
||||
authOpts := make(map[string]string)
|
||||
authOpts["pg_host"] = "localhost"
|
||||
authOpts["pg_port"] = "5432"
|
||||
authOpts["pg_dbname"] = "go_auth_test"
|
||||
authOpts["pg_user"] = "go_auth_test_mutual_tls"
|
||||
authOpts["pg_password"] = "go_auth_test_mutual_tls"
|
||||
authOpts["pg_userquery"] = "SELECT password_hash FROM test_user WHERE username = $1 limit 1"
|
||||
authOpts["pg_superquery"] = "select count(*) from test_user where username = $1 and is_admin = true"
|
||||
authOpts["pg_aclquery"] = "SELECT test_acl.topic FROM test_acl, test_user WHERE test_user.username = $1 AND test_acl.test_user_id = test_user.id AND (rw = $2 or rw = 3)"
|
||||
|
||||
authOpts["pg_sslmode"] = "verify-full"
|
||||
authOpts["pg_sslrootcert"] = "/test-files/certificates/ca.pem"
|
||||
|
||||
Convey("Given custom ssl enabled and no client certificate is given, it should fail", t, func() {
|
||||
postgres, err := NewPostgres(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, "postgres"))
|
||||
So(err, ShouldBeError)
|
||||
So(err.Error(), ShouldEqual, "PG backend error: couldn't open db: couldn't ping database postgres: pq: connection requires a valid client certificate")
|
||||
So(postgres.DB, ShouldBeNil)
|
||||
})
|
||||
|
||||
authOpts["pg_sslcert"] = "/test-files/certificates/grpc/client.pem"
|
||||
authOpts["pg_sslkey"] = "/test-files/certificates/grpc/client-key.pem"
|
||||
|
||||
Convey("Given custom ssl enabled and invalid client certificate is given, it should fail", t, func() {
|
||||
postgres, err := NewPostgres(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, "postgres"))
|
||||
So(err, ShouldBeError)
|
||||
So(err.Error(), ShouldEqual, "PG backend error: couldn't open db: couldn't ping database postgres: pq: connection requires a valid client certificate")
|
||||
So(postgres.DB, ShouldBeNil)
|
||||
})
|
||||
|
||||
authOpts["pg_sslcert"] = "/test-files/certificates/db/client.pem"
|
||||
authOpts["pg_sslkey"] = "/test-files/certificates/db/client-key.pem"
|
||||
|
||||
Convey("Given custom ssl enabled and client certificate is given, it should work", t, func() {
|
||||
postgres, err := NewPostgres(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, "postgres"))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
rows, err := postgres.DB.Query("SELECT cipher FROM pg_stat_activity JOIN pg_stat_ssl USING(pid);")
|
||||
So(err, ShouldBeNil)
|
||||
So(rows.Next(), ShouldBeTrue)
|
||||
|
||||
var sslCipher string
|
||||
err = rows.Scan(&sslCipher)
|
||||
So(err, ShouldBeNil)
|
||||
So(sslCipher, ShouldNotBeBlank)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,17 +1,127 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
# This script is make to be run in Docker image build by Dockerfile.test
|
||||
|
||||
service postgresql start
|
||||
service mariadb start
|
||||
service redis-server start
|
||||
function checkIfContainer {
|
||||
if [[ $MOSQUITTO_GO_AUTH_TEST_RUNNING_IN_A_CONTAINER != "true" ]]; then
|
||||
echo "This script is only supposed run in a container as it modifies the system and databases."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
sudo -u mongodb mongod --config /etc/mongod.conf &
|
||||
function prepareAndStartPostgres {
|
||||
local POSTGRES_MAJOR_VERSION=$(sudo find /usr/lib/postgresql -wholename '/usr/lib/postgresql/*/bin/postgres' | grep -Eo '[0-9]+')
|
||||
local POSTGRES_POSTGRESQL_CONF_FILE="/etc/postgresql/$POSTGRES_MAJOR_VERSION/main/postgresql.conf"
|
||||
local POSTGRES_PG_HBA_FILE="/etc/postgresql/$POSTGRES_MAJOR_VERSION/main/pg_hba.conf"
|
||||
|
||||
mkdir /tmp/cluster-test
|
||||
cd /tmp/cluster-test
|
||||
mkdir 7000 7001 7002 7003 7004 7005
|
||||
cat > 7000/redis.conf << EOF
|
||||
# Postgres requires 'postgres' to be owner of the server key
|
||||
mkdir -p /etc/ssl/private/postgresql
|
||||
cp -r /test-files/certificates/db/server-key.pem /etc/ssl/private/postgresql/server-key.pem
|
||||
chown postgres:postgres -R /etc/ssl/private/postgresql
|
||||
usermod -aG ssl-cert postgres
|
||||
|
||||
sed -i "/^ssl_(ca|cert|key)_file)/d" $POSTGRES_POSTGRESQL_CONF_FILE
|
||||
cat >> $POSTGRES_POSTGRESQL_CONF_FILE <<- EOF
|
||||
ssl_ca_file = '/test-files/certificates/db/fullchain-server.pem'
|
||||
ssl_cert_file = '/test-files/certificates/db/server.pem'
|
||||
ssl_key_file = '/etc/ssl/private/postgresql/server-key.pem'
|
||||
EOF
|
||||
|
||||
local PG_HBA_TLS_ENTRIES=$(cat <<- EOF
|
||||
hostssl all go_auth_test_tls 0.0.0.0/0 md5
|
||||
hostnossl all go_auth_test_tls 0.0.0.0/0 reject
|
||||
hostssl all go_auth_test_mutual_tls 0.0.0.0/0 md5 clientcert=verify-ca
|
||||
hostnossl all go_auth_test_mutual_tls 0.0.0.0/0 reject
|
||||
EOF)
|
||||
# Add the tls entries to the beginning of the file, because entry order is important
|
||||
echo "${PG_HBA_TLS_ENTRIES}$(cat $POSTGRES_PG_HBA_FILE)" > $POSTGRES_PG_HBA_FILE
|
||||
|
||||
service postgresql stop && service postgresql start
|
||||
|
||||
sudo -u postgres psql <<- "EOF"
|
||||
create user go_auth_test with login password 'go_auth_test';
|
||||
create database go_auth_test with owner go_auth_test;
|
||||
|
||||
create user go_auth_test_tls with login password 'go_auth_test_tls';
|
||||
grant all privileges on database go_auth_test TO go_auth_test_tls;
|
||||
|
||||
create user go_auth_test_mutual_tls with login password 'go_auth_test_mutual_tls';
|
||||
grant all privileges on database go_auth_test TO go_auth_test_mutual_tls;
|
||||
EOF
|
||||
|
||||
psql "user=go_auth_test password=go_auth_test host=127.0.0.1" <<- "EOF"
|
||||
create table test_user(
|
||||
id bigserial primary key,
|
||||
username character varying (100) not null,
|
||||
password_hash character varying (200) not null,
|
||||
is_admin boolean not null);
|
||||
|
||||
create table test_acl(
|
||||
id bigserial primary key,
|
||||
test_user_id bigint not null references test_user on delete cascade,
|
||||
topic character varying (200) not null,
|
||||
rw int not null);
|
||||
EOF
|
||||
}
|
||||
|
||||
function prepareAndStartMariaDb {
|
||||
# Mariadb requires 'mysql' to be owner of the server key
|
||||
mkdir -p /etc/ssl/private/mariadb
|
||||
cp -r /test-files/certificates/db/server-key.pem /etc/ssl/private/mariadb/server-key.pem
|
||||
chown mysql:mysql -R /etc/ssl/private/mariadb
|
||||
usermod -aG ssl-cert mysql
|
||||
|
||||
cat > /etc/mysql/mariadb.conf.d/100-server-ssl-config.cnf <<- EOF
|
||||
[mysqld]
|
||||
ssl-ca=/test-files/certificates/db/fullchain-server.pem
|
||||
ssl-cert=/test-files/certificates/db/server.pem
|
||||
ssl-key=/etc/ssl/private/mariadb/server-key.pem
|
||||
EOF
|
||||
|
||||
service mariadb stop && service mariadb start
|
||||
|
||||
mysql <<- "EOF"
|
||||
create database go_auth_test;
|
||||
|
||||
create user 'go_auth_test'@'localhost' identified by 'go_auth_test';
|
||||
grant all privileges on go_auth_test.* to 'go_auth_test'@'localhost';
|
||||
|
||||
create user 'go_auth_test_tls'@'localhost' identified by 'go_auth_test_tls' REQUIRE SSL;
|
||||
grant all privileges on go_auth_test.* to 'go_auth_test_tls'@'localhost';
|
||||
create user 'go_auth_test_mutual_tls'@'localhost' identified by 'go_auth_test_mutual_tls' REQUIRE SUBJECT '/CN=Mosquitto Go Auth Test DB Client';
|
||||
grant all privileges on go_auth_test.* to 'go_auth_test_mutual_tls'@'localhost';
|
||||
flush privileges;
|
||||
EOF
|
||||
|
||||
mysql go_auth_test <<- "EOF"
|
||||
create table test_user(
|
||||
id mediumint not null auto_increment,
|
||||
username varchar(100) not null,
|
||||
password_hash varchar(200) not null,
|
||||
is_admin boolean not null,
|
||||
primary key(id)
|
||||
);
|
||||
|
||||
create table test_acl(
|
||||
id mediumint not null auto_increment,
|
||||
test_user_id mediumint not null,
|
||||
topic varchar(200) not null,
|
||||
rw int not null,
|
||||
primary key(id),
|
||||
foreign key(test_user_id) references test_user(id)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE CASCADE
|
||||
);
|
||||
EOF
|
||||
}
|
||||
|
||||
function prepareAndStartRedis() {
|
||||
service redis-server start
|
||||
|
||||
mkdir /tmp/cluster-test
|
||||
cd /tmp/cluster-test
|
||||
mkdir 7000 7001 7002 7003 7004 7005
|
||||
cat > 7000/redis.conf <<- EOF
|
||||
port 7000
|
||||
cluster-enabled yes
|
||||
cluster-config-file nodes.conf
|
||||
|
@ -19,65 +129,36 @@ cluster-node-timeout 5000
|
|||
appendonly yes
|
||||
EOF
|
||||
|
||||
for i in 7001 7002 7003 7004 7005; do
|
||||
sed s/7000/$i/ < 7000/redis.conf > $i/redis.conf
|
||||
done
|
||||
for i in 7001 7002 7003 7004 7005; do
|
||||
sed s/7000/$i/ < 7000/redis.conf > $i/redis.conf
|
||||
done
|
||||
|
||||
for i in 7000 7001 7002 7003 7004 7005; do
|
||||
(cd $i; redis-server redis.conf > server.log 2>&1 &)
|
||||
done
|
||||
for i in 7000 7001 7002 7003 7004 7005; do
|
||||
(cd $i; redis-server redis.conf > server.log 2>&1 &)
|
||||
done
|
||||
|
||||
sudo -u postgres psql << "EOF"
|
||||
create user go_auth_test with login password 'go_auth_test';
|
||||
create database go_auth_test with owner go_auth_test;
|
||||
EOF
|
||||
sleep 3
|
||||
|
||||
psql "user=go_auth_test password=go_auth_test host=127.0.0.1" << "EOF"
|
||||
yes yes | redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 \
|
||||
127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
|
||||
--cluster-replicas 1
|
||||
}
|
||||
|
||||
create table test_user(
|
||||
id bigserial primary key,
|
||||
username character varying (100) not null,
|
||||
password_hash character varying (200) not null,
|
||||
is_admin boolean not null);
|
||||
checkIfContainer
|
||||
|
||||
create table test_acl(
|
||||
id bigserial primary key,
|
||||
test_user_id bigint not null references test_user on delete cascade,
|
||||
topic character varying (200) not null,
|
||||
rw int not null);
|
||||
EOF
|
||||
# Copy certificates structure to container so we
|
||||
# don't overwrite anything
|
||||
mkdir -p /test-files/certificates
|
||||
cp -r /app/test-files/certificates/* /test-files/certificates
|
||||
# Remove all generated certificates because the generator does not delete already existing files
|
||||
rm -rf /test-files/certificates/*.pem && rm -rf /test-files/certificates/*.csr
|
||||
rm -rf /test-files/certificates/**/*.pem && rm -rf /test-files/certificates/**/*.csr
|
||||
/test-files/certificates/generate-all.sh
|
||||
|
||||
|
||||
mysql << "EOF"
|
||||
create user 'go_auth_test'@'localhost' identified by 'go_auth_test';
|
||||
create database go_auth_test;
|
||||
grant all privileges on go_auth_test.* to 'go_auth_test'@'localhost';
|
||||
EOF
|
||||
|
||||
mysql go_auth_test << "EOF"
|
||||
create table test_user(
|
||||
id mediumint not null auto_increment,
|
||||
username varchar(100) not null,
|
||||
password_hash varchar(200) not null,
|
||||
is_admin boolean not null,
|
||||
primary key(id)
|
||||
);
|
||||
|
||||
create table test_acl(
|
||||
id mediumint not null auto_increment,
|
||||
test_user_id mediumint not null,
|
||||
topic varchar(200) not null,
|
||||
rw int not null,
|
||||
primary key(id),
|
||||
foreign key(test_user_id) references test_user(id)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE CASCADE
|
||||
);
|
||||
EOF
|
||||
|
||||
yes yes | redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 \
|
||||
127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
|
||||
--cluster-replicas 1
|
||||
prepareAndStartPostgres
|
||||
prepareAndStartMariaDb
|
||||
prepareAndStartRedis
|
||||
sudo -u mongodb mongod --config /etc/mongod.conf &
|
||||
|
||||
cd /app
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"CN": "Mosquitto Go Auth Test Root CA",
|
||||
"CA": {
|
||||
"expiry": "1h",
|
||||
"pathlen": 1
|
||||
},
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"CN": "Mosquitto Go Auth Test DB Intermediate CA",
|
||||
"CA": {
|
||||
"expiry": "1h",
|
||||
"pathlen": 0
|
||||
},
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"CN": "Mosquitto Go Auth Test DB Client",
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"hosts": [""]
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
cfssl genkey -initca ca.json | cfssljson -bare ca
|
||||
cfssl sign -ca ../ca.pem -ca-key ../ca-key.pem -config=profiles.json -profile=ca ca.csr | cfssljson -bare ca
|
||||
cfssl gencert -ca ca.pem -ca-key ca-key.pem -config=profiles.json -profile=server server.json | cfssljson -bare server
|
||||
cfssl gencert -ca ca.pem -ca-key ca-key.pem -config=profiles.json -profile=client client.json | cfssljson -bare client
|
||||
cfssl gencert -ca ca.pem -ca-key ca-key.pem -config=profiles.json -profile=client unauthorized-second-client.json | cfssljson -bare unauthorized-second-client
|
||||
|
||||
cat server.pem > fullchain-server.pem
|
||||
cat ca.pem >> fullchain-server.pem
|
||||
cat ../ca.pem >> fullchain-server.pem
|
||||
|
||||
cat client.pem > fullchain-client.pem
|
||||
cat ca.pem >> fullchain-client.pem
|
||||
cat ../ca.pem >> fullchain-client.pem
|
||||
|
||||
cd -
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"signing": {
|
||||
"default": {
|
||||
"expiry": "1h"
|
||||
},
|
||||
"profiles": {
|
||||
"ca": {
|
||||
"usages": [
|
||||
"cert sign"
|
||||
],
|
||||
"expiry": "1h",
|
||||
"ca_constraint": {
|
||||
"is_ca": true,
|
||||
"max_path_len": 0,
|
||||
"max_path_len_zero": true
|
||||
}
|
||||
},
|
||||
"server": {
|
||||
"usages": [
|
||||
"key encipherment",
|
||||
"server auth"
|
||||
],
|
||||
"expiry": "1h"
|
||||
},
|
||||
"client": {
|
||||
"usages": [
|
||||
"signing",
|
||||
"key encipherment",
|
||||
"client auth"
|
||||
],
|
||||
"expiry": "1h"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"CN": "Mosquitto Go Auth Test DB Server",
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"hosts": [
|
||||
"localhost",
|
||||
"127.0.0.1",
|
||||
"db.mosquitto-go-auth.invalid"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"CN": "Mosquitto Go Auth Test DB Second Client",
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"hosts": [""]
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
cfssl genkey -initca ca.json | cfssljson -bare ca
|
||||
|
||||
# New subcommand so we don't mess up our last cd location
|
||||
bash -c "./db/generate.sh"
|
||||
bash -c "./grpc/generate.sh"
|
||||
|
||||
cd -
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"CN": "Mosquitto Go Auth Test gRPC Intermediate CA",
|
||||
"CA": {
|
||||
"expiry": "1h",
|
||||
"pathlen": 0
|
||||
},
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"CN": "Mosquitto Go Auth Test gRPC Client",
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"hosts": [""]
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
cfssl genkey -initca ca.json | cfssljson -bare ca
|
||||
cfssl sign -ca ../ca.pem -ca-key ../ca-key.pem -config=profiles.json -profile=ca ca.csr | cfssljson -bare ca
|
||||
cfssl gencert -ca ca.pem -ca-key ca-key.pem -config=profiles.json -profile=server server.json | cfssljson -bare server
|
||||
cfssl gencert -ca ca.pem -ca-key ca-key.pem -config=profiles.json -profile=client client.json | cfssljson -bare client
|
||||
|
||||
cat server.pem > fullchain-server.pem
|
||||
cat ca.pem >> fullchain-server.pem
|
||||
cat ../ca.pem >> fullchain-server.pem
|
||||
|
||||
cat client.pem > fullchain-client.pem
|
||||
cat ca.pem >> fullchain-client.pem
|
||||
cat ../ca.pem >> fullchain-client.pem
|
||||
|
||||
cd -
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"signing": {
|
||||
"default": {
|
||||
"expiry": "1h"
|
||||
},
|
||||
"profiles": {
|
||||
"ca": {
|
||||
"usages": [
|
||||
"cert sign"
|
||||
],
|
||||
"expiry": "1h",
|
||||
"ca_constraint": {
|
||||
"is_ca": true,
|
||||
"max_path_len": 0,
|
||||
"max_path_len_zero": true
|
||||
}
|
||||
},
|
||||
"server": {
|
||||
"usages": [
|
||||
"key encipherment",
|
||||
"server auth"
|
||||
],
|
||||
"expiry": "1h"
|
||||
},
|
||||
"client": {
|
||||
"usages": [
|
||||
"signing",
|
||||
"key encipherment",
|
||||
"client auth"
|
||||
],
|
||||
"expiry": "1h"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"CN": "Mosquitto Go Auth Test gRPC Server",
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"hosts": [
|
||||
"localhost",
|
||||
"127.0.0.1",
|
||||
"grpc.mosquitto-go-auth.invalid"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue