bt-cli 0.4.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bt_cli/__init__.py +3 -0
- bt_cli/cli.py +830 -0
- bt_cli/commands/__init__.py +1 -0
- bt_cli/commands/configure.py +415 -0
- bt_cli/commands/learn.py +229 -0
- bt_cli/commands/quick.py +784 -0
- bt_cli/core/__init__.py +1 -0
- bt_cli/core/auth.py +213 -0
- bt_cli/core/client.py +313 -0
- bt_cli/core/config.py +393 -0
- bt_cli/core/config_file.py +420 -0
- bt_cli/core/csv_utils.py +91 -0
- bt_cli/core/errors.py +247 -0
- bt_cli/core/output.py +205 -0
- bt_cli/core/prompts.py +87 -0
- bt_cli/core/rest_debug.py +221 -0
- bt_cli/data/CLAUDE.md +88 -0
- bt_cli/data/__init__.py +0 -0
- bt_cli/data/skills/bt/SKILL.md +98 -0
- bt_cli/data/skills/entitle/SKILL.md +159 -0
- bt_cli/data/skills/epmw/SKILL.md +145 -0
- bt_cli/data/skills/pra/SKILL.md +149 -0
- bt_cli/data/skills/pws/SKILL.md +197 -0
- bt_cli/entitle/__init__.py +1 -0
- bt_cli/entitle/client/__init__.py +5 -0
- bt_cli/entitle/client/base.py +443 -0
- bt_cli/entitle/commands/__init__.py +24 -0
- bt_cli/entitle/commands/accounts.py +53 -0
- bt_cli/entitle/commands/applications.py +39 -0
- bt_cli/entitle/commands/auth.py +68 -0
- bt_cli/entitle/commands/bundles.py +218 -0
- bt_cli/entitle/commands/integrations.py +60 -0
- bt_cli/entitle/commands/permissions.py +70 -0
- bt_cli/entitle/commands/policies.py +97 -0
- bt_cli/entitle/commands/resources.py +131 -0
- bt_cli/entitle/commands/roles.py +74 -0
- bt_cli/entitle/commands/users.py +123 -0
- bt_cli/entitle/commands/workflows.py +187 -0
- bt_cli/entitle/models/__init__.py +31 -0
- bt_cli/entitle/models/bundle.py +28 -0
- bt_cli/entitle/models/common.py +37 -0
- bt_cli/entitle/models/integration.py +30 -0
- bt_cli/entitle/models/permission.py +27 -0
- bt_cli/entitle/models/policy.py +25 -0
- bt_cli/entitle/models/resource.py +29 -0
- bt_cli/entitle/models/role.py +28 -0
- bt_cli/entitle/models/user.py +24 -0
- bt_cli/entitle/models/workflow.py +55 -0
- bt_cli/epmw/__init__.py +1 -0
- bt_cli/epmw/client/__init__.py +5 -0
- bt_cli/epmw/client/base.py +848 -0
- bt_cli/epmw/commands/__init__.py +33 -0
- bt_cli/epmw/commands/audits.py +250 -0
- bt_cli/epmw/commands/auth.py +55 -0
- bt_cli/epmw/commands/computers.py +140 -0
- bt_cli/epmw/commands/events.py +233 -0
- bt_cli/epmw/commands/groups.py +215 -0
- bt_cli/epmw/commands/policies.py +673 -0
- bt_cli/epmw/commands/quick.py +348 -0
- bt_cli/epmw/commands/requests.py +224 -0
- bt_cli/epmw/commands/roles.py +78 -0
- bt_cli/epmw/commands/tasks.py +38 -0
- bt_cli/epmw/commands/users.py +219 -0
- bt_cli/epmw/models/__init__.py +1 -0
- bt_cli/pra/__init__.py +1 -0
- bt_cli/pra/client/__init__.py +5 -0
- bt_cli/pra/client/base.py +618 -0
- bt_cli/pra/commands/__init__.py +30 -0
- bt_cli/pra/commands/auth.py +55 -0
- bt_cli/pra/commands/import_export.py +442 -0
- bt_cli/pra/commands/jump_clients.py +139 -0
- bt_cli/pra/commands/jump_groups.py +146 -0
- bt_cli/pra/commands/jump_items.py +638 -0
- bt_cli/pra/commands/jumpoints.py +95 -0
- bt_cli/pra/commands/policies.py +197 -0
- bt_cli/pra/commands/quick.py +470 -0
- bt_cli/pra/commands/teams.py +81 -0
- bt_cli/pra/commands/users.py +87 -0
- bt_cli/pra/commands/vault.py +564 -0
- bt_cli/pra/models/__init__.py +27 -0
- bt_cli/pra/models/common.py +12 -0
- bt_cli/pra/models/jump_client.py +25 -0
- bt_cli/pra/models/jump_group.py +15 -0
- bt_cli/pra/models/jump_item.py +72 -0
- bt_cli/pra/models/jumpoint.py +19 -0
- bt_cli/pra/models/team.py +14 -0
- bt_cli/pra/models/user.py +17 -0
- bt_cli/pra/models/vault.py +45 -0
- bt_cli/pws/__init__.py +1 -0
- bt_cli/pws/client/__init__.py +5 -0
- bt_cli/pws/client/base.py +356 -0
- bt_cli/pws/client/beyondinsight.py +869 -0
- bt_cli/pws/client/passwordsafe.py +1786 -0
- bt_cli/pws/commands/__init__.py +33 -0
- bt_cli/pws/commands/accounts.py +372 -0
- bt_cli/pws/commands/assets.py +311 -0
- bt_cli/pws/commands/auth.py +166 -0
- bt_cli/pws/commands/clouds.py +221 -0
- bt_cli/pws/commands/config.py +344 -0
- bt_cli/pws/commands/credentials.py +347 -0
- bt_cli/pws/commands/databases.py +306 -0
- bt_cli/pws/commands/directories.py +199 -0
- bt_cli/pws/commands/functional.py +298 -0
- bt_cli/pws/commands/import_export.py +452 -0
- bt_cli/pws/commands/platforms.py +118 -0
- bt_cli/pws/commands/quick.py +1646 -0
- bt_cli/pws/commands/search.py +256 -0
- bt_cli/pws/commands/secrets.py +1343 -0
- bt_cli/pws/commands/systems.py +389 -0
- bt_cli/pws/commands/users.py +415 -0
- bt_cli/pws/commands/workgroups.py +166 -0
- bt_cli/pws/config.py +18 -0
- bt_cli/pws/models/__init__.py +19 -0
- bt_cli/pws/models/account.py +186 -0
- bt_cli/pws/models/asset.py +102 -0
- bt_cli/pws/models/common.py +132 -0
- bt_cli/pws/models/system.py +121 -0
- bt_cli-0.4.7.dist-info/METADATA +172 -0
- bt_cli-0.4.7.dist-info/RECORD +121 -0
- bt_cli-0.4.7.dist-info/WHEEL +4 -0
- bt_cli-0.4.7.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""REST API debugging module for bt-cli.
|
|
2
|
+
|
|
3
|
+
Provides httpx event hooks to display API call details when --show-rest is enabled.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import re
|
|
8
|
+
from typing import Any, Dict
|
|
9
|
+
|
|
10
|
+
import httpx
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
from rich.panel import Panel
|
|
13
|
+
from rich.syntax import Syntax
|
|
14
|
+
|
|
15
|
+
# Global flag for REST debugging
|
|
16
|
+
_show_rest = False
|
|
17
|
+
|
|
18
|
+
# Console for output
|
|
19
|
+
_console = Console(stderr=True)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def set_show_rest(enabled: bool) -> None:
|
|
23
|
+
"""Enable or disable REST API call display."""
|
|
24
|
+
global _show_rest
|
|
25
|
+
_show_rest = enabled
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def is_show_rest() -> bool:
|
|
29
|
+
"""Check if REST debugging is enabled."""
|
|
30
|
+
return _show_rest
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _sanitize_headers(headers: httpx.Headers) -> Dict[str, str]:
|
|
34
|
+
"""Sanitize headers by fully redacting sensitive values.
|
|
35
|
+
|
|
36
|
+
Security: Never show any part of sensitive values like tokens or API keys.
|
|
37
|
+
"""
|
|
38
|
+
sanitized = {}
|
|
39
|
+
sensitive_patterns = [
|
|
40
|
+
r"authorization",
|
|
41
|
+
r"ps-auth",
|
|
42
|
+
r"x-api-key",
|
|
43
|
+
r"api-key",
|
|
44
|
+
r"secret",
|
|
45
|
+
r"token",
|
|
46
|
+
r"password",
|
|
47
|
+
r"bearer",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
for key, value in headers.items():
|
|
51
|
+
key_lower = key.lower()
|
|
52
|
+
is_sensitive = any(re.search(p, key_lower) for p in sensitive_patterns)
|
|
53
|
+
|
|
54
|
+
if is_sensitive and value:
|
|
55
|
+
# Fully redact sensitive values - never show any characters
|
|
56
|
+
sanitized[key] = "[REDACTED]"
|
|
57
|
+
else:
|
|
58
|
+
sanitized[key] = value
|
|
59
|
+
|
|
60
|
+
return sanitized
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _sanitize_body(body: Any) -> Any:
|
|
64
|
+
"""Sanitize request/response body by redacting sensitive fields.
|
|
65
|
+
|
|
66
|
+
Security: Redact credentials in form data and JSON bodies.
|
|
67
|
+
"""
|
|
68
|
+
if body is None:
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
# Sensitive field names (case-insensitive matching)
|
|
72
|
+
sensitive_fields = {
|
|
73
|
+
"password", "secret", "token", "api_key", "apikey", "api-key",
|
|
74
|
+
"client_secret", "client-secret", "clientsecret",
|
|
75
|
+
"authorization", "bearer", "credential", "credentials",
|
|
76
|
+
"access_token", "refresh_token", "id_token",
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if isinstance(body, dict):
|
|
80
|
+
sanitized = {}
|
|
81
|
+
for key, value in body.items():
|
|
82
|
+
key_lower = key.lower().replace("-", "_")
|
|
83
|
+
if any(s in key_lower for s in sensitive_fields):
|
|
84
|
+
sanitized[key] = "[REDACTED]"
|
|
85
|
+
elif isinstance(value, (dict, list)):
|
|
86
|
+
sanitized[key] = _sanitize_body(value)
|
|
87
|
+
else:
|
|
88
|
+
sanitized[key] = value
|
|
89
|
+
return sanitized
|
|
90
|
+
elif isinstance(body, list):
|
|
91
|
+
return [_sanitize_body(item) for item in body]
|
|
92
|
+
else:
|
|
93
|
+
return body
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _truncate_body(body: Any, max_length: int = 500, sanitize: bool = True) -> str:
|
|
97
|
+
"""Truncate body for display.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
body: Request/response body
|
|
101
|
+
max_length: Maximum characters to display
|
|
102
|
+
sanitize: If True, redact sensitive fields before display
|
|
103
|
+
"""
|
|
104
|
+
if body is None:
|
|
105
|
+
return "(empty)"
|
|
106
|
+
|
|
107
|
+
if isinstance(body, bytes):
|
|
108
|
+
try:
|
|
109
|
+
body = body.decode("utf-8")
|
|
110
|
+
except UnicodeDecodeError:
|
|
111
|
+
return f"(binary data, {len(body)} bytes)"
|
|
112
|
+
|
|
113
|
+
# Sanitize sensitive data before display
|
|
114
|
+
if sanitize and isinstance(body, (dict, list)):
|
|
115
|
+
body = _sanitize_body(body)
|
|
116
|
+
|
|
117
|
+
if isinstance(body, (dict, list)):
|
|
118
|
+
body = json.dumps(body, indent=2)
|
|
119
|
+
|
|
120
|
+
body_str = str(body)
|
|
121
|
+
if len(body_str) > max_length:
|
|
122
|
+
return body_str[:max_length] + f"\n... ({len(body_str) - max_length} more chars)"
|
|
123
|
+
return body_str
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def log_request(request: httpx.Request) -> None:
|
|
127
|
+
"""Log outgoing HTTP request."""
|
|
128
|
+
if not _show_rest:
|
|
129
|
+
return
|
|
130
|
+
|
|
131
|
+
# Build request info
|
|
132
|
+
method = request.method
|
|
133
|
+
url = str(request.url)
|
|
134
|
+
headers = _sanitize_headers(request.headers)
|
|
135
|
+
|
|
136
|
+
# Get request body if present
|
|
137
|
+
body = None
|
|
138
|
+
if request.content:
|
|
139
|
+
try:
|
|
140
|
+
body = json.loads(request.content)
|
|
141
|
+
except (json.JSONDecodeError, UnicodeDecodeError):
|
|
142
|
+
body = request.content
|
|
143
|
+
|
|
144
|
+
# Build output
|
|
145
|
+
lines = [
|
|
146
|
+
f"[bold cyan]{method}[/bold cyan] [white]{url}[/white]",
|
|
147
|
+
"",
|
|
148
|
+
"[dim]Headers:[/dim]",
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
for key, value in headers.items():
|
|
152
|
+
lines.append(f" [green]{key}:[/green] {value}")
|
|
153
|
+
|
|
154
|
+
if body:
|
|
155
|
+
lines.append("")
|
|
156
|
+
lines.append("[dim]Body:[/dim]")
|
|
157
|
+
body_str = _truncate_body(body, max_length=300)
|
|
158
|
+
lines.append(f" {body_str}")
|
|
159
|
+
|
|
160
|
+
_console.print(Panel(
|
|
161
|
+
"\n".join(lines),
|
|
162
|
+
title="[bold yellow]REST Request[/bold yellow]",
|
|
163
|
+
border_style="yellow",
|
|
164
|
+
expand=False,
|
|
165
|
+
))
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def log_response(response: httpx.Response) -> None:
|
|
169
|
+
"""Log HTTP response."""
|
|
170
|
+
if not _show_rest:
|
|
171
|
+
return
|
|
172
|
+
|
|
173
|
+
# Get status info
|
|
174
|
+
status_code = response.status_code
|
|
175
|
+
status_text = response.reason_phrase or ""
|
|
176
|
+
|
|
177
|
+
# Color based on status
|
|
178
|
+
if status_code < 300:
|
|
179
|
+
status_color = "green"
|
|
180
|
+
elif status_code < 400:
|
|
181
|
+
status_color = "yellow"
|
|
182
|
+
else:
|
|
183
|
+
status_color = "red"
|
|
184
|
+
|
|
185
|
+
# Get response body
|
|
186
|
+
try:
|
|
187
|
+
# Need to read the response to get body
|
|
188
|
+
response.read()
|
|
189
|
+
body = response.json()
|
|
190
|
+
except (json.JSONDecodeError, UnicodeDecodeError):
|
|
191
|
+
body = response.text if response.text else "(empty)"
|
|
192
|
+
except Exception:
|
|
193
|
+
body = "(could not read response)"
|
|
194
|
+
|
|
195
|
+
# Build output
|
|
196
|
+
lines = [
|
|
197
|
+
f"[bold {status_color}]{status_code} {status_text}[/bold {status_color}]",
|
|
198
|
+
"",
|
|
199
|
+
"[dim]Response Body:[/dim]",
|
|
200
|
+
_truncate_body(body, max_length=500),
|
|
201
|
+
]
|
|
202
|
+
|
|
203
|
+
_console.print(Panel(
|
|
204
|
+
"\n".join(lines),
|
|
205
|
+
title="[bold blue]REST Response[/bold blue]",
|
|
206
|
+
border_style="blue",
|
|
207
|
+
expand=False,
|
|
208
|
+
))
|
|
209
|
+
_console.print() # Add spacing between calls
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def get_event_hooks() -> Dict[str, list]:
|
|
213
|
+
"""Get httpx event hooks for request/response logging.
|
|
214
|
+
|
|
215
|
+
Usage:
|
|
216
|
+
client = httpx.Client(event_hooks=get_event_hooks())
|
|
217
|
+
"""
|
|
218
|
+
return {
|
|
219
|
+
"request": [log_request],
|
|
220
|
+
"response": [log_response],
|
|
221
|
+
}
|
bt_cli/data/CLAUDE.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# BT-Admin CLI
|
|
2
|
+
|
|
3
|
+
BeyondTrust Platform CLI for Password Safe, Entitle, PRA, and EPM Windows.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd /home/admin/entitl-sko/bt-cli
|
|
9
|
+
source .venv/bin/activate && source .env
|
|
10
|
+
bt whoami # Test all connections
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Skills Available
|
|
14
|
+
|
|
15
|
+
Use these slash commands for detailed product guidance:
|
|
16
|
+
|
|
17
|
+
| Skill | Purpose |
|
|
18
|
+
|-------|---------|
|
|
19
|
+
| `/bt` | Cross-product commands (PASM onboard/offboard/search) |
|
|
20
|
+
| `/pws` | Password Safe - credentials, systems, secrets |
|
|
21
|
+
| `/pra` | PRA - jump items, vault, SSH CA |
|
|
22
|
+
| `/entitle` | Entitle - JIT access, bundles, workflows |
|
|
23
|
+
| `/epmw` | EPM Windows - computers, policies, requests |
|
|
24
|
+
|
|
25
|
+
## Command Structure
|
|
26
|
+
|
|
27
|
+
| Product | Command | Key Operations |
|
|
28
|
+
|---------|---------|----------------|
|
|
29
|
+
| Cross-product | `bt quick` | `pasm-onboard`, `pasm-offboard`, `pasm-search` |
|
|
30
|
+
| Password Safe | `bt pws` | `systems`, `accounts`, `credentials`, `secrets`, `quick` |
|
|
31
|
+
| PRA | `bt pra` | `jump-items`, `vault`, `jump-groups`, `quick` |
|
|
32
|
+
| Entitle | `bt entitle` | `integrations`, `resources`, `bundles`, `permissions` |
|
|
33
|
+
| EPM Windows | `bt epmw` | `computers`, `groups`, `policies`, `requests`, `quick` |
|
|
34
|
+
|
|
35
|
+
## Common Patterns
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# All list commands support JSON output
|
|
39
|
+
bt pws systems list -o json
|
|
40
|
+
bt pra jump-items shell list -o json
|
|
41
|
+
|
|
42
|
+
# Quick commands combine multiple API calls
|
|
43
|
+
bt pws quick checkout -s "system" -a "account"
|
|
44
|
+
bt pws quick onboard -n "host" -i "10.0.1.50" -w 3
|
|
45
|
+
|
|
46
|
+
# Raw output for scripting
|
|
47
|
+
PASSWORD=$(bt pws quick checkout -s server -a admin --raw)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## API Quirks (Gotchas)
|
|
51
|
+
|
|
52
|
+
| Product | Pagination | Response Format |
|
|
53
|
+
|---------|------------|-----------------|
|
|
54
|
+
| PWS | `limit`/`offset` | `{"TotalCount": N, "Data": [...]}` |
|
|
55
|
+
| Entitle | `page`/`perPage` | `{"result": [...], "pagination": {...}}` |
|
|
56
|
+
| PRA | `per_page`/`current_page` (1-indexed) | Array (pagination in headers) |
|
|
57
|
+
| EPMW | `pageNumber`/`pageSize` | `{"data": [...], "totalCount": N}` |
|
|
58
|
+
|
|
59
|
+
**Important:**
|
|
60
|
+
- EPMW computers: Use `archive` not `delete` (405 error)
|
|
61
|
+
- PRA K8s tunnels: Require Linux jumpoint
|
|
62
|
+
- PWS assets: Must create via workgroup endpoint
|
|
63
|
+
- ECM integration: PWS system name must match PRA jump item name
|
|
64
|
+
|
|
65
|
+
## Key Reference IDs
|
|
66
|
+
|
|
67
|
+
| Resource | ID | Notes |
|
|
68
|
+
|----------|-----|-------|
|
|
69
|
+
| PWS Workgroup AWS | 3 | |
|
|
70
|
+
| PWS Workgroup Datacenter | 2 | |
|
|
71
|
+
| PWS Functional Account | 7 | SSH key auth |
|
|
72
|
+
| PRA Jumpoint AWS | 3 | |
|
|
73
|
+
| PRA Jumpoint Datacenter | 2 | |
|
|
74
|
+
| PRA ec2-admin SSH CA | 31 | For EC2 provisioning |
|
|
75
|
+
|
|
76
|
+
## Project Structure
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
src/bt_cli/
|
|
80
|
+
├── cli.py # Root dispatcher
|
|
81
|
+
├── core/ # Shared (config, auth, output)
|
|
82
|
+
├── pws/ # Password Safe
|
|
83
|
+
├── pra/ # PRA
|
|
84
|
+
├── entitle/ # Entitle
|
|
85
|
+
└── epmw/ # EPM Windows
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Each product follows: `client/` (API), `commands/` (CLI), `models/` (Pydantic)
|
bt_cli/data/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bt
|
|
3
|
+
description: BeyondTrust platform CLI cross-product commands. Use when working across PWS, PRA, Entitle, or EPMW together, or for PASM workflows combining Password Safe and PRA.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# BT-Admin Cross-Product Commands
|
|
7
|
+
|
|
8
|
+
CLI for BeyondTrust platform: Password Safe, PRA, Entitle, EPM Windows.
|
|
9
|
+
|
|
10
|
+
## IMPORTANT: Destructive Operations
|
|
11
|
+
|
|
12
|
+
**ALWAYS confirm with the user before running destructive commands:**
|
|
13
|
+
- `delete` - Removes resources permanently
|
|
14
|
+
- `offboard` - Removes systems/accounts from management
|
|
15
|
+
- `archive` - Archives computers (EPMW)
|
|
16
|
+
- `revoke` - Revokes permissions (Entitle)
|
|
17
|
+
|
|
18
|
+
Before executing any destructive operation:
|
|
19
|
+
1. List what will be affected
|
|
20
|
+
2. Ask user for explicit confirmation
|
|
21
|
+
3. Never use `--force` flag without user approval
|
|
22
|
+
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
cd /home/admin/entitl-sko/bt-cli
|
|
27
|
+
source .venv/bin/activate && source .env
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Test All Connections
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
bt whoami # Test all configured products
|
|
34
|
+
bt whoami -o json # JSON output
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Cross-Product Quick Commands (`bt quick`)
|
|
38
|
+
|
|
39
|
+
### PASM Search (PWS + PRA)
|
|
40
|
+
Find systems/accounts across both products. Shows ECM alignment (names must match for credential injection).
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
bt quick pasm-search axion
|
|
44
|
+
bt quick pasm-search web-server -o json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### PASM Onboard (PWS + PRA)
|
|
48
|
+
Onboard a host to both Password Safe and PRA in one command.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Linux SSH host
|
|
52
|
+
bt quick pasm-onboard -n "my-server" -i "10.0.1.50" -w 3 -j 3 -g 24
|
|
53
|
+
|
|
54
|
+
# Full options
|
|
55
|
+
bt quick pasm-onboard \
|
|
56
|
+
--name "web-01" \
|
|
57
|
+
--ip "10.0.1.100" \
|
|
58
|
+
--workgroup 3 \
|
|
59
|
+
--jumpoint 3 \
|
|
60
|
+
--jump-group 24 \
|
|
61
|
+
--functional-account 7 \
|
|
62
|
+
--elevation "sudo" \
|
|
63
|
+
--pra-username "ec2-admin"
|
|
64
|
+
|
|
65
|
+
# Windows RDP host
|
|
66
|
+
bt quick pasm-onboard -n "win-srv" -i "10.0.2.10" -w 2 -p 1 -j 3 -g 31 --jump-type rdp --port 3389
|
|
67
|
+
|
|
68
|
+
# Skip one product
|
|
69
|
+
bt quick pasm-onboard -n "pra-only" -i "10.0.1.5" -j 3 -g 24 --skip-pws
|
|
70
|
+
bt quick pasm-onboard -n "pws-only" -i "10.0.1.6" -w 3 --skip-pra
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### PASM Offboard
|
|
74
|
+
Remove from both products.
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
bt quick pasm-offboard -n "my-server"
|
|
78
|
+
bt quick pasm-offboard -n "web-01" --force
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Environment Reference IDs
|
|
82
|
+
|
|
83
|
+
| Resource | ID | Notes |
|
|
84
|
+
|----------|-----|-------|
|
|
85
|
+
| PWS Workgroup (AWS) | 3 | AWS_Account Workgroup |
|
|
86
|
+
| PWS Workgroup (Datacenter) | 2 | Datacenter_West |
|
|
87
|
+
| PWS Functional Account | 7 | pws-functional SSH key |
|
|
88
|
+
| PWS Platform Linux | 2 | |
|
|
89
|
+
| PWS Platform Windows | 1 | |
|
|
90
|
+
| PRA Jumpoint (AWS) | 3 | AWS Account |
|
|
91
|
+
| PRA Jumpoint (Datacenter) | 2 | Data Center 01 |
|
|
92
|
+
| PRA Vault Account (ec2-admin) | 31 | SSH CA for EC2 |
|
|
93
|
+
| Entitle PRA Integration | bb2a3c79-02a9-45d9-be7f-f209d97cb1d7 | |
|
|
94
|
+
| Entitle Customer Access | 22f4960f-b2ee-435f-9fa2-b82baeca06b2 | Virtual integration |
|
|
95
|
+
|
|
96
|
+
## Product-Specific Skills
|
|
97
|
+
|
|
98
|
+
Use `/pws`, `/pra`, `/entitle`, `/epmw` for product-specific commands.
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: entitle
|
|
3
|
+
description: Entitle commands for JIT access, bundles, workflows, and permissions. Use when working with access requests, approval workflows, or managing user entitlements.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Entitle Commands (`bt entitle`)
|
|
7
|
+
|
|
8
|
+
## IMPORTANT: Destructive Operations
|
|
9
|
+
|
|
10
|
+
**ALWAYS confirm with the user before:**
|
|
11
|
+
- `bt entitle resources delete` - Deletes resource from integration
|
|
12
|
+
- `bt entitle bundles delete` - Deletes access bundle
|
|
13
|
+
- `bt entitle permissions revoke` - Revokes active permission
|
|
14
|
+
|
|
15
|
+
List affected resources first, then ask for explicit confirmation.
|
|
16
|
+
|
|
17
|
+
## Integrations & Resources
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# List integrations (connected apps)
|
|
21
|
+
bt entitle integrations list
|
|
22
|
+
bt entitle integrations get <integration_id>
|
|
23
|
+
|
|
24
|
+
# List resources in an integration
|
|
25
|
+
bt entitle resources list --integration <integration_id>
|
|
26
|
+
bt entitle resources get <resource_id>
|
|
27
|
+
|
|
28
|
+
# Virtual integration resources
|
|
29
|
+
bt entitle resources create-virtual \
|
|
30
|
+
--name "Customer-05 (Bing7)" \
|
|
31
|
+
--integration 22f4960f-b2ee-435f-9fa2-b82baeca06b2 \
|
|
32
|
+
--source-role-id <role_id> \
|
|
33
|
+
--role-name "Start Session"
|
|
34
|
+
bt entitle resources delete <resource_id>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Bundles
|
|
38
|
+
|
|
39
|
+
Access bundles group multiple roles across integrations.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bt entitle bundles list
|
|
43
|
+
bt entitle bundles get <bundle_id>
|
|
44
|
+
bt entitle bundles create \
|
|
45
|
+
--name "Dev AWS Access" \
|
|
46
|
+
--description "Development AWS console access" \
|
|
47
|
+
--workflow <workflow_id> \
|
|
48
|
+
--role <role_id> \
|
|
49
|
+
--duration 3600
|
|
50
|
+
bt entitle bundles delete <bundle_id>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Workflows
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
bt entitle workflows list
|
|
57
|
+
bt entitle workflows get <workflow_id>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Available Workflows:**
|
|
61
|
+
| Name | Type | Use Case |
|
|
62
|
+
|------|------|----------|
|
|
63
|
+
| Auto Approve | Automatic | Requests <= 12 hours |
|
|
64
|
+
| Low sensitivity | Simple | Single approver |
|
|
65
|
+
| Medium Sensitivity | Standard | Standard approval |
|
|
66
|
+
| Production access | Multi-step | Duration-based tiers |
|
|
67
|
+
|
|
68
|
+
## Users & Permissions
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Users
|
|
72
|
+
bt entitle users list
|
|
73
|
+
bt entitle users get <user_id>
|
|
74
|
+
|
|
75
|
+
# Active permissions
|
|
76
|
+
bt entitle permissions list
|
|
77
|
+
bt entitle permissions list --user <user_id>
|
|
78
|
+
bt entitle permissions revoke <permission_id>
|
|
79
|
+
|
|
80
|
+
# Accounts
|
|
81
|
+
bt entitle accounts list --integration <integration_id>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Roles & Policies
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
bt entitle roles list
|
|
88
|
+
bt entitle roles list --resource <resource_id>
|
|
89
|
+
bt entitle roles get <role_id>
|
|
90
|
+
|
|
91
|
+
bt entitle policies list
|
|
92
|
+
bt entitle policies get <policy_id>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Common Workflows
|
|
96
|
+
|
|
97
|
+
### Add PRA Jump Group to Entitle
|
|
98
|
+
|
|
99
|
+
**Important:** PRA integration sync is **asynchronous** (runs hourly). After creating a new PRA jump group, either:
|
|
100
|
+
- Wait up to 1 hour for auto-sync
|
|
101
|
+
- Or manually trigger sync in Entitle UI: Integrations → PRA → Sync Now
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# 1. Trigger PRA sync in Entitle UI (or wait for hourly sync)
|
|
105
|
+
|
|
106
|
+
# 2. Find the new PRA resource
|
|
107
|
+
bt entitle resources list --integration bb2a3c79-02a9-45d9-be7f-f209d97cb1d7
|
|
108
|
+
|
|
109
|
+
# 3. Get "Start Sessions Only" role ID
|
|
110
|
+
bt entitle roles list --resource <pra_resource_id>
|
|
111
|
+
|
|
112
|
+
# 4. Add to Customer Access virtual integration
|
|
113
|
+
bt entitle resources create-virtual \
|
|
114
|
+
--name "Customer-05" \
|
|
115
|
+
--integration 22f4960f-b2ee-435f-9fa2-b82baeca06b2 \
|
|
116
|
+
--source-role-id <role_id> \
|
|
117
|
+
--role-name "Start Session"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Check User Access
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
bt entitle permissions list --user "user@example.com" -o json
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Key IDs
|
|
127
|
+
|
|
128
|
+
| Resource | ID |
|
|
129
|
+
|----------|-----|
|
|
130
|
+
| PRA Integration | bb2a3c79-02a9-45d9-be7f-f209d97cb1d7 |
|
|
131
|
+
| Customer Access (Virtual) | 22f4960f-b2ee-435f-9fa2-b82baeca06b2 |
|
|
132
|
+
| AWS SandBox | (check `bt entitle integrations list`) |
|
|
133
|
+
|
|
134
|
+
## Integrations Available
|
|
135
|
+
|
|
136
|
+
- Cloud10 (Virtual Application)
|
|
137
|
+
- NexusDyn - Azure
|
|
138
|
+
- Customer Access (Virtual)
|
|
139
|
+
- Privileged Remote Access (PRA)
|
|
140
|
+
- AWS - SandBox Account
|
|
141
|
+
- Nexusdyn - Postgres ERP Database
|
|
142
|
+
- NexusDyn - EntraID
|
|
143
|
+
|
|
144
|
+
## Supported Applications (75+)
|
|
145
|
+
|
|
146
|
+
**Cloud:** AWS, Azure, GCP, Oracle OCI
|
|
147
|
+
**Identity:** Okta, Entra ID, OneLogin, JumpCloud
|
|
148
|
+
**DevOps:** GitHub, GitLab, Jenkins, Terraform Cloud
|
|
149
|
+
**Databases:** Postgres, MySQL, MSSQL, MongoDB, Snowflake
|
|
150
|
+
**Kubernetes:** EKS, AKS, GKE, Rancher
|
|
151
|
+
**BeyondTrust:** Password Safe, PRA, Remote Support
|
|
152
|
+
|
|
153
|
+
## API Notes
|
|
154
|
+
|
|
155
|
+
- Base path: `/public/v1`
|
|
156
|
+
- Pagination: `page`/`perPage`
|
|
157
|
+
- Response: `{"result": [...], "pagination": {...}}`
|
|
158
|
+
- All IDs are UUIDs (strings)
|
|
159
|
+
- Bearer token auth
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: epmw
|
|
3
|
+
description: EPM Windows commands for endpoint privilege management. Use when working with Windows computers, policies, admin access requests, or audit logs.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# EPM Windows Commands (`bt epmw`)
|
|
7
|
+
|
|
8
|
+
## IMPORTANT: Destructive Operations
|
|
9
|
+
|
|
10
|
+
**ALWAYS confirm with the user before:**
|
|
11
|
+
- `bt epmw computers archive` - Archives computer from management
|
|
12
|
+
- `bt epmw groups delete` - Deletes computer group
|
|
13
|
+
- `bt epmw policies delete` - Deletes policy
|
|
14
|
+
- `bt epmw quick stale --delete` - Deletes stale computers
|
|
15
|
+
|
|
16
|
+
List affected resources first, then ask for explicit confirmation.
|
|
17
|
+
|
|
18
|
+
## Quick Commands
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Find stale computers (not checked in recently)
|
|
22
|
+
bt epmw quick stale # 24+ hours
|
|
23
|
+
bt epmw quick stale --hours 48 # 48+ hours
|
|
24
|
+
bt epmw quick stale -h 12 -g "Workstations"
|
|
25
|
+
|
|
26
|
+
# Delete stale computers
|
|
27
|
+
bt epmw quick stale --delete # With confirmation
|
|
28
|
+
bt epmw quick stale --delete --force # Skip confirmation
|
|
29
|
+
|
|
30
|
+
# Find disconnected computers
|
|
31
|
+
bt epmw quick disconnected
|
|
32
|
+
bt epmw quick disconnected -g "Servers"
|
|
33
|
+
|
|
34
|
+
# Status summary by group
|
|
35
|
+
bt epmw quick status
|
|
36
|
+
bt epmw quick status -g "Datacenter"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Computers
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bt epmw computers list
|
|
43
|
+
bt epmw computers list -o json
|
|
44
|
+
bt epmw computers get <computer_id>
|
|
45
|
+
bt epmw computers delete <computer_id>
|
|
46
|
+
bt epmw computers archive <computer_id>
|
|
47
|
+
bt epmw computers unarchive <computer_id>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Groups
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
bt epmw groups list
|
|
54
|
+
bt epmw groups get <group_id>
|
|
55
|
+
bt epmw groups create --name "NewGroup" --description "Description"
|
|
56
|
+
bt epmw groups update <group_id> --name "UpdatedName"
|
|
57
|
+
bt epmw groups delete <group_id>
|
|
58
|
+
bt epmw groups assign-policy <group_id> --policy <policy_id>
|
|
59
|
+
bt epmw groups assign-computers <group_id> --computers <id1>,<id2>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Policies
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
bt epmw policies list
|
|
66
|
+
bt epmw policies get <policy_id>
|
|
67
|
+
bt epmw policies groups <policy_id> # Show assigned groups
|
|
68
|
+
|
|
69
|
+
# Download policy XML (for template)
|
|
70
|
+
bt epmw policies download <policy_id> > template.xml
|
|
71
|
+
|
|
72
|
+
# Create policy from XML
|
|
73
|
+
bt epmw policies create -n "My Policy" -f template.xml
|
|
74
|
+
|
|
75
|
+
# Policy revisions
|
|
76
|
+
bt epmw policies revisions list <policy_id>
|
|
77
|
+
bt epmw policies revisions get <policy_id> <revision_id>
|
|
78
|
+
bt epmw policies revisions upload <policy_id> -f policy.xml
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Admin Access Requests
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
bt epmw requests list
|
|
85
|
+
bt epmw requests get <request_id>
|
|
86
|
+
bt epmw requests create --computer <id> --duration 30 --reason "Maintenance"
|
|
87
|
+
bt epmw requests approve <request_id>
|
|
88
|
+
bt epmw requests deny <request_id> --reason "Not authorized"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Users & Roles
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
bt epmw users list
|
|
95
|
+
bt epmw users get <user_id>
|
|
96
|
+
bt epmw users create --username "newuser" --email "user@example.com"
|
|
97
|
+
bt epmw users enable <user_id>
|
|
98
|
+
bt epmw users disable <user_id>
|
|
99
|
+
bt epmw users assign-roles <user_id> --roles <role1>,<role2>
|
|
100
|
+
|
|
101
|
+
bt epmw roles list
|
|
102
|
+
bt epmw roles get <role_id>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Audits
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Activity audits
|
|
109
|
+
bt epmw audits activity list
|
|
110
|
+
bt epmw audits activity get <audit_id>
|
|
111
|
+
|
|
112
|
+
# Authorization requests
|
|
113
|
+
bt epmw audits authorization list
|
|
114
|
+
bt epmw audits authorization get <audit_id>
|
|
115
|
+
|
|
116
|
+
# Request audits
|
|
117
|
+
bt epmw audits requests list
|
|
118
|
+
bt epmw audits requests get <audit_id>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Key Groups
|
|
122
|
+
|
|
123
|
+
| ID | Name | Computers |
|
|
124
|
+
|----|------|-----------|
|
|
125
|
+
| 042267ec-... | Servers - Datacenter1 | CorpMem01, CorpMem02 |
|
|
126
|
+
| 1c8f6310-... | Workstations - Datacenter1 | CorpWS01, CorpWS02 |
|
|
127
|
+
| 67ca23ad-... | Engineering | BenC-Skynet |
|
|
128
|
+
|
|
129
|
+
## Key Computers
|
|
130
|
+
|
|
131
|
+
| Host | Domain | Group | Status |
|
|
132
|
+
|------|--------|-------|--------|
|
|
133
|
+
| CorpMem01 | nexusdyn.corp | Servers | Connected |
|
|
134
|
+
| CorpMem02 | nexusdyn.corp | Servers | Connected |
|
|
135
|
+
| CorpWS01 | nexusdyn.corp | Workstations | Connected |
|
|
136
|
+
| CorpWS02 | nexusdyn.corp | Workstations | Connected |
|
|
137
|
+
|
|
138
|
+
## API Notes
|
|
139
|
+
|
|
140
|
+
- Base path: `/management-api/v3`
|
|
141
|
+
- Token endpoint: `/oauth/token`
|
|
142
|
+
- Pagination: `pageNumber`/`pageSize`
|
|
143
|
+
- Response: `{"data": [...], "totalCount": N}`
|
|
144
|
+
- All IDs are UUIDs
|
|
145
|
+
- Delete returns 405 - use archive instead
|