How to connect Loopback app to google database with ssl enabled? - loopbackjs

I'm attempting to connect a Loopback app to a Google SQL database, and I've altered the Datasource.json file to match the credentials. However, when I make a GET request in the Loopback API explorer I get an error. I have not found any docs on how to specify the ssl credentials in Datasource.json and I think this is causing the error.
I've fruitlessly attempted to change Datasource.json and below is the current state. I've changed details for privacy, but I'm 100% certain the credentials are correct as I can make a successful connection with javascript.
{
"nameOfModel": {
"name": "db",
"connector": "mysql",
"host": "xx.xxx.x.xxx",
"port": xxxx,
"user": "user",
"password": "password",
"database": "sql_db",
"ssl": true,
"ca" : "/server-ca.pem",
"cert" : "/client-cert.pem",
"key" : "/client-key.pem"
}
}
This is the error the command line returns when I attempt a GET request on the loopback API explorer. The "Error:
Timeout in connecting after 5000 ms" leads me to believe it's not reading the ssl credentials.
Unhandled error in GET /edd-sales?filter[offset]=0&filter[limit]=0&filter[skip]=0: 500 TypeError: Cannot read property 'name' of undefined
at EddDbDataSource.DataSource.queueInvocation.DataSource.ready (D:\WebstormProjects\EDD-Database\edd-api\node_modules\loopback-datasource-juggler\lib\datasource.js:2577:81)
(node:10176) UnhandledPromiseRejectionWarning: Error: Timeout in connecting after 5000 ms
at Timeout._onTimeout (D:\WebstormProjects\EDD-Database\edd-api\node_modules\loopback-datasource-juggler\lib\datasource.js:2572:10)
at ontimeout (timers.js:498:11)
(node:10176) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:10176) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Are you sure datasource.json allows you to specify "ssl" connections? Where did you get that information? I have checked their documentation and they don't show the "ssl" properties that you are using. Neither it specifies so on the MySQL connector properties.
You have two options:
1.- Create the connection without using SSL.
2.- Create your own connector or use an existing one with ssl options implemented. Have in mind that this might causes issues with LoopBack framework.
Don't matter which of the two options you decide to use, remember to Whitelist your IP (the IP from where you are trying to access the database instance), you can do so on the Cloud Console, on the "Connections" tab, under "public IP" Authorized networks. If you don't do this it can cause the timeout error that you are getting.

Try this. I am using lookback3 and it works well for me. You need to create datasources.local.js in order to properly load CA files.
datasources.local.js
const fs = require('fs');
module.exports = {
nameOfModel: {
name: 'db',
connector: 'mysql',
host: 'xx.xxx.x.xxx',
port: 'xxxx',
user: 'user',
password: 'password',
database: 'sql_db',
ssl: {
ca: fs.readFileSync(`${__dirname}/server-ca.pem`),
cert: fs.readFileSync(`${__dirname}/client-cert.pem`),
key: fs.readFileSync(`${__dirname}/client-key.pem`),
},
}
}
Notice that instead of using ssl: true, you need to use an object with those properties.

Related

Errors connecting to AWS Keyspaces using a lambda layer

