rds_ssm_connect 1.3.0 → 1.3.4
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/npm-publish.yml +1 -3
- package/README.md +0 -133
- package/connect.js +8 -5
- package/package.json +5 -17
|
@@ -9,11 +9,9 @@ jobs:
|
|
|
9
9
|
- uses: actions/checkout@v3
|
|
10
10
|
- uses: actions/setup-node@v3
|
|
11
11
|
with:
|
|
12
|
-
node-version: '
|
|
12
|
+
node-version: '20.x'
|
|
13
13
|
registry-url: 'https://registry.npmjs.org'
|
|
14
14
|
- run: npm ci
|
|
15
|
-
- name: Run lint
|
|
16
|
-
run: npm run lint
|
|
17
15
|
- run: npm publish
|
|
18
16
|
env:
|
|
19
17
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/README.md
CHANGED
|
@@ -106,136 +106,3 @@ These modules will be automatically installed when you install the application w
|
|
|
106
106
|
4. **Output**:
|
|
107
107
|
|
|
108
108
|
The application displays the connection string and password for the RDS database along with a command to start a port forwarding session to the RDS cluster, allowing secure access from the local machine.
|
|
109
|
-
|
|
110
|
-
### Code File
|
|
111
|
-
|
|
112
|
-
Here is the `connect.js` file used in the application:
|
|
113
|
-
|
|
114
|
-
```javascript
|
|
115
|
-
#!/usr/bin/env node
|
|
116
|
-
|
|
117
|
-
import { EC2Client, DescribeInstancesCommand } from "@aws-sdk/client-ec2";
|
|
118
|
-
import { RDSClient, DescribeDBClustersCommand } from "@aws-sdk/client-rds";
|
|
119
|
-
import { SecretsManagerClient, GetSecretValueCommand, ListSecretsCommand } from "@aws-sdk/client-secrets-manager";
|
|
120
|
-
import inquirer from 'inquirer';
|
|
121
|
-
import fs from 'fs';
|
|
122
|
-
import os from 'os';
|
|
123
|
-
import path from 'path';
|
|
124
|
-
import { envPortMapping, REGION, TABLE_NAME } from './envPortMapping.js';
|
|
125
|
-
|
|
126
|
-
// Load AWS config
|
|
127
|
-
const awsConfigPath = path.join(os.homedir(), '.aws', 'config');
|
|
128
|
-
const awsConfig = fs.readFileSync(awsConfigPath, 'utf-8');
|
|
129
|
-
const ENVS = awsConfig
|
|
130
|
-
.split('\n')
|
|
131
|
-
.filter(line => line.startsWith('[') && line.endsWith(']'))
|
|
132
|
-
.map(line => line.slice(1, -1))
|
|
133
|
-
.map(line => line.replace('profile ', ''));
|
|
134
|
-
|
|
135
|
-
// Initialize AWS SDK clients
|
|
136
|
-
const ec2Client = new EC2Client({ region: REGION });
|
|
137
|
-
const rdsClient = new RDSClient({ region: REGION });
|
|
138
|
-
const secretsManagerClient = new SecretsManagerClient({ region: REGION });
|
|
139
|
-
|
|
140
|
-
// Function to list secrets
|
|
141
|
-
async function listSecrets() {
|
|
142
|
-
const command = new ListSecretsCommand({
|
|
143
|
-
Filters: [{ Key: 'name', Values: ['rds!cluster'] }]
|
|
144
|
-
});
|
|
145
|
-
const response = await secretsManagerClient.send(command);
|
|
146
|
-
return response.SecretList.map(secret => secret.Name);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Function to get secret value
|
|
150
|
-
async function getSecretValue(secretName) {
|
|
151
|
-
const command = new GetSecretValueCommand({ SecretId: secretName });
|
|
152
|
-
const response = await secretsManagerClient.send(command);
|
|
153
|
-
return JSON.parse(response.SecretString);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Function to get instance ID
|
|
157
|
-
async function getInstanceId() {
|
|
158
|
-
const command = new DescribeInstancesCommand({
|
|
159
|
-
Filters: [
|
|
160
|
-
{ Name: 'tag:Name', Values: ['*bastion*'] },
|
|
161
|
-
{ Name: 'instance-state-name', Values: ['running'] }
|
|
162
|
-
]
|
|
163
|
-
});
|
|
164
|
-
const response = await ec2Client.send(command);
|
|
165
|
-
const instances = response.Reservations.flatMap(reservation => reservation.Instances.map(instance => instance.InstanceId));
|
|
166
|
-
return instances[0];
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Function to get RDS endpoint
|
|
170
|
-
async function getRdsEndpoint() {
|
|
171
|
-
const command = new DescribeDBClustersCommand({
|
|
172
|
-
Filters: [{ Name: 'Status', Values: ['available'] }]
|
|
173
|
-
});
|
|
174
|
-
const response = await rdsClient.send(command);
|
|
175
|
-
const clusters = response.DBClusters.filter(cluster => cluster.DBClusterIdentifier.endsWith('-rds-aurora'));
|
|
176
|
-
return clusters[0].Endpoint;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
async function main() {
|
|
180
|
-
const answers = await inquirer.prompt([
|
|
181
|
-
{
|
|
182
|
-
type: 'list',
|
|
183
|
-
name: 'ENV',
|
|
184
|
-
message: 'Please select the environment:',
|
|
185
|
-
choices: ENVS
|
|
186
|
-
}
|
|
187
|
-
]);
|
|
188
|
-
|
|
189
|
-
const ENV = answers.ENV;
|
|
190
|
-
console.log(`You selected: ${ENV}`);
|
|
191
|
-
|
|
192
|
-
// Sort all environment suffixes by length, longest first
|
|
193
|
-
const allEnvSuffixes = Object.keys(envPortMapping).sort((a, b) => b.length - a.length);
|
|
194
|
-
const matchedSuffix = allEnvSuffixes.find(suffix => ENV.endsWith(suffix));
|
|
195
|
-
let portNumber = envPortMapping[matchedSuffix] || '5432';
|
|
196
|
-
|
|
197
|
-
if (portNumber === '5432') {
|
|
198
|
-
console.error(`No port number found for environment: ${ENV}. Defaulting to 5432.`);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// List secrets and get the first matching secret name
|
|
202
|
-
const secretNames = await listSecrets();
|
|
203
|
-
const SECRET_NAME = secretNames.find(name => name.startsWith('rds!cluster'));
|
|
204
|
-
if (!SECRET_NAME) {
|
|
205
|
-
console.error('No secret found with name starting with rds!cluster.');
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Get secret value
|
|
210
|
-
const CREDENTIALS = await getSecretValue(SECRET_NAME);
|
|
211
|
-
const USERNAME = CREDENTIALS.username;
|
|
212
|
-
const PASSWORD = CREDENTIALS.password;
|
|
213
|
-
|
|
214
|
-
console.log(`Your connection string is: psql -h localhost -p ${portNumber} -U ${USERNAME} -d ${TABLE_NAME}`);
|
|
215
|
-
console.log(`Use the password: ${PASSWORD}`);
|
|
216
|
-
|
|
217
|
-
// Get instance ID
|
|
218
|
-
const INSTANCE_ID = await getInstanceId();
|
|
219
|
-
if (!INSTANCE_ID) {
|
|
220
|
-
console.error('Failed to find a running instance with tag Name=*bastion*.');
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Get RDS endpoint
|
|
225
|
-
const RDS_ENDPOINT = await getRdsEndpoint();
|
|
226
|
-
if (!RDS_ENDPOINT) {
|
|
227
|
-
console.error('Failed to find the RDS endpoint.');
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Start a port forwarding session (this requires AWS CLI tool as the SDK doesn't support starting sessions)
|
|
232
|
-
const portForwardingCommand = `aws ssm start-session --target ${INSTANCE_ID} --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters "host=${RDS_ENDPOINT},portNumber='5432',localPortNumber='${portNumber}'" --cli-connect-timeout 0`;
|
|
233
|
-
console.log(`Run this command to start port forwarding: ${portForwardingCommand}`);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
main().catch(err => {
|
|
237
|
-
console.error(err);
|
|
238
|
-
});
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
This documentation provides detailed instructions on installation, usage, prerequisites, and how the system works, making it easy for users to understand and use your application effectively.
|
package/connect.js
CHANGED
|
@@ -73,9 +73,12 @@ async function main () {
|
|
|
73
73
|
const USERNAME = CREDENTIALS.username
|
|
74
74
|
const PASSWORD = CREDENTIALS.password
|
|
75
75
|
|
|
76
|
-
console.log(`Your connection
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
console.log(`Your connection details:
|
|
77
|
+
Host: localhost
|
|
78
|
+
Port: ${portNumber}
|
|
79
|
+
User: ${USERNAME}
|
|
80
|
+
Database: ${TABLE_NAME}
|
|
81
|
+
Password: ${PASSWORD}`)
|
|
79
82
|
const instanceIdCommand = `aws-vault exec ${ENV} -- aws ec2 describe-instances --region ${REGION} --filters "Name=tag:Name,Values='*bastion*'" "Name=instance-state-name,Values=running" --query "Reservations[].Instances[].[InstanceId] | [0][0]" --output text`
|
|
80
83
|
const INSTANCE_ID = await runCommand(instanceIdCommand)
|
|
81
84
|
|
|
@@ -109,7 +112,7 @@ async function main () {
|
|
|
109
112
|
console.log(`Port forwarding session ended with code ${code}`)
|
|
110
113
|
})
|
|
111
114
|
|
|
112
|
-
console.log('Port forwarding session established. You can now connect to the database using the provided connection
|
|
115
|
+
console.log('Port forwarding session established. You can now connect to the database using the provided connection details.')
|
|
113
116
|
console.log('Press Ctrl+C to end the session.')
|
|
114
117
|
} catch (error) {
|
|
115
118
|
console.error(`Error: ${error.message}`)
|
|
@@ -123,4 +126,4 @@ main().catch(error => {
|
|
|
123
126
|
setImmediate(() => {
|
|
124
127
|
throw new Error('Forcing exit due to unhandled error')
|
|
125
128
|
})
|
|
126
|
-
})
|
|
129
|
+
})
|
package/package.json
CHANGED
|
@@ -1,28 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rds_ssm_connect",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@aws-sdk/client-ec2": "^3.
|
|
7
|
-
"@aws-sdk/client-rds": "^3.
|
|
8
|
-
"@aws-sdk/client-ssm": "^3.
|
|
6
|
+
"@aws-sdk/client-ec2": "^3.674.0",
|
|
7
|
+
"@aws-sdk/client-rds": "^3.674.0",
|
|
8
|
+
"@aws-sdk/client-ssm": "^3.674.0",
|
|
9
9
|
"glob": "^11.0.0",
|
|
10
|
-
"inquirer": "^
|
|
11
|
-
"process": "^0.11.10",
|
|
10
|
+
"inquirer": "^12.0.0",
|
|
12
11
|
"rimraf": "^6.0.1"
|
|
13
12
|
},
|
|
14
13
|
"bin": {
|
|
15
14
|
"rds_ssm_connect": "./connect.js"
|
|
16
|
-
},
|
|
17
|
-
"scripts": {
|
|
18
|
-
"lint": "eslint .",
|
|
19
|
-
"lint:fix": "eslint . --fix"
|
|
20
|
-
},
|
|
21
|
-
"devDependencies": {
|
|
22
|
-
"eslint": "^8.57.0",
|
|
23
|
-
"eslint-config-standard": "^17.1.0",
|
|
24
|
-
"eslint-plugin-import": "^2.29.1",
|
|
25
|
-
"eslint-plugin-n": "^16.6.2",
|
|
26
|
-
"eslint-plugin-promise": "^6.1.1"
|
|
27
15
|
}
|
|
28
16
|
}
|