# Synchronizing Trustelem Groups with the Enterprise Vault CLI

### 🎯 Goal

Automatically define access rights to **shared vaults** and **collections** in Enterprise Vault based on membership in **Trustelem groups**, using a custom JSON attribute called `vaultSync`.

---

### 🧩 Overall Workflow

The script reads all Trustelem groups that include the `vaultSync` attribute.

1. For each Trustelem group with the attribute:
    
    
    - A **shared vault** is created or updated.
    - **Collections** can be created or removed according to the configuration.
    - **User permissions** are applied.
2. If a user also has a `vaultSync` attribute, it **overrides** the group configuration.

---

### 🧷 Trustelem Configuration

#### Step 1 – Add custom attributes

##### 🔹 `vaultSync` JSON attribute on a **Trustelem Group** (mandatory)

Example to adapt:

```json
[
  { 
    "sharedVault": "SharedVault1",
    "mode": "exact",
    "collections": ["Collec1", "Collec2"],
    "createCollections": true,
    "deleteCollections": false,
    "role": "User",
    "permission": "view" 
  },
  { 
    "sharedVault": "SharedVault2",
    "mode": "exact",
    "collections": ["Colletion1", "Collection2"],
    "createCollections": true,
    "deleteCollections": false,
    "role": "User",
    "permission": "edit" 
  }
]
```

<div class="contain-inline-size rounded-md border-[0.5px] border-token-border-medium relative bg-token-sidebar-surface-primary" id="bkmrk--2"><div class="overflow-y-auto p-4" dir="ltr">  
</div></div><div class="_tableContainer_16hzy_1" id="bkmrk-field-type-descripti"><div class="_tableWrapper_16hzy_14 group flex w-fit flex-col-reverse" tabindex="-1"><table class="w-fit min-w-(--thread-content-width)" data-end="1707" data-start="1102" style="width: 100%;"><thead data-end="1150" data-start="1102"><tr data-end="1150" data-start="1102"><th data-col-size="sm" data-end="1122" data-start="1102" style="width: 18.0445%;">Field</th><th data-col-size="sm" data-end="1135" data-start="1122" style="width: 10.5043%;">Type</th><th data-col-size="md" data-end="1150" data-start="1135" style="width: 71.4375%;">Description</th></tr></thead><tbody data-end="1707" data-start="1199"><tr data-end="1267" data-start="1199"><td data-col-size="sm" data-end="1218" data-start="1199" style="width: 18.0445%;">`sharedVault`</td><td data-col-size="sm" data-end="1231" data-start="1218" style="width: 10.5043%;">`string`</td><td data-col-size="md" data-end="1267" data-start="1231" style="width: 71.4375%;">Name of the shared vault to sync</td></tr><tr><td style="width: 18.0445%;">`mode`</td><td style="width: 10.5043%;">`string`</td><td style="width: 71.4375%;">"exact" or "pattern". Not mandatory, default to "exact"

If "exact" is used, "collections" list must be exact names of synchronized collections

if "pattern" is used, "collections" list is patterns for collections names.

</td></tr><tr data-end="1333" data-start="1268"><td data-col-size="sm" data-end="1287" data-start="1268" style="width: 18.0445%;">`collections`</td><td data-col-size="sm" data-end="1300" data-start="1287" style="width: 10.5043%;">`string[]`</td><td data-col-size="md" data-end="1333" data-start="1300" style="width: 71.4375%;">List of collections name or patterns</td></tr><tr data-end="1403" data-start="1334"><td data-col-size="sm" data-end="1356" data-start="1334" style="width: 18.0445%;">`createCollections`</td><td data-col-size="sm" data-end="1368" data-start="1356" style="width: 10.5043%;">`boolean`</td><td data-col-size="md" data-end="1403" data-start="1368" style="width: 71.4375%;">Auto-create missing collections (can only be used with exact mode)</td></tr><tr data-end="1476" data-start="1404"><td data-col-size="sm" data-end="1426" data-start="1404" style="width: 18.0445%;">`deleteCollections`</td><td data-col-size="sm" data-end="1438" data-start="1426" style="width: 10.5043%;">`boolean`</td><td data-col-size="md" data-end="1476" data-start="1438" style="width: 71.4375%;">Auto-remove collections not listed (can only be used with exact mode)</td></tr><tr data-end="1570" data-start="1477"><td data-col-size="sm" data-end="1496" data-start="1477" style="width: 18.0445%;">`role`</td><td data-col-size="sm" data-end="1509" data-start="1496" style="width: 10.5043%;">`string`</td><td data-col-size="md" data-end="1570" data-start="1509" style="width: 71.4375%;">User role in the vault: `"Owner"`, `"Admin"`, or `"User"`</td></tr><tr data-end="1707" data-start="1571"><td data-col-size="sm" data-end="1590" data-start="1571" style="width: 18.0445%;">`permission`</td><td data-col-size="sm" data-end="1603" data-start="1590" style="width: 10.5043%;">`string`</td><td data-col-size="md" data-end="1707" data-start="1603" style="width: 71.4375%;">Permission in the collection: `"view"`, `"viewExceptPass"`, `"edit"`, `"editExceptPass"`, `"manage"`</td></tr></tbody></table>

