Aha Service Discovery

The Aha service discovery is a native Synapse tool and protocol for doing service discovery when multiple Synapse services are being deployed in an environment. This page covers how Aha works, what services the Aha server provides, and demonstrates a Cortex configurations using Aha.

How Aha Works

The Aha protocol is very simple. From a high level, the Aha service runs in a standalone, mirrored, or clustered mode of operation.

  • A Synapse service built from a Cell (a Cortex, a Axon, a Storm Service, etc) can be configured to register itself with the Aha service with a given name.

  • The Aha service stores the connection information from the Cell. By default, this is remote IP which the Aha service saw the connection come from and the Telepath listening port of the Cell.

  • When a service or client wants to connect to a service for that name, it will connect the Aha server, lookup the name, and get back the connection information.

  • The client will then make the actual Telepath connection using the connection information provided by the Aha server.

Configuring A Cell

There are several configuration options to setup on a Cell when deploying it with Aha.

aha:name

The name of the Cell to register itself as. This should be unique within a given Aha network. This is required for Aha registration to work.

aha:registry

This is a string, or list of strings, representing Telepath URLs for the Aha servers the cell should register itself as. This is required for Aha registration to work.

aha:network

The Aha network name used to register the Cell under. This acts like a namespace.

aha:leader

If this is configured, and the Cell is active (a leader in a mirror or clustered deployement), it will also register itself with the Aha server with the name.

One of the following two configuration values must be set as well:

dmon:listen

This is a string defining the Telepath listener. This takes takes precedence over any configured SYN_<cell>_TELEPATH values. The scheme will be used to dictate what scheme clients should use to connect to the Cell. The port value that the listener binds too will be the value that is given to the Aha service for clients to connect to. If the port value is zero (0), then an ephemeral port will be bound and used.

aha:svcinfo

The svcinfo data can be used to provide the entire structure of the Telepath information that a client may use to connect to the service. This can include host, port, scheme, and other connection options. This allows the definition of a explicit host name, port, and scheme that can be used to connect to the service. For example this could look like the following:

aha:svcinfo:
  urlinfo:
    host: core.demo.net
    port: 30000
    schema: tcp

This information is used by the Aha server instead of relying on the dynamic resolution of urlinfo data, which is the default behavior. This can enable a configuration where DNS names are used instead of IP addresses for doing connections; where the Telepath listening port on the Cell may not be the same port that users reach the service by; or for providing additional Telepath connection information.

Using Aha with Synapse Clients

Synapse clients which need to use aha:// connections need to know how to connect to the Aha server. This can be accomplished by loading a SYN_DIR/telepath.yaml file. This file contains locations of Aha servers that a client may connect to in order to resolve names for. For example:

$ cat ~/.syn/telepath.yaml
version: 1
aha:servers:
  - - tcp://demouser:[email protected]:8081/
  - - ssl://[email protected]:33391/
    - ssl://[email protected]:33391/
    - ssl://[email protected]:33391/
certdirs:
  - /home/user/special/certdir

This defines two sets of Aha servers and a list of additional certificate directories. When this file is loaded via synapse.telepath.loadTeleEnv(), it registers the lists of Aha servers and list of certificate directories with the Synapse process, and returns a callback function which will remove those directories from the process.

In the above example, two sets of Aha servers are registered, and a additional certificate directory.

Synapse tools, such as synapse.tools.cmdr, synapse.tools.cellauth, will load the telepath.yaml if it is present.

Bootstrapping An Aha Environment

The following shows an example of bootstrapping a local Aha instance, configuring a machine user and a client user for it, adding a Cortex to the network and then connecting to the Cortex via Aha.

Start an Aha service:

SYN_AHACELL_AHA_URLS=tcp://127.0.0.1:8081 SYN_AHACELL_DMON_LISTEN=tcp://0.0.0.0:8081 \
SYN_AHACELL_AUTH_PASSWD=root python -m synapse.servers.aha cells/ahatcp

Add a user to the Aha service. There needs to be a user that a Cell can use to connect and register itself to to the Aha server:

# Add a user to the Aha cell.
python -m synapse.tools.cellauth cell://./cells/ahatcp modify --adduser reguser

# Give the user a password.
python -m synapse.tools.cellauth cell://./cells/ahatcp modify --passwd secret reguser

# Grant it the permissions for authenticating with Aha and registering a service.
python -m synapse.tools.cellauth cell://./cells/aha001modify \
--addrule aha.service.add reguser

Start up a Cortex, configured to register itself with the Aha service. This Cortex is binding a listener on port 0, so the OS will assign the listening port for us:

SYN_CORTEX_DMON_LISTEN=tcp://0.0.0.0:0/ SYN_CORTEX_HTTPS_PORT=8443 SYN_CORTEX_AHA_NAME=ahacore \
SYN_CORTEX_AHA_REGISTRY=tcp://reguser:[email protected]:8081/ SYN_CORTEX_AHA_NETWORK=demonet \
SYN_CORTEX_AUTH_PASSWD=root python -m synapse.servers.cortex cells/ahacore01

