How to iterate through multiple AWS accounts? - amazon-web-services

Consider an AWS organization with 50+ accounts. Each account has a role created that allows read-only access to the EC2 service - named "EC2ReadAccess" - and a trust relationship with the master(/management) account. A single IAM user in the master account has a policy applied to allow it to assume the role in every single account.
I would like to be able to iterate through all the accounts in order to retrieve all the EC2 instances, using the unique IAM user. I know that running a CLI command against all the accounts at once is out of the question. Leaving aside cycling through the regions in each account, which has been discussed extensively, is there an elegant solution for doing this?
One hack that comes to mind is to programmatically build the credentials file so that it contains a profile for each account. Each profile, in turn, will be "linked" to the profile of the IAM user (as described here), and have the account id within the role updated for each entry. An example below:
[user1]
aws_access_key_id=<key_id>
aws_secret_access_key=<secret_key>
[marketing]
role_arn = arn:aws:iam::123456789012:role/EC2ReadAccess
source_profile = user1
[dev]
role_arn = arn:aws:iam::234567890123:role/EC2ReadAccess
source_profile = user1
...
[prod]
role_arn = arn:aws:iam::345678901234:role/EC2ReadAccess
source_profile = user1
Running the CLI command - in this case aws ec2 describe-instances - can be accompanied by the --profile parameter in order to cycle through all the profiles present in the credentials file. The region can be cycled through within another loop. So a list of commands to be issued, generated programmatically beforehand, could look something like:
aws ec2 describe-instances --profile marketing --region us-east-1
aws ec2 describe-instances --profile marketing --region us-east-2
...
aws ec2 describe-instances --profile marketing --region sa-east-1
aws ec2 describe-instances --profile dev --region us-east-1
aws ec2 describe-instances --profile dev --region us-east-2
...
aws ec2 describe-instances --profile dev --region sa-east-1
...
aws ec2 describe-instances --profile prod --region us-east-1
aws ec2 describe-instances --profile prod --region us-east-2
...
aws ec2 describe-instances --profile prod --region sa-east-1
Is there a better way of doing this? Am I missing something obvious here?

Don't use the CLI to do this. If you're able to "programmatically build the credentials file", then you should be able to write a program that does the following for every child account:
Assumes the administrator role for that account.
Invokes the DescribeInstances API call.
Do whatever you want with the information
You don't indicate what programming language(s) you're familiar with, but here's some Python that I use to create an SDK client with the standard "OrganizationalAccountAccessRole" in a child account:
def create_boto_resource(account, region, resource_type):
creds = assumeRole(account)
return boto3.resource(resource_type,
region_name=region,
aws_access_key_id=creds['AccessKeyId'],
aws_secret_access_key=creds['SecretAccessKey'],
aws_session_token=creds['SessionToken'])
def assumeRole(account, role_name='OrganizationAccountAccessRole', duration=900):
stsClient = boto3.client('sts')
request = {}
request['RoleArn'] = f"arn:aws:iam::{account}:role/{role_name}"
request['RoleSessionName'] = 'DESCRIPTIVE_TEXT_HERE'
request['DurationSeconds'] = duration
return stsClient.assume_role(**request)['Credentials']
This code actually creates a Boto resource object, which is a simplified API that's supported for EC2 and a few other services. Here's and example of using the resource API to create an instance iterator.

Another way to attack this kind of problem might be via Systems Manager Inventory and Querying inventory data from multiple Regions and accounts.

Related

How to Push to Account Using ASSUME_ROLE in AWS ECR

