Skip to content

RDP via Bridge

Overview

This pattern combines the temporary local user approach with Britive Bridge: the broker creates a temporary Windows local user at checkout, but instead of returning the password, it registers a proxied RDP session with Bridge. All traffic flows through the Bridge proxy where it is audited and recorded.

One checkout gives the user two ways in:

  • Their own RDP client (mstsc, Remmina, Microsoft Remote Desktop), pointed at the Bridge’s native RDP listener
  • The browser, with no client at all

Either way the Windows account password stays server-side. The user authenticates to Bridge with the Bridge Password on their Britive profile — never with the temporary account’s password.

What you’ll accomplish:

  • Create a temporary Windows local user at checkout (over WinRM or SSH)
  • Register a Bridge session that accepts the user’s Bridge credentials
  • Tear down the session and delete the account at checkin

This guide covers Bridge v2 only. v2 scripts call broker-bridge-api.sh and register the checkout with native_auth=bridge_credentials. The retired v1 scripts called bridge.sh and returned a tokenized browser URL. A v1 script on a v2 Bridge fails at the API call with nothing to indicate the version is the reason.

Before You Begin

  • Bridge v2 is deployed and reachable by users
  • The Bridge native RDP listener is enabled and reachable on NATIVE_PORT (default 3389)
  • A provisioning account with admin rights on each target (default Administrator)
  • For WinRM transport: WinRM enabled on the target (5985/5986, NTLM auth), and pywinrm installed on the broker host
  • For SSH transport: OpenSSH Server + PowerShell 5.1+ on the target, and the broker’s key authorized
  • Broker host has python3 and jq (plus ssh for SSH transport) — extend the Bridge image with a custom build if needed
  • broker-bridge-api.sh present at /opt/britive-broker/scripts/broker-bridge-api.sh
  • Each user has a Bridge Password set on their Britive profile (Manage Account → Bridge Attributes)

How It Works

checkout → derive Windows username from BRITIVE_USER_EMAIL (SAM-safe, max 20 chars)
         → generate password meeting Windows complexity rules
         → WinRM or SSH: New-LocalUser (description bridge:<TRX>),
           Add-LocalGroupMember "Remote Desktop Users"
         → broker-bridge-api.sh checkout-create
             { protocol: rdp, target_password, rdp_security,
               native_auth: bridge_credentials, bridge_auth_password }
         → return { command, browser_session, bridge_username, ... }

checkin  → broker-bridge-api.sh checkout-delete <TRX>   ← session dies FIRST
         → WinRM or SSH: Remove-LocalGroupMember, Remove-LocalUser

The checkin order matters: the Bridge session is terminated before the account is deleted, so the RDP proxy tunnel closes cleanly rather than being pulled out from under a live session.

The Identity Model

The native RDP login is <email>%<target-host>, where <email> is the user’s Britive identity — the same value as the checkout owner. Bridge matches both the native RDP username (the part before %) and the browser SSO identity against the checkout’s username field, so they must be identical.

The profile’s Bridge Username field is not used for this matching. Setting it does not change the login name.

Environment Variables

VariableRequiredDefaultNotes
BRITIVE_USER_EMAILYesInjected — Windows username derived from the local part
TRXYesInjected — transaction ID; tags the account description
TARGET_HOSTYesRDP target host
BRIDGE_URLYesBridge hostname. One NLB serves both browser and native sessions
EXPIRATIONYesCheckout duration in seconds
BRIDGE_AUTH_PASSWORDYesInjected from the user’s profile. Bridge rejects a bridge_credentials checkout without it
TARGET_PORTNo3389RDP port on the target
TARGET_DOMAINNoWindows/AD domain for the RDP login
NATIVE_PORTNo3389Bridge native RDP listener port
RDP_SECURITYNonlaany, nla, tls, or rdp
RDP_ENABLE_DRIVENofalsetrue allows drive redirection
PROVISION_TRANSPORTNowinrmwinrm or ssh
PROVISION_USERNoAdministratorProvisioning account
PROVISION_PASSWORDWinRM onlyPassword for the provisioning account
PROVISION_HOSTNoTARGET_HOSTSeparate provisioning host if needed
PROVISION_PORTNo5985/5986/22Auto-selected per transport and WINRM_NO_SSL
PROVISION_KEY / PROVISION_KEY_PEMSSH only/home/bridge/.ssh/id_ed25519Key file path, or PEM content injected as a variable
WINRM_NO_SSLNo11 = HTTP (5985), 0 = HTTPS (5986)
LOCAL_GROUPNoRemote Desktop UsersComma-separated groups to add the user to
BRITIVE_FIRST_NAME / BRITIVE_LAST_NAMENoUsed for the account display name
BROKER_APINo/opt/britive-broker/scripts/broker-bridge-api.shPath to the Bridge API helper

Checkout Routine

Full script: Windows/permissions/temp-user-bridge/checkout_rdp_bridge.sh

Key sections — create the user, then register the session against the user’s Bridge credentials:

