Iterate Variables of array into command which itself is a variable bash - linux

I am almost there, the "$i" is where I am having trouble. I have tried ${i}, "$i", $i. I am sure someone with more experience can help me here I have been working on this for 1 full day. Driving me nuts.
session_name="Some-sesh_name"
profile_name="ephemeral-${account_id}-${profile_path}-`date +%Y%m%d%H%M%S`"
roles=( "arn:aws:iam::11111111111111:role/role_name" "arn:aws:iam::222222222222:role/role_name" )
sts=( $(
aws sts assume-role \
--role-arn "$i" \
--role-session-name "$session_name" \
--query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
--output text
) )
for i in "${roles[#]}";
do $sts ; done
aws configure set aws_access_key_id ${sts[0]} --profile ${profile_name}
aws configure set aws_secret_access_key ${sts[1]} --profile ${profile_name}
aws configure set aws_session_token ${sts[2]} --profile ${profile_name}

That $i is expanded at the moment you define the sts array. After that, it doesn't exist.
To make that aws command reusable, use a function:
roles=(
"arn:aws:iam::11111111111111:role/role_name"
"arn:aws:iam::222222222222:role/role_name"
)
sts() {
aws sts assume-role \
--role-arn "$1" \
--role-session-name "$session_name" \
--query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
--output text
}
for role in "${roles[#]}"; do
sts "$role"
done
Note the use of $1 in the function, to retrieve the first argument. The global variable $session_name is still OK
I don't understand what you're thinking with the sts array. In the for loop you want to call it as a command, but the configure commands take elements of the array? After all the roles have been assumed? Are you wanting to use the returned data instead?
Do you want:
for role in "${roles[#]}"; do
data=( $(sts "$role") )
aws configure set aws_access_key_id "${data[0]}" --profile "$profile_name"
aws configure set aws_secret_access_key "${data[1]}" --profile "$profile_name"
aws configure set aws_session_token "${data[2]}" --profile "$profile_name"
done
?

Related

AWS CLI put cloudwatch logs with a JSON in message

I am trying to put logs to AWS CloudWatch logs via AWS CLI using a bash script:
#!/bin/bash
EVENT_TIME=$(date +%s%3N)
LOG_LEVEL=6
EVENT_SOURCE=myapp
MESSAGE=1
OUTPUT=$(jq -n \
--arg EventTime "$EVENT_TIME" \
--arg LogLevel "$LOG_LEVEL" \
--arg EventSource "$EVENT_SOURCE" \
--arg Message "$MESSAGE" \
'{EventTime:$EventTime,LogLevel:$LogLevel,EventSource:$EventSource,Message:$Message}')
MESSAGE="$OUTPUT"
aws logs put-log-events --log-group-name test --log-stream-name local --log-events timestamp=$(date +%s%3N),message=$MESSAGE
but I am getting error:
Error parsing parameter '--log-events': Expected: '<double quoted>', received: '<none>'
for input:
timestamp=1654692489664,message="{
The command works fine, if I remove the JSON message to a simple string. It should be an issue with quoting but not sure where the problem is. Any idea?
The message parameter needs to be a string containing the json, not the direct json created with jq.
Something like this should work:
#!/bin/bash
EVENT_TIME=$(date +%s000)
LOG_LEVEL=6
EVENT_SOURCE=myapp
MESSAGE=1
OUTPUT=$(jq -n \
--arg EventTime "$EVENT_TIME" \
--arg LogLevel "$LOG_LEVEL" \
--arg EventSource "$EVENT_SOURCE" \
--arg Message "$MESSAGE" \
'{EventTime:$EventTime,LogLevel:$LogLevel,EventSource:$EventSource,Message:$Message}')
LOG_MESSAGE=$(echo $OUTPUT | sed 's/"/\\"/g')
aws logs put-log-events --log-group-name test --log-stream-name local --log-events timestamp=$(date +%s000),message=\""$LOG_MESSAGE"\"
Also, if you plan to use the put-log-events like this, you will need to provide the --sequence-token for consecutive puts. See here: https://docs.aws.amazon.com/cli/latest/reference/logs/put-log-events.html
Might be best to setup CloudWatch agent to publish the logs.

aws-cli - Filter output with --query or --filter

I try to list all my AutoScalingGroups with "Desiredcapacity" = 3.
I can run this but it gives me all ASG back and it's to many.
aws autoscaling describe-auto-scaling-groups --query "AutoScalingGroups[*].{NAME:AutoScalingGroupName,DesiredCapacity:DesiredCapacity} | sort_by([], &DesiredCapacity)" --profile MyProfile --output table
I tried :
aws autoscaling describe-auto-scaling-groups --query "AutoScalingGroups[?DesiredCapacity == '3'].{NAME:AutoScalingGroupName,DesiredCapacity:DesiredCapacity} | sort_by([], &DesiredCapacity)" --profile MyProfile --output table
I dont get any error msg but it does not return anything, as it should
I actually improved my search and find a solution.
aws autoscaling describe-auto-scaling-groups --query 'AutoScalingGroups[?DesiredCapacity>=`3`].[AutoScalingGroupName,DesiredCapacity,MinSize,MaxSize]' --output table --profile MyProfile
is exactly what i want.

