Crossbar and Letsencrypt

#1

Hi

I am trying to use crossbar with the plugin letsencrypt for dokku. The problem is when i try to use the certificates generated by the letsencrypt on the crossbar config.json i am always getting the error “Lost connection to component ‘component-001’ with code ‘1006’.” Any idea? Here is my config.json

config.json (4.2 KB)

0 Likes

#2

Hi, just to clarify, the error you’re seeing is with the component connection, which is using a client certificate ??
(rather than with the web transport? [which looks ok?])

In which case, do you not also need “certificate” and “key” options??

0 Likes

#3

can you show me a example how to config the config.json file?

sexta-feira, 11 de Novembro de 2016 às 15:19:28 UTC, Gareth Bult escreveu:

···

Hi, just to clarify, the error you’re seeing is with the component connection, which is using a client certificate ??
(rather than with the web transport? [which looks ok?])

In which case, do you not also need “certificate” and “key” options??

0 Likes

#4

here the terminal output

sexta-feira, 11 de Novembro de 2016 às 17:43:31 UTC, Vitor escreveu:

output (6 KB)

···

can you show me a example how to config the config.json file?

sexta-feira, 11 de Novembro de 2016 às 15:19:28 UTC, Gareth Bult escreveu:

Hi, just to clarify, the error you’re seeing is with the component connection, which is using a client certificate ??
(rather than with the web transport? [which looks ok?])

In which case, do you not also need “certificate” and “key” options??

0 Likes

#5

Ok, so this is from an auto-generated config.json with client certificate authentication;

“endpoint”: {
“port”: 8443,
“tls”: {
“certificate”: “…/static/keys/cert.pem”,
“ciphers”: “ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SH A256:”,
“dhparam”: “…/static/keys/dhparam.pem”,
“key”: “…/static/keys/key.pem”
},
“type”: “tcp”
},

``

This is the generated client-side code;

def application(self):
“”“start things up and return an application instance”""
host = self.get(‘global’, ‘host’, ‘localhost’)
port = self.get(‘global’, ‘port’, ‘8800’)
relm = self.get(‘global’, ‘realm’, ‘none’)
name = self.get(‘global’, ‘app’, ‘microservice’)
if self.get(‘global’, ‘ssl’, ‘false’) == ‘true’:
proto = “wss”
else:
proto = “ws”

component_config = ComponentConfig(realm=relm, extra=self)
factory = ApplicationSessionFactory(config=component_config)
factory.session = self.component
server_url = "%s://%s:%s/ws" % (proto, host, port)
transport = ComponentFactory(factory, server_url)
transport.setProtocolOptions(acceptMaskedServerFrames=True)
if proto == 'wss':
    class CtxFactory(ssl.ClientContextFactory):
        def getContext(self):
            self.method = SSL.SSLv23_METHOD
            ctx = ssl.ClientContextFactory.getContext(self)
            ctx.use_certificate_file('certificate.pem')
            ctx.use_privatekey_file('private_key.pem')
            return ctx
    ctx = CtxFactory()

else:
    ctx = None
connectWS(transport, ctx)
return Application(name)

``

