Azure / Azure/azure-cli-extensions

[bastion] Concurrent tunnel connections overwrite last_token; only last session is cleaned up

Open
#10,137 2 comments 0 reactions 1 assignee Claimed by @necusjz View on GitHub
act-quality-productivity-squad Auto-Assign bug customer-reported Network - Bastion Service Attention
Dominant language
Python
Stars
454
Forks
1.7k
Avg merge
2d 19h
Merged PRs (30d)
64

Description

### Describe the bug

With concurrent local TCP accepts on `az network bastion tunnel`, each connection requests a Bastion token via `POST /api/tokens` and stores it in a single instance field `self.last_token`. When `active_connections` reaches 0, `cleanup()` only `DELETE`s that last token.
Browsers / SOCKS clients that open multiple connections therefore create multiple Bastion active sessions (often with the same start time). After the tunnel stops, earlier sessions can remain visible in `getActiveSessions` / Portal until idle timeout.

### Related command

az network bastion tunnel

### Errors

no error but does not close all opened connections

### Issue script & Debug output

the script does not error it just doesn't close all sessions

### Expected behavior

When I close the tunnel I expect all sessions created to be closed.

### Environment Summary

azure-cli 2.88.0

core 2.88.0
telemetry 1.1.0

Extensions:
account 0.2.5
ad 0.1.0
amg 3.0.0
azure-devops 1.0.6
bastion 1.4.3
databricks 1.3.2
datadog 3.0.0
front-door 2.3.0
resource-graph 2.1.1
ssh 2.0.9
stream-analytics 1.0.5

Dependencies:
msal 1.36.0
azure-mgmt-resource 24.0.0

### Additional context

### Summary

With concurrent local TCP accepts on `az network bastion tunnel`, each connection requests a Bastion token via `POST /api/tokens` and stores it in a single instance field `self.last_token`. When `active_connections` reaches 0, `cleanup()` only `DELETE`s that last token.

Browsers / SOCKS clients that open multiple connections therefore create multiple Bastion active sessions (often with the same start time). After the tunnel stops, earlier sessions can remain visible in `getActiveSessions` / Portal until idle timeout.

### Related

- Concurrent connections were added to fix https://github.com/Azure/azure-cli/issues/24600 (bastion extension ≥ 1.0.1)
- Adjacent: https://github.com/Azure/azure-cli/issues/28367 (tunnel drop / cleanup races)

### Environment

- azure-cli 2.88.0
- bastion extension **1.4.3**
- Observed while using a local SOCKS5 proxy through `az network bastion tunnel` (multiple concurrent local accepts)

### Code path (`azext_bastion/tunnel.py`)

1. Each accept → `_handle_client` → `_get_auth_token()` overwrites `self.last_token` / `self.node_id`
2. On client exit, when `active_connections == 0`, `cleanup()` deletes only `self.last_token`

So if connections A/B/C obtained tokens T1/T2/T3, only T3 is deleted when the last client leaves. T1/T2 are never deleted by this path.

### Steps to reproduce

1. Start `az network bastion tunnel` to a TCP/SOCKS resource port
2. Open 2–3 concurrent local connections to the local tunnel port (or drive traffic through a browser SOCKS proxy)
3. Check Bastion active sessions (`getActiveSessions` / Portal) — expect multiple sessions for the same user, same/near start time
4. Stop the tunnel (`Ctrl+C` / kill the process)
5. Re-check active sessions — earlier sessions may still appear

### Expected

All tokens/sessions created by this tunnel process are cleaned up when their connections close and/or when the tunnel process exits.

### Ask

Track tokens **per connection** (or a set of outstanding tokens) and `DELETE` each on close / process exit, instead of a single overwritten `last_token`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.