DN Rallypoint Additional Identities - rallytac/pub GitHub Wiki
Developer Note: Rallypoint Additional Identities and SNI
A Rallypoint normally presents a single TLS server identity—the certificate / key pair in rallypointd_conf.json. The additionalIdentities array lets a Rallypoint load extra named certificate/key pairs and select among them at TLS handshake time using Server Name Indication (SNI).
This is useful when:
- Multiple logical domains (in the operational sense—France, Germany, tenant A, tenant B, and so on) share one Rallypoint IP/port or sit behind a load balancer.
- Different clients or peer Rallypoints must authenticate against different server certificates (different CAs, subject DNs, or policy boundaries) while dialing the same
host:port. - You want domain-specific server certs without running a separate
rallypointdprocess per domain.
For general Rallypoint installation, meshing, and the full configuration schema, see Engage Rallypoints. For certificate stores and CA management, see Engage Security and Using ecstool.
How It Works
At startup, rallypointd loads:
- The primary identity from
certificate(internally keyed as*—the default when no SNI is sent or no name matches). - Each entry in
additionalIdentities, keyed by itsname(stored case-insensitively).
When a TLS client connects, OpenSSL invokes an SNI callback. If the client sent an SNI string that matches a loaded identity name, that identity's certificate is presented. Otherwise the primary certificate is used.
Outbound connections—Engage Engine clients and peer Rallypoints—supply the SNI string via the sni field on their Rallypoint connection object. The Rallypoint sets SSL_set_tlsext_host_name() with that value during the TLS ClientHello.
Important: SNI is sent in the clear in the TLS ClientHello. Treat
snias a certificate-selector label, not a secret. It does not replace mutual X.509 authentication or group encryption.
Startup behavior: If any
additionalIdentitiesentry fails to load, the Rallypoint aborts at startup. Validate all referenced certs and keys before deploying.
Two Different "Domain" Concepts
Rallypoints use the word domain in two places. They are often configured together in multi-domain deployments, but they are not the same mechanism.
| Concept | Configuration | Purpose |
|---|---|---|
| TLS identity selection | additionalIdentities[].name + outbound sni |
Choose which server certificate the Rallypoint presents during TLS |
| Logical routing domain | domainName, allowedDomains, blockedDomains, extraDomains |
Control which peer Rallypoints may connect when domain enforcement is enabled; advertise reachable domains in peer hello and mDNS |
domainNameempty ⇒ domain checks are off; any peer may connect regardless of the domain it declares.domainNameset ⇒ connecting peers must declare a domain in the Rallypoint hello handshake, and that domain must appear inallowedDomains(your owndomainNameis included automatically unless blocked).
additionalIdentities names and domainName values do not have to match, but using the same label (for example FRANCE) in both places is a common convention and makes operations easier to reason about.
Rallypoint Server Configuration
Each additionalIdentities element is a NamedIdentity:
name— label sent as TLS SNI by clients/peers that want this identity. Matching is case-insensitive (FRANCE,france, andFranceare equivalent).certificate—SecurityCertificateobject withcertificateandkey(PEM text,@/path/to/file, or@certstore://elementName).
Minimal Example
Primary cert for default connections; two extra identities for domain-specific certs:
{
"id": "core-rp",
"listenPort": 7443,
"certificate": {
"certificate": "@certstore://coreRpDefault",
"key": "@certstore://coreRpDefault"
},
"tls": {
"verifyPeers": true,
"caCertificates": [ "@certstore://rtsCA" ]
},
"additionalIdentities": [
{
"name": "FRANCE",
"certificate": {
"certificate": "@certstore://franceRpSrv",
"key": "@certstore://franceRpSrv"
}
},
{
"name": "GERMANY",
"certificate": {
"certificate": "@certstore://germanyRpSrv",
"key": "@certstore://germanyRpSrv"
}
}
]
}
Clients that omit sni (or send a name that does not match) receive coreRpDefault. Clients or peers that send sni FRANCE receive franceRpSrv.
File-path references work the same way as the primary cert:
{
"name": "france",
"certificate": {
"certificate": "@./france.cert",
"key": "@./france.key"
}
}
Multi-Domain Server with Logical Domain Enforcement
When peer Rallypoints also use domainName, combine TLS identities with domain policy on the same Rallypoint or across a mesh:
{
"id": "core-rp",
"domainName": "CORE",
"allowedDomains": [ "FRANCE", "GERMANY" ],
"extraDomains": [ "FRANCE", "GERMANY" ],
"certificate": {
"certificate": "@certstore://coreRpDefault",
"key": "@certstore://coreRpDefault"
},
"additionalIdentities": [
{
"name": "FRANCE",
"certificate": {
"certificate": "@certstore://franceRpSrv",
"key": "@certstore://franceRpSrv"
}
},
{
"name": "GERMANY",
"certificate": {
"certificate": "@certstore://germanyRpSrv",
"key": "@certstore://germanyRpSrv"
}
}
]
}
A leaf Rallypoint in the France operational domain might be configured as:
{
"id": "france-leaf",
"domainName": "FRANCE",
"isMeshLeaf": true,
"certificate": {
"certificate": "@certstore://franceLeafSrv",
"key": "@certstore://franceLeafSrv"
},
"peeringConfigurationFileName": "/etc/rallypointd/peers.json"
}
The leaf's peers.json dials the core using SNI to select the France server cert on the shared core address (see Peering below).
Engage Engine Configuration
Engage Engine-powered applications (mobile apps, gateways, Engage Bridge Service, engage-cmd, and so on) attach to Rallypoints through the Rallypoint JSON object. Set sni on that object to request a non-default server identity.
Per-group rallypoints is the most common pattern—each group can use a different Rallypoint connection, including a different sni:
{
"groups": [
{
"id": "{a1b2c3d4-e5f6-7890-abcd-ef1234567890}",
"name": "France Ops",
"type": 1,
"cryptoPassword": "62022266D3E22F85B7E23E66EA6C639C0FBD96C37FEF40DD51A06E2119882F44",
"rallypoints": [
{
"host": {
"address": "rp.example.com",
"port": 7443
},
"sni": "FRANCE",
"verifyPeer": true,
"caCertificates": [ "@certstore://franceCA" ],
"certificate": "@certstore://myClientCert",
"certificateKey": "@certstore://myClientCert"
}
]
},
{
"id": "{b2c3d4e5-f6a7-8901-bcde-f23456789012}",
"name": "Germany Ops",
"type": 1,
"cryptoPassword": "62022266D3E22F85B7E23E66EA6C639C0FBD96C37FEF40DD51A06E2119882F44",
"rallypoints": [
{
"host": {
"address": "rp.example.com",
"port": 7443
},
"sni": "GERMANY",
"verifyPeer": true,
"caCertificates": [ "@certstore://germanyCA" ],
"certificate": "@certstore://myClientCert",
"certificateKey": "@certstore://myClientCert"
}
]
}
]
}
Both groups dial the same rp.example.com:7443. TLS SNI selects which server certificate the Rallypoint presents. Each group's caCertificates should include the CA that signed the identity being selected—France clients trust franceCA, Germany clients trust germanyCA.
Rallypoint Cluster (Failover / Multi-RP)
When using rallypointCluster instead of a flat rallypoints array, each cluster member is a full Rallypoint object and may carry its own sni:
{
"id": "{group-id}",
"name": "France Ops with failover",
"type": 1,
"cryptoPassword": "...",
"rallypointCluster": {
"connectionStrategy": 0,
"rolloverSecs": 10,
"rallypoints": [
{
"host": { "address": "rp-primary.example.com", "port": 7443 },
"sni": "FRANCE",
"verifyPeer": true,
"caCertificates": [ "@certstore://franceCA" ]
},
{
"host": { "address": "rp-secondary.example.com", "port": 7443 },
"sni": "FRANCE",
"verifyPeer": true,
"caCertificates": [ "@certstore://franceCA" ]
}
]
}
}
If rallypointCluster.rallypoints is non-empty, it takes precedence over a sibling rallypoints array on the same group.
Engage Bridge Service (EBS)
EBS group definitions use the same rallypoints / rallypointCluster shapes. A bridged raw group that reaches a domain-specific Rallypoint identity:
{
"id": "france-bridge-group",
"name": "France bridge leg",
"type": 3,
"cryptoPassword": "...",
"rallypoints": [
{
"host": { "address": "rp.example.com", "port": 7443 },
"sni": "FRANCE",
"verifyPeer": true,
"caCertificates": [ "@certstore://franceCA" ],
"certificate": "@certstore://ebsClientCert",
"certificateKey": "@certstore://ebsClientCert"
}
]
}
See Engage Bridging Service for broader EBS configuration patterns.
WebSocket Rallypoint Connections
If the group uses protocol 1 (rppTlsWs—WebSocket over TLS), sni behaves the same way on the underlying TLS connection. The Rallypoint's WebSocket listener currently uses a single identity (websocket.certificate); additionalIdentities apply to the primary listenPort TLS listener.
Rallypoint Peering
Peer Rallypoints in a mesh dial each other using the peers.json format documented in Engage Rallypoints — Meshing. Add sni to a peer entry when the far-end Rallypoint exposes multiple server identities on the same host:port.
Single Peer, Domain-Specific SNI
france-leaf peers into core-rp at 172.16.10.10:7443 and requests the France server identity:
{
"peers": [
{
"id": "core-rp",
"enabled": true,
"host": {
"address": "172.16.10.10",
"port": 7443
},
"sni": "FRANCE"
}
]
}
On core-rp, additionalIdentities must include an entry with name FRANCE (or france—case does not matter). The peer link comes up with mutual TLS using core-rp's France server cert.
Switching Identities on the Same Peer
Changing sni in peers.json and reloading peering configuration (or waiting for the periodic file check) causes the Rallypoint to tear down and re-establish the peer connection with the new SNI. This is useful when testing or when repointing a leaf at a different logical domain on a shared core.
Example progression on germany-leaf:
"sni": "FRANCE"⇒ peer link uses France server cert oncore-rp.- Change to
"sni": "GERMANY"⇒germany-leafreconnects;core-rppresents the Germany identity.
Watch rallypointd logs for lines like:
adding peer connection [core-rp @ '172.16.10.10':7443] sni='FRANCE' with certificate
SSL_set_tlsext_host_name() succeeded for 172.16.10.10:7443 regarding sni of [FRANCE]
Mesh with Per-Domain Leaf Rallypoints
Typical layout: a core mesh RP (or cluster behind a load balancer) with additionalIdentities for each operational domain; leaf RPs per site/domain peer into the core.
+------------------+
| Load Balancer |
| rp.example.com |
+--------+---------+
|
+--------------+--------------+
| core-rp |
| additionalIdentities: |
| FRANCE, GERMANY, ... |
+--------------+--------------+
^ ^
sni=FRANCE | | sni=GERMANY
| |
+-------+----+ +------+-------+
| france-leaf| | germany-leaf |
| domainName | | domainName |
| FRANCE | | GERMANY |
+------------+ +--------------+
^ ^
local clients local clients
Core rallypointd_conf.json (abbreviated):
{
"id": "core-rp",
"domainName": "CORE",
"allowedDomains": [ "FRANCE", "GERMANY" ],
"certificate": { "certificate": "@certstore://coreDefault", "key": "@certstore://coreDefault" },
"additionalIdentities": [
{ "name": "FRANCE", "certificate": { "certificate": "@certstore://franceSrv", "key": "@certstore://franceSrv" } },
{ "name": "GERMANY", "certificate": { "certificate": "@certstore://germanySrv", "key": "@certstore://germanySrv" } }
],
"peeringConfigurationFileName": "/etc/rallypointd/peers.json"
}
France leaf peers.json:
{
"peers": [
{
"id": "core-rp",
"enabled": true,
"host": { "address": "rp.example.com", "port": 7443 },
"sni": "FRANCE"
}
]
}
Germany leaf peers.json:
{
"peers": [
{
"id": "core-rp",
"enabled": true,
"host": { "address": "rp.example.com", "port": 7443 },
"sni": "GERMANY"
}
]
}
Each leaf sets isMeshLeaf true and its own domainName so the core mesh forwards traffic correctly. See Connecting Into A Mesh.
Optional Per-Peer Client Certificate
Peer entries may also specify a certificate object (client cert for mutual TLS to that peer). sni is independent—it only selects the server identity on the far end:
{
"id": "core-rp",
"enabled": true,
"host": { "address": "rp.example.com", "port": 7443 },
"sni": "FRANCE",
"certificate": {
"certificate": "@certstore://franceLeafPeerCert",
"key": "@certstore://franceLeafPeerCert"
}
}
End-to-End Walkthrough
This walkthrough uses two Rallypoints on a private network: a core Rallypoint (core-rp at 172.16.10.10) with two additional identities, and a leaf Rallypoint (france-leaf at 172.16.20.5) that peers in with sni set.
1. Configure core-rp with additional identities
{
"id": "core-rp",
"listenPort": 7443,
"certificate": {
"certificate": "@certstore://rtsFactoryDefaultRpSrv",
"key": "@certstore://rtsFactoryDefaultRpSrv"
},
"additionalIdentities": [
{
"name": "france",
"certificate": { "certificate": "@./france.cert", "key": "@./france.key" }
},
{
"name": "germany",
"certificate": { "certificate": "@./germany.cert", "key": "@./germany.key" }
}
]
}
2. Start core-rp
rallypointd -cfg:core-rp.json
Confirm log lines showing each identity loaded:
loaded identity certificate for '*': ...
loaded identity certificate for 'france': ...
loaded identity certificate for 'germany': ...
3. Configure france-leaf to peer with SNI
france-leaf.json points at peers.json:
{
"id": "france-leaf",
"listenPort": 7443,
"peeringConfigurationFileName": "./peers.json"
}
peers.json:
{
"peers": [
{
"id": "core-rp",
"enabled": true,
"host": { "address": "172.16.10.10", "port": 7443 },
"sni": "FRANCE"
}
]
}
4. Configure an Engage client for the same identity
An application group that connects as a client the same way:
"rallypoints": [
{
"host": { "address": "172.16.10.10", "port": 7443 },
"sni": "FRANCE",
"verifyPeer": true,
"caCertificates": [ "@certstore://rtsCA" ]
}
]
5. Verify
- Peer link on
france-leafreachesconnectedstate in the status report. openssl s_clientwith explicit SNI shows the expected server cert:
openssl s_client -connect 172.16.10.10:7443 -servername FRANCE </dev/null 2>/dev/null | openssl x509 -noout -subject
Repeat with -servername GERMANY to see the other identity.
Certificate and Trust Planning
- Primary vs additional CAs: France and Germany identities may be signed by different CAs. Client and peer
caCertificatesmust trust the cert chain for the identity they select viasni. - Mutual TLS still applies:
snionly picks the server cert.tls.verifyPeerson the Rallypoint still requires valid client certificates regardless of SNI. - Naming convention: Pick stable, operator-friendly
namestrings (FRANCE,TENANT_A,SITE_42). They are not required to be DNS hostnames. - Load balancers: TCP/TLS passthrough to
listenPortpreserves SNI end-to-end. TLS termination at the load balancer without forwarding SNI to the Rallypoint breaks identity selection—use passthrough or configure the LB to send the appropriate SNI to backends.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Rallypoint aborts at startup after adding identities | Bad cert/key path, password-protected key without unlock, or PEM parse error in one additionalIdentities entry |
| TLS verify failure on client/peer despite correct address | sni mismatch—client sent no SNI or wrong name, so server presented primary cert signed by a different CA than the client trusts |
| Peer connects but wrong cert in logs | sni case differs from name—should still work (case-insensitive); check for typos or trailing whitespace |
| Peer rejected with domain error | domainName enforcement on far-end RP; ensure peer declares an allowed domain in hello, separate from SNI |
| Identity works for clients but not peers | Confirm sni is set in peers.json, not only in Engine group config |
Enable debug logging and look for cb_SslSniCallback set SSL_CTX for ... on the server and SSL_set_tlsext_host_name() succeeded ... regarding sni of [...] on the client/peer side.
Related Documentation
- Engage Rallypoints — full RP configuration, meshing,
peers.jsonschema - Engage Security — TLS, mutual authentication, certificate stores
- Rallypoint Link Options — TCP vs UDP streaming
- Rallypoint Group Restrictions —
groupRestrictionsandextendedGroupRestrictionsfor per-group access control (independent of SNI identity selection) - Engage Bridging Service — bridging groups that connect via Rallypoint