DN Rallypoint Group Restrictions - rallytac/pub GitHub Wiki
Developer Note: Rallypoint Group Restrictions
Rallypoints can control which Engage groups may register—and, with extended restrictions, which client certificates may register for a given group. Together, groupRestrictions and extendedGroupRestrictions let operators run a shared Rallypoint without opening every group to every authenticated client.
For general Rallypoint configuration, meshing, and reflection, see Engage Rallypoints. For mutual TLS and certificate stores, see Engage Security and Using ecstool. If you are also using multiple TLS server identities (additionalIdentities and sni) on the same Rallypoint—for example in multi-domain or load-balanced deployments—see Rallypoint Additional Identities and SNI.
When Restrictions Apply
Restrictions are evaluated when an Engage Engine (or peer Rallypoint acting on behalf of downstream clients) registers a stream/group on the Rallypoint TLS link—not at TCP connect time.
Typical registration flow:
- Client completes mutual TLS authentication.
- Client sends a group registration for a stream ID (Engage group ID).
- Rallypoint normalizes the group ID to uppercase and checks
maxSecurityLevel. - Rallypoint evaluates basic group policy via
groupRestrictionAccessPolicyTypeandgroupRestrictions. - If configured and supported in your build, Rallypoint evaluates extended rules in
extendedGroupRestrictionsagainst the client's X.509 certificate. - On success, the group is wired into the Rallypoint routing table; on failure, registration is denied and the Engine receives a disconnect reason (for example
NotAllowed,NotOnWhitelist, orOnBlacklist).
Mesh peers exchange basic groupRestrictions during the peer hello handshake. When subscribing to streams across the mesh, each Rallypoint skips groups that are disallowed locally or on the far-end peer, reducing unwanted traffic early.
Configuration Overview
| Key | Purpose |
|---|---|
groupRestrictionAccessPolicyType |
Default policy: permissive (0) or strict (1) |
groupRestrictions |
Allow/deny group IDs (exact match) |
extendedGroupRestrictions |
Per-group certificate rules (tags, Subject, Issuer, serial, fingerprint) |
All three live in rallypointd_conf.json at the root of the Rallypoint server object.
Relationship to additionalIdentities
Group restrictions and additionalIdentities solve different problems and are often deployed together:
| Layer | Configuration | When it applies |
|---|---|---|
| TLS identity | additionalIdentities + outbound sni |
TLS handshake—selects which server certificate the Rallypoint presents |
| Group access | groupRestrictions / extendedGroupRestrictions |
Stream registration—controls which groups may register and which client certs qualify per group |
A client may connect successfully (correct sni, valid mutual TLS) and still be denied registration on a specific group if group restrictions block it. Conversely, permissive group policy does not bypass TLS—clients must still authenticate.
Multi-domain deployments commonly combine both: additionalIdentities let France and Germany clients trust different server CAs on the same host:port, while groupRestrictions and extendedGroupRestrictions control which talkgroups each certificate may join once connected. See Rallypoint Additional Identities and SNI for server, Engine, and peering examples.
groupRestrictionAccessPolicyType
Controls the default before groupRestrictions is applied.
| Value | Name | Behavior |
|---|---|---|
0 |
Permissive (default) | Groups are allowed unless groupRestrictions says otherwise |
1 |
Strict | Groups are denied unless explicitly whitelisted in groupRestrictions |
Permissive + no list (open groups)
{
"groupRestrictionAccessPolicyType": 0,
"groupRestrictions": {
"type": 0,
"elements": []
}
}
Any authenticated client may register any group (subject to maxSecurityLevel and extended rules if configured).
Strict + whitelist required
{
"groupRestrictionAccessPolicyType": 1,
"groupRestrictions": {
"type": 1,
"elements": [
"{58E3E468-C0E1-4AD8-86D2-9931251E6EA0}",
"{B7694A4F-9724-44A6-AE57-C63232AD1F57}"
]
}
}
Only those two group IDs may register. Everything else is denied with reason NotAllowed.
Strict mode note: With
groupRestrictionAccessPolicyType1, a blacklist (type2) ingroupRestrictionsdenies all groups—the strict default wins. Use strict mode with a whitelist.
groupRestrictions
Basic group ID filtering. Applies to clients and peer Rallypoints.
"groupRestrictions": {
"type": 1,
"elements": [
"{58E3E468-C0E1-4AD8-86D2-9931251E6EA0}",
"OPS-ALPHA-01"
]
}
Fields
type— restriction mode:0(rtUndefined) — no basic group list active1(rtWhitelist) — only listed group IDs may register2(rtBlacklist) — listed group IDs are denied; all others allowed (in permissive mode)
elements— array of group ID strings (exact match after uppercase normalization)elementsType— may appear in sample JSON; ignored by basicgroupRestrictions. Always use literal group IDs here.
Group ID normalization
At startup the Rallypoint uppercases every entry in groupRestrictions.elements. Incoming registrations also uppercase the stream ID before comparison. These are equivalent:
"{58e3e468-c0e1-4ad8-86d2-9931251e6ea0}"
"{58E3E468-C0E1-4AD8-86D2-9931251E6EA0}"
"ops-alpha-01"
Permissive whitelist (common production pattern)
Allow only known operational groups; deny everything else:
{
"groupRestrictionAccessPolicyType": 0,
"groupRestrictions": {
"type": 1,
"elements": [
"{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}",
"{B2C3D4E5-F6A7-8901-BCDE-F23456789012}",
"INCIDENT-COMMAND-01"
]
}
}
Permissive blacklist (block specific groups)
Allow all groups except a deny list:
{
"groupRestrictionAccessPolicyType": 0,
"groupRestrictions": {
"type": 2,
"elements": [
"{DEADBEEF-0000-4000-8000-000000000001}",
"LAB-EXPERIMENTAL-99"
]
}
}
Clients may register any group except those two.
Static reflector alignment
If you use staticReflectors, include each reflector's group ID in groupRestrictions (or ensure it is not blacklisted). Example from an internal demo configuration:
{
"groupRestrictions": {
"type": 1,
"elements": [ "DS-DEMO-01" ]
},
"staticReflectors": [
{
"id": "DS-DEMO-01",
"rx": { "address": "172.16.50.10", "port": 13000 },
"tx": { "address": "234.5.6.7", "port": 15000 }
}
]
}
Also align multicastRestrictions with reflector multicast address/port pairs—see Engage Rallypoints — Multicast Restrictions.
Startup validation
| Configuration | Result |
|---|---|
type 1 (whitelist) with empty elements |
Rallypoint aborts at startup (nothing to route) |
type 0 with non-empty elements |
Rallypoint aborts (list without a type) |
Invalid type value |
Rallypoint aborts |
extendedGroupRestrictions
Fine-grained control per group ID, based on the connecting client's X.509 certificate presented during mutual TLS.
"extendedGroupRestrictions": [
{
"id": "{58E3E468-C0E1-4AD8-86D2-9931251E6EA0}",
"restrictions": [
{
"type": 1,
"elementsType": 2,
"elements": [ "-educators\\b", "-teachers\\b" ]
}
]
}
]
Object shape
id— group ID this rule set applies to (case-insensitive match after registration normalization)restrictions— array ofStringRestrictionListobjects, each with:type—1whitelist or2blacklistelementsType— how to interpretelements(see table below)elements— strings (literal or PCRE2 regex patterns depending onelementsType)
Prerequisite: basic group access
Extended rules only run after the group passes groupRestrictions. In practice:
- Put the group on a permissive whitelist, or
- Use strict mode and include the group in
groupRestrictions.elements, or - Leave basic policy open (permissive +
type0)
Extended restrictions refine who may use an already-permitted group—they do not by themselves add a group to a strict whitelist.
Evaluation algorithm
For a registration on group G:
- Find the
extendedGroupRestrictionsentry whoseidmatchesG(case-insensitive). If none, extended checks are skipped. - Blacklist pass: For each restriction object with
type2, testelementsagainst the client certificate. If any element matches, registration is denied (OnBlacklist). - Whitelist pass: For each restriction object with
type1, testelements. If at least one whitelist object exists and no whitelist element matched across all whitelist objects, registration is denied (NotOnWhitelist). - Otherwise registration proceeds.
Within a single restriction object, elements are OR'd—matching any one element satisfies that object (for whitelist) or triggers denial (for blacklist).
Across multiple whitelist objects, the implementation treats them as OR as well—matching any whitelist object is sufficient. Use blacklist objects to express exclusions (for example "must have educator tag and must not be in WA/ID").
elementsType reference
| Value | Enum | Matches against |
|---|---|---|
0 |
retGroupId |
Not used in extended restrictions (ignored) |
1 |
retGroupIdPattern |
Not used in extended restrictions (ignored) |
2 |
retGenericAccessTagPattern |
RTS access-tag field in certificate Subject (OID 1.3.6.1.4.1.58217.1) |
3 |
retCertificateSerialNumberPattern |
Client certificate serial number |
4 |
retCertificateFingerprintPattern |
Client certificate SHA-256 fingerprint |
5 |
retCertificateSubjectPattern |
Full client certificate Subject DN string |
6 |
retCertificateIssuerPattern |
Client certificate Issuer DN string |
Except for types 0/1 in this context, patterns use PCRE2. In JSON, escape backslashes: write \\b to express \b word boundaries.
Platform note: Extended restriction regex validation and matching require PCRE2. On Windows builds, extended regex features may be unavailable—validate on your target platform before relying on extended rules in production.
Build note: Extended group restriction enforcement is compiled into builds that define
RTS_PRIVATE_CODE. The configuration is always parsed; confirm behavior on your specificrallypointdpackage.
Example Scenarios
1. School talkgroup — role tags + geographic deny
Goal: Group {58E3E468-C0E1-4AD8-86D2-9931251E6EA0} is for educators. Allow certificates tagged as educators/teachers/instructors, but exclude Washington and Idaho subjects.
{
"groupRestrictionAccessPolicyType": 0,
"groupRestrictions": {
"type": 1,
"elements": [
"{58E3E468-C0E1-4AD8-86D2-9931251E6EA0}",
"{B7694A4F-9724-44A6-AE57-C63232AD1F57}"
]
},
"extendedGroupRestrictions": [
{
"id": "{58e3e468-c0e1-4ad8-86d2-9931251e6ea0}",
"restrictions": [
{
"type": 1,
"elementsType": 2,
"elements": [
"-educators\\b",
"-teachers\\b",
"-instructors\\b"
]
},
{
"type": 2,
"elementsType": 5,
"elements": [
"(ST=WA)|(ST=ID)"
]
}
]
}
]
}
Certificate access tags are embedded in the client certificate Subject under OID 1.3.6.1.4.1.58217.1. Tags are typically hyphen-prefixed strings such as -educators, -teachers. Your PKI / provisioning process must place them there—see Engage Security for certificate structure background.
Use \\b word boundaries so -educators does not also match -educatorsInPhysics.
2. Executive net — issuer whitelist
Goal: Group {B7694A4F-9724-44A6-AE57-C63232AD1F57} accepts only clients issued by a specific organization CA.
"extendedGroupRestrictions": [
{
"id": "{B7694A4F-9724-44A6-AE57-C63232AD1F57}",
"restrictions": [
{
"type": 1,
"elementsType": 6,
"elements": [
"O=My Fictional Issuing Organization"
]
}
]
}
]
elementsType 6 matches against the Issuer DN. Useful when multiple CAs issue client certificates but only one CA is authorized for a sensitive group.
3. Operations floor — OU-based Subject rule
Goal: Restrict OPS-ALPHA-01 to clients whose Subject contains OU=Operations.
"extendedGroupRestrictions": [
{
"id": "OPS-ALPHA-01",
"restrictions": [
{
"type": 1,
"elementsType": 5,
"elements": [
"OU=Operations"
]
}
]
}
]
4. Mixed tag and Subject whitelist (OR semantics)
Goal: Allow either operations tag or operations OU for the same group.
"extendedGroupRestrictions": [
{
"id": "OPS-ALPHA-01",
"restrictions": [
{
"type": 1,
"elementsType": 2,
"elements": [ "-operations\\b" ]
},
{
"type": 1,
"elementsType": 5,
"elements": [ "OU=Operations" ]
}
]
}
]
Because multiple whitelist objects are OR'd, a client matching either rule is admitted.
5. Device blocklist by fingerprint
Goal: Allow group {C1111111-2222-3333-4444-555555555555} for everyone except two known-compromised devices.
"extendedGroupRestrictions": [
{
"id": "{C1111111-2222-3333-4444-555555555555}",
"restrictions": [
{
"type": 2,
"elementsType": 4,
"elements": [
"AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF",
"11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88"
]
}
]
}
]
Fingerprint and serial patterns (types 3/4) are best for break-glass allow/deny lists—not day-to-day role management.
6. Serial allowlist (single authorized handset)
Goal: Only one known serial may register on a maintenance group.
"extendedGroupRestrictions": [
{
"id": "MAINT-HANDSET-ONLY",
"restrictions": [
{
"type": 1,
"elementsType": 3,
"elements": [
"04:A1:B2:C3:D4:E5:F6:07"
]
}
]
}
]
7. Strict hub — closed by default, tags per group
Goal: Hospital Rallypoint denies all groups by default; each approved group has its own certificate tag rule.
{
"groupRestrictionAccessPolicyType": 1,
"groupRestrictions": {
"type": 1,
"elements": [
"EMERGENCY-ED",
"SECURITY-DISPATCH",
"FACILITIES-MAINT"
]
},
"extendedGroupRestrictions": [
{
"id": "EMERGENCY-ED",
"restrictions": [
{
"type": 1,
"elementsType": 2,
"elements": [ "-emergency\\b", "-ed-clinical\\b" ]
}
]
},
{
"id": "SECURITY-DISPATCH",
"restrictions": [
{
"type": 1,
"elementsType": 2,
"elements": [ "-security\\b", "-dispatch\\b" ]
}
]
},
{
"id": "FACILITIES-MAINT",
"restrictions": [
{
"type": 1,
"elementsType": 2,
"elements": [ "-facilities\\b", "-maintenance\\b" ]
}
]
}
]
}
8. Complete reference configuration
Combined basic + extended rules, static reflector, and permissive policy—similar to a fully locked-down operational RP:
{
"id": "ops-rp-01",
"listenPort": 7443,
"groupRestrictionAccessPolicyType": 0,
"groupRestrictions": {
"type": 1,
"elements": [
"{58E3E468-C0E1-4AD8-86D2-9931251E6EA0}",
"{B7694A4F-9724-44A6-AE57-C63232AD1F57}"
]
},
"extendedGroupRestrictions": [
{
"id": "{58E3E468-C0E1-4AD8-86D2-9931251E6EA0}",
"restrictions": [
{
"type": 1,
"elementsType": 2,
"elements": [ "-educators\\b", "-teachers\\b", "-instructors\\b" ]
},
{
"type": 2,
"elementsType": 5,
"elements": [ "ST=WA", "ST=ID" ]
}
]
},
{
"id": "{B7694A4F-9724-44A6-AE57-C63232AD1F57}",
"restrictions": [
{
"type": 1,
"elementsType": 6,
"elements": [ "O=My Fictional Issuing Organization" ]
}
]
}
],
"staticReflectors": [
{
"id": "{58E3E468-C0E1-4AD8-86D2-9931251E6EA0}",
"rx": { "address": "234.1.2.3", "port": 25000 },
"tx": { "address": "234.1.2.3", "port": 25000 }
}
]
}
Mesh Peering and Group Restrictions
When Rallypoints peer, they exchange groupRestrictions in the hello handshake. Each side stores the far-end peer's list and uses it when deciding whether to subscribe to streams toward that peer.
Example: Core RP allows groups A and B; Leaf RP allows only group A. When the core learns of group B from a local client, it will not register for group B toward the leaf—the leaf's exchanged whitelist does not include B.
Configure peer groupRestrictions on each Rallypoint independently. Extended certificate rules are local—they are not exchanged on the peer link; each RP enforces its own extendedGroupRestrictions for registrations arriving on its client and peer connections.
Client-Side Effects
Engage Engine-powered applications do not configure groupRestrictions—that is Rallypoint-side only. When registration is denied, the Engine receives a group disconnect reason. Common values:
| Reason | Typical cause |
|---|---|
NotAllowed |
Failed basic groupRestrictions / strict policy |
NotOnWhitelist |
Failed extended whitelist rule |
OnBlacklist |
Matched extended blacklist rule |
SecurityClassificationLevelTooHigh |
Group security level exceeds maxSecurityLevel |
Check Rallypoint logs for lines such as:
onRegisterStream will NOT allow {58E3E468-C0E1-4AD8-86D2-9931251E6EA0}
onRegisterStream denying registration of ... - far-end does not meet group restriction requirements (WL)
onRegisterStream denying registration of ... - far-end does not meet group restriction requirements (BL)
Regex Tips
- JSON escaping: PCRE escapes need doubling in JSON—
\\b,\\d+,(ST=WA)|(ST=ID). - Word boundaries: Prefer
-tagname\\bover bare-tagnamefor access tags. - Subject DN matching: Type
5searches the full Subject string—patterns likeOU=Operationsmatch anywhere in the DN. Anchor if you need precision:^CN=device01,OU=Operations,O=Example$(adjust for your CA's DN ordering). - Validate at startup: Invalid regex in
extendedGroupRestrictionscauses the Rallypoint to abort during startup validation. - Test before production: Use known-good and known-bad certificates; enable debug logging to see
regexContentSearchoutput in debug builds.
Troubleshooting
| Symptom | Things to check |
|---|---|
| RP aborts at startup | Empty whitelist; list with type 0; invalid regex in extended rules |
| All groups denied | groupRestrictionAccessPolicyType 1 without whitelist; empty peer whitelist exchanged |
| One group denied for all users | Group missing from groupRestrictions whitelist; extended whitelist too narrow |
| One user denied, others fine | Access tags missing from certificate; Subject/Issuer pattern mismatch; typo in regex |
| Worked on Linux, not Windows | Extended regex (PCRE2) may be unavailable on Windows builds |
| Static reflector silent | Group ID not in groupRestrictions whitelist; multicast also restricted |
| Peer mesh missing audio | Far-end peer's exchanged groupRestrictions excludes the group—check both sides' configs |
Related Documentation
- Rallypoint Additional Identities and SNI —
additionalIdentities,sni, and multi-domain TLS server certificate selection - Engage Rallypoints — full RP schema, meshing, multicast restrictions
- Engage Security — mutual TLS, certificate structure
- Using ecstool — certificate store management and tagging