ec2 roles vs ec2 roles with temporary keys for s3 access - ruby-on-rails

So I have a standard Rails app running on ec2 that needs access to s3. I am currently doing it with long-term access keys, but rotating keys is a pain, and I would like to move away from this. It seems I have two alternative options:
One, tagging the ec2 instance with a role with proper permissions to access the s3 bucket. This seems easy to setup, yet not having any access keys seems like a bit of a security threat. If someone is able to access a server, it would be very difficult to stop access to s3. Example
Two, I can 'Assume the role' using the ruby SDK and STS classes to get temporary access keys from the role, and use them in the rails application. I am pretty confused how to set this up, but could probably figure it out. It seems like a very secure method, however, as even if someone gets access to your server, the temporary access keys make it considerably harder to access your s3 data over the long term. General methodology of this setup.
I guess my main question is which should I go with? Which is the industry standard nowadays? Does anyone have experience setting up STS?
Sincere thanks for the help and any further understanding on this issue!

All of the methods in your question require AWS Access Keys. These keys may not be obvious but they are there. There is not much that you can do to stop someone once they have access inside the EC2 instance other than terminating the instance. (There are other options, but that is for forensics)
You are currently storing long term keys on your instance. This is strongly NOT recommended. The recommended "best practices" method is to use IAM Roles and assign a role with only required permissions. The AWS SDKs will get the credentials from the instance's metadata.
You are giving some thought to using STS. However, you need credentials to call STS to obtain temporary credentials. STS is an excellent service, but is designed to for handing out short term temporary credentials to others - such as the case where your web server is creating credentials via STS to hand to your users for limited case use such as accessing files on S3 or sending an email, etc. The fault in your thinking about STS is that once the bad guy has access to your server, he will just steal the keys that you call STS with, thereby defeating the need to call STS.
In summary, follow best practices for securing your server such as NACLs, security groups, least privilege, minimum installed software, etc. Then use IAM Roles and assign the minimum privileges to your EC2 instance. Don't forget the value of always backing up your data to a location that your access keys CANNOT access.

Related

Prevent attacker from decompiling iOS app and getting database access

According to this post, it's possible to decompile an iOS application.
How can I prevent an attacker from gaining access to my AWS DynamoDB database? Just having the access keys out in the open like shown on the Amazon developer guide doesn't seem like it would be very safe.
I would think that I could use keychain to store the keys, but I feel like there would be an easy way to get past this for a motivated attacker, given they have the app's assembly source code.
Currently, I connect using Amazon Cognito. All I have to use to connect are the identity ID and the role name. I don't see anything stopping an attacker from simply getting those values and connecting to the database.
For example, what stops an attacker from decompiling the Facebook iOS app code and deleting all of the users?
How can I prevent attackers from decompiling my iOS application and getting access to the database access keys, or at least prevent them from doing any major damage, such as deleting users?
Based on my admittedly limited experience, I'd say that a really motivated attacker will always be able to retrieve the credentials you use to access your database regardless of what you do to your executable. I would, however, question why you application needs to have direct access to your database in the first place.
The usual way to safeguard your serverside data is to use a web service to access it. App contacts web service with request, service contacts db, gets data, sends it back. Since the web service and the db are both hosted on your server and only the web service needs direct access to your db, there is no need to store db access info in your app. Problem solved.
It's impossible. In order for your program to do something, it must contain the instructions that allow the computer to follow to do that thing, which means anyone else can also follow those instructions to learn how to do the exact same thing.
You can use SQLCipher and use your auth's userToken and/or userId as cipher keys.

Storing remote database credentials safely in iPhone app