Intermittently getting the following error when connecting to an AWS keyspace using a lambda layer
All host(s) tried for query failed. First host tried, 3.248.244.53:9142: Host considered as DOWN. See innerErrors.
I am trying to query a table in a keyspace using a nodejs lambda function as follows:
import cassandra from 'cassandra-driver';
import fs from 'fs';
export default class AmazonKeyspace {
tpmsClient = null;
constructor () {
let auth = new cassandra.auth.PlainTextAuthProvider('cass-user-at-xxxxxxxxxx', 'zzzzzzzzz');
let sslOptions1 = {
ca: [ fs.readFileSync('/opt/utils/AmazonRootCA1.pem', 'utf-8')],
host: 'cassandra.eu-west-1.amazonaws.com',
rejectUnauthorized: true
};
this.tpmsClient = new cassandra.Client({
contactPoints: ['cassandra.eu-west-1.amazonaws.com'],
localDataCenter: 'eu-west-1',
authProvider: auth,
sslOptions: sslOptions1,
keyspace: 'tpms',
protocolOptions: { port: 9142 }
});
}
getOrganisation = async (orgKey) => {
const SQL = 'select * FROM organisation where organisation_id=?;';
return new Promise((resolve, reject) => {
this.tpmsClient.execute(SQL, [orgKey], {prepare: true}, (err, result) => {
if (!err?.message) resolve(result.rows);
else reject(err.message);
});
});
};
}
I am basically following this recommended AWS documentation.
https://docs.aws.amazon.com/keyspaces/latest/devguide/using_nodejs_driver.html
It seems that around 10-20% of the time the lambda function (cassandra driver) cannot connect to the endpoint.
I am pretty familiar with Cassandra (I already use a 6 node cluster that I manage) and don't have any issues with that.
Could this be a timeout or do I need more contact points?
Followed the recommended guides. Checked from the AWS console for any errors but none shown.
UPDATE:
Update to the above question....
I am occasionally (1 in 50 if I parallel call the function (5 concurrent calls)) getting the below error:
"All host(s) tried for query failed. First host tried,
3.248.244.5:9142: DriverError: Socket was closed at Connection.clearAndInvokePending
(/opt/node_modules/cassandra-driver/lib/connection.js:265:15) at
Connection.close
(/opt/node_modules/cassandra-driver/lib/connection.js:618:8) at
TLSSocket.
(/opt/node_modules/cassandra-driver/lib/connection.js:93:10) at
TLSSocket.emit (node:events:525:35)\n at node:net:313:12\n at
TCP.done (node:_tls_wrap:587:7) { info: 'Cassandra Driver Error',
isSocketError: true, coordinator: '3.248.244.5:9142'}
This exception may be caused by throttling in the keyspaces side, resulting the Driver Error that you are seeing sporadically.
I would suggest taking a look over this repo which should help you to put measures in place to either prevent the occurrence of this issue or at least reveal the true cause of the exception.
Some of the errors you see in the logs you will need to investigate Amazon CloudWatch metrics to see if you have throttling or system errors. I've built this AWS CloudFormation template to deploy a CloudWatch dashboard with all the appropriate metrics. This will provide better observability for your application.
A System Error indicates an event that must be resolved by AWS and often part of normal operations. Activities such as timeouts, server faults, or scaling activity could result in server errors. A User error indicates an event that can often be resolved by the user such as invalid query or exceeding a capacity quota. Amazon Keyspaces passes the System Error back as a Cassandra ServerError. In most cases this a transient error, in which case you can retry your request until it succeeds. Using the Cassandra driver’s default retry policy customers can also experience NoHostAvailableException or AllNodesFailedException or messages like yours "All host(s) tried for query failed". This is a client side exception that is thrown once all host in the load balancing policy’s query plan have attempted the request.
Take a look at this retry policy for NodeJs which should help resolve your "All hosts failed" exception or pass back the original exception.
The retry policies in the Cassandra drivers are pretty crude and will not be able to do more sophisticated things like circuit breaker patters. You may want to eventually use a "failfast" retry policy for the driver and handle the exceptions in your application code.

DNS Lookup Error when uploading to localhost (local S3 server)