What am I missing? Regardless of what syntax I try, pushing to AWS ECR always lands in the main / management AWS account. In the AWS console I can switch into that account with the appropriate role. Using Terraform I can set the assume_role.role_arn property to create resources in the correct account. However, no config or syntax for Docker and the AWS CLI seems to work. I'm clearly missing a step, property, or global option.
If I go the Terraform route, I can do anything I need. So, I know it should work ...
provider "aws" {
region = "us-gov-west-1"
shared_credentials_file = "~/.aws/credentials"
profile = "govcloud"
assume_role {
role_arn = "arn:aws-us-gov:iam::123456789012:role/Build_Administrator"
}
}
However, I would rather NOT use Terraform for such a simple task as pushing to ECR.
I've tried using the role_arn property in the ~/.aws/config and that doesn't work...
[govcloud]
region = us-gov-west-1
output = json
[govcloud-assume]
region = us-gov-west-1
output = json
role_arn=arn:aws-us-gov:iam::123456789012:role/Build_Administrator
In any other scenario, calling get-login-password / create-repository will leverage the current configured keys and will manipulate the configured account...
aws ecr get-login-password | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-gov-west-1.amazonaws.com
aws ecr create-repository --repository-name "complexapi" --image-tag-mutability MUTABLE
It feels as if there should be some type of global option to set the target account or role_arn, however no combination works...
aws ecr get-login-password --profile govcloud-assume --region us-gov-west-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-gov-west-1.amazonaws.com
aws ecr create-repository --profile govcloud-assume --region us-gov-west-1 --repository-name "complexapi" --image-tag-mutability MUTABLE
Update 1:
Feels like I'm getting closer. After setting the access key I can successfully call aws sts assume-role and return a Credentials object. Just don't know what to do with it yet.
Update 2:
STS was a waste of time and sent me down the wrong path. Don't go there. It's not needed and will pollute your local auth environment for the AWS CLI.
To assume a role using the AWS CLI with ECR, you must use the --profile property within your scripts and structure the ~/.aws/config with two properties together: role_arn and source_profile
The ~/.aws/config requires both the main account and the sub-account you wish to work with. This sub-account contains the role you wish to assume with the ARN is maintained in its role_arn property. The profile of the sub-account is what you will reference in your scripts however the config must also point back to the source_profile which will maintain the actual credentials:
[default]
region = us-gov-west-1
output = json
[profile gov-mgmt]
region = us-west-1
output = json
[profile gov-staging]
role_arn = arn:aws-us-gov:iam::123456789123:role/BuildBoxRole
source_profile = gov-mgmt
region = us-gov-west-1
Your ~/.aws/credentials file then contains the keys for the main account:
[gov-mgmt]
aws_access_key_id = ABCDEFGHIJKLMNOPQRST
aws_secret_access_key = abcdefghijklmnopqrstuvwxyz1234567890ab12
Once in place, your commands will reference the profile containing the role you wish to assume (the target account) and, where needed, you use that account ID. In the example of the get-login-password command, the AWC CLI is passed the --profile property using the name of the sub-account. Docker will receive the resulting password from the AWS CLI and directly reference the sub-account by number.
For example, here are the commands to create the AWS ECR repository in the sub-account (note both the sub-account ID is used as well as the name of that account's profile):
aws ecr get-login-password --profile gov-staging | docker login \
--username AWS \
--password-stdin 123456789123.dkr.ecr.us-gov-west-1.amazonaws.com
aws ecr create-repository \
--profile gov-staging \
--repository-name "complexapi" \
--image-tag-mutability MUTABLE
... and the commands needed to push an image into the sub-account's registry with both the latest tag and a proper version number:
docker tag fredlackey/complexapi:0.0.0 \
123456789012.dkr.ecr.us-gov-west-1.amazonaws.com/complexapi:0.0.0
docker tag fredlackey/complexapi:0.0.0 \
123456789012.dkr.ecr.us-gov-west-1.amazonaws.com/complexapi:latest
aws ecr get-login-password \
--profile gov-staging | docker login \
--username AWS \
--password-stdin 123456789012.dkr.ecr.us-gov-west-1.amazonaws.com
docker push 123456789012.dkr.ecr.us-gov-west-1.amazonaws.com/complexapi:0.0.0
docker push 123456789012.dkr.ecr.us-gov-west-1.amazonaws.com/complexapi:latest

aws-cli only return certain fields

Given this example of aws-cli command
aws rds describe-db-cluster-snapshots
I returns a list of objects with fields.
I only want to display the fields: "SnapshotCreateTime" and "DBClusterIdentifier"
How do I do this?
AWS CLI provides built-in output filtering capabilities with the --query option.
aws rds describe-db-cluster-snapshots --query 'DBClusterSnapshots[*].[SnapshotCreateTime,DBClusterIdentifier]'
The above will work if your AWS CLI configured in the same region and have single AWS CLI profile. If AWS CLI configured in a different region and different profile then you can use below command.
aws rds describe-db-cluster-snapshots --query 'DBClusterSnapshots[*].[SnapshotCreateTime,DBClusterIdentifier]' --region us-west-2 --profile test
cli-usage-output

AWS cli is asking for secret key and access key Id even though right IAM role is attached to the instance

I have an ec2 instance which has the IAM role attached to it for creation of EC2 instances. It also has aws cli installed.
I am trying to use cloudformation cli command to create a stack based on a json template in s3. But it's asking me to provide accessKeyId and secret key etc which I do not have as I do not want to create any IAM user.
Is there any workaround to this ?
Here is the command which I am using:
aws --region us-east-1 cloudformation create-stack --stack-name myteststack --template-url https://s3.console.aws.amazon.com/s3/object/aws-cli-test11/test_ct.json?region=us-east-1&tab=properties --parameters ParameterKey=KeyName,ParameterValue=eai_ec2user,ParameterKey=InstanceType,ParameterValue=t2.medium
EDIT----------
I receive the error messaage Unable to locate credentials. You can configure credentials by running "aws configure". on all aws cli commands. I tried below command and got the same error.:
aws ec2 describe-instances --filters "Name=availability-zone,Values=us-east-1a"
The question is why it's not using the IAM role which is assigned to the instance. That role is having all the necessary policies attached.
The commands are working fine under root user but not under non root user. All the above errors are for non root users.

How can I get the RDS endpoint for use in Userdata

I am trying to get the RDS endpoint to use in user data with cli but unable to figure it out.
I need to get the RDS endpoint to inject into a php file but when I try the following I get:
Unable to locate credentials. You can configure credentials by running "aws configure".
I am building the ec2 and vpc using CLI and need to be able to get RDS endpoint as part of the Userdata.
I tried the following on the EC2 instance itself and I get the above error.
aws rds --region ca-central-1 describe-db-instances --query "DBInstances[*].Endpoint.Address"
Even if I am able to resolve that, I need to be able to get the endpoint to pass as part of the userdata. Is that even possible?
The Unable to locate credentials error says that the AWS Command-Line Interface (CLI) does not have any credentials to call the AWS APIs.
You should assign a role to the EC2 instance with sufficient permission to call describe-db-instances on RDS. See: IAM Roles for Amazon EC2
Then, your User Data can include something like:
#!
RDS=`aws rds --region ca-central-1 describe-db-instances --query "DBInstances[*].Endpoint.Address"`
echo >file $RDS
Or pass it as a parameter:
php $RDS
I have it working with this -
mac=curl -s http://169.254.169.254/latest/meta-data/mac
VPC_ID=curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/$mac/vpc-id
aws rds describe-db-instances --region us-east-2 | jq -r --arg VPC_ID "VPC_ID" '.DBInstances[] |select (.DBSubnetGroup.VpcId=="'$VPC_ID'") | .Endpoint.Address'

Query the list of supported regions in aws amazon

How to get list available regions from amazon?
Before I tried next query
https://ec2.amazonaws.com/?Action=DescribeRegions&AWSAccessKeyId=****&SignatureMethod=HmacSHA256&SignatureVersion=1&Version=2013-08-15
But I get "AWS was not able to validate the provided access credentials" and I don't sure that it correct query.
Your Question Does not seem to specify what services you need to use and how but here is generic example from AWS CLI:
Using describe-regions will give answer to your question , example to describe region names only:
aws ec2 describe-regions --query 'Regions[].{Name:RegionName}' --output text output will be like:
ap-south-1
eu-west-1
ap-southeast-1
ap-southeast-2
eu-central-1
ap-northeast-2
ap-northeast-1
us-east-1
sa-east-1
us-west-1
us-west-2
This is the AWS CLI Documentation that you can refer.