And (!) you’ll be wanting some dynamic TLS authentication code to link into crossbar as a component;
(typically you’d register this as something like; “xbar.security.auth_tls” and list it in your config.json as a “ticket” authenticator.

“”“Custom authentication module for Crossbar.io!”""

from autobahn.wamp.exception import ApplicationError
from twisted.internet.defer import inlineCallbacks

@inlineCallbacks
def function(self, realm, authid, details=None):
“”“Authenticate a new session”""

def raise_error(key):
    """come here if authentication fails"""
    err = self.errors[key]
    print('Authentication failed "{}" - "{}"'.format(err['tag'], err['txt']))
    raise ApplicationError(err['tag'], err['txt'])

if not details:
    print('%% client did not supplier certificate details "{}"'.format(authid))
    raise_error(self.TLS_ERROR)

transport = details.get('transport', None)
if not transport:
    print('%% client did not present transport "{}"'.format(authid))
    raise_error(self.TLS_ERROR)

certificate = transport.get('client_cert', None)
if not certificate:
    print('%% client did not present certificate "{}"'.format(authid))
    raise_error(self.TLS_ERROR)

sha1 = certificate.get('sha1', None)
if not sha1:
    print('%% client did not present fingerprint "{}"'.format(authid))
    raise_error(self.TLS_ERROR)

fingerprint = yield self.db.fingerprints.find_one({'ident': sha1})
if not fingerprint:
    print('%% client fingerprint was incorrect "{}" - "{}"'.format(authid, sha1))
    raise_error(self.TLS_ERROR)

common = certificate['subject']['cn']
serial = certificate['serial']
company = certificate['issuer']['ou']
host = certificate['issuer']['cn']
print("+-----------------+")
print("| Connection from | {}@{} - Serial# {}".format(authid, common, serial))
print("| Cert Authority  | {} @ {}".format(company, host))
print("| Fingerprint     | {}".format(sha1))
print("+-----------------+")
return {'role': 'server'}

``

It may not be exactly what you want, but it might help rule something in or out …

0 Likes

#6

Thanks for your response and help Gareth but i am looking for something less complicated. I dont need client authentication, i just want a server, that receives some info from the clients (beaglebones) and send some data to a https webpage like pub/sub. If i use insecure websokets, everything woks fine, but until now, i can publish using secure websokets. Any ideia?

sexta-feira, 11 de Novembro de 2016 às 22:37:40 UTC, Gareth Bult escreveu:

···

Ok, so this is from an auto-generated config.json with client certificate authentication;

“endpoint”: {
“port”: 8443,
“tls”: {
“certificate”: “…/static/keys/cert.pem”,
“ciphers”: “ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SH A256:”,
“dhparam”: “…/static/keys/dhparam.pem”,
“key”: “…/static/keys/key.pem”
},
“type”: “tcp”
},

``

This is the generated client-side code;

def application(self):
“”“start things up and return an application instance”""
host = self.get(‘global’, ‘host’, ‘localhost’)
port = self.get(‘global’, ‘port’, ‘8800’)
relm = self.get(‘global’, ‘realm’, ‘none’)
name = self.get(‘global’, ‘app’, ‘microservice’)
if self.get(‘global’, ‘ssl’, ‘false’) == ‘true’:
proto = “wss”
else:
proto = “ws”

component_config = ComponentConfig(realm=relm, extra=self)
factory = ApplicationSessionFactory(config=component_config)
factory.session = self.component
server_url = "%s://%s:%s/ws" % (proto, host, port)
transport = ComponentFactory(factory, server_url)
transport.setProtocolOptions(acceptMaskedServerFrames=True)
if proto == 'wss':
    class CtxFactory(ssl.ClientContextFactory):
        def getContext(self):
            self.method = SSL.SSLv23_METHOD
            ctx = ssl.ClientContextFactory.getContext(self)
            ctx.use_certificate_file('certificate.pem')
            ctx.use_privatekey_file('private_key.pem')
            return ctx
    ctx = CtxFactory()

else:
    ctx = None
connectWS(transport, ctx)
return Application(name)

``

And (!) you’ll be wanting some dynamic TLS authentication code to link into crossbar as a component;
(typically you’d register this as something like; “xbar.security.auth_tls” and list it in your config.json as a “ticket” authenticator.

“”“Custom authentication module for Crossbar.io!”""

from autobahn.wamp.exception import ApplicationError
from twisted.internet.defer import inlineCallbacks

@inlineCallbacks
def function(self, realm, authid, details=None):
“”“Authenticate a new session”""

def raise_error(key):
    """come here if authentication fails"""
    err = self.errors[key]
    print('Authentication failed "{}" - "{}"'.format(err['tag'], err['txt']))
    raise ApplicationError(err['tag'], err['txt'])

if not details:
    print('%% client did not supplier certificate details "{}"'.format(authid))
    raise_error(self.TLS_ERROR)

transport = details.get('transport', None)
if not transport:
    print('%% client did not present transport "{}"'.format(authid))
    raise_error(self.TLS_ERROR)

certificate = transport.get('client_cert', None)
if not certificate:
    print('%% client did not present certificate "{}"'.format(authid))
    raise_error(self.TLS_ERROR)

sha1 = certificate.get('sha1', None)
if not sha1:
    print('%% client did not present fingerprint "{}"'.format(authid))
    raise_error(self.TLS_ERROR)

fingerprint = yield self.db.fingerprints.find_one({'ident': sha1})
if not fingerprint:
    print('%% client fingerprint was incorrect "{}" - "{}"'.format(authid, sha1))
    raise_error(self.TLS_ERROR)

common = certificate['subject']['cn']
serial = certificate['serial']
company = certificate['issuer']['ou']
host = certificate['issuer']['cn']
print("+-----------------+")
print("| Connection from | {}@{} - Serial# {}".format(authid, common, serial))
print("| Cert Authority  | {} @ {}".format(company, host))
print("| Fingerprint     | {}".format(sha1))
print("+-----------------+")
return {'role': 'server'}

``

It may not be exactly what you want, but it might help rule something in or out …

0 Likes

#7

Ok, well, looking at the error message you’re quoting, I would assume this is coming from the connection between crossbar and your component, rather than crossbar and the client … what happens if you copy the tls section from web into the component section for 127.0.0.1 ??

To quote the documentation;

ca_certificates when set requires that a connecting client’s certificate be issued by one of the listed

So again, I would expect the component connection to be failing as you seem to have set up a partial client certificate configuration …

If you just want https with no certificates, why not let the component and clients connect to the same host/port, i.e. the “type: web” ??

This is what my config.json typically looks like, and this will take connections from local microservices and clients;

“endpoint”: {
“port”: 8443,
“tls”: {
“certificate”: “…/static/keys/cert.pem”,
“ciphers”: “ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:”,
“dhparam”: “…/static/keys/dhparam.pem”,
“key”: “…/static/keys/key.pem”
},
“type”: “tcp”
},
“options”: {
“access_log”: false
},
“paths”: {
“/”: {
“module”: “lib_wsgi”,
“object”: “app”,
“type”: “wsgi”
},
“ws”: {
“auth”: {
“anonymous”: {
“role”: “anonymous”,
“type”: “static”
},
“tls”: {
“authenticator”: “xbr.security.auth_tls”,
“type”: “dynamic”
}
},
“debug”: true,
“options”: {
“enable_webstatus”: false,
},
“type”: “websocket”
}
},
“type”: “web”
}

``

For what it’s worth; in every instance where I’ve started using static authentication, I always ended up converting to dynamic, now I just start with dynamic and take it from there.

If you want to convert this to use client certificates, you add a ca_certificates clause (as you have now) to the “tls” section.

0 Likes