How to use an environment variable in an AWS CLI command

I run this command and it works :
aws elb describe-load-balancers --query 'LoadBalancerDescriptions[?VPCId==`vpc-#########`]|[].LoadBalancerName' --region us-east-2
If I try and use an environemnt variable it does not work :
aws elb describe-load-balancers --query 'LoadBalancerDescriptions[?VPCId==`$VPC_ID`]|[].LoadBalancerName' --region us-east-2
I know that VPC_ID is valid - echo $VPC_ID returns the correct value
What am I not seeing?
Thanks!!!!!
I also tried this command with the same results :
This works fine :
aws elb describe-load-balancers --output text --query 'LoadBalancerDescriptions[?Instances[?InstanceId==`i-0############`]].[LoadBalancerName]' --region us-east-2
This returns nothing :
aws elb describe-load-balancers --output text --query 'LoadBalancerDescriptions[?Instances[?InstanceId=="$InstanceID"]].[LoadBalancerName]' --region us-east-2
I know that the environment variable $InstanceID is populated and correct - I perform an echo $InstanceID and get the correct ID output.
Got it!!
The environment variable need to be in brackets - { }
This works -
aws elb describe-load-balancers --output text --query "LoadBalancerDescriptions[?Instances[?InstanceId=='${InstanceID}']].LoadBalancerName" --region us-east-2
I am able to reproduce this using the following:
export MY_VPC_ID=vpc-1234
echo 'LoadBalancerDescriptions[?VPCId==`$MY_VPC_ID`]|[].LoadBalancerName'
OUTPUT:
LoadBalancerDescriptions[?VPCId==`$MY_VPC_ID`]|[].LoadBalancerName
I believe this has to do with how bash interprets quotes as shown in this other post
Evaluating variables in a string
Can you try using this?
echo "LoadBalancerDescriptions[?VPCId==\"$MY_VPC_ID\"]|[].LoadBalancerName"
OUTPUT:
LoadBalancerDescriptions[?VPCId=="vpc-1234"]|[].LoadBalancerName

Use AWS CLI to pull in multiple information

Right now this following code segment will list the 'Name' tag of the resource of any instance that doesn't have a 'Grant' tag.
for region in `aws ec2 describe-regions --output text | cut -f3`
do
aws ec2 describe-instances \
--region $region \
--output text \
--query 'Reservations[].Instances[?!not_null(Tags[?Key == `Grant`].Value)] | [].Tags[?Key==`Name`].Value'
done
I've tried a few ways to get the Public IP address but I keep getting errors for bad syntax.
Is it possible to pull in the Public IP here?
Yes, It is possible to pull the PublicIp address along with the Tags value.
Replace query syntax as below,
--query 'Reservations[].Instances[?!not_null(Tags[?Key == `Grant`].Value)] | [].[PublicIpAddress, Tags[?Key==`Name`].Value]'

How to get an RDS endpoint for a specific VPC using AWS CLI

I have the command to list all the RDS endpoints I have running in my aws account but I want to find RDS endpoint for RDS running in the same VPC as the ec2 instance I want to use it from.
I have multiple VPC's up with multiple RDS's so when I issue the command it gives me all the running RDS's. How can i filter this to just show me the one in the same VPC?
I run the command -
aws rds --region us-east-2 describe-db-instances --query "DBInstances[*].Endpoint.Address"
And I get -
"acme-networkstack.vbjrxfom0phf.us-east-2.rds.amazonaws.com",
"acme-aws-beta-network.vbjrxfom0phf.us-east-2.rds.amazonaws.com",
"acme-demo.vbjrxfom0phf.us-east-2.rds.amazonaws.com",
"acme-dev.vbjrxfom0phf.us-east-2.rds.amazonaws.com"
I only want the one endpoint that is in the same VPC as the instance I am running the CLI command from.
Thanks!
Ernie
Here's a little script that should do the trick, just replace the ec2 describe-instanceswith your rds cli command:
#!/bin/bash
mac=`curl -s http://169.254.169.254/latest/meta-data/mac`
vpcID=`curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/$mac/vpc-id`
aws ec2 describe-instances --region eu-west-1 --filter "Name=vpc-id,Values=$vpcID"
You're first curling the instance meta-data to find it's VpcId, and then filtering the outputs of your cli command to limit to a certain vpc.
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html
https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-output.html
describe-db-instances has a limited set of filters which doesn't include the VPC. The solution I suggest uses a combination of the meta-data information from the host and jq to select only the endpoints that match the VPC.
First, You can get the VPC ID as suggested by WarrenG.
#!/bin/bash
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`
Then uses the AWS CLI in combination with jq to derive your desired output.
aws rds describe-db-instances | jq -r --arg VPC_ID "VPC_ID" '.DBInstances[] |select (.DBSubnetGroup.VpcId==$VPC_ID) | .Endpoint.Address'
I haven't run this from a script but it works from the command line. If it doesn't work in a script let me know.
References
https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-instances.html
Passing bash variable to jq select

Resources