Using EC2 instance profile with IAM authentication in RDS - amazon-web-services

I set up IAM authentication on an RDS instance, and I'm able to use IAM to get database passwords that work for 15-minutes. This is fine to access the database for backups, but this database backs an web application so currently after 15 minutes the password used by the app to connect to the DB becomes invalid and the app crashes as it can no longer access the DB.
However, in the RDS IAM docs there's this line:
For applications running on Amazon EC2, you can use EC2 instance profile credentials to access the database, so you don't need to use database passwords on your EC2 instance.
This implies that on EC2 there's no need to use the IAM temporary DB password, which would mean that my app should be able to connect to the DB as long as it's running on EC2 and I set up the role permissions (which I think I did correctly). However, I can't get my app running on EC2 to be able to connect to the RDS DB except by using the 15-minute temporary password. If I try connecting with a normal MySQL connection with no password I get permission denied. Is there something special that needs to be done to connect to RDS using the EC2 instance profile, or is it not possible without using 15-minute temporary passwords?

According to the documentation you linked (http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html), you need to perform the following steps (See under "Authenticating to a DB Instance or DB Cluster Using IAM Database Authentication"):
Use the AWS SDK for Java or AWS CLI to get an authentication token you can use to identify the IAM user or role. To learn how to get an authentication token, see Getting an Authentication Token.
Connect to the database using an SSL connection, specifying the IAM user or role as the database user account and the authentication token as the password. For more information, see Connecting to a DB Instance or DB Cluster Using IAM Database Authentication.
That means for every connection you intend to open, you need to get a valid Token using the AWS SDK. This is where using the correct instance profile with the RDS permission is needed. See also the code examples further down the AWS documentation page.
I think however this requires quite a bit of effort on your side, to always get a valid token before opening a connection. It makes using an off-the-shelf connection pool difficult. Probably once open, the connection will remain open even after the token expires, but you still need to handle the case where more connections need to be opened at a later time.
I would stick with a normal user/password access for the application, using IAM for this case seems to be too much effort.

For applications running on Amazon EC2, you can use EC2 instance profile credentials to access the database, so you don't need to use database passwords on your EC2 instance.
You're misinterpreting what this means. It means you don't have to use static passwords or store them on the instance.
The idea is that you generate a new authentication token each time you establish a connection to the database. The token is generated on your instance, using the instance role credentials. It can only be used to authenticate for 15 minutes, but once connected, you don't lose your database connection after 15 minutes. You remain connected.
If your application doesn't reuse database connections, then you likely have a design flaw there.

Related

Use AWS API and RDS to securely access data

I want an API which can query a MySQL database and return the desired data. Currently for development, I am using a AWS lambda. I am passing an access token in the request, so I am able to verify that a valid user is making the request. However, when I fetch data from the database, I am logging on to the database using a username and password and the database is open for public access. I think this application has security vulnerabilities because if anyone knows the database endpoint, they can brute force the username and password.
Is there a more secure approach in accomplishing this. The general workflow is:
API Gateway -> Lambda -> RDS (MySQL) -> Client
And the vulnerability I would like to avoid is the open access of the RDS MySQL DB.
You should configure the Lambda function to run inside the VPC with the RDS instance, and then disable public access to the RDS instance.

Django + AWS Secret Manager Password Rotation

I have a Django app that fetches DB secret from AWS Secret Manager. It contains all the DB parameters like username, password, host, port, etc. When I start the Django application on EC2, it successfully retrieves the secret from the Secret Manager and establishes a DB connection.
Now the problem is that I have a password rotation policy set for 30 days. To test the flow, at present, I have set it to 1 day. Every time the password rotates, my Django app loses DB connectivity. So, I have to manually restart the application to allow the app to fetch the new DB credentials from the Secret Manager.
Is there a way that secret fetching can happen automatically and without a manual restart of the server.? Once way possibly is to trigger an AWS CodeDeploy or similar service that will restart the server automatically. However, there will be some downtime if I take this approach.
Any other approach that can seamlessly work without any downtime.
If the old DB credentials are invalidated immediately during the rotation, then it will probably be pretty difficult to do this without some downtime. One option would be to have your app catch the credential error and (try to) fetch the new secret at that point from Secrets Manager, creating a new DB connection. Another other option is to have two valid user/password pairs, leaving the old valid while creating the new. I'm not sure if automatic rotation gives you this option. Then you can restart your app as you like. To do even that without a brief outage probably requires a load balancer and multiple instances of your application running, so that you can up one with new creds before you terminate the old one.
This was previously answered in how to use new secret created by key rotation.
If you are using multi user rotation (the "Use a secret that I have previously stored in AWS Secrets Manager" option in the console) you can use the Secrets Manager python caching library to cache and periodically refresh the secret.
If you use the single user rotation option you will need to write a connection wrapper (similar to the JDBC wrapper) that refresh the credentials when you get an error establishing a new connection.

