rds_ssm_connect 2.0.0 → 2.0.2
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.
- package/.github/workflows/release.yml +3 -0
- package/.github/workflows/update-homebrew.yml +0 -11
- package/CLAUDE.md +92 -41
- package/README.md +90 -70
- package/connect.js +19 -3
- package/package.json +3 -3
- package/scripts/download-ssm-plugin.js +37 -1
- package/src/App.svelte +1 -30
- package/src-tauri/Cargo.lock +1 -1
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/src/lib.rs +0 -131
- package/src-tauri/tauri.conf.json +1 -1
- package/RESEARCH-AWS-TOOLS-INTEGRATION.md +0 -538
- package/src/lib/PrerequisitesCheck.svelte +0 -253
|
@@ -1,538 +0,0 @@
|
|
|
1
|
-
# Research: Integrating AWS CLI, aws-vault, and session-manager-plugin
|
|
2
|
-
|
|
3
|
-
## Executive Summary
|
|
4
|
-
|
|
5
|
-
**Yes, it is possible to eliminate external dependencies on AWS CLI and aws-vault entirely, and to reduce (but not fully eliminate) the dependency on session-manager-plugin.** Here is a detailed analysis of each tool, integration strategies, and a phased implementation plan that accounts for all edge cases including cross-platform support, SSO vs credential-based profiles, and tool availability detection.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 1. Tool-by-Tool Analysis
|
|
10
|
-
|
|
11
|
-
### 1.1 AWS CLI — **FULLY REPLACEABLE**
|
|
12
|
-
|
|
13
|
-
| Attribute | Details |
|
|
14
|
-
|-----------|---------|
|
|
15
|
-
| **License** | Apache 2.0 (permissive, allows integration) |
|
|
16
|
-
| **Written in** | Python |
|
|
17
|
-
| **Current usage** | 8 distinct API call types, all shelled out via `execAsync` |
|
|
18
|
-
| **Can replace?** | **YES — 100% replaceable with @aws-sdk v3** |
|
|
19
|
-
|
|
20
|
-
The application already lists `@aws-sdk/client-ec2`, `@aws-sdk/client-rds`, and `@aws-sdk/client-ssm` in `package.json` but doesn't use them. Every AWS CLI command currently used has a direct SDK equivalent:
|
|
21
|
-
|
|
22
|
-
| Current CLI Command | SDK Package | SDK Command |
|
|
23
|
-
|---|---|---|
|
|
24
|
-
| `aws sts get-caller-identity` | `@aws-sdk/client-sts` | `GetCallerIdentityCommand` |
|
|
25
|
-
| `aws secretsmanager list-secrets` | `@aws-sdk/client-secrets-manager` | `ListSecretsCommand` |
|
|
26
|
-
| `aws secretsmanager get-secret-value` | `@aws-sdk/client-secrets-manager` | `GetSecretValueCommand` |
|
|
27
|
-
| `aws ec2 describe-instances` | `@aws-sdk/client-ec2` | `DescribeInstancesCommand` |
|
|
28
|
-
| `aws ec2 terminate-instances` | `@aws-sdk/client-ec2` | `TerminateInstancesCommand` |
|
|
29
|
-
| `aws rds describe-db-clusters` | `@aws-sdk/client-rds` | `DescribeDBClustersCommand` |
|
|
30
|
-
| `aws rds describe-db-instances` | `@aws-sdk/client-rds` | `DescribeDBInstancesCommand` |
|
|
31
|
-
| `aws ssm describe-instance-information` | `@aws-sdk/client-ssm` | `DescribeInstanceInformationCommand` |
|
|
32
|
-
| `aws ssm start-session` | `@aws-sdk/client-ssm` | `StartSessionCommand` (partial — see Section 1.3) |
|
|
33
|
-
|
|
34
|
-
**Benefits of migration:**
|
|
35
|
-
- Eliminates Python/AWS CLI runtime dependency
|
|
36
|
-
- Structured responses (no JMESPath/text parsing)
|
|
37
|
-
- Typed exceptions for better error handling
|
|
38
|
-
- Eliminates shell injection surface (currently mitigated with regex patterns)
|
|
39
|
-
- Better performance (no subprocess spawn per API call)
|
|
40
|
-
|
|
41
|
-
**New dependency needed:** `@aws-sdk/client-secrets-manager` (not currently in package.json)
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
### 1.2 aws-vault — **FULLY REPLACEABLE**
|
|
46
|
-
|
|
47
|
-
| Attribute | Details |
|
|
48
|
-
|-----------|---------|
|
|
49
|
-
| **License** | MIT (permissive, allows integration) |
|
|
50
|
-
| **Written in** | Go |
|
|
51
|
-
| **Status** | Abandoned by 99designs (active fork at ByteNess/aws-vault) |
|
|
52
|
-
| **Current usage** | Credential wrapper: `aws-vault exec ${profile} -- aws ...` |
|
|
53
|
-
| **Can replace?** | **YES — with @aws-sdk credential providers** |
|
|
54
|
-
|
|
55
|
-
aws-vault's core function is reading `~/.aws/config`, resolving credentials (including SSO, MFA, and assume-role chains), and injecting them as environment variables. The AWS SDK for JavaScript v3 has built-in credential providers that replicate all of this functionality natively:
|
|
56
|
-
|
|
57
|
-
#### Credential Provider Mapping
|
|
58
|
-
|
|
59
|
-
| aws-vault Feature | SDK Equivalent | Package |
|
|
60
|
-
|---|---|---|
|
|
61
|
-
| Read `~/.aws/config` profiles | `fromIni()` | `@aws-sdk/credential-providers` |
|
|
62
|
-
| AWS SSO / Identity Center | `fromSSO()` | `@aws-sdk/credential-provider-sso` |
|
|
63
|
-
| Assume role with MFA | `fromIni({ mfaCodeProvider })` | `@aws-sdk/credential-providers` |
|
|
64
|
-
| Assume role chain | `fromIni()` (auto-resolved) | `@aws-sdk/credential-providers` |
|
|
65
|
-
| Environment variables | `fromEnv()` | `@aws-sdk/credential-providers` |
|
|
66
|
-
| Instance metadata (EC2) | `fromInstanceMetadata()` | `@aws-sdk/credential-providers` |
|
|
67
|
-
| Credential caching | `fromTemporaryCredentials()` | `@aws-sdk/credential-providers` |
|
|
68
|
-
| Default chain (all of above) | `fromNodeProviderChain()` | `@aws-sdk/credential-providers` |
|
|
69
|
-
|
|
70
|
-
#### Key Implementation Details
|
|
71
|
-
|
|
72
|
-
**MFA Handling:**
|
|
73
|
-
```javascript
|
|
74
|
-
import { fromIni } from '@aws-sdk/credential-providers';
|
|
75
|
-
import { input } from '@inquirer/prompts';
|
|
76
|
-
|
|
77
|
-
const credentials = fromIni({
|
|
78
|
-
profile: selectedProfile,
|
|
79
|
-
mfaCodeProvider: async (serialArn) => {
|
|
80
|
-
return await input({ message: `Enter MFA code for ${serialArn}:` });
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
**SSO Handling:**
|
|
86
|
-
```javascript
|
|
87
|
-
import { fromSSO } from '@aws-sdk/credential-providers';
|
|
88
|
-
|
|
89
|
-
const credentials = fromSSO({ profile: selectedProfile });
|
|
90
|
-
// User must have run `aws sso login --profile <name>` first
|
|
91
|
-
// Or we can trigger `SSOOIDCClient.createToken()` flow programmatically
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
**Universal Default Chain:**
|
|
95
|
-
```javascript
|
|
96
|
-
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
|
|
97
|
-
|
|
98
|
-
// Automatically resolves: env vars → SSO → INI file → process → instance metadata
|
|
99
|
-
const credentials = fromNodeProviderChain({ profile: selectedProfile });
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
#### Edge Cases for Credential Resolution
|
|
103
|
-
|
|
104
|
-
| Scenario | How to Handle |
|
|
105
|
-
|----------|--------------|
|
|
106
|
-
| **SSO profile** (sso_start_url defined) | `fromSSO()` reads cached token from `~/.aws/sso/cache/`. If expired, prompt user to run `aws sso login` or trigger OIDC device auth flow. |
|
|
107
|
-
| **MFA + AssumeRole** (mfa_serial defined) | `fromIni()` with `mfaCodeProvider` callback prompts for MFA code interactively. |
|
|
108
|
-
| **Simple credentials** (access_key in file) | `fromIni()` reads directly from `~/.aws/credentials`. |
|
|
109
|
-
| **Environment variables** (CI/CD) | `fromEnv()` reads `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`. |
|
|
110
|
-
| **aws-vault still installed** | Can use `fromProcess()` calling `aws-vault exec <profile> -- env` as a fallback. |
|
|
111
|
-
| **Chained roles** (source_profile → role_arn) | `fromIni()` handles recursively, including multi-hop chains. |
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
### 1.3 session-manager-plugin — **PARTIALLY REPLACEABLE** (with significant effort)
|
|
116
|
-
|
|
117
|
-
| Attribute | Details |
|
|
118
|
-
|-----------|---------|
|
|
119
|
-
| **License** | Apache 2.0 (permissive, allows integration/bundling) |
|
|
120
|
-
| **Written in** | Go |
|
|
121
|
-
| **Current usage** | Auto-invoked by `aws ssm start-session` for WebSocket tunnel |
|
|
122
|
-
| **Can replace?** | **PARTIAL — see options below** |
|
|
123
|
-
|
|
124
|
-
This is the most complex component. The session-manager-plugin implements a custom binary protocol over WebSockets for port forwarding. Here's the full picture:
|
|
125
|
-
|
|
126
|
-
#### What the Plugin Does
|
|
127
|
-
|
|
128
|
-
1. Receives `StreamUrl` + `TokenValue` from `StartSession` API
|
|
129
|
-
2. Opens WebSocket connection to `wss://ssmmessages.<region>.amazonaws.com`
|
|
130
|
-
3. Authenticates via JSON token message
|
|
131
|
-
4. Switches to custom **binary protocol** (not JSON)
|
|
132
|
-
5. Performs handshake with SSM agent on EC2 instance
|
|
133
|
-
6. Opens local TCP listener on `localPortNumber`
|
|
134
|
-
7. Forwards bidirectional traffic: local TCP ↔ WebSocket ↔ SSM agent ↔ remote host:port
|
|
135
|
-
8. Handles keepalives, acknowledgments, sequencing, and optional smux multiplexing
|
|
136
|
-
|
|
137
|
-
#### The SSM Binary Protocol
|
|
138
|
-
|
|
139
|
-
The protocol is defined in [aws/amazon-ssm-agent/agent/session/contracts/agentmessage.go](https://github.com/aws/amazon-ssm-agent/blob/mainline/agent/session/contracts/agentmessage.go):
|
|
140
|
-
|
|
141
|
-
```
|
|
142
|
-
Binary message layout (per AgentMessage):
|
|
143
|
-
┌──────────────────────────────┐
|
|
144
|
-
│ HeaderLength (4 bytes) │
|
|
145
|
-
│ MessageType (32 bytes) │ UTF-8 string
|
|
146
|
-
│ SchemaVersion (4 bytes) │
|
|
147
|
-
│ CreatedDate (8 bytes) │ Epoch millis
|
|
148
|
-
│ SequenceNumber (8 bytes) │
|
|
149
|
-
│ Flags (8 bytes) │ SYN=bit0, FIN=bit1
|
|
150
|
-
│ MessageId (40 bytes) │ UUID as UTF-8
|
|
151
|
-
│ PayloadDigest (32 bytes) │ SHA-256
|
|
152
|
-
│ PayloadType (4 bytes) │
|
|
153
|
-
│ PayloadLength (4 bytes) │
|
|
154
|
-
│ Payload (variable len) │
|
|
155
|
-
└──────────────────────────────┘
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
Port forwarding adds a handshake phase (request → response → complete) and optionally smux multiplexing for concurrent connections.
|
|
159
|
-
|
|
160
|
-
#### Integration Options
|
|
161
|
-
|
|
162
|
-
##### Option A: Bundle the session-manager-plugin Binary (Recommended for Phase 1)
|
|
163
|
-
|
|
164
|
-
**Approach:** Download and bundle pre-compiled binaries for each platform.
|
|
165
|
-
|
|
166
|
-
| Platform | Binary Location | Architecture |
|
|
167
|
-
|----------|----------------|-------------|
|
|
168
|
-
| macOS x64 | `sessionmanagerplugin-bundle/bin/session-manager-plugin` | x86_64 |
|
|
169
|
-
| macOS ARM | Same path | arm64 (Apple Silicon) |
|
|
170
|
-
| Linux x64 | `/usr/local/sessionmanagerplugin/bin/session-manager-plugin` | x86_64 |
|
|
171
|
-
| Linux ARM | Same path | aarch64 |
|
|
172
|
-
| Windows | `C:\Program Files\Amazon\SessionManagerPlugin\bin\session-manager-plugin.exe` | x86_64/arm64 |
|
|
173
|
-
|
|
174
|
-
**Implementation strategy:**
|
|
175
|
-
1. Check if plugin is already installed system-wide
|
|
176
|
-
2. If not found, use a bundled binary from `./bin/<platform>-<arch>/session-manager-plugin`
|
|
177
|
-
3. Call `StartSessionCommand` via SDK to get `StreamUrl` + `TokenValue`
|
|
178
|
-
4. Spawn the bundled plugin binary directly (bypassing AWS CLI):
|
|
179
|
-
```javascript
|
|
180
|
-
spawn('session-manager-plugin', [
|
|
181
|
-
JSON.stringify(startSessionResponse), // API response
|
|
182
|
-
region,
|
|
183
|
-
'StartSession',
|
|
184
|
-
'', // profile (empty)
|
|
185
|
-
JSON.stringify(startSessionParams), // original request
|
|
186
|
-
`https://ssm.${region}.amazonaws.com` // endpoint
|
|
187
|
-
]);
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
**Pros:** Reliable, battle-tested, cross-platform
|
|
191
|
-
**Cons:** Binary distribution (~15MB per platform), update maintenance
|
|
192
|
-
**License:** Apache 2.0 — bundling is permitted with attribution
|
|
193
|
-
|
|
194
|
-
##### Option B: Compile session-manager-plugin from Source
|
|
195
|
-
|
|
196
|
-
**Approach:** Cross-compile the Go source for all target platforms at build time.
|
|
197
|
-
|
|
198
|
-
```bash
|
|
199
|
-
# Example cross-compilation
|
|
200
|
-
GOOS=darwin GOARCH=arm64 go build -o bin/darwin-arm64/session-manager-plugin ./src/...
|
|
201
|
-
GOOS=linux GOARCH=amd64 go build -o bin/linux-amd64/session-manager-plugin ./src/...
|
|
202
|
-
GOOS=windows GOARCH=amd64 go build -o bin/windows-amd64/session-manager-plugin.exe ./src/...
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
**Pros:** Full control, can pin exact version, reproducible
|
|
206
|
-
**Cons:** Requires Go toolchain in CI/CD, increases build complexity
|
|
207
|
-
**License:** Apache 2.0 — compiling from source is permitted
|
|
208
|
-
|
|
209
|
-
##### Option C: Implement SSM Port Forwarding Protocol in Node.js (Future/Advanced)
|
|
210
|
-
|
|
211
|
-
**Approach:** Pure JavaScript implementation of the SSM WebSocket data channel protocol, including port forwarding.
|
|
212
|
-
|
|
213
|
-
**Existing references:**
|
|
214
|
-
- [`ssm-session` (npm)](https://github.com/bertrandmartel/aws-ssm-session) — Implements shell sessions only, NOT port forwarding. ~348 weekly downloads, unmaintained.
|
|
215
|
-
- [`ssm-session-client` (Go)](https://github.com/mmmorris1975/ssm-session-client) — Full Go implementation including `PortForwardingSession()`. Single-stream only (no multiplexing). Could be used as a reference.
|
|
216
|
-
- [Formal.ai blog post](https://www.joinformal.com/blog/down-the-rabbit-hole-implementing-ssh-port-forwarding-over-aws-session-manager/) — Documents the protocol in detail, including bugs they found in AWS's implementation.
|
|
217
|
-
|
|
218
|
-
**What would need to be implemented:**
|
|
219
|
-
1. WebSocket connection management (using `ws` npm package)
|
|
220
|
-
2. Binary message serialization/deserialization (144-byte header + variable payload)
|
|
221
|
-
3. Sequence number tracking and acknowledgment protocol
|
|
222
|
-
4. Handshake flow (request → response → complete)
|
|
223
|
-
5. Local TCP server (using Node.js `net` module)
|
|
224
|
-
6. Bidirectional data forwarding (TCP ↔ WebSocket)
|
|
225
|
-
7. Keepalive/heartbeat mechanism
|
|
226
|
-
8. Error recovery and reconnection
|
|
227
|
-
9. Optional: smux multiplexing (for concurrent connections)
|
|
228
|
-
|
|
229
|
-
**Estimated complexity:** ~1500-2500 lines of Node.js code
|
|
230
|
-
**Pros:** Zero binary dependencies, full control, true single-binary deployment
|
|
231
|
-
**Cons:** High implementation effort, must track AWS protocol changes, no official support
|
|
232
|
-
**Risk:** AWS could change the protocol without notice (though it's been stable since 2019)
|
|
233
|
-
|
|
234
|
-
##### Option D: Hybrid — Use Go via WebAssembly (Experimental)
|
|
235
|
-
|
|
236
|
-
**Approach:** Compile the session-manager-plugin Go code to WebAssembly and run it in Node.js.
|
|
237
|
-
|
|
238
|
-
**Pros:** Single-language distribution
|
|
239
|
-
**Cons:** WASM doesn't have native TCP socket access, would require complex bridging. Not practical for this use case.
|
|
240
|
-
|
|
241
|
-
**Verdict: Not recommended.**
|
|
242
|
-
|
|
243
|
-
---
|
|
244
|
-
|
|
245
|
-
## 2. Cross-Platform & Edge Case Matrix
|
|
246
|
-
|
|
247
|
-
### 2.1 Platform Detection & Binary Resolution
|
|
248
|
-
|
|
249
|
-
```
|
|
250
|
-
Platform Detection Strategy:
|
|
251
|
-
┌────────────────────────────────────────────────────┐
|
|
252
|
-
│ process.platform │ process.arch │ Binary Suffix │
|
|
253
|
-
├───────────────────┼───────────────┼─────────────────┤
|
|
254
|
-
│ 'darwin' │ 'arm64' │ darwin-arm64 │
|
|
255
|
-
│ 'darwin' │ 'x64' │ darwin-x64 │
|
|
256
|
-
│ 'linux' │ 'x64' │ linux-x64 │
|
|
257
|
-
│ 'linux' │ 'arm64' │ linux-arm64 │
|
|
258
|
-
│ 'win32' │ 'x64' │ win32-x64.exe │
|
|
259
|
-
│ 'win32' │ 'arm64' │ win32-arm64.exe │
|
|
260
|
-
└────────────────────────────────────────────────────┘
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### 2.2 Tool Availability Detection
|
|
264
|
-
|
|
265
|
-
```
|
|
266
|
-
For each external tool:
|
|
267
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
268
|
-
│ Tool │ Detection Method │ Fallback │
|
|
269
|
-
├──────────────────────┼─────────────────────────┼────────────────┤
|
|
270
|
-
│ aws CLI │ `which aws` │ Use SDK (built-in) — NO FALLBACK NEEDED │
|
|
271
|
-
│ aws-vault │ `which aws-vault` │ Use SDK credential providers — NO FALLBACK NEEDED │
|
|
272
|
-
│ session-manager-plugin│ `which session-manager-plugin` │ Use bundled binary │
|
|
273
|
-
│ │ or check known paths: │ │
|
|
274
|
-
│ │ macOS: /usr/local/sessionmanagerplugin/bin/ │ │
|
|
275
|
-
│ │ Linux: /usr/local/sessionmanagerplugin/bin/ │ │
|
|
276
|
-
│ │ Windows: C:\Program Files\Amazon\... │ │
|
|
277
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
### 2.3 Credential Type Detection
|
|
281
|
-
|
|
282
|
-
```
|
|
283
|
-
Profile Analysis (from ~/.aws/config):
|
|
284
|
-
┌──────────────────────────────────────────────────────────────┐
|
|
285
|
-
│ Profile Config │ Auth Type │ SDK Provider │
|
|
286
|
-
├─────────────────────────────┼──────────────────┼──────────────┤
|
|
287
|
-
│ sso_start_url defined │ AWS SSO/IdC │ fromSSO() │
|
|
288
|
-
│ sso_session defined │ AWS SSO (new) │ fromSSO() │
|
|
289
|
-
│ role_arn + mfa_serial │ AssumeRole+MFA │ fromIni() with mfaCodeProvider │
|
|
290
|
-
│ role_arn (no mfa) │ AssumeRole │ fromIni() │
|
|
291
|
-
│ aws_access_key_id in creds │ Static creds │ fromIni() │
|
|
292
|
-
│ credential_process defined │ External process │ fromProcess()│
|
|
293
|
-
│ AWS_* env vars set │ Environment │ fromEnv() │
|
|
294
|
-
└──────────────────────────────────────────────────────────────┘
|
|
295
|
-
|
|
296
|
-
Recommended approach: Use fromNodeProviderChain() which tries all of the above
|
|
297
|
-
in the correct order automatically.
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### 2.4 Edge Case Handling
|
|
301
|
-
|
|
302
|
-
| Edge Case | Current Behavior | New Behavior |
|
|
303
|
-
|-----------|-----------------|-------------|
|
|
304
|
-
| **aws-vault installed, user prefers it** | Required | Optional — detect and offer as choice |
|
|
305
|
-
| **aws-vault NOT installed** | Fatal error | Works natively with SDK credential providers |
|
|
306
|
-
| **AWS CLI not installed** | Fatal error | Works — SDK handles all API calls |
|
|
307
|
-
| **session-manager-plugin not installed** | Fails at tunnel creation | Auto-detect → use bundled binary |
|
|
308
|
-
| **SSO session expired** | aws-vault handles re-auth | Detect `CredentialsProviderError`, prompt user to run `aws sso login` or trigger OIDC device flow |
|
|
309
|
-
| **MFA required** | aws-vault prompts | `mfaCodeProvider` callback prompts via inquirer |
|
|
310
|
-
| **Profile with chained roles** | aws-vault resolves chain | `fromIni()` resolves chain recursively |
|
|
311
|
-
| **Windows PowerShell** | Untested (macOS/Linux only) | Full support with platform-specific binary paths |
|
|
312
|
-
| **CI/CD (no interactive TTY)** | Not supported | `fromEnv()` picks up env vars automatically |
|
|
313
|
-
| **Apple Silicon (M1/M2/M3)** | Depends on installed binary arch | Detect `process.arch === 'arm64'` and use correct binary |
|
|
314
|
-
| **Linux ARM (Graviton)** | Depends on installed binary | Detect and use `linux-arm64` binary |
|
|
315
|
-
|
|
316
|
-
---
|
|
317
|
-
|
|
318
|
-
## 3. Phased Implementation Plan
|
|
319
|
-
|
|
320
|
-
### Phase 1: Replace AWS CLI with SDK (Low risk, high reward)
|
|
321
|
-
|
|
322
|
-
**Goal:** Eliminate `aws` CLI dependency for all API calls except `start-session`.
|
|
323
|
-
|
|
324
|
-
**Changes:**
|
|
325
|
-
1. Create `src/aws-clients.js` — Factory module that creates SDK clients with proper credentials
|
|
326
|
-
2. Create `src/credential-resolver.js` — Unified credential resolution:
|
|
327
|
-
- Parse `~/.aws/config` to detect profile type (SSO, MFA, static, etc.)
|
|
328
|
-
- Use `fromNodeProviderChain()` as default
|
|
329
|
-
- Add `mfaCodeProvider` callback using inquirer
|
|
330
|
-
- Detect if aws-vault is running (check `AWS_VAULT` env var) and use those creds if present
|
|
331
|
-
3. Refactor `connect.js` functions to use SDK clients:
|
|
332
|
-
- `checkCredentialsValid()` → `STSClient.send(GetCallerIdentityCommand)`
|
|
333
|
-
- `getConnectionCredentials()` → `SecretsManagerClient.send(ListSecretsCommand)` + `GetSecretValueCommand`
|
|
334
|
-
- `findBastionInstance()` → `EC2Client.send(DescribeInstancesCommand)`
|
|
335
|
-
- `getRdsEndpoint()` / `getRdsPort()` → `RDSClient.send(DescribeDBClustersCommand)` or `DescribeDBInstancesCommand`
|
|
336
|
-
- `terminateBastionInstance()` → `EC2Client.send(TerminateInstancesCommand)`
|
|
337
|
-
- `waitForNewBastionInstance()` → `EC2Client.send(DescribeInstancesCommand)` in loop
|
|
338
|
-
- `waitForSSMAgentReady()` → `SSMClient.send(DescribeInstanceInformationCommand)` in loop
|
|
339
|
-
4. Add `@aws-sdk/client-secrets-manager` and `@aws-sdk/client-sts` to dependencies
|
|
340
|
-
5. Keep `executePortForwardingCommand()` using shell for now (Phase 2)
|
|
341
|
-
|
|
342
|
-
**New dependencies:**
|
|
343
|
-
- `@aws-sdk/client-secrets-manager`
|
|
344
|
-
- `@aws-sdk/client-sts`
|
|
345
|
-
- `@aws-sdk/credential-providers` (includes fromIni, fromSSO, fromNodeProviderChain)
|
|
346
|
-
|
|
347
|
-
**Backward compatibility:**
|
|
348
|
-
- If `AWS_VAULT` env var is detected, skip custom credential resolution (already resolved)
|
|
349
|
-
- If `aws-vault` is in PATH and user preference is set, offer to use it as wrapper
|
|
350
|
-
|
|
351
|
-
---
|
|
352
|
-
|
|
353
|
-
### Phase 2: Replace aws-vault with Native Credential Resolution
|
|
354
|
-
|
|
355
|
-
**Goal:** Eliminate `aws-vault` as a required dependency.
|
|
356
|
-
|
|
357
|
-
**Changes:**
|
|
358
|
-
1. Implement profile type detection in `credential-resolver.js`:
|
|
359
|
-
```
|
|
360
|
-
Read ~/.aws/config → parse profile sections → detect auth type → select provider
|
|
361
|
-
```
|
|
362
|
-
2. Add SSO login flow:
|
|
363
|
-
- Detect expired SSO tokens
|
|
364
|
-
- Option A: Prompt user to run `aws sso login` externally
|
|
365
|
-
- Option B: Implement OIDC device authorization flow using `@aws-sdk/client-sso-oidc`
|
|
366
|
-
3. Add MFA prompt integration:
|
|
367
|
-
- Detect `mfa_serial` in profile config
|
|
368
|
-
- Prompt using inquirer within the existing interactive flow
|
|
369
|
-
4. Update the interactive flow:
|
|
370
|
-
- Currently: Select project → Select profile → aws-vault handles auth → API calls
|
|
371
|
-
- New: Select project → Select profile → Detect auth type → Resolve credentials → API calls
|
|
372
|
-
5. Maintain backward compatibility:
|
|
373
|
-
- Detect if running under `aws-vault exec` (check `AWS_VAULT` env var)
|
|
374
|
-
- If yes, use environment credentials directly
|
|
375
|
-
- If no, use SDK credential providers
|
|
376
|
-
|
|
377
|
-
---
|
|
378
|
-
|
|
379
|
-
### Phase 3: Direct session-manager-plugin Integration
|
|
380
|
-
|
|
381
|
-
**Goal:** Eliminate AWS CLI from the `start-session` call, call the plugin binary directly.
|
|
382
|
-
|
|
383
|
-
**Changes:**
|
|
384
|
-
1. Replace `aws-vault exec ${ENV} -- aws ssm start-session ...` with:
|
|
385
|
-
```javascript
|
|
386
|
-
// Step 1: SDK call
|
|
387
|
-
const session = await ssmClient.send(new StartSessionCommand({
|
|
388
|
-
Target: instanceId,
|
|
389
|
-
DocumentName: 'AWS-StartPortForwardingSessionToRemoteHost',
|
|
390
|
-
Parameters: { host: [rdsEndpoint], portNumber: [remotePort], localPortNumber: [portNumber] }
|
|
391
|
-
}));
|
|
392
|
-
|
|
393
|
-
// Step 2: Spawn plugin directly
|
|
394
|
-
const plugin = spawn(pluginBinaryPath, [
|
|
395
|
-
JSON.stringify(session),
|
|
396
|
-
region,
|
|
397
|
-
'StartSession',
|
|
398
|
-
'',
|
|
399
|
-
JSON.stringify(startSessionParams),
|
|
400
|
-
`https://ssm.${region}.amazonaws.com`
|
|
401
|
-
]);
|
|
402
|
-
```
|
|
403
|
-
2. Implement plugin binary resolution:
|
|
404
|
-
- Check system PATH
|
|
405
|
-
- Check known installation paths per platform
|
|
406
|
-
- Fall back to bundled binary
|
|
407
|
-
3. Add plugin availability check at startup with helpful error messages
|
|
408
|
-
|
|
409
|
-
---
|
|
410
|
-
|
|
411
|
-
### Phase 4: Bundle session-manager-plugin Binary (Optional)
|
|
412
|
-
|
|
413
|
-
**Goal:** True zero-external-dependency experience.
|
|
414
|
-
|
|
415
|
-
**Changes:**
|
|
416
|
-
1. Set up CI/CD workflow to download official plugin binaries for all platforms
|
|
417
|
-
2. Structure bundled binaries:
|
|
418
|
-
```
|
|
419
|
-
bin/
|
|
420
|
-
├── darwin-arm64/session-manager-plugin
|
|
421
|
-
├── darwin-x64/session-manager-plugin
|
|
422
|
-
├── linux-arm64/session-manager-plugin
|
|
423
|
-
├── linux-x64/session-manager-plugin
|
|
424
|
-
├── win32-arm64/session-manager-plugin.exe
|
|
425
|
-
└── win32-x64/session-manager-plugin.exe
|
|
426
|
-
```
|
|
427
|
-
3. Implement platform-aware binary selection at runtime
|
|
428
|
-
4. Add npm postinstall script to set execute permissions on Unix
|
|
429
|
-
5. Consider using `optionalDependencies` with platform-specific packages (like esbuild does)
|
|
430
|
-
|
|
431
|
-
**Alternative packaging strategy (recommended for npm):**
|
|
432
|
-
```
|
|
433
|
-
@rds-ssm-connect/session-plugin-darwin-arm64
|
|
434
|
-
@rds-ssm-connect/session-plugin-darwin-x64
|
|
435
|
-
@rds-ssm-connect/session-plugin-linux-x64
|
|
436
|
-
@rds-ssm-connect/session-plugin-linux-arm64
|
|
437
|
-
@rds-ssm-connect/session-plugin-win32-x64
|
|
438
|
-
```
|
|
439
|
-
Each package contains only the binary for that platform, listed as `optionalDependencies`.
|
|
440
|
-
|
|
441
|
-
---
|
|
442
|
-
|
|
443
|
-
### Phase 5: Pure Node.js SSM Protocol (Future/Advanced)
|
|
444
|
-
|
|
445
|
-
**Goal:** Eliminate the session-manager-plugin binary entirely.
|
|
446
|
-
|
|
447
|
-
**Scope:** Implement the SSM WebSocket data channel protocol in pure JavaScript.
|
|
448
|
-
|
|
449
|
-
**Key modules to implement:**
|
|
450
|
-
1. `src/ssm-protocol/connection.js` — WebSocket connection management
|
|
451
|
-
2. `src/ssm-protocol/message.js` — Binary message serialization/deserialization
|
|
452
|
-
3. `src/ssm-protocol/handshake.js` — Port forwarding handshake flow
|
|
453
|
-
4. `src/ssm-protocol/port-forwarder.js` — Local TCP server + bidirectional forwarding
|
|
454
|
-
5. `src/ssm-protocol/keepalive.js` — Heartbeat/acknowledgment management
|
|
455
|
-
|
|
456
|
-
**Reference implementations:**
|
|
457
|
-
- [aws/amazon-ssm-agent](https://github.com/aws/amazon-ssm-agent) — Server-side protocol (Go)
|
|
458
|
-
- [aws/session-manager-plugin](https://github.com/aws/session-manager-plugin) — Client-side protocol (Go)
|
|
459
|
-
- [mmmorris1975/ssm-session-client](https://github.com/mmmorris1975/ssm-session-client) — Independent Go client with port forwarding
|
|
460
|
-
- [bertrandmartel/aws-ssm-session](https://github.com/bertrandmartel/aws-ssm-session) — Partial JS implementation (shell only)
|
|
461
|
-
|
|
462
|
-
**Risk assessment:** Medium-high. The protocol is undocumented by AWS and could change. However, it has been stable since 2019 and the Go source code provides a complete reference. The `mmmorris1975/ssm-session-client` proves that independent implementations work.
|
|
463
|
-
|
|
464
|
-
---
|
|
465
|
-
|
|
466
|
-
## 4. Architecture After Full Integration
|
|
467
|
-
|
|
468
|
-
```
|
|
469
|
-
BEFORE (Current):
|
|
470
|
-
┌──────────────────────────────────────────────────────────────┐
|
|
471
|
-
│ User's Machine Must Have Installed: │
|
|
472
|
-
│ ✗ Node.js + npm │
|
|
473
|
-
│ ✗ aws-vault (Go binary) │
|
|
474
|
-
│ ✗ AWS CLI v2 (Python runtime) │
|
|
475
|
-
│ ✗ session-manager-plugin (Go binary) │
|
|
476
|
-
│ ✗ Properly configured ~/.aws/config │
|
|
477
|
-
└──────────────────────────────────────────────────────────────┘
|
|
478
|
-
|
|
479
|
-
AFTER Phase 3 (Recommended Target):
|
|
480
|
-
┌──────────────────────────────────────────────────────────────┐
|
|
481
|
-
│ User's Machine Must Have Installed: │
|
|
482
|
-
│ ✗ Node.js + npm │
|
|
483
|
-
│ ✗ session-manager-plugin (Go binary) — auto-detected │
|
|
484
|
-
│ ✗ Properly configured ~/.aws/config │
|
|
485
|
-
│ │
|
|
486
|
-
│ Optional (backward-compatible): │
|
|
487
|
-
│ ○ aws-vault (if user prefers) │
|
|
488
|
-
│ ○ AWS CLI (no longer required) │
|
|
489
|
-
└──────────────────────────────────────────────────────────────┘
|
|
490
|
-
|
|
491
|
-
AFTER Phase 4 (Zero-dependency Target):
|
|
492
|
-
┌──────────────────────────────────────────────────────────────┐
|
|
493
|
-
│ User's Machine Must Have Installed: │
|
|
494
|
-
│ ✗ Node.js + npm (plugin binary bundled) │
|
|
495
|
-
│ ✗ Properly configured ~/.aws/config │
|
|
496
|
-
└──────────────────────────────────────────────────────────────┘
|
|
497
|
-
|
|
498
|
-
AFTER Phase 5 (Pure Node.js — Future):
|
|
499
|
-
┌──────────────────────────────────────────────────────────────┐
|
|
500
|
-
│ User's Machine Must Have Installed: │
|
|
501
|
-
│ ✗ Node.js + npm │
|
|
502
|
-
│ ✗ Properly configured ~/.aws/config │
|
|
503
|
-
│ (Everything else is pure JavaScript) │
|
|
504
|
-
└──────────────────────────────────────────────────────────────┘
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
---
|
|
508
|
-
|
|
509
|
-
## 5. Risk Assessment & Recommendations
|
|
510
|
-
|
|
511
|
-
| Risk | Impact | Mitigation |
|
|
512
|
-
|------|--------|-----------|
|
|
513
|
-
| AWS changes SSM protocol | Phase 5 breaks | Pin to known-good protocol version; Phase 4 (bundled binary) is safer |
|
|
514
|
-
| SSO token refresh complexity | User frustration | Start with "prompt user to run `aws sso login`", add OIDC flow later |
|
|
515
|
-
| Plugin binary size (~15MB per platform) | Large npm package | Use platform-specific optional dependencies |
|
|
516
|
-
| Windows support gaps | Reduced user base | Test early with Windows CI; process management differs significantly |
|
|
517
|
-
| Credential caching complexity | Slower auth | Implement in-memory cache with TTL matching STS token duration |
|
|
518
|
-
|
|
519
|
-
### Recommendation
|
|
520
|
-
|
|
521
|
-
**Implement Phases 1-3 first.** This eliminates AWS CLI and aws-vault dependencies with moderate effort and low risk. Phase 4 (bundling) is a packaging concern. Phase 5 (pure JS protocol) is high effort but provides the best long-term user experience — consider it as a separate project.
|
|
522
|
-
|
|
523
|
-
---
|
|
524
|
-
|
|
525
|
-
## 6. Sources
|
|
526
|
-
|
|
527
|
-
- [aws-vault (GitHub, MIT License)](https://github.com/99designs/aws-vault)
|
|
528
|
-
- [session-manager-plugin (GitHub, Apache 2.0)](https://github.com/aws/session-manager-plugin)
|
|
529
|
-
- [AWS CLI (GitHub, Apache 2.0)](https://github.com/aws/aws-cli)
|
|
530
|
-
- [@aws-sdk/credential-providers (npm)](https://www.npmjs.com/package/@aws-sdk/credential-providers)
|
|
531
|
-
- [@aws-sdk/credential-provider-sso (npm)](https://www.npmjs.com/package/@aws-sdk/credential-provider-sso)
|
|
532
|
-
- [ssm-session (npm) — JS SSM protocol](https://github.com/bertrandmartel/aws-ssm-session)
|
|
533
|
-
- [ssm-session-client (Go) — Port forwarding](https://github.com/mmmorris1975/ssm-session-client)
|
|
534
|
-
- [amazon-ssm-agent — Binary protocol spec](https://github.com/aws/amazon-ssm-agent/blob/mainline/agent/session/contracts/agentmessage.go)
|
|
535
|
-
- [SSM StartSession API](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_StartSession.html)
|
|
536
|
-
- [AWS re:Post — SSM port forwarding via SDK](https://repost.aws/questions/QU5pDJCPALRlGKtGyuHjMJaw/aws-ssm-port-forwarding-session-using-aws-sdk)
|
|
537
|
-
- [Formal.ai — SSM protocol deep dive](https://www.joinformal.com/blog/down-the-rabbit-hole-implementing-ssh-port-forwarding-over-aws-session-manager/)
|
|
538
|
-
- [DeepWiki — session-manager-plugin analysis](https://deepwiki.com/aws/session-manager-plugin)
|