In a docker container, the scality/s3server-image is running. I am connecting to it with NodeJS using the #aws-sdk/client-s3 API.
The S3Client setup looks like this:
const s3Client = new S3Client({
region: undefined, // See comment below
endpoint: 'http://127.0.0.1:8000',
credentials: {
accessKeyId: 'accessKey1',
secretAccessKey: 'verySecretKey1',
},
})
Region undefined: this answer to a similar question mentions to leave the region out, but, accessing the region with await s3Client.config.region() still displays eu-central-1, which was the value I passed to the constructor in a previous version. Although I changed it to undefined, it does still take the old configuration. Could that be connected to the issue?
It was possible to successfully create a bucket (test) and it could be listed by running a ListBucketsCommand (await s3Client.send(new ListBucketsCommand({}))).
However, as mentionned in the title, uploading content or streams to the Bucket with
bucketParams = {
Bucket: 'test',
Key: 'test.txt',
Body: 'Test Content',
}
await s3Client.send(new PutObjectCommand(bucketParams))
does not work, instead I am getting a DNS resolution error (which seems odd, since I manually typed the IP-address, not localhost.
Anyway, here the error message:
Error: getaddrinfo EAI_AGAIN test.127.0.0.1
at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:72:26) {
errno: -3001,
code: 'EAI_AGAIN',
syscall: 'getaddrinfo',
hostname: 'test.127.0.0.1',
'$metadata': { attempts: 1, totalRetryDelay: 0 }
}
Do you have any idea on
why the region is still configured and/or
why the DNS lookup happens / and then fails, but only when uploading, not when retrieving metadata about the Buckets / creating the Buckets?
For the second question, I found a workaround:
Instead of specifying the IP-Address directly, using endpoint: http://localhost:8000 (so using the Hostname instead of the IP-Adress) fixes the DNS lookup exception. However, there is no obvious reason on why this should happen.

AWS Appsync subscriptions - "Connection failed: Connection handshake error"