Best way to authenticate application to use AWS services?

lets say I have a on-premise application that needs to access various AWS services such as S3, Cloudwatch etc. What is the correct way to handle this authentication? I have read recommendations to create a new iam role and then distribute the AWS keys on the server that the application runs. But wouldn't this be very bad practice in case the keys gets stolen or exposed in some way? It would also be more work to rotate credentials for example. Is it possible to assign roles in some other ways or this is the correct way to do it? Isn't it better to assign roles or that isn't possible when not running the app in AWS?
Creat an IAM user with “Programmatic Access” only, which will provide you with a key and secret pair.
As a general rule, your application can use one set of credentials to get another, more privileged set of credentials. The app must be able to authenticate somehow so it needs some basic form of service account credentials to start with.
One way you can do this is to create an IAM user with minimal privileges. This IAM user is able to assume a specific IAM service role, but nothing else. That service role actually confers permissions to interact with S3, CloudWatch etc. Your application is configured with, or somehow securely retrieves, the credentials associated with the IAM user. Your application then uses these to call STS and assume the IAM service role, getting back short-lived STS credentials (access key, secret key, and session token). You should leverage the additional 'external ID' with the IAM role, as one more security factor.
Your application is also responsible for getting a new set of credentials before the existing set expires. You can do that in a number of ways, for example by using new STS credentials for every single request you make (so they never expire) or simply paying attention to the credentials expiration time and refreshing prior.
Also, read Temporary Credentials for Users in Untrusted Environments.
If your application is running on an Amazon EC2 instance and it is the only application on that instance, then:
Create an IAM Role
Assign the appropriate permissions to the Role
Assign the IAM Role to the EC2 instance
Any software running on the instance will automatically have access to credentials to access AWS. These credentials automatically rotate every 6 hours.
If you are not running on an EC2 instance:
Create an IAM User
Assign the appropriate permissions to the User
Generate credentials for the User (Access Key, Secret Key) and store them in a credentials file on the computer being used by the application
Any software running on the instance will automatically have access to these credentials to access AWS.

Connecting to AWS RDS from java without exposing password

I was successfully able to connect to RDS like any other database connection.
I use spring jpa data ( repository ) to do CRUD operation on postgres db.
currently I provide the db url and the credential in the properties file
spring:
datasource:
url: jdbc:postgresql://<rds-endpoint>:5432/<dbschema>
username: <dbuser>
password: <dbpassword>
However this is not an option while connecting to production or preproduction.
what is the best practise here.
Does AWS provide any inbuild mechanism to read these details from an endpoint like in the case of accessing S3 ?
My intention is not expose the password.
Several options are available to you:
Use the recently announced IAM access to Postgres RDS
Use Systems Manager Parameter Store to store the password
Use Secrets Manager to store the password and automatically rotate credentials
For 2 and 3, look up the password on application start in Spring using a PropertyPlaceholderConfiguration and the AWSSimpleSystemsManagement client (GetParameter request). SystemsManager can proxy requests to SecretsManager to keep a single interface in your code to access parameters.
IAM credentials is more secure in that:
If using EC2 instance profiles, access to the database uses short lived temporary credentials.
If not on EC2 you can generate short lived authentication tokens.
The password is not stored in your configuration.
If you have a separate database team they can manage access independent of the application user.
Removing access can be done via IAM
another generic option I found was to use AWS Secret Manager
(doc link)
RDS specific solution is to connect to DB Instance Using the AWS SDK using IAMDBAuth

password encryption for use by aws automated process

I have an application that creates automatically some AWS instances and runs a script on them.
Each script tries to connect to a remote DB for which I need to provide the Public DNS Hostname, DB password, DB Username, etc...
What is the most secure way to do that without having to store the plain password?
And without risking somebody else running the same script being able to get those credentials?
Thanks a lot
You could use the AWS SSM service's Parameter Store:
Parameter Store centralizes the management of configuration data -
such as passwords, license keys, or database connection strings - that
you commonly reference in scripts, commands, or other automation and
configuration workflows. With granular security controls for managing
user access and strong encryption for sensitive data such as
passwords, Parameter Store improves the overall security posture of
your managed instances. Encrypting parameters with Parameter Store is
not supported in all regions.
You would create an IAM role that has access to the Parameter Store values, and assigned that role to the EC2 instances you are dynamically creating. Then the script would be able to use the AWS SDK/CLI to retrieve those values from the parameter store.
Alternatively, if the database is an RDS database that supports IAM authentication (only MySQL and Aurora at this time) then you could create an IAM role that has direct access to the database and assign that role to the EC2 instances.