node-red-contrib-aws-sqs-variable 1.0.0
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 +179 -0
- package/aws-sqs-config.html +366 -0
- package/aws-sqs-config.js +272 -0
- package/aws-sqs.html +253 -0
- package/aws-sqs.js +260 -0
- package/examples/advanced-usage.json +267 -0
- package/examples/basic-usage.json +160 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# node-red-contrib-aws-sqs-variable
|
|
2
|
+
|
|
3
|
+
A production-ready Node-RED node for AWS SQS operations that sends and receives messages with flexible credential handling.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ๐ฌ Send messages to AWS SQS
|
|
8
|
+
- ๐ฅ Receive messages from AWS SQS
|
|
9
|
+
- ๐๏ธ Flexible credential configuration (IAM roles, direct credentials, context variables)
|
|
10
|
+
- ๐ฏ TypedInput support for dynamic Queue URL and payload
|
|
11
|
+
- ๐ FIFO support with Message Group and Deduplication IDs
|
|
12
|
+
- ๐งพ Optional JSON parsing for received messages
|
|
13
|
+
- โฑ๏ธ Built-in polling mode with status indicator
|
|
14
|
+
- ๐ก๏ธ Production-ready with comprehensive error handling
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
Run the following command in your Node-RED user directory (typically `~/.node-red`):
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install node-red-contrib-aws-sqs-variable
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
After installation, restart Node-RED to load the new nodes.
|
|
25
|
+
|
|
26
|
+
## Configuration
|
|
27
|
+
|
|
28
|
+
### AWS Configuration Node
|
|
29
|
+
|
|
30
|
+
The module uses a configuration node that supports multiple authentication methods:
|
|
31
|
+
|
|
32
|
+
#### IAM Role Authentication (Recommended)
|
|
33
|
+
- โ
Use when running on EC2 instances with IAM roles
|
|
34
|
+
- โ
No credentials needed in Node-RED
|
|
35
|
+
- โ
Automatic credential rotation
|
|
36
|
+
|
|
37
|
+
#### Access Key Authentication
|
|
38
|
+
Supports multiple credential sources:
|
|
39
|
+
|
|
40
|
+
- **String**: Stored securely in Node-RED credentials (encrypted)
|
|
41
|
+
- **Flow Context**: Retrieved from flow context variables
|
|
42
|
+
- **Global Context**: Retrieved from global context variables
|
|
43
|
+
- **Environment Variables**: Retrieved from environment variables
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### Basic Usage
|
|
48
|
+
|
|
49
|
+
1. **Create AWS Configuration**
|
|
50
|
+
- Add an "aws-sqs-config" node
|
|
51
|
+
- Configure your AWS region and credentials
|
|
52
|
+
|
|
53
|
+
2. **Add AWS SQS Node**
|
|
54
|
+
- Drag "aws-sqs" node to your flow
|
|
55
|
+
- Select your AWS configuration
|
|
56
|
+
- Choose operation: Send or Receive
|
|
57
|
+
|
|
58
|
+
### Send Messages
|
|
59
|
+
|
|
60
|
+
Configure:
|
|
61
|
+
- **Queue URL** (string, msg, flow, global, env)
|
|
62
|
+
- **Message Body** (string, msg, flow, global, env)
|
|
63
|
+
|
|
64
|
+
Optional for FIFO:
|
|
65
|
+
- **Message Group ID** (required for FIFO)
|
|
66
|
+
- **Deduplication ID** (optional if content-based deduplication is enabled)
|
|
67
|
+
|
|
68
|
+
### Receive Messages
|
|
69
|
+
|
|
70
|
+
Configure:
|
|
71
|
+
- **Queue URL**
|
|
72
|
+
- **Max Messages** (1-10)
|
|
73
|
+
- **Wait Time (s)** (0-20, long polling)
|
|
74
|
+
- **Visibility Timeout (s)**
|
|
75
|
+
- **Delete After Receive**
|
|
76
|
+
- **Parse JSON Body** (optional)
|
|
77
|
+
|
|
78
|
+
Polling:
|
|
79
|
+
- Enable **Polling** to receive messages on a schedule
|
|
80
|
+
- Set **Poll Interval (s)**
|
|
81
|
+
|
|
82
|
+
## Input
|
|
83
|
+
|
|
84
|
+
### Message Properties
|
|
85
|
+
|
|
86
|
+
- `msg.queueUrl` (optional): Queue URL if not configured in node
|
|
87
|
+
- `msg.messageGroupId` (optional): FIFO Message Group ID
|
|
88
|
+
- `msg.messageDeduplicationId` (optional): FIFO Deduplication ID
|
|
89
|
+
|
|
90
|
+
### Example Input
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
msg = {
|
|
94
|
+
queueUrl: "https://sqs.eu-central-1.amazonaws.com/123456789012/my-queue",
|
|
95
|
+
payload: { message: "Hello!" }
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Output
|
|
100
|
+
|
|
101
|
+
### Send Success Response
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
msg = {
|
|
105
|
+
payload: {
|
|
106
|
+
messageId: "abcd-1234",
|
|
107
|
+
md5OfMessageBody: "e99a18c428cb38d5f260853678922e03"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Receive Success Response
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
msg = {
|
|
116
|
+
payload: [
|
|
117
|
+
{
|
|
118
|
+
MessageId: "...",
|
|
119
|
+
ReceiptHandle: "...",
|
|
120
|
+
Body: "raw string or parsed JSON when enabled"
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Error Response
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
msg = {
|
|
130
|
+
payload: {
|
|
131
|
+
error: "Error message"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## FIFO Notes
|
|
137
|
+
|
|
138
|
+
- **Message Group ID** is required for FIFO queues
|
|
139
|
+
- **Deduplication ID** must be unique within a 5-minute window
|
|
140
|
+
- Ordering is guaranteed only within the same Message Group
|
|
141
|
+
|
|
142
|
+
## Security Best Practices
|
|
143
|
+
|
|
144
|
+
- โ
Use IAM roles when possible (recommended for EC2 instances)
|
|
145
|
+
- โ
Store credentials in context variables rather than hardcoding
|
|
146
|
+
- โ
Use environment variables for sensitive configuration
|
|
147
|
+
- โ
Rotate access keys regularly
|
|
148
|
+
- โ
Follow the principle of least privilege
|
|
149
|
+
- โ
Enable AWS CloudTrail for audit logging
|
|
150
|
+
|
|
151
|
+
## Error Handling
|
|
152
|
+
|
|
153
|
+
The node provides comprehensive error handling:
|
|
154
|
+
|
|
155
|
+
- **Configuration errors**: Missing or invalid AWS configuration
|
|
156
|
+
- **Authentication errors**: Invalid credentials or permissions
|
|
157
|
+
- **Queue errors**: Invalid Queue URL or insufficient permissions
|
|
158
|
+
- **Network errors**: Connection issues with AWS
|
|
159
|
+
|
|
160
|
+
All errors are logged and sent in the message payload for downstream processing.
|
|
161
|
+
|
|
162
|
+
## Requirements
|
|
163
|
+
|
|
164
|
+
- Node.js >= 12.0.0
|
|
165
|
+
- Node-RED >= 2.0.0
|
|
166
|
+
- AWS account with SQS access
|
|
167
|
+
- Appropriate IAM permissions
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT
|
|
172
|
+
|
|
173
|
+
## Contributing
|
|
174
|
+
|
|
175
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
176
|
+
|
|
177
|
+
## Support
|
|
178
|
+
|
|
179
|
+
If you encounter any issues or have questions, please open an issue in the project repository.
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('aws-sqs-config', {
|
|
3
|
+
category: 'config',
|
|
4
|
+
defaults: {
|
|
5
|
+
name: { value: "" },
|
|
6
|
+
region: { value: "eu-central-1", required: true },
|
|
7
|
+
regionType: { value: "str" },
|
|
8
|
+
regionContext: { value: "" },
|
|
9
|
+
useIAMRole: { value: false, required: true },
|
|
10
|
+
deferMissingConfig: { value: true },
|
|
11
|
+
accessKeyId: { value: "" },
|
|
12
|
+
accessKeyIdType: { value: "str" },
|
|
13
|
+
accessKeyIdContext: { value: "" },
|
|
14
|
+
secretAccessKey: { value: "" },
|
|
15
|
+
secretAccessKeyType: { value: "str" },
|
|
16
|
+
secretAccessKeyContext: { value: "" }
|
|
17
|
+
},
|
|
18
|
+
credentials: {
|
|
19
|
+
accessKeyId: { type: "text" },
|
|
20
|
+
secretAccessKey: { type: "password" }
|
|
21
|
+
},
|
|
22
|
+
label: function() {
|
|
23
|
+
return this.name || "AWS SQS Config (" + this.region + ")";
|
|
24
|
+
},
|
|
25
|
+
icon: "font-awesome/fa-key",
|
|
26
|
+
color: "#b2e2b2",
|
|
27
|
+
oneditprepare: function() {
|
|
28
|
+
// Set initial IAM role checkbox state
|
|
29
|
+
var useIAMRole = this.useIAMRole === true || this.useIAMRole === "true" || this.useIAMRole === 1;
|
|
30
|
+
$("#node-config-input-useIAMRole").prop('checked', useIAMRole);
|
|
31
|
+
$("#node-config-input-deferMissingConfig").prop('checked', this.deferMissingConfig === true || this.deferMissingConfig === "true");
|
|
32
|
+
|
|
33
|
+
// Initialize tooltips
|
|
34
|
+
$('.node-config-input').tooltip({
|
|
35
|
+
delay: { show: 500, hide: 100 },
|
|
36
|
+
trigger: 'hover'
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Use only flow, global, str, env for typedInput
|
|
40
|
+
var stdTypes = ['str', 'flow', 'global', 'env'];
|
|
41
|
+
|
|
42
|
+
// Initialize typedInput for Region
|
|
43
|
+
$("#node-config-input-region-typed").typedInput({
|
|
44
|
+
default: 'str',
|
|
45
|
+
types: stdTypes,
|
|
46
|
+
typeField: "#node-config-input-regionType"
|
|
47
|
+
});
|
|
48
|
+
$("#node-config-input-region-typed").typedInput('type', this.regionType || 'str');
|
|
49
|
+
|
|
50
|
+
if (this.regionType === 'str') {
|
|
51
|
+
$("#node-config-input-region-typed").typedInput('value', this.region || 'eu-central-1');
|
|
52
|
+
} else {
|
|
53
|
+
$("#node-config-input-region-typed").typedInput('value', this.regionContext || '');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Initialize typedInput for Access Key ID
|
|
57
|
+
$("#node-config-input-accessKeyId-typed").typedInput({
|
|
58
|
+
default: 'str',
|
|
59
|
+
types: stdTypes,
|
|
60
|
+
typeField: "#node-config-input-accessKeyIdType"
|
|
61
|
+
});
|
|
62
|
+
$("#node-config-input-accessKeyId-typed").typedInput('type', this.accessKeyIdType || 'str');
|
|
63
|
+
|
|
64
|
+
// Set value based on type for Access Key ID
|
|
65
|
+
if (this.accessKeyIdType === 'str') {
|
|
66
|
+
// For string type, use credentials if available
|
|
67
|
+
var credValue = this.credentials && this.credentials.accessKeyId ? this.credentials.accessKeyId : '';
|
|
68
|
+
$("#node-config-input-accessKeyId-typed").typedInput('value', credValue);
|
|
69
|
+
} else {
|
|
70
|
+
// For context types, use the stored context value
|
|
71
|
+
$("#node-config-input-accessKeyId-typed").typedInput('value', this.accessKeyIdContext || '');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Secret Access Key type selection
|
|
75
|
+
if (this.secretAccessKeyType && this.secretAccessKeyType !== 'str') {
|
|
76
|
+
// Context type
|
|
77
|
+
$("#node-config-input-secretAccessKey-type").val(this.secretAccessKeyType);
|
|
78
|
+
$("#node-config-input-secretAccessKey-context").val(this.secretAccessKeyContext || '');
|
|
79
|
+
} else {
|
|
80
|
+
// String type
|
|
81
|
+
$("#node-config-input-secretAccessKey-type").val('str');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Secret Access Key field visibility logic
|
|
85
|
+
var updateSecretAccessKeyFieldVisibility = function() {
|
|
86
|
+
var secretAccessKeyType = $("#node-config-input-secretAccessKey-type").val();
|
|
87
|
+
|
|
88
|
+
if (secretAccessKeyType === 'str') {
|
|
89
|
+
$("#secretAccessKey-str-row").show();
|
|
90
|
+
$("#secretAccessKey-context-row").hide();
|
|
91
|
+
} else {
|
|
92
|
+
$("#secretAccessKey-str-row").hide();
|
|
93
|
+
$("#secretAccessKey-context-row").show();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
$("#node-config-input-secretAccessKey-type").on("change", updateSecretAccessKeyFieldVisibility);
|
|
98
|
+
|
|
99
|
+
// Call immediately to set initial state
|
|
100
|
+
updateSecretAccessKeyFieldVisibility();
|
|
101
|
+
|
|
102
|
+
// Also call after a short delay to ensure DOM is ready
|
|
103
|
+
setTimeout(updateSecretAccessKeyFieldVisibility, 100);
|
|
104
|
+
|
|
105
|
+
// Sync visible password field with hidden credentials field
|
|
106
|
+
$("#node-config-input-secretAccessKey-visible").on("input", function() {
|
|
107
|
+
$("#node-config-input-secretAccessKey").val($(this).val());
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Handle placeholder behavior for Secret Access Key
|
|
111
|
+
$("#node-config-input-secretAccessKey-visible").on("focus", function() {
|
|
112
|
+
if ($(this).attr('placeholder') === 'โขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโข') {
|
|
113
|
+
$(this).attr('placeholder', 'Enter new secret key or leave empty to keep existing');
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
$("#node-config-input-secretAccessKey-visible").on("blur", function() {
|
|
118
|
+
var inputVal = $(this).val();
|
|
119
|
+
if (!inputVal && this.credentials && this.credentials.has_secretAccessKey) {
|
|
120
|
+
$(this).attr('placeholder', 'โขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโข');
|
|
121
|
+
}
|
|
122
|
+
}.bind(this));
|
|
123
|
+
|
|
124
|
+
// Load existing secret access key if available
|
|
125
|
+
if (this.credentials && this.credentials.secretAccessKey) {
|
|
126
|
+
$("#node-config-input-secretAccessKey-visible").val(this.credentials.secretAccessKey);
|
|
127
|
+
$("#node-config-input-secretAccessKey").val(this.credentials.secretAccessKey);
|
|
128
|
+
} else if (this.credentials && this.credentials.has_secretAccessKey) {
|
|
129
|
+
// Secret key exists but not shown for security - show placeholder
|
|
130
|
+
$("#node-config-input-secretAccessKey-visible").attr('placeholder', 'โขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโข');
|
|
131
|
+
$("#node-config-input-secretAccessKey-visible").val('');
|
|
132
|
+
} else {
|
|
133
|
+
// No secret key - set default placeholder
|
|
134
|
+
$("#node-config-input-secretAccessKey-visible").attr('placeholder', 'Enter secret access key');
|
|
135
|
+
$("#node-config-input-secretAccessKey-visible").val('');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Handle IAM role toggle
|
|
139
|
+
$('#node-config-input-useIAMRole').change(function() {
|
|
140
|
+
var isIAMRole = $(this).is(':checked');
|
|
141
|
+
|
|
142
|
+
if (isIAMRole) {
|
|
143
|
+
$('.credentials-row').hide();
|
|
144
|
+
} else {
|
|
145
|
+
$('.credentials-row').show();
|
|
146
|
+
// Re-apply field visibility logic
|
|
147
|
+
updateSecretAccessKeyFieldVisibility();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Set initial visibility
|
|
152
|
+
if (useIAMRole) {
|
|
153
|
+
$('.credentials-row').hide();
|
|
154
|
+
} else {
|
|
155
|
+
// Ensure proper field visibility
|
|
156
|
+
setTimeout(function() {
|
|
157
|
+
updateSecretAccessKeyFieldVisibility();
|
|
158
|
+
}, 200);
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
oneditsave: function() {
|
|
162
|
+
// Save basic configuration
|
|
163
|
+
this.name = $("#node-config-input-name").val();
|
|
164
|
+
// Handle Region
|
|
165
|
+
var regionType = $("#node-config-input-regionType").val();
|
|
166
|
+
var regionValue = $("#node-config-input-region-typed").typedInput('value');
|
|
167
|
+
this.regionType = regionType;
|
|
168
|
+
if (regionType === 'str') {
|
|
169
|
+
this.region = regionValue || '';
|
|
170
|
+
this.regionContext = '';
|
|
171
|
+
$("#node-config-input-region-context").val('');
|
|
172
|
+
$("#node-config-input-region").val(regionValue || '');
|
|
173
|
+
} else {
|
|
174
|
+
this.region = '';
|
|
175
|
+
this.regionContext = regionValue || '';
|
|
176
|
+
$("#node-config-input-region").val('');
|
|
177
|
+
$("#node-config-input-region-context").val(regionValue || '');
|
|
178
|
+
}
|
|
179
|
+
this.useIAMRole = $("#node-config-input-useIAMRole").is(':checked');
|
|
180
|
+
this.deferMissingConfig = $("#node-config-input-deferMissingConfig").is(':checked');
|
|
181
|
+
|
|
182
|
+
// Handle Access Key ID (TypedInput logic)
|
|
183
|
+
var accessKeyIdType = $("#node-config-input-accessKeyIdType").val();
|
|
184
|
+
var accessKeyIdValue = $("#node-config-input-accessKeyId-typed").typedInput('value');
|
|
185
|
+
|
|
186
|
+
// Explicitly set the type first
|
|
187
|
+
this.accessKeyIdType = accessKeyIdType;
|
|
188
|
+
|
|
189
|
+
if (accessKeyIdType === 'str') {
|
|
190
|
+
// String type - save to credentials, clear from defaults
|
|
191
|
+
this.accessKeyId = '';
|
|
192
|
+
this.accessKeyIdContext = '';
|
|
193
|
+
$("#node-config-input-accessKeyId-context").val('');
|
|
194
|
+
// Set the credential field
|
|
195
|
+
$("#node-config-input-accessKeyId").val(accessKeyIdValue || '');
|
|
196
|
+
} else {
|
|
197
|
+
// Context type - save to context field, clear credentials
|
|
198
|
+
this.accessKeyId = '';
|
|
199
|
+
this.accessKeyIdContext = accessKeyIdValue || '';
|
|
200
|
+
$("#node-config-input-accessKeyId").val('');
|
|
201
|
+
$("#node-config-input-accessKeyId-context").val(accessKeyIdValue || '');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Handle Secret Access Key based on type
|
|
205
|
+
var secretAccessKeyType = $("#node-config-input-secretAccessKey-type").val();
|
|
206
|
+
this.secretAccessKeyType = secretAccessKeyType;
|
|
207
|
+
|
|
208
|
+
if (secretAccessKeyType === 'str') {
|
|
209
|
+
// String secret key - save to credentials, clear context
|
|
210
|
+
this.secretAccessKeyContext = '';
|
|
211
|
+
this.secretAccessKey = ''; // Clear from defaults
|
|
212
|
+
$("#node-config-input-secretAccessKeyContext").val('');
|
|
213
|
+
// Sync visible field to hidden credentials field only if not empty
|
|
214
|
+
var visibleSecretAccessKey = $("#node-config-input-secretAccessKey-visible").val();
|
|
215
|
+
if (visibleSecretAccessKey) {
|
|
216
|
+
$("#node-config-input-secretAccessKey").val(visibleSecretAccessKey);
|
|
217
|
+
}
|
|
218
|
+
// If empty, keep existing secret key (don't overwrite)
|
|
219
|
+
} else {
|
|
220
|
+
// Context secret key - save context reference
|
|
221
|
+
var secretAccessKeyValue = $("#node-config-input-secretAccessKey-context").val();
|
|
222
|
+
this.secretAccessKeyContext = secretAccessKeyValue || '';
|
|
223
|
+
this.secretAccessKey = ''; // Clear from defaults
|
|
224
|
+
$("#node-config-input-secretAccessKeyContext").val(secretAccessKeyValue || '');
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
</script>
|
|
229
|
+
|
|
230
|
+
<script type="text/x-red" data-template-name="aws-sqs-config">
|
|
231
|
+
<div class="form-row">
|
|
232
|
+
<label for="node-config-input-name">
|
|
233
|
+
<i class="fa fa-tag"></i> Name
|
|
234
|
+
</label>
|
|
235
|
+
<input type="text" id="node-config-input-name" placeholder="Configuration Name" style="width: 70%;">
|
|
236
|
+
</div>
|
|
237
|
+
<div class="form-row">
|
|
238
|
+
<label for="node-config-input-region-typed">
|
|
239
|
+
<i class="fa fa-globe"></i> Region
|
|
240
|
+
</label>
|
|
241
|
+
<input type="text" id="node-config-input-region-typed" style="width: 70%;" placeholder="eu-central-1">
|
|
242
|
+
<input type="hidden" id="node-config-input-regionType">
|
|
243
|
+
</div>
|
|
244
|
+
<div class="form-row">
|
|
245
|
+
<label for="node-config-input-useIAMRole">
|
|
246
|
+
<i class="fa fa-user"></i> Use IAM Role
|
|
247
|
+
</label>
|
|
248
|
+
<input type="checkbox" id="node-config-input-useIAMRole" style="display: inline-block; width: auto; vertical-align: middle;">
|
|
249
|
+
<span style="margin-left: 5px; vertical-align: middle;">Use IAM role for authentication<br><small>(recommended for EC2 instances)</small></span>
|
|
250
|
+
</div>
|
|
251
|
+
<div class="form-row">
|
|
252
|
+
<label for="node-config-input-deferMissingConfig">
|
|
253
|
+
<i class="fa fa-clock-o"></i> Defer Missing Config
|
|
254
|
+
</label>
|
|
255
|
+
<input type="checkbox" id="node-config-input-deferMissingConfig" style="display: inline-block; width: auto; vertical-align: middle;">
|
|
256
|
+
<span style="margin-left: 5px; vertical-align: middle;">Wait for credentials/region without throwing errors</span>
|
|
257
|
+
</div>
|
|
258
|
+
<div class="form-row credentials-row">
|
|
259
|
+
<label for="node-config-input-accessKeyId-typed">
|
|
260
|
+
<i class="fa fa-key"></i> Access Key ID
|
|
261
|
+
</label>
|
|
262
|
+
<input type="text" id="node-config-input-accessKeyId-typed" style="width: 70%;">
|
|
263
|
+
<input type="hidden" id="node-config-input-accessKeyIdType">
|
|
264
|
+
</div>
|
|
265
|
+
<div class="form-row credentials-row">
|
|
266
|
+
<label for="node-config-input-secretAccessKey-type">
|
|
267
|
+
<i class="fa fa-key"></i> Secret Access Key Type
|
|
268
|
+
</label>
|
|
269
|
+
<select id="node-config-input-secretAccessKey-type" style="width: 70%;">
|
|
270
|
+
<option value="str">Direct Secret Key (secure)</option>
|
|
271
|
+
<option value="flow">Flow Context</option>
|
|
272
|
+
<option value="global">Global Context</option>
|
|
273
|
+
<option value="env">Environment Variable</option>
|
|
274
|
+
</select>
|
|
275
|
+
</div>
|
|
276
|
+
<div class="form-row credentials-row" id="secretAccessKey-str-row">
|
|
277
|
+
<label for="node-config-input-secretAccessKey-visible">
|
|
278
|
+
<i class="fa fa-key"></i> Secret Access Key
|
|
279
|
+
</label>
|
|
280
|
+
<input type="password" id="node-config-input-secretAccessKey-visible" style="width: 70%;">
|
|
281
|
+
</div>
|
|
282
|
+
<div class="form-row credentials-row" id="secretAccessKey-context-row" style="display: none;">
|
|
283
|
+
<label for="node-config-input-secretAccessKey-context">
|
|
284
|
+
<i class="fa fa-code"></i> Variable Name
|
|
285
|
+
</label>
|
|
286
|
+
<input type="text" id="node-config-input-secretAccessKey-context" style="width: 70%;">
|
|
287
|
+
</div>
|
|
288
|
+
<!-- Hidden fields for Node-RED credentials system -->
|
|
289
|
+
<input type="text" id="node-config-input-accessKeyId" style="display: none;">
|
|
290
|
+
<input type="password" id="node-config-input-secretAccessKey" style="display: none;">
|
|
291
|
+
<!-- Hidden field for region -->
|
|
292
|
+
<input type="text" id="node-config-input-region" style="display: none;">
|
|
293
|
+
<!-- Hidden field for region context value -->
|
|
294
|
+
<input type="text" id="node-config-input-region-context" style="display: none;">
|
|
295
|
+
<!-- Hidden field for accessKeyId context value -->
|
|
296
|
+
<input type="text" id="node-config-input-accessKeyId-context" style="display: none;">
|
|
297
|
+
<!-- Hidden field for secretAccessKeyContext -->
|
|
298
|
+
<input type="text" id="node-config-input-secretAccessKeyContext" style="display: none;">
|
|
299
|
+
</script>
|
|
300
|
+
|
|
301
|
+
<script type="text/x-red" data-help-name="aws-sqs-config">
|
|
302
|
+
<p>AWS SQS configuration node with flexible context support:</p>
|
|
303
|
+
|
|
304
|
+
<h3>Authentication Methods</h3>
|
|
305
|
+
<ul>
|
|
306
|
+
<li><b>IAM Role</b>: Use IAM role for authentication (recommended for EC2 instances)</li>
|
|
307
|
+
<li><b>Access Keys</b>: Use AWS access key and secret key</li>
|
|
308
|
+
</ul>
|
|
309
|
+
|
|
310
|
+
<h3>Credential Sources</h3>
|
|
311
|
+
<p>When not using IAM role, credentials support multiple input types:</p>
|
|
312
|
+
<ul>
|
|
313
|
+
<li><b>String</b>: Stored securely in Node-RED credentials (encrypted)</li>
|
|
314
|
+
<li><b>Flow Context</b>: Retrieved from flow context variables</li>
|
|
315
|
+
<li><b>Global Context</b>: Retrieved from global context variables</li>
|
|
316
|
+
<li><b>Environment Variable</b>: Retrieved from environment variables</li>
|
|
317
|
+
</ul>
|
|
318
|
+
|
|
319
|
+
<h3>Security Notes</h3>
|
|
320
|
+
<ul>
|
|
321
|
+
<li>String credentials are stored encrypted in Node-RED's credentials store</li>
|
|
322
|
+
<li>Context types only store variable names, actual credentials retrieved at runtime</li>
|
|
323
|
+
<li>Use IAM roles when possible for better security</li>
|
|
324
|
+
<li>Rotate access keys regularly</li>
|
|
325
|
+
<li>Follow the principle of least privilege</li>
|
|
326
|
+
</ul>
|
|
327
|
+
</script>
|
|
328
|
+
|
|
329
|
+
<style>
|
|
330
|
+
.form-row {
|
|
331
|
+
margin-bottom: 10px;
|
|
332
|
+
}
|
|
333
|
+
.form-row label {
|
|
334
|
+
display: inline-block;
|
|
335
|
+
width: 120px;
|
|
336
|
+
vertical-align: top;
|
|
337
|
+
margin-top: 6px;
|
|
338
|
+
}
|
|
339
|
+
.form-row input[type="text"],
|
|
340
|
+
.form-row input[type="password"],
|
|
341
|
+
.form-row select {
|
|
342
|
+
width: 70%;
|
|
343
|
+
}
|
|
344
|
+
.form-row input[type="checkbox"] {
|
|
345
|
+
width: auto;
|
|
346
|
+
margin: 0;
|
|
347
|
+
vertical-align: middle;
|
|
348
|
+
}
|
|
349
|
+
.credentials-row {
|
|
350
|
+
margin-top: 10px;
|
|
351
|
+
}
|
|
352
|
+
.help-text {
|
|
353
|
+
font-size: 0.8em;
|
|
354
|
+
color: #666;
|
|
355
|
+
margin-top: 4px;
|
|
356
|
+
margin-left: 125px;
|
|
357
|
+
}
|
|
358
|
+
.error-text {
|
|
359
|
+
color: #d00;
|
|
360
|
+
font-size: 0.8em;
|
|
361
|
+
margin-top: 4px;
|
|
362
|
+
}
|
|
363
|
+
.input-error {
|
|
364
|
+
border-color: #d00 !important;
|
|
365
|
+
}
|
|
366
|
+
</style>
|