I am trying to make a simple subscription run on AWS amplify's appsync.
the subscription never fires and after about 30sec I get this error message when waiting for the sub in the appsync console:
Error: {
"errors": [
{
"message": "Connection failed: Connection handshake error"
}
]
}
at Object.error (https://d3owqdqy53mge.cloudfront.net/4e0034b0d516077971e58313cecbbabc76608841/main.js:135:859689)
at d (https://d3owqdqy53mge.cloudfront.net/4e0034b0d516077971e58313cecbbabc76608841/main.js:203:1070669)
at m (https://d3owqdqy53mge.cloudfront.net/4e0034b0d516077971e58313cecbbabc76608841/main.js:203:1071013)
at e.value (https://d3owqdqy53mge.cloudfront.net/4e0034b0d516077971e58313cecbbabc76608841/main.js:203:1072095)
at n.<anonymous> (https://d3owqdqy53mge.cloudfront.net/4e0034b0d516077971e58313cecbbabc76608841/main.js:135:679765)
at r (https://d3owqdqy53mge.cloudfront.net/4e0034b0d516077971e58313cecbbabc76608841/main.js:135:675841)
at Object.throw (https://d3owqdqy53mge.cloudfront.net/4e0034b0d516077971e58313cecbbabc76608841/main.js:135:675176)
at s (https://d3owqdqy53mge.cloudfront.net/4e0034b0d516077971e58313cecbbabc76608841/main.js:135:674969)
If I recreate the call from my browser I get this error:
WebSocket connection to 'wss://r23irwx4tndnjdfh7tlethffca.appsync-realtime-api.us-east-2.amazonaws.com/graphql?header=eyJBdXRob3JpemF0aW9uIjoiZXlKcmFXUWlPaUpTYWx3dlVEVkxOV2N5ZUd0blVXRXhWa3g2YmxVd1YwTmxZbnBsVFdsek4zZHpjelZ0Ym5SYVZrMVpUVDBpTENKaGJHY2lPaUpTVXpJMU5pSjkuZXlKemRXSWlPaUl3WldVNFlUZzVNUzB6TnpFeUxUUXhNekV0T1RsalpTMDFNelZrTTJVeE5UQmpaR0VpTENKbGRtVnVkRjlwWkNJNklqTXpZV1E0T1RneUxXUTBaalV0TkRCa09TMWlaRFl3TFdFNFpEWXlOelprTVRFellTSXNJblJ2YTJWdVgzVnpaU0k2SW1GalkyVnpjeUlzSW5OamIzQmxJam9pWVhkekxtTnZaMjVwZEc4dWMybG5ibWx1TG5WelpYSXVZV1...VSDNCYnJURTM5YmVWNEEzdW1JdGdPN0RjOVFCVkI2U09uX1ZJdVFvUElIOUZGNk10QzdtWTJLby0wQ19NTF9tSVAxdEFTVkNzSW5Zbjd4MWZzalFoUFpaS1J6MTFKbHJPdE5rOWNzOXVrd29yMU1iRGlBNklIOEJiaXIzSjNRNDlSckhXODZLM3RhQmNGSlphQVpnTEhKS05QajlBWWZhVHRNTnZnVmV4UUJhZzQ2cW5VZ3l1amF0SUMwamZ1Mk9LUUh1d2NNaGt6WjJjYlB6aWNwcG5kVk5aVVdnY1hzUlBadndFTzlENnZmZ3UyZTM0eHZXRW9mZld1RGh4LVc5Ui1HSEktbG1YTU4ydk9xd1RURTRxejdNM2Q3WGJvN3VyWUpsSHlGUUIxQSIsImhvc3QiOiJyMjNpcnd4NHRuZG5qZGZoN3RsZXRoZmZjYS5hcHBzeW5jLWFwaS51cy1lYXN0LTIuYW1hem9uYXdzLmNvbSJ9&payload=e30=' failed: Error during WebSocket handshake: net::ERR_SSL_PROTOCOL_ERROR
The only solution I found to this was to change my router...
Have no idea why it makes a difference, tried all the router setting I could think of
I used my home LTE WiFi router and kept getting this error, eventually changed to a local sim card-based router from my cell provider and it connected every time.
I have used this on many different models and works every time. The router which was failing was a Huawei B525 router, any other router doesn't give the issues...

AWS Error retrieving credentials from the instance profile metadata server

Can someone please give me an insight on this error? Credentials are set via IAM policy. This box is included in auto scaling group, and this is the only one that got the following error.
Error retrieving credentials from the instance profile metadata server. When you are not running inside of Amazon EC2, you must provide your AWS access key ID and secret access key in the \"key\" and \"secret\" options when creating a client or provide an instantiated Aws\Common\Credentials\CredentialsInterface object"
Logs:
CRITICAL
Phalconry\Mvc\Exceptions\ServerException
Extra
"remoteip": "XX.XX.XX.XX, XX.XX.XX.XX",
"userid": "1357416",
"session": "fcke8khsqe4lfo2lj6kdmrd4l7",
"url": "GET:\/manage-competition\/athlete",
"request_identifier": "xxxxxx5c80516bc11532.74367732",
"server": "companydomain.com",
"client_agent": "Mozilla\/5.0 (Linux; Android 9; SM-G965U) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/72.0.3626.121 Mobile Safari\/537.36",
"instance_ip_address": "xx.xx.xx.xx",
"process_id": 29528,
"file": "\/var\/www\/code_deploy\/cfweb\/releases\/20190306195438\/core\/classes\/phalconry\/mvc\/exceptions\/MvcException.php",
"line": 51,
"class": "Phalconry\\Mvc\\Exceptions\\MvcException",
"function": "dispatch"
}```
Context
```{
"Status Code": 500,
"Reason": "Internal Server Error",
"Details": "Array\n(\n [code] => server_error\n [description] => Uncaught Server Error\n [details] => Request could not be processed. Please contact Support.\n)\n",
"Log": "Error retrieving credentials from the instance profile metadata server. When you are not running inside of Amazon EC2, you must provide your AWS access key ID and secret access key in the \"key\" and \"secret\" options when creating a client or provide an instantiated Aws\\Common\\Credentials\\CredentialsInterface object. (Unable to parse response body into JSON: 4)",
"Trace": "#0 [internal function]: Phalconry\\Mvc\\MvcApplication::Phalconry\\Mvc\\{closure}(Object(Phalcon\\Events\\Event), Object(Phalcon\\Mvc\\Dispatcher), Object(Aws\\Common\\Exception\\InstanceProfileCredentialsException))\n#1 [internal function]: Phalcon\\Events\\Manager->fireQueue(Array, Object(Phalcon\\Events\\Event))\n#2 [internal function]: Phalcon\\Events\\Manager->fire('dispatch:before...', Object(Phalcon\\Mvc\\Dispatcher), Object(Aws\\Common\\Exception\\InstanceProfileCredentialsException))\n#3 [internal function]: Phalcon\\Mvc\\Dispatcher->_handleException(Object(Aws\\Common\\Exception\\InstanceProfileCredentialsException))\n#4 [internal function]: Phalcon\\Dispatcher->dispatch()\n#5 \/var\/www\/code_deploy\/cfweb\/releases\/20190306195438\/sites\/games\/lib\/phalcon.php(101): Phalcon\\Mvc\\Application->handle()\n#6 \/var\/www\/code_deploy\/cfweb\/releases\/20190306195438\/sites\/games\/index.php(4): require_once('\/var\/www\/code_d...')\n#7 {main}"
}```
The meta-data of instance-profile credentials is under
http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance
If that is failing it might be an issue with the hypervisor/droplet that your server has been spun up on. This endpoint will give you the last time credentials were refreshed.
'http://169.254.169.254/latest/meta-data/identity-credentials/ec2/info'
If other servers with identical AMI's and availability zones aren't having an issue, I would log a support ticket, terminate and move on.
These credentials come from the instance metadata URL (http://169.254.169.254).
The problem that you are likely having (esp since you are running in an ASG) is that when you create an AMI and then launch it in another AZ, the route to the metadata URL is not updated. What you need to do is force cloud-init to run on next boot.
The simple way to do this is to clear out the cloud-init metadata directory:
sudo rm -f /var/lib/cloud/instances/*/sem/config_scripts_user
After you run that command, then shutdown the machine and create an AMI from it. If you use that AMI for your ASG, cloud-init will do a full run on first boot which will update the routes to the instance metadata URL and your IAM creds should work.

Certificate configuration parameter problems connecting to AWS IOT

Trying to get my node.js IOT example working but not sure what configuration I need to set to pass to my thingShadow constructor awsIot.thingShadow(config)
This is the sample config I get from the AWS dashboard
{
"host": "foo.iot.us-east-1.amazonaws.com",
"port": 8883,
"clientId": "bar",
"thingName": "bar",
"caCert": "root-CA.crt",
"clientCert": "bar-certificate.pem.crt",
"privateKey": "bar-private.pem.key"
}
However this is the constructor I set based on the sdk readme
{
keyPath: 'bar-private.pem.key',
certPath: 'bar-certificate.pem.crt',
caCert: "root-CA.crt",
clientId: 'bar'
}
I get the error
events.js:141
throw er; // Unhandled 'error' event
^
Error: unable to get local issuer certificate
at Error (native)
at TLSSocket.<anonymous> (_tls_wrap.js:1017:38)
at emitNone (events.js:67:13)
at TLSSocket.emit (events.js:166:7)
at TLSSocket._init.ssl.onclienthello.ssl.oncertcb.TLSSocket._finishInit (_tls_wrap.js:582:8)
at TLSWrap.ssl.onclienthello.ssl.oncertcb.ssl.onnewsession.ssl.onhandshakedone (_tls_wrap.js:424:38)
What is caCert based on - is that a cert that I have in my local path? If so where do I get it from, the dashboard as a download somewhere? Am I sending the right certificate files for privateKey?
So the issue was the root-CA.crt file. I found mine from the node_modules directory in the aws library and that was not valid.
I needed to get the crt file from
https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem
As noted in this doc http://docs.aws.amazon.com/iot/latest/developerguide/iot-device-sdk-node.html