The synapse.tools.aha.list utility can be used to inspect the services that have been registered with a given Aha cell.

$ python -m synapse.tools.aha.list cell://./cells/ahatcp
Service              network                        online scheme host                 port   connection opts
ahacore              demonet                        True   tcp    127.0.0.1            45463

Now we can add a client user to the Aha cell so that they can look up the Cell

# Add a client user to Aha.
python -m synapse.tools.cellauth cell://./cells/ahatcp modify --adduser alice

# Give them a password
python -m synapse.tools.cellauth cell://./cells/ahatcp modify --passwd secret alice

# Allow the client to lookup services
python -m synapse.tools.cellauth cell://./cells/ahatcp modify \
--addrule aha.service.get alice

The clients telepath.yaml file will need to include the Aha server location.

$ cat ~/.syn/telepath.yaml
version: 1
aha:servers:
  - - tcp://alice:[email protected]:8081/

Now the user can connect to the Cortex by resolving its IP and port via the Aha server.

python -m synapse.tools.cmdr aha://root:[email protected]/

This will lookup the ahacore.demonet service in the Aha service, and then connect to the Cortex using the information provided by Aha.

The Aha Server as a TLS CA

The Aha server also has the ability to work as a Certificate Authority. Can be used to create a new TLS CA for a given Aha network, and then perform certificate request signing for servers and clients. This can be used in conjunction with devops practices to enable an entire network of Synapse based services to utilize TLS and Telepath together.

Bootstrapping AHA with TLS

The following steps show bootstraping an Aha cell and using TLS to secure the connections between the services.

Note

This example assumes that everything is locally hosted, so no DNS names are used here. The hostname parameter provided to the Telepath URLS instructs the client to confirm, regardless of IP or DNS name, the common name of the certificate to expect when connecting.

Setup a few directories:

mkdir -p cells/aha
mkdir -p cells/ahacore02/certs

Start an Aha Cell

SYN_LOG_LEVEL=DEBUG [email protected] \
python -m synapse.servers.aha cells/aha

This also creates an admin user named admin@demo.net in the Cell.

Connect to the Aha cell and generate a CA for the Aha network and a server certificate for the Aha cell

python -m synapse.tools.aha.easycert -a cell://./cells/aha --ca demo.net

python -m synapse.tools.aha.easycert -a cell://./cells/aha --server \
--network demo.net aha.demo.net

The server private key would have been saved to the users default certdir directory, so we can copy it over Cell certificate directory:

mv ~/.syn/certs/hosts/aha.demo.net.key cells/aha/certs/hosts/aha.demo.net.key

Restart the Aha Cell with TLS:

SYN_AHACELL_DMON_LISTEN="ssl://0.0.0.0:8081/?ca=demo.net&hostname=aha.demo.net" \
SYN_AHACELL_AHA_ADMIN="[email protected]" python -m synapse.servers.aha cells/aha

Add groups to the Aha Cell and grant them permissions:

python -m synapse.tools.cellauth "ssl://[email protected]:8081/?hostname=aha.demo.net" \
modify --addrole aha_svc

python -m synapse.tools.cellauth "ssl://[email protected]:8081/?hostname=aha.demo.net" \
modify --addrole aha_user

python -m synapse.tools.cellauth "ssl://[email protected]:8081/?hostname=aha.demo.net" \
modify --addrule aha.service.get aha_user

python -m synapse.tools.cellauth "ssl://[email protected]:8081/?hostname=aha.demo.net" \
modify --addrule aha.service.add aha_svc

Add a user for the Cortex to register with, and a client user for connecting to Aha for doing service lookups:

python -m synapse.tools.cellauth "ssl://[email protected]:8081/?hostname=aha.demo.net" \
modify --adduser [email protected]

python -m synapse.tools.cellauth "ssl://[email protected]:8081/?hostname=aha.demo.net" \
modify --grant aha_user [email protected]

python -m synapse.tools.cellauth "ssl://[email protected]:8081/?hostname=aha.demo.net" \
modify --grant aha_svc [email protected]

python -m synapse.tools.cellauth "ssl://[email protected]:8081/?hostname=aha.demo.net" \
modify --adduser [email protected]

python -m synapse.tools.cellauth "ssl://[email protected]:8081/?hostname=aha.demo.net" \
modify --grant aha_user [email protected]

Setup CA, server and user certificates for the Cortex:

# Get a copy of the demo.net CA certificate
python -m synapse.tools.aha.easycert -a "ssl://[email protected]:8081/?hostname=aha.demo.net" \
--certdir cells/ahacore02/certs/ --ca demo.net

# Server certificate for ahacore02.demo.net
python -m synapse.tools.aha.easycert -a "ssl://[email protected]:8081/?hostname=aha.demo.net" \
--certdir cells/ahacore02/certs/ --network demo.net --server core02.demo.net