I'm developing a simple iPhone app where users register, and sign in with their email/password. These values are stored in a remote database.
I'm using Cloudant to store this information (CouchDB is great), and have granted read-only privileges to a new user (created API key/pass). In order to communicate with Cloudant, you obviously need a URL to access it (eg https://user:pass#db.cloudant.com), which is stored in the app as a string.
Now, while I know this is pretty unsafe, I can't think of any other alternatives in order to keep the db URL safe (specifically the username/password for it). I've seen people talk about using another server to proxy through to obtain the credentials, but it seems a little awkward.
Any help or thoughts would be really appreciated!
Are you trying to make a connection from your iPhone app directly to the database? You shouldn't give your app read access to the whole remote user table / database. Sooner or later someone would find out and would have read access to your data. No matter how you try to obfuscate it, the user/password combination would need to be stored somehow in your app.
What you should do is build a web service that connects to your DB and verifies your users. The database password stays on a server. This proxy-approach is not awkward, it is the only way to keep your database logins away from your users.
One option is to create your own service in the cloud that abstracts away your storage. That also has the benefit of allowing you to change your storage without updating all your devices.
In that model, the service stores the credentials to access the storage and you implement user security in your application layer. I also wouldn't think of it as a proxy layer - that implies that it's a thin pass through. If you develop a service, you should define a web interface (rest, soap) that's agnostic to the storage. In that case, it's a service, not a proxy.
EDIT:
Typically the web service authenticates the user (don't write your own). Basic Auth with SSL is typical. Then, in that services context API, you get access to the username. From there, you do you what you need. Your storage is accessed with the one storage account that has full access to all content.
Another auth option is OAuth which allows them to authenticate with someone like google - you never get the password - just a token from google letting you know they authenticated and they are who they claim to be. For example, that's how stack overflow works.

How can I secure my OAUTH secret in Phusion Passenger Sinatra app?

I have an app that uses a single-user OAUTH token. I can store the four values (consumer key/secret, token/secret) directly inside the app but that's not recommended and I don't want the secrets to be checked into source code. The app doesn't use a database. I know that however I store them, someone with access to the server could figure them out but I'd like to at least get it out of the source code. I've thought of passing them as Passenger environment variables or storing them in a separate file on the server but are there better ways? Is there any point to encrypting them since anyone that could see them would also have the access needed to decrypt?
Not having the keys stored in the source code actually is actually bad a practice in the accoding to the most agile setup (continuous deployment).
But, by what you say, you want to have two groups: those who can make the code, and those who can deploy it. Those who can deploy it have access to the keys, and, in the most secure setting, must NOT use the code of the application. You can make the oauth still work by having those who code autenticate to a system that proxies all the authorization part, and authenticates de application. Such keys (app -> auth middle man) can be in repository, as they are internal.
Any other setup: authentication library created by those who can deploy, encrypted keys, anything else can be broken by those who make the code. If you don't trust them enough to have access to the keys, you probably don't trust them enough not to try to jailbreak the keys.
The resulting deployment scheme is much more complicated, and, therefore much more prone to erros. But it is, otherwise, more secure. You still have to trust someone, like those who install the operating system, the proxy's system middleware, those who maintain the proxy's machine(s), those who can long on it, and so on. If the groupo of people with access to the keys is small enough, and you trust them, then you've gained security. Otherwise, you lost security, ability to respond to change, and wasted a lot of people's time.
Unfortunately, all authorization schemes require you to trust someone. No way around it. This is valid for any application/framework/authorization scheme, not only sinatra, rails, oauth, java, rsa signatures, elliptic curves, and so on.

Securing S3 via your own application

Imagine the following use case:
You have a basecamp style application hosting files with S3. Accounts all have their own files, but stored on S3.
How, therefore, would a developer go about securing files so users of account 1, couldn't somehow get to files of account 2?
We're talking Rails if that's a help.
S3 supports signed time expiring URLs that mean you can furnish a user with a URL that effectively lets only people with that link view the file, and only within a certain time period from issue.
http://www.miracletutorials.com/s3-amazon-expiring-urls/
If you want to restrict control of those remote resources you could proxy the files through your app. For something like S3 this may defeat the purpose of what you are trying to do, but it would still allow you to keep the data with amazon and restrict access.
You should be careful with an approach like this as it could cause your ruby thread to block while it is proxying the file, which could become a real problem with the application.
Serve the files using an EC2 Instance
If you set your S3 bucket to private, then start up an EC2 instance, you could serve your files on S3 via EC2, using the EC2 instance to verify permissions based on your application's rules. Because there is no charge for EC2 to transfer to/from S3 (within the same region), you don't have to double up your bandwidth consumption costs at Amazon.
I haven't tackled this exact issue. But that doesn't stop me from having an opinion :)
Check out cancan:
http://github.com/ryanb/cancan
http://railscasts.com/episodes/192-authorization-with-cancan
It allows custom authorization schemes, without too much hassle.

How do I securely store passwords in a configuration file in a Ruby/Rails web server environment?

I need to store payment gateway processor username/password credentials on a production web server, but would prefer not to do so in clear-text. What is the best way to store these credentials? Are their best practices for encrypting and decrypting this information?
It's a classic chicken-egg problem. Encryption does not help you at all if you can't protect the keys. And you obviously can't.
What I would suggest is to try to make the other services / users use hashes towards your authentication code, and save those hashes instead. That way at worst you will lose the hashes, but it might prove hard (depending on the rest of the setup) to actually use them maliciously. You might also want to salt the hashes properly.
An other possibility would be using an external authentication store if you can't enforce using hashes. It does not really solve the problem, but you can control the attack vectors and make it safer by allowing only very specific contact with the actual source with the important data.
Store outside of any directory that is web accessible.
Make sure only the app processes have read access.
Harden server.

Resources