# SAM-safe username from the email local part (a-z0-9, max 20 chars)
USERNAME="$(python3 -c "
import re, sys
name = re.sub(r'[^a-z0-9]', '', sys.argv[1].split('@')[0].lower())
if name[0].isdigit(): name = 'brg' + name
print(name[:20])
" "$USER_EMAIL")"

# Password meeting Windows complexity: upper + lower + digit + special
RAND="$(head -c 12 /dev/urandom | base64 | tr -d "+/='\\\\" | head -c 12)"
PASSWORD="${RAND}Aa1@"

# PowerShell run over WinRM (pywinrm) or SSH (-EncodedCommand):
#   New-LocalUser -Description 'bridge:<TRX>' ... ;
#   Add-LocalGroupMember -Group 'Remote Desktop Users' ...

# The Windows password goes to Bridge as target_password; the user never sees
# it. What the user types is their own Bridge Password.
AUTH_FIELDS="$(jq -n --arg p "$BRIDGE_AUTH_PASSWORD" \
  '{native_auth:"bridge_credentials", bridge_auth_password:$p}')"

jq -n --arg transaction_id "$TRANSACTION_ID" --arg username "$USER_EMAIL" \
      --arg target_username "$USERNAME" --arg target_password "$PASSWORD" \
      --arg rdp_security "$RDP_SECURITY" --argjson auth "$AUTH_FIELDS" \
  '{transaction_id: $transaction_id, protocol: "rdp",
    username: $username, target_username: $target_username,
    target_password: $target_password, rdp_security: $rdp_security,
    record_session: true} + $auth' > "$PAYLOAD_FILE"

"${BROKER_API}" checkout-create --file "$PAYLOAD_FILE" >/dev/null

The response carries both routes in:

{
  "BRIDGE_URL": "bridge.example.com",
  "command": "mstsc /v:bridge.example.com:3389",
  "auth_method": "password",
  "bridge_username": "alice@corp%server.internal",
  "bridge_port": "3389",
  "target_username": "alicecorp",
  "browser_session": "https://bridge.example.com/rdp/#transaction_id=<TRX>"
}

The RDP client prompts for credentials on connect: the username is bridge_username, the password is the user’s Bridge Password.

Checkin Routine

Full script: Windows/permissions/temp-user-bridge/checkin_rdp_bridge.sh

# Terminate the Bridge session FIRST so the RDP tunnel closes cleanly
"${BROKER_API}" checkout-delete "${TRANSACTION_ID}"

# Then deprovision over WinRM or SSH (best-effort after the session is revoked):
#   Remove-LocalGroupMember -Group 'Remote Desktop Users' ... ;
#   Remove-LocalUser -Name <username>

Configure in Britive

Create the permission

Resource Manager → Resource Type Permissions → New Permission. Language = Shell. Paste the checkout and checkin routines. Declare TARGET_HOST, BRIDGE_URL, EXPIRATION, and the provisioning variables for your transport (PROVISION_PASSWORD for WinRM, or key variables for SSH); BRITIVE_USER_EMAIL, TRX, and the BRIDGE_AUTH_* values are system-defined.

Attach a response template

Surface {{command}} and {{bridge_username}} for native clients, and {{browser_session}} for the browser. The same template works for the Linux SSH and database bridge patterns — they return the same keys.

Create a profile and policy

Create a profile (e.g. 1h), add the permission, associate it with the Windows resources, and add a policy assigning members by tag.

Verify

Check out

Check out the profile. The response contains a command, a bridge_username, and a browser_session URL.

Connect with your own client

mstsc /v:bridge.example.com:3389

At the credential prompt, enter the bridge_username from the response and your Bridge Password — not the temporary Windows account’s password. On the target, Get-LocalUser shows the account with description bridge:<TRX>.

Or open the browser session

The browser_session URL opens the same desktop with no client installed.

Check in

Check in. Any live session is cut and the local account is gone (Get-LocalUser no longer lists it).

Troubleshoot

SymptomLikely CauseFix
required env var missing: BRIDGE_AUTH_PASSWORDUser has no Bridge Password on their profileSet one under Manage Account → Bridge Attributes
Checkout registration failsScript is v1, or Bridge is v1v2 scripts call broker-bridge-api.sh; confirm both ends are v2
pywinrm not installedBroker host missing the librarypip install pywinrm or bake it into a custom Bridge image
PROVISION_PASSWORD required for winrm transportWinRM selected without a passwordSet PROVISION_PASSWORD, or switch to PROVISION_TRANSPORT=ssh
WinRM connection refusedWinRM disabled or wrong portEnable WinRM on the target; check WINRM_NO_SSL matches the listener (5985 vs 5986)
Provisioning succeeds but access deniedNon-built-in admin over WinRMSet LocalAccountTokenFilterPolicy=1 on the target
RDP client cannot reach the BridgeNative listener not enabled or not exposedEnable the native RDP listener and expose NATIVE_PORT (3389) on the load balancer
Bridge rejects the login nameUsername not in <email>%<target-host> formUse the bridge_username from the response verbatim
Account remains after checkinDeprovisioning failed (best-effort)Accounts are tagged bridge:<TRX> in the description — re-run checkin or remove manually

Next Steps

Last updated on