rds_ssm_connect 1.2.1 → 1.2.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/README.md +198 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
# AWS
|
|
1
|
+
# AWS RDS SSM Connector
|
|
2
2
|
|
|
3
|
-
This Node.js application allows you to select an AWS environment and execute various AWS commands within that environment. The environments are read from your AWS configuration file, and the application
|
|
3
|
+
This Node.js application allows you to select an AWS environment and execute various AWS commands within that environment to connect to an RDS database securely. The environments are read from your AWS configuration file, and the application retrieves credentials and other necessary information using AWS Secrets Manager and other AWS services.
|
|
4
4
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
7
7
|
Before running this application, make sure you have the following installed:
|
|
8
8
|
|
|
9
|
-
- Node.js
|
|
10
|
-
-
|
|
11
|
-
- AWS CLI
|
|
9
|
+
- **Node.js**: You can download it from the [official website](https://nodejs.org/).
|
|
10
|
+
- **`aws-vault` tool**: You can install it following the instructions on the [official GitHub page](https://github.com/99designs/aws-vault).
|
|
11
|
+
- **AWS CLI**: You can install it following the instructions on the [official AWS page](https://aws.amazon.com/cli/).
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Additionally, ensure that your AWS configuration file (`~/.aws/config`) is appropriately set up with the environments you want to use.
|
|
14
14
|
|
|
15
15
|
## Installation
|
|
16
16
|
|
|
@@ -20,13 +20,11 @@ You can install this application globally using npm:
|
|
|
20
20
|
npm install -g rds_ssm_connect
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
2. Select the environment you want to use. The application will then execute a series of AWS commands within that environment.
|
|
24
|
-
|
|
25
|
-
Given your provided code, here's how to connect to the database:
|
|
26
|
-
|
|
27
23
|
## Connecting to the Database
|
|
28
24
|
|
|
29
|
-
1. Invoke
|
|
25
|
+
1. **Invoke the Application**:
|
|
26
|
+
|
|
27
|
+
Run the following command in your terminal:
|
|
30
28
|
|
|
31
29
|
```bash
|
|
32
30
|
rds_ssm_connect
|
|
@@ -34,49 +32,210 @@ Given your provided code, here's how to connect to the database:
|
|
|
34
32
|
|
|
35
33
|
The application will read your AWS configuration file and prompt you to select an environment.
|
|
36
34
|
|
|
37
|
-
2. Select
|
|
35
|
+
2. **Select an Environment**:
|
|
36
|
+
|
|
37
|
+
The application will list the environments found in your AWS configuration file. Select the desired environment for which you want to connect to the RDS instance.
|
|
38
|
+
|
|
39
|
+
3. **Execution of AWS Commands**:
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
- Get the
|
|
45
|
-
-
|
|
41
|
+
After selecting the environment, the application will:
|
|
42
|
+
|
|
43
|
+
- Extract environments from the AWS configuration file.
|
|
44
|
+
- Use AWS Secrets Manager to list and retrieve the secret containing the RDS credentials.
|
|
45
|
+
- Display the connection credentials and connection string.
|
|
46
|
+
- Get the ID of the bastion instance.
|
|
47
|
+
- Get the endpoint of the RDS cluster.
|
|
48
|
+
- Provide a command to start a port forwarding session to the RDS cluster.
|
|
46
49
|
|
|
47
|
-
|
|
50
|
+
4. **Receive Connection Information**:
|
|
51
|
+
|
|
52
|
+
After executing the necessary AWS commands, the application will provide the connection information, as shown below:
|
|
48
53
|
|
|
49
54
|
```
|
|
50
|
-
Your connection string is: psql -h localhost -p <port> -U <username> -d
|
|
55
|
+
Your connection string is: psql -h localhost -p <port> -U <username> -d <database>
|
|
51
56
|
Use the password: <password>
|
|
52
57
|
```
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
5. **Port Forwarding**:
|
|
60
|
+
|
|
61
|
+
Use the provided command to start port forwarding. This step is crucial as it sets up the local port to tunnel to the RDS cluster through the bastion host.
|
|
55
62
|
|
|
56
|
-
|
|
63
|
+
For example:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
aws ssm start-session --target <instance-id> --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters "host=<rds-endpoint>,portNumber='5432',localPortNumber='<port>'" --cli-connect-timeout 0
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
6. **Connect to Your Database**:
|
|
70
|
+
|
|
71
|
+
Use the provided connection string and password to connect to your database via a database administration tool of your choice, such as pgAdmin, DBeaver, or the `psql` command-line interface.
|
|
72
|
+
|
|
73
|
+
Ensure that the database administration tool is installed and configured on your local machine.
|
|
57
74
|
|
|
58
75
|
## Requirements
|
|
59
76
|
|
|
60
77
|
This application requires the following Node.js modules:
|
|
61
78
|
|
|
62
|
-
- `
|
|
63
|
-
- `
|
|
64
|
-
- `
|
|
65
|
-
- `
|
|
66
|
-
- `path`: For working with file paths.
|
|
79
|
+
- `@aws-sdk/client-ec2`
|
|
80
|
+
- `@aws-sdk/client-rds`
|
|
81
|
+
- `@aws-sdk/client-secrets-manager`
|
|
82
|
+
- `inquirer`
|
|
67
83
|
|
|
68
|
-
These modules will be installed
|
|
84
|
+
These modules will be automatically installed when you install the application with npm.
|
|
69
85
|
|
|
70
86
|
## How It Works
|
|
71
87
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
88
|
+
1. **Reading AWS Configuration**:
|
|
89
|
+
|
|
90
|
+
The application first reads the AWS configuration file (`~/.aws/config`) and extracts the environments configured.
|
|
91
|
+
|
|
92
|
+
2. **User Prompt**:
|
|
93
|
+
|
|
94
|
+
The user is prompted to select one of the configured environments using `inquirer`.
|
|
95
|
+
|
|
96
|
+
3. **AWS Commands Execution**:
|
|
97
|
+
|
|
98
|
+
Upon selecting an environment, the application performs the following operations using the AWS SDK and `aws-vault`:
|
|
99
|
+
|
|
100
|
+
- **Listing Secrets**: Uses AWS Secrets Manager to list secrets and identify the one containing the RDS credentials.
|
|
101
|
+
- **Retrieving Secret Value**: Fetches the secret value containing the RDS username and password.
|
|
102
|
+
- **Describing Instances**: Gets the ID of a bastion instance tagged with `Name=*bastion*`.
|
|
103
|
+
- **Describing RDS Clusters**: Retrieves the endpoint of the RDS cluster identified with `-rds-aurora`.
|
|
104
|
+
- **Port Forwarding Command**: Outputs a command to start an AWS SSM session for port forwarding.
|
|
105
|
+
|
|
106
|
+
4. **Output**:
|
|
107
|
+
|
|
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
|
+
```
|
|
81
240
|
|
|
82
|
-
|
|
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.
|