</div></div>`createCollections` and `deleteCollections` are automatically considered to false with mode "pattern".

You can synchronize a group in one or more shared vaults.

You can synchronize one or more Trustelem groups in the same Shared Vault. By this way, you can affect different roles and rights to the differents groups of users.

##### 🔹 `vaultSync` JSON attribute on a **Trustelem User** (optional)

Overrides group settings when applied.  
Example to adapt (the value needs to be an array):

```json
[ 
  { 
    "sharedVault": "SharedVault1",
    "mode": "pattern",
    "collections": ["collection1", "collection1/**"],
    "role": "Admin",
    "permission": "edit" 
  }
]
```

<p class="callout info">**How to use patterns ?**</p>

Patterns uses **glob matching** syntax to consider collections names as filesystem path. It allow you to use wildcard and more complex syntax.

**Glob matching** - Using wildcards (`*` to match at one level of directories and `?` to replace one character), globstars (`**`) to include nested directories.

You can use POSIX character classes \[:alpha:\] or \[:digit:\], regex classes \[1-5\], regex logical (abc|xyz) and brace expansion. If you wont to have an exhausted documentation, you can refer to the library [micromatch](https://www.npmjs.com/package/micromatch "micromatch").

**examples :**

With collections tree as follow

```
collection1/
      collection11
      collection12/
          collection121
          collection122
collection2/
      collection21
```

<table border="1" id="bkmrk-pattern-matching-res" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 35.0001%;"></col><col style="width: 65.1235%;"></col></colgroup><tbody><tr><td class="align-center">**Pattern**</td><td class="align-center">**Matching results**</td></tr><tr><td>`collection1/**`</td><td>`collection1`, `collection11`, `collection12`, `collection121`, `collection122`

collection1 and all childs of collection1

with wildcard "\*\*", parent is included

</td></tr><tr><td>`*`</td><td>`collection1`, `collection2`

all collection of first level

</td></tr><tr><td>`collection?/*`</td><td>`collection11`, `collection12`, `collection21`

all collection of second level with parent 'collection' and an other character.

with wildcard "\*", parent is not included

</td></tr><tr><td>`*/collection[0-9]{1,2}`</td><td>all second level collections with a name 'collection' followed by one or two digits.</td></tr></tbody></table>

#### Step 2 – Generate a Trustelem API Key

1. In the Trustelem admin console, go to **Rest API &gt; New API key** ⚠️if you can't see the **Rest API** tab, you have to create a ticket to require the feature.
2. Click the **edit (pencil)** icon
3. Check:
    
    
    - `users_read`
    - `groups_read`
4. Save.
5. Note the following values:
    
    
    - **KEY ID**
    - **Bearer Token**

---

### 🛠 CLI Script Configuration

##### 1/ Download Enterprise Vault CLI.

##### 2/ Create the `synchro` script

Example with the Linux CLI:

```shell
#!/bin/bash
# --- Configuration ---
vault_id="to_replace"
vault_secret="to_replace"
vault_password="to_replace"
vault_url="to_replace"
trustelem_key_id="to_replace"
trustelem_bearer="to_replace"
trustelem_url="to_replace"

# --- Function: Connect and unlock the Vault CLI ---
connect_to_vault() {
    ./wv logout > /dev/null 2>&1
    ./wv config server "$vault_url" > /dev/null 2>&1
    export WV_CLIENTID=$vault_id
    export WV_CLIENTSECRET=$vault_secret
    export WV_TRUSTELEMKEYID=$trustelem_key_id
    export WV_TRUSTELEMBEARER=$trustelem_bearer
    export WV_TRUSTELEMURL=$trustelem_url
    ./wv login --apikey > /dev/null 2>&1
    export WV_SESSION=$(./wv unlock "$vault_password" --raw)
}

# --- Main Execution ---
connect_to_vault
./wv syncgroups

```

PowerShell example with the Windows CLI:

```powershell
# --- Configuration ---
$vault_id = "to_replace"
$vault_secret = "to_replace"
$vault_password = "to_replace"
$vault_url = "to_replace"
$trustelem_key_id = "to_replace"
$trustelem_bearer = "to_replace"
$trustelem_url = "to_replace"

# --- Function: Connect and unlock the Vault CLI ---
function Connect-ToVault {
    ./wv.exe logout | Out-Null
    ./wv.exe config server $vault_url | Out-Null
    $env:WV_CLIENTID = $vault_id
    $env:WV_CLIENTSECRET = $vault_secret
    $env:WV_TRUSTELEMKEYID = $trustelem_key_id
    $env:WV_TRUSTELEMBEARER = $trustelem_bearer
    $env:WV_TRUSTELEMURL = $trustelem_url
    ./wv.exe login --apikey | Out-Null
    $session = ./wv.exe unlock $vault_password --raw
    $env:WV_SESSION = $session.Trim()
}

# --- Main Execution ---
Connect-ToVault
./wv.exe syncgroups

```

Values to replace:

<div class="_tableContainer_16hzy_1" id="bkmrk-variable-description"><div class="_tableWrapper_16hzy_14 group flex w-fit flex-col-reverse" tabindex="-1"><table class="w-fit min-w-(--thread-content-width)" data-end="2941" data-start="2336" style="width: 104.565%; height: 296.915px;"><thead data-end="2376" data-start="2336"><tr data-end="2376" data-start="2336" style="height: 29.4147px;"><th data-col-size="sm" data-end="2361" data-start="2336" style="width: 22.7952%; height: 29.4147px;">Variable</th><th data-col-size="md" data-end="2376" data-start="2361" style="width: 77.1529%; height: 29.4147px;">Description</th></tr></thead><tbody data-end="2941" data-start="2418"><tr data-end="2515" data-start="2418" style="height: 30.5357px;"><td data-col-size="sm" data-end="2443" data-start="2418" style="width: 22.7952%; height: 30.5357px;">`vault_id`</td><td data-col-size="md" data-end="2515" data-start="2443" style="width: 77.1529%; height: 30.5357px;">API service account ID (web client &gt; Account parameters &gt; Security &gt; API Keys)</td></tr><tr data-end="2577" data-start="2516" style="height: 30.5357px;"><td data-col-size="sm" data-end="2541" data-start="2516" style="width: 22.7952%; height: 30.5357px;">`vault_secret`</td><td data-col-size="md" data-end="2577" data-start="2541" style="width: 77.1529%; height: 30.5357px;">API service account secret (web client &gt; Account parameters &gt; Security &gt; API Keys)</td></tr><tr data-end="2644" data-start="2578" style="height: 30.5357px;"><td data-col-size="sm" data-end="2603" data-start="2578" style="width: 22.7952%; height: 30.5357px;">`vault_password`</td><td data-col-size="md" data-end="2644" data-start="2603" style="width: 77.1529%; height: 30.5357px;">Master password for the service account</td></tr><tr data-end="2741" data-start="2645" style="height: 30.5357px;"><td data-col-size="sm" data-end="2670" data-start="2645" style="width: 22.7952%; height: 30.5357px;">`vault_url`</td><td data-col-size="md" data-end="2741" data-start="2670" style="width: 77.1529%; height: 30.5357px;">Vault instance URL (e.g., `https://vault-yourdomain.trustelem.com`)</td></tr><tr data-end="2789" data-start="2742" style="height: 48.4524px;"><td data-col-size="sm" data-end="2767" data-start="2742" style="width: 22.7952%; height: 48.4524px;">`trustelem_key_id`</td><td data-col-size="md" data-end="2789" data-start="2767" style="width: 77.1529%; height: 48.4524px;">KEY ID from Step 2</td></tr><tr data-end="2843" data-start="2790" style="height: 48.4524px;"><td data-col-size="sm" data-end="2815" data-start="2790" style="width: 22.7952%; height: 48.4524px;">`trustelem_bearer`</td><td data-col-size="md" data-end="2843" data-start="2815" style="width: 77.1529%; height: 48.4524px;">Bearer Token from Step 2</td></tr><tr data-end="2941" data-start="2844" style="height: 48.4524px;"><td data-col-size="sm" data-end="2869" data-start="2844" style="width: 22.7952%; height: 48.4524px;">`trustelem_url`</td><td data-col-size="md" data-end="2941" data-start="2869" style="width: 77.1529%; height: 48.4524px;">Trustelem admin URL (e.g., `https://admin-yourdomain.trustelem.com`)</td></tr></tbody></table>

</div></div>##### 3/ Start the script.

---

### ⚙️ Detailed Synchronization Behavior

#### 1. Shared Vault Management

- **If the shared vault doesn't exist**:
    
    
    - It is **automatically created** and the service account becomes the `Owner`.
- **If it already exists**:
    
    
    - The script checks if the service account is the `Owner`.
    - If not, an **error is returned**.

⚠️ **Important**: if the service account is not a shared vault member, it has no way to know if the shared vault already exists or not. In this case, the script will assume the shared vault doesn't exist and a new shared vault with the same name will be created.

#### 2. Collection Management

- **With `createCollections=true`**:
    
    
    - Collections missing in the vault but listed in the JSON will be created.
    - The service account is given `manage` rights on these.
- **With `deleteCollections=true`**:
    
    
    - Collections present in the vault but not in the list will be deleted.
    - The service account must have `manage` rights to delete them.

⚠️ **Important**: do not set both `createCollections=true` and `deleteCollections=true` at the same time.

🔸 **Note on User Attributes**: User-level `vaultSync` attributes **cannot** create or delete collections—only assign permissions.

#### 3. User Membership &amp; Permissions

- **If a user is not in Vault**:
    
    
    - An **error is returned**.
- **Adding users to collections**:
    
    
    - If the user is not already in a listed collection, they are added with the `role` and `permission` defined.
    - If the user has their own `vaultSync` config, it **overrides** the group config.
    - The service account must have `"manage"` rights.
- **Updating permissions**:
    
    
    - If the user has different permissions in a collection, they are updated accordingly.
    - Requires `"manage"` permission.
- **Removing from collections**:
    
    
    - If a user is in a collection not listed, they are removed.
    - Requires `"manage"` permission.

---

### 🧾 Special Cases

<div class="_tableContainer_16hzy_1" id="bkmrk-scenario-behavior-%F0%9F%94%81-"><div class="_tableWrapper_16hzy_14 group flex w-fit flex-col-reverse" tabindex="-1"><table class="w-fit min-w-(--thread-content-width)" data-end="5078" data-start="4749"><thead data-end="4772" data-start="4749"><tr data-end="4772" data-start="4749"><th data-col-size="sm" data-end="4760" data-start="4749">Scenario</th><th data-col-size="md" data-end="4772" data-start="4760">Behavior</th></tr></thead><tbody data-end="5078" data-start="4797"><tr data-end="4889" data-start="4797"><td data-col-size="sm" data-end="4832" data-start="4797">🔁 Trustelem group renamed in AD</td><td data-col-size="md" data-end="4889" data-start="4832">Synchronization continues (attribute remains present)</td></tr><tr data-end="4977" data-start="4890"><td data-col-size="sm" data-end="4919" data-start="4890">🗑 Trustelem group deleted</td><td data-col-size="md" data-end="4977" data-start="4919">Synchronization stops, but the vault remains unchanged</td></tr><tr data-end="5078" data-start="4978"><td data-col-size="sm" data-end="5011" data-start="4978">♻️ Group deleted and recreated</td><td data-col-size="md" data-end="5078" data-start="5011">Vault is no longer linked; re-adding the attribute resumes sync</td></tr></tbody></table>

</div></div>---

### ✅ Permissions Summary

<div class="_tableContainer_16hzy_1" id="bkmrk-action-required-righ"><div class="_tableWrapper_16hzy_14 group flex w-fit flex-col-reverse" tabindex="-1"><table class="w-fit min-w-(--thread-content-width)" data-end="5423" data-start="5111"><thead data-end="5156" data-start="5111"><tr data-end="5156" data-start="5111"><th data-col-size="sm" data-end="5120" data-start="5111">Action</th><th data-col-size="sm" data-end="5156" data-start="5120">Required Right (Service Account)</th></tr></thead><tbody data-end="5423" data-start="5203"><tr data-end="5251" data-start="5203"><td data-col-size="sm" data-end="5225" data-start="5203">Create shared vault</td><td data-col-size="sm" data-end="5251" data-start="5225">None (becomes `Owner`)</td></tr><tr data-end="5295" data-start="5252"><td data-col-size="sm" data-end="5276" data-start="5252">Modify existing vault</td><td data-col-size="sm" data-end="5295" data-start="5276">Must be `Owner`</td></tr><tr data-end="5335" data-start="5296"><td data-col-size="sm" data-end="5323" data-start="5296">Create/delete collection</td><td data-col-size="sm" data-end="5335" data-start="5323">`manage`</td></tr><tr data-end="5384" data-start="5336"><td data-col-size="sm" data-end="5372" data-start="5336">Add/remove users from collections</td><td data-col-size="sm" data-end="5384" data-start="5372">`manage`</td></tr><tr data-end="5423" data-start="5385"><td data-col-size="sm" data-end="5411" data-start="5385">Update user permissions</td><td data-col-size="sm" data-end="5423" data-start="5411">`manage`</td></tr></tbody></table>

<div class="sticky end-(--thread-content-margin) h-0 self-end select-none">  
</div></div></div>