Connecting to a web service on EC2 AWS - ruby-on-rails

We have a web service api running on an EC2 instance on aws. We want to connect to it from external applications managed by us, eg iphone app, other frontend applications on different servers. I can't get my head around how to authenticate these. Do i add the ip to the EC2 security group, or IAM? and then when making JSON requests do i need to send the AWS access keys? are these sent in the headers? So say a sample call would be:
API.post("http://awsserver.com/app_api/v1/request", query: {
customer_name: "John Doe", customer_email: "test#test.com" }, headers:
{"AWS_ACCESS_KEY_ID"=>"exampletoken", "AWS_SECRET_KEY" =>
"secretexample"})
I have tried searching but surprisingly not a lot found. Any help would be great, thanks.

First of, do not send your access key and secret with any POST ever in plain text. The access key and secret key are used to generate unique tokens that expire to access AWS resources at your account level, not your application (API).
There are lots of assumptions I am making, however you will need to have the authentication done at your application level if you intend to have this API accessible from mobile devices as they will have changing IP's.
Look into OAuth where devices request access from some authentication mechanism in your application which will return a token you can send along in subsequent POST requests in the header.
For servers accessing your API you could certainly add those EC2 instance IP's to a security group opening access to your API server and deny all other IP's access, however keep in mind if the EC2 instances do not have Elastic IP's then on any restart they will have a different IP and need to be added to your security group.

Related

Newly deployed cloud run app inaccessible, despite having requisite permissions (403)

Following this quickstart guide (Python version), I was able to quickly create and deploy a Python Flask app to a project owned by my organization. However, toward the end the guide instructs "Visit your deployed container by opening the service URL in a web browser", and but this is the step I can't get to work.
Curiously, in the logs
(https://console.cloud.google.com/logs/) the 'textPayload' data element for the request is "The request was not authenticated. Either...", which seems unusual, as I'd expect an unauthenticated request to return 401, not 403. In any case, it does not list my org email address in the request, suggesting my identity for some reason isn't being supplied. Any way to fix this so I can access the URL using a user with appropriate permissions?
Note: I can access the URL by manually running "curl -H 'Authorization: Bearer <my token>'"
Cloud Run URLs aren't directly accessible if the service only allows authenticated invocations because passing the URL on your browser will not generate the credential for you. You will have to pass auth credentials on your request and the easiest way to invoke the service is to use a tool like curl which is exactly what you noted.
You have two options to authenticate your end users which are the following:
Integrate Google Sign-In.
Implement Identity Platform or Firebase Authentication.
In either of the above choices, you need a public web or mobile app that handles the sign-in flow and then makes authenticated API calls to a Cloud Run (fully managed) service.
For more information on authenticating end users, check out the official documentation.
To complement what Mr. Donnald Cucharo said, you can also use Identity Aware Proxy (IAP) to expose your application in a secure way.

How to access RestFul Apis through Appium-TestNG framework in AWS-Device Farm?

We have created our automation framework using Appium-TestNG in which we are accessing our backend servers through RestFul Apis externally. The backend server is also based on AWS and has whitelisted the device farm IPs. When we are executing the tests locally its working fine but when we execute it on AWS Device Farm, it is giving ‘Socket Exception’ when trying to access the backend servers via our apis.
Can anyone give us a solution of how to access external Rest APIS via Device Farm?
The IP range that's in the FAQ of Device Farm point to the devices but not the device host. The device host could have a wide range of IPs but there are two ways(that I've found so far) to get around this issue in theory:
Use the private offering from Device Farm.
If you have access to the private offering for Device Farm, you're able to use the VPC integration with both the devices and the device host. So there shouldn't be any white-listing needed using this method.
Use API Gateway's private VPC integration and call this API from the tests
When using the public offering(metered and unmetered options) we should be able to take advantage of API Gateway's VPC integration. Using an private NLB in the same VPC as the REST API we can create a VPC link. The ending architecture I believe should look like this:
Then we can secure the API using an API key or custom authorizers. So then we can call this API which links to the private REST API from the device host.
Note: This might not be the best workaround depending on the use-case as then the device host will have access to the API key.
Additionally(I know you didn't ask this but wanted to link to it anyway), the easiest way I've found so far to develop REST API calls is to use Postman to make a successful call to the REST API. Then use the code snippet feature to make the same calls in the support languages from postman.
Hope that helps
-James

Google Map API Key in Directions (iOS app)

i want to use google map api for route between two location. in my IOS application. i try create public key for project and enable uses API in developer console. but i got this error: this ip site or mobile application is not authorized to use this api key IOS. after this error i try create API key for Key restriction for (IP addresses (web servers, cron jobs, etc.)) and set my ip address and then routing is work fine. but when i try this from other device again and again i get this error.
i should use this URL for routing :
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving&key=APIKEY"
how can solve this problem for working my code in all devices.
The API key that you use with Google Maps web service (Directions API) supports an IP restriction as mentioned in the following document:
https://developers.google.com/maps/faq#using-google-maps-apis
The issue is that you cannot know the IP addresses of all devices where your application is installed.
You have the following options:
Use unrestricted API key. Note that API key requires HTTPS connection, so the API key won't be intercepted from the request itself, because the request is encrypted. So, in this case you should procure that the API key is not put directly in your source code. If you can read it from config or the environment, it might be feasible.
Create an intermediate server. Your iOS application should send requests to the intermediate server, intermediate server should send requests to Google and pass responses back to your app. In this case you can restrict an API key by IP address of your intermediate server.
I hope this helps!

How to uniquely identify remote request host

I'm building an API with Rails that is going to receive HTTP requests from other sites.
Every time a new request is issued, I need to know in my app if this site has already sent this request. So, I'm wondering if there is a way to uniquely identify the site sending the request. I'm thinking of using request.remote_ip however if the site is on a shared hosting, it would share the same IP address with other sites.
Is there any other way to identify the remote origin?
If the request is issued from an API client then the IP is all you have that you can (somewhat) rely on.
And as you mentioned this is not really unique (proxy, shared hosting, ...).

can I securely access Gmail for a Rails app on shared hosting non-SSL without putting credentials at risk?

That is, want a Rails application that lets me see a customized view of the user's Gmail calendar. But it'll be on shared hosting so don't want to store credentials, or have them in the clear.
Question: Can I securely access Gmail for a Rails app on shared hosting non-SSL without putting credentials at risk? How would I do this? (e.g. does OAuth or OpenID solve this)
Requirements would be:
Rails application will call Google Calendar via API
No credentials stored on shared hosting site (e.g. in database or whatever) - MANDATORY
Rails site is non-SSL - MANDATORY (for the purpose of this question)
Ability to stay logged in whilst browser still open - DESIREABLE (assume using session id...assuming this is secure)
For example exiting approach I've used which wouldn't satisfy my requirements on my non-SSL rails site (on a shared host) would be:
# Get Google Calendar
service = GCal4Ruby::Service.new
service.authenticate("<google account name>", "<password>") # <== requires password
cal = GCal4Ruby::Calendar.find(service, "myCalendar")[0]
# Get Google Events
search_str = "<search str>"
#events = GCal4Ruby::Event.find(cal, search_str, params)
You will get mixed content if you try to include in an http page an https Google calendar view loaded as an iframe.
If you're just doing API calls, as long as the API calls are from your server to an encrypted endpoint, https://calendar.google.com or something similar, then there are no problems.
If you're doing API calls from a non-http page in the browser, then a determined attacker will be able to eavesdrop on any data you serve, including credentials sent to the browser for forwarding to the calendar service.
If you're sending credentials to the browser you should also worry about exfiltration via XSS.

Resources