AWS Database Blog
Managing Amazon RDS databases in multi-account environments with the AWS CLI
AWS provides AWS organizations and AWS Landing Zone solutions to manage and automate new account creation. This helps you to create multiple AWS accounts separated based on applications, development, production, or organizations within a company. This approach helps with resource isolation and separating development from production, but makes it complex for some of the teams that support the whole organization. For example, a database operations team helps manage Amazon Relational Database Service (Amazon RDS) databases in your AWS accounts. Supporting AWS resources in multiple AWS accounts can increase your management activities because each AWS account can have its own AWS Identity and Access Management (IAM) users, groups, and roles. Sometimes teams like database support write common scripts to query information about RDS databases or check the status or configuration of database resources in all AWS accounts from a centralized location. Multiple users across AWS accounts also can pose a challenge because more users can result in maintaining more AWS access keys. Furthermore, it’s important that you protect users.
Solution Overview
One way of reducing the number of credentials to manage is to use temporary AWS security credentials. You can do this by using AWS Security Token Service (AWS STS) and IAM roles. To use an IAM role, you have to make an API call to STS:AssumeRole
, which returns a temporary access key ID, secret key, and security token that can then be used to sign future API calls. Formerly, secure cross-account, role-based access from the AWS Command Line Interface (CLI) required an explicit call to STS:AssumeRole
, and used your long-term credentials. The resulting temporary credentials were captured and stored in your profile, and that profile was used for subsequent AWS API calls. This process had to be repeated when the temporary credentials expired (after 1 hour, by default).
Currently, even though the actual chain of API calls is still necessary, the AWS API automates this workflow for you. With a simple setup, you can achieve secure cross-account access with the AWS CLI by simply adding different profiles to the AWS CLI config file or even setting up additional environment variables to your session. Database management or bastion host uses credential_source
as Ec2InstanceMetadata
to avoid each user storing AWS credentials.
In this post, we show how to use an IAM role with the AWS CLI to access all your AWS accounts from a DB management or bastion host without using AWS account credentials. We also provide tips to automate the RDS database management with AWS CLI configurations and settings for all database administrators.
Prerequisites
Before you get started, make sure you have the following prerequisites:
- You need at least two AWS accounts to simulate the scenario:
- Assume 11111111111 is one of the application accounts where we have Amazon RDS running.
- Assume 99999999999 is the management account where we have a bastion or DB management host (EC2).
- Optionally, you can configure Active Directory authentication for users to access the DB management host. SSH login to either host also works.
- Install the AWS CLI utility on the DB management host (you can use AWS CLI version 2 and refer to specific instructions for your operating system).
- For this post, we use the AWS CLI to configure IAM roles, polices, and profiles. You need appropriate IAM permissions in your AWS accounts to create resources such as IAM polices and roles to complete this setup. You can achieve the same steps via the AWS Management Console, but it’s not covered in this post.
Creating an IAM role and configuring DB management or bastion host (EC2)
To start configuring your IAM credentials, complete the following steps in the management AWS account 99999999999, where a specific Amazon Elastic Compute Cloud (Amazon EC2) instance is running as a DB management or Bastion host.
- Create the JSON file that defines the trust relationship:
The contents of the DB-Management-Host-Assume-Role-Trust-Policy.json
file are:
- Create the IAM role using the trust policy created in step 1 and take a note of the Amazon Resource Name (ARN) available in the output for the role being created:
The aws iam create-role
command outputs several pieces of information, including the Amazon Resource Name (ARN) of the IAM policy:
- Create an IAM policy that grants the permissions to users who are in the DB management host running from the management account to run the sts:AssumeRole action using the AWS CLI for each application account:
The contents of the DB-Management-Host-ApplicationAccountAccess-Policy.json
file should be similar to the following (the ARN is the ARN of the role you create on each application in the next section):
You can use * instead of a specific AWS account name or number. This way, you avoid updating this policy in the future if you add more AWS accounts for different applications to your organization however it depends on your security/infosec guidelines.
- Create the IAM policy using the JSON document created earlier and take a note of the Amazon Resource Name (ARN) available in the output for the policy being created:
The command outputs several pieces of information, including the ARN of the IAM policy:
- Attach the IAM policy created from the previous step to the role
DB-Management-Host-CrossAccountAccess-Role
created in step 2:
- Create an instance profile named
DB-Management-Host-Profile
:
The command outputs several pieces of information, including the ARN of the IAM policy:
- Add the
DB-Management-Host-CrossAccountAccess-Role
role created from step 2 to theDB-Management-Host-Profile
instance profile created in the previous step:
- Use the following
associate-iam-instance-profile
command to associate the instance profile created from the step 6 to the EC2 instance (for this post, DB management or Bastion host) by specifying the appropriateinstance-id
andiam-instance-profile
. You can use the ARN of the instance profile, or you can use its name. You can get theinstance-id
of the DB management host from the console as well.
The command outputs several pieces of information, including the ARN of the IAM policy:
At this point, we have created the following in the centralized AWS account from where we want to manage all the databases running on different application accounts:
- An IAM role with the assumed role as a trust policy
- A policy that allows users to assume a role in application accounts
- An instance profile with an added IAM role
- An instance profile associated to the DB management or Bastion host (EC2 instance)
Creating an IAM role on AWS Accounts where Amazon RDS Instance is running
Complete the following policy and role creation steps on each application account (1111111111111, in this case). This gives access to run commands from the AWS CLI on the DB management host by assuming roles.
- Create the JSON file that defines the trust relationship:
The contents of the DB-Management-Host-Access-Role-Trust-Policy.json
file should be similar to the following:
For this post, the principal attribute states who has the DB-Management-Host-CrossAccountAccess-Role
role (Created in Step 2) from the 99999999999 account (which is an AWS management account where you run the AWS CLI in the DB management or Bastion host) can assume the role being created in the application accounts. You need to use the ARN in the trust policy document when you created the IAM role earlier.
- Create the IAM role and define the trust relationship according to the contents of the JSON file:
The command outputs several pieces of information, including the ARN of the IAM role. Take a note of the Amazon Resource Name (ARN) available in the output for the role being created:
You’re now ready to create the IAM customer managed policy. This policy grants the permissions to run specific commands on AWS application accounts by users who are coming from a specific EC2 instance (for this post, the DB management host in a centralized AWS account) using the AWS CLI. For this post, we allow users to run Amazon RDS-specific commands, but you can add more permissions related to other services where database administrators want to query from the AWS CLI as per your requirements.
You can use an AWS managed policy instead of creating customer managed polices if that suits your requirements, such as AmazonRDSReadOnlyAccess
.
You can replace DB-Cross-Account-RDS-Describe-Policy.json
with your own policy name, action, and resource as per your requirements. For actions, consider what kind of commands the user can run on specific services or resources. The following code lists all actions for Amazon RDS. You can add other permissions, such as retrieving secrets, as per your requirements. Regarding resources, consider what specific resources are included in this access. It can be specific to a database by providing the resource ARN or all of that service type.
- Create your customer managed policy with the following code:
You can add specific conditions on who can use this policy, such as MFA and Source IP range, by adding a condition class to the policy document:
- Create the IAM policy using the JSON document created earlier:
The command outputs several pieces of information, including the ARN of the IAM policy:
- Attach the customer managed policy
DB-Management-Host-RDS-Describe-Policy
created in previous step to the role that created in step 2 (you can also attach additional policies based on your needs of what AWS cli should have permission to execute):
- Repeat these steps on each application account by creating the role and policy to allow users to run AWS CLI commands from the DB management or Bastion host running from the DB management account.
Installing and configuring the AWS CLI on an EC2 instance (DB management host)
For instructions on installing the AWS CLI, see Installing, updating, and uninstalling the AWS CLI version 2.
To avoid AWS CLI configuration for each user or database administrator who has access to the DB management or bastion host, we install the AWS CLI in the centralized location and update the config files with appropriate information. See the following code for Linux based EC2 instance running as a DB management or bastion host:
You can install the AWS CLI in a non-default location and have the aws command path added to /usr/local/bin
. For example, see the following code:
Make sure /usr/local/bin
is in your path to run aws
commands.
Note: Please ensure that, you have AWS CLI installed on windows based EC2 instance running as a DB management or bastion host if you are using windows-based operating system. You can also install AWS CLI in a common location for all users and make sure they are in the PATH variable
For Linux, You can export or set the AWS_CONFIG_FILE=<PATH>
variable in the user session to specify the non-default and common location. This way, you’re not required to add profiles in the AWS config file for each user in that DB management or bastion host. You can automate this environment non-default location setup for all users by adding a script under /etc/profile.d
for Linux OS. This sets up the environment variables during each user login process. For example, see the following code:
Add the following lines to the /etc/profile.d/awsclienvironment.sh
file and save it:
Also, you can set up a system environment variable for AWS_CONFIG_FILE
in Windows OS to point to centralized location.
Add the following lines in your AWS_CONFIG_FILE
(/u01/aws/aws-cli/config
) and you can query an RDS instance by specifying the --profile
option to DB1 from the DB management host. You add the profile section for each application account by getting the role ARN you created earlier. See the following code:
You can use the AWS CLI to query profiles configured in the AWS_CONFIG_FILE
with the following code:
Query each account with the following code:
You can set up an environment variable in .bash_profile
for Linux-based operating systems or use the SET command in Windows if you want to avoid passing the --profile
option in your AWS CLI commands:
Further automation for Oracle Databases
You can further automate this if you’re using the oraenv script from an Oracle client or Oracle database installations on the DB management or Bastion host running with Linux OS. You can open the default oraenv script located in $ORACLE_HOME/bin/oraenv
and add the following lines to the script to set the AWS_PROFILE
environment variable based on the SID you pick during environment setup:
You can add all the database information in /etc/oratab
from all the accounts and configure your profile names in the AWS_CONFIG_FILE
to match with SID names that are in /etc/oratab
. For example, see the following code:
Conclusion
In this post, we demonstrated how to use a cross-account IAM role with AWS CLI to access all your AWS accounts from a bastion or DB management host without using AWS account credentials. We also provided tips to automate Amazon RDS database management with AWS CLI configurations and settings for all database administrators. Please try this walkthrough for yourself, and leave any comments!
About the Authors
Siva Subramaniam is a Database Consultant with the AWS Professional Services team at Amazon Web Services. He has experience in technical leadership, application and database design, infrastructure and application support, DBA including database architecture, design, build, data modeling, infrastructure automation, migrations and upgrades, performance tuning, monitoring, backup and recovery, and disaster recovery. Siva holds a master’s degree in Computer Applications and is a certified professional in various database and cloud technologies including AWS, Azure, OCI, Oracle, MSSQL, MySQL, Cassandra, and VMware.
Sharath Lingareddy is a Database Architect with the AWS Professional Services team at Amazon Web Services. He has provided solutions using Oracle, PostgreSQL, and Amazon RDS. His focus area is homogeneous and heterogeneous migrations of on-premises databases to Amazon RDS and Amazon Aurora PostgreSQL.
John Young is a Sr Cloud Infrastructure Architect with the AWS Professional Services team at Amazon Web Services. He has experience designing and implementing multi-account AWS environments utilizing landing zone frameworks and infrastructure-as-code. John works with customers on designing, building and migrating applications to AWS. John holds eight active AWS Certifications.