# User certificate for [email protected]
python -m synapse.tools.aha.easycert -a "ssl://[email protected]:8081/?hostname=aha.demo.net" \
--certdir cells/ahacore02/certs/ --network demo.net [email protected]

Setup a client certificate for bob@demo.net:

python -m synapse.tools.aha.easycert -a "ssl://[email protected]:8081/?hostname=aha.demo.net" \
--network demo.net [email protected]

Startup the Cortex using TLS:

SYN_LOG_LEVEL=DEBUG  SYN_CORTEX_AHA_ADMIN="[email protected]" SYN_CORTEX_HTTPS_PORT=8443 \
SYN_CORTEX_DMON_LISTEN="ssl://0.0.0.0:0/?ca=demo.net&hostname=core02.demo.net" \
SYN_CORTEX_AHA_REGISTRY="ssl://127.0.0.1:8081/?hostname=aha.demo.net&[email protected]" \
SYN_CORTEX_AHA_NAME=core02 SYN_CORTEX_AHA_NETWORK=demo.net \
python -m synapse.servers.cortex cells/ahacore02

Add the bob@demo.net user to the Cortex:

python -m synapse.tools.cellauth "aha://[email protected]/" modify --adduser [email protected]
# And make him a admin so he can do things on the Cortex
python -m synapse.tools.cellauth "aha://[email protected]/" modify --admin [email protected]

One the Cortex is up, it should register itself with the Aha Cell:

python -m synapse.tools.aha.list "ssl://[email protected]:8081/?hostname=aha.demo.net"
Service              network                        online scheme host                 port   connection opts
core02               demo.net                    True   ssl    127.0.0.1            36283  {'name': 'core02.demo.net'}

Update the client telepath.yaml file for the new Aha server:

version: 1
aha:servers:
  - - ssl://[email protected]:8081/?hostname=aha.demo.net

Now Aha can be used to connect to the Cortex:

python -m synapse.tools.cmdr "aha://[email protected]/"

Cell aha:svcinfo Configuration

The aha:svcinfo option, as noted earlier, can be used to dictate the exact information registered with the Aha service. This needs to be used if the Cell is deployed in such a manner that the Telepath listening port is not the same port number that external user would connect to the Cell with.

For example, take a Cortex which uses TLS to listen on a fixed port locally, but also expects clients to connect to it via a DNS name and a remapped port. This could be running in a container inside of a orchestration platform, where its possible that routing rules prevent the use of the port the service binds from also being the port that a user connect to the container.

The relevant cell configuration would look like the following:

aha:name: cortex
aha:network: aha.net
aha:registry: ssl://reguser:[email protected]:8081/
dmon:listen: ssl://127.0.0.1:27492/?hostname=cortex.private.lan
aha:svcinfo:
    urlinfo:
        host: cortex.private.lan
        port: 8081
        scheme: ssl

This would cause the Cortex to share itself locally with the TLS certificate cortex.private.lan and the aha:svcinfo is what would be registered at aha01.private.lan.

A user connecting to aha://someuser:somepass@cortex.aha.net/ would end resolving cortex.aha.net via the Aha service, and then end up using ssl://someuser:somepass@cortex.private.lan:8081/ as the actual connection information.

Running Aha in Mirror Mode

Using Aha in a mirror configuration is similar to setting up a Cortex in a mirror configuration. First, the Aha service needs to have the nexslog:en configuration option set to true. One that is configured, the copy of the Nexus must have its mirror configuration option set to the Telepath url of the upstream Aha server.

Once this is configured, service registration updates done on on the upstream Aha service will be automatically available from the mirror cells. Similarly, CA certificate generation is also mirrored, so any newly created CAs are available from any Aha cell.

Using Aha with Custom Client Code

Custom Synapse client which expects to utilize Aha servers for doing service discovery can easily configure the Aha servers by loading the same telepath.yaml file that is used by CLI tools.

Example code loading telepath.yaml

import contextlib
import synapse.common as s_common
import synapse.telepath as s_telepath

async def main(argv):

    # Get the full path to the default telepath.yaml file
    path = s_common.getSynPath('telepath.yaml')

    # Create a exitstack
    async with contextlib.AsyncExitStack() as ctx:

        # Load the telepath environment. If the file
        # Exists, then the return value will be an
        # async callback.
        telefini = await s_telepath.loadTeleEnv(path)

        if telefini is not None:

            # register the callback to be executed
            ctx.push_async_callback(telefini)

        # Now that the telepath environment is setup, we can
        # connect to aha:// URLs if they are provided.
        async with await s_telepath.openurl(argv[0]) as proxy:

            await doStuff(proxy)

    return 0

async def doStuff(proxy):
    pass

sys.exit(asyncio.run(main(sys.argv[1:]))))

A standalone Synapse Cell does not use a telepath.yaml. The Cell will add its own ./certs directory for any local certificates it needs for Telepath, and the URLs in the aha:registry configuration parameter will be added to the running processes list of Aha servers. This allows code running inside of the Cell to connect to aha:// URLs.