Skip to content

2022

AWS run multiple commands in multiple AWS accounts in the AWS Organizations at the same time

AWS run multiple commands in multiple AWS accounts in the AWS Organizations at the same time

** USE AT YOUR OWN RESPONSABILITY **

I needed to run the same AWS CLI command in multiple accounts within an AWS Organization.

I like code that is easy to read, does what is meant to do, is quick to run, is "safe" and efficient.

Might not be perfect for everyone, but it does well what I need it to do, and might be useful for others or for me again in the feature.

So, I built a script to do what I need in a way that can be re-used for multiple commands in multiple accounts at the same time.

If you have, for example +100 AWS Accounts, you might want to "slow down" this script.

for example, I sometimes use the for-loop below to "slow down" my script :)

for NUMBER in $(seq 0 9); do
    ./99-run-this-command-on-this-account.sh ${NUMBER} ; sleep 20
done

Script to run command multiple AWS account within the organisation

Important

cat 99-run-this-command-on-this-account.txt

#!/bin/bash


run_this_command () {
      account_id=$1
    account_name=$2
       role_name=$3

    echo "--------------------------------------------"
    echo "Going to run a command on ${account_id}, ${account_name}, using the role: ${role_name}"

    # assume a role in the account
    new_role=$(aws sts assume-role --role-arn "arn:aws:iam::${account_id}:role/${role_name}" --role-session-name ${account_id}-${role_name})

    AWS_ACCESS_KEY_ID=$(echo ${new_role} | jq -r '.Credentials.AccessKeyId' )
    AWS_SECRET_ACCESS_KEY=$(echo ${new_role} | jq -r '.Credentials.SecretAccessKey' )
    AWS_SESSION_TOKEN=$(echo ${new_role} | jq -r '.Credentials.SessionToken' )

    ACCOUNT_ID=$(echo ${new_role} | jq -r '.AssumedRoleUser.Arn' | cut -f 5 -d ':')

    export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
    export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
    export AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN}

    export ACCOUNT_ID={ACCOUNT_ID}

    echo "Got key_id >>${AWS_ACCESS_KEY_ID}<< for account_id >>${account_id}, ${account_name}<< "

    #aws s3 ls

    aws securityhub update-standards-control \
        --standards-control-arn "arn:aws:securityhub:eu-west-2:${account_id}:control/cis-aws-foundations-benchmark/v/1.2.0/1.13" \
        --control-status "DISABLED" \
        --disabled-reason "SCP applied at the root level for the organisation will block any root actions."

    aws securityhub update-standards-control \
        --standards-control-arn "arn:aws:securityhub:eu-west-2:${account_id}:control/cis-aws-foundations-benchmark/v/1.2.0/1.14" \
        --control-status "DISABLED" \
        --disabled-reason "SCP applied at the root level for the organisation will block any root actions."

    aws securityhub update-standards-control \
        --standards-control-arn "arn:aws:securityhub:eu-west-2:${account_id}:control/aws-foundational-security-best-practices/v/1.0.0/IAM.6" \
        --control-status "DISABLED" \
        --disabled-reason "SCP applied at the root level for the organisation will block any root actions."

    #for bucket in $(aws s3api list-buckets | jq '.Buckets[].Name' | sed s/'"'//g) ; do
    #    echo "${account_id}, ${account_name}, enabling PublicAccessBlockConfiguration for bucket: ${bucket}" ;
    #    #aws s3api get-public-access-block --bucket ${MYBUCKET} | jq '.PublicAccessBlockConfiguration' ;
    #    aws s3api put-public-access-block \
    #          --bucket ${bucket} \
    #          --public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
    #done

}




number=$1
role_name=<ROLE_NAME_IN_HERE>
filter_name="prod"

# DO I NEED to filter by account name?
#
# DO I NEED a specific list of accounts?  >> command to list account - 'aws organizations list-accounts'
#
# Below, sample filter to list account by creation date.
# cat ./results/00-list-of-accounts-in-org.txt
# jq -r '.Accounts[] | "\(.JoinedTimestamp);\(.Id);\(.Name)" ' ./results/00-list-of-accounts-in-org.txt  | sort | grep '2022-03' | awk -F ';' '{print $2 ";" $3}'
# jq -r '.Accounts[] | "\(.JoinedTimestamp);\(.Id);\(.Name)" ' ./results/00-list-of-accounts-in-org.txt  | sort | grep '2022-03' | awk -F ';' '{print $2 ";" $3}' > work-on-this-list-of-accounts.txt
#
# pick your for-loop
#
#for account in $(jq '.Accounts[] | .Id + ";" + .Name' ./results/00-list-of-accounts-in-org.txt | tr -d '"' | sort | grep ^${number} | grep -v ${filter_name} ); do
#for account in $(jq '.Accounts[] | .Id + ";" + .Name' ./results/00-list-of-accounts-in-org.txt | tr -d '"' | sort | grep ^${number} ); do
 for account in $(cat ./work-on-this-list-of-acocunts.txt | tr -d '"' | sort | grep ^${number} ); do

    #sample account result: "000123456789;my-super-aws-account-name"
    account_id=$(  echo ${account} | cut -f1 -d ';' )
    account_name=$(echo ${account} | cut -f2 -d ';' )

    echo "Getting ready to run a command on this account : ${account_id}; ${account_name}
        "
    run_this_command ${account_id} ${account_name} ${role_name} &

done

AWS Systems Manager or AWS SSM to create a private Networking tunnel to resources in the private subnet

AWS Systems Manager or AWS SSM to create a private Networking tunnel to resources in the private subnet

Pre-requisit

you need the AWS SSM agent installed on your laptop/desktop - documentation here https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent.html

AWS SSM create a tunnel to Linux instance in an AWS private subnet

1) Assume a role in the account

2) Get the instance ID you want to tunnel to

3) Start a session with AWS SSM agent

Sample commands for creating a tunnel to the instance on port 3389 and my PC/laptop localhost on port 5222

# Using a variable, so easier to reuse the command

instance_id="i-Xxxxxx"


# Sample command for creating a tunnel to the instance on port 22 and my PC/laptop localhost on port 5222

aws ssm start-session --target ${instance_id} \
    --document-name AWS-StartPortForwardingSession \
    --parameters portNumber="22",localPortNumber="5222" \
    --region eu-west-2

After creating the tunnel to the instance, you still need a valid ssh key to ssh into the ec2 instance.

Via the SSM in the console, you could add your public key to the authorized-keys - where is another website explaning that https://www.ssh.com/academy/ssh/authorized-keys-file


Example using AWS SSM to create a private networking tunnel to use as remote desktop into a Windows instance in a private subnet

Sample command for creating a tunnel to the instance on port 3389 and my PC/laptop localhost on port 5222

Same step above 1) and 2)

3) Create the tunnel with the RDP port as a destination portNumber

# Using a variable, so easier to reuse the command

instance_id="i-Xxxxxx"


# Sample command for creating a tunnel to the instance on port 22 and my PC/laptop localhost on port 5222

aws ssm start-session --target ${instance_id} \
    --document-name AWS-StartPortForwardingSession \
    --parameters portNumber="3389",localPortNumber="5222" \
    --region eu-west-2

Now, using your favourity remote destop application, you can RDP to localhost:5222 which will be tunneled into the Windows instance in the private subnet on port 3389.


Additional documentation

  • "Port Forwarding Using AWS System Manager Session Manager"

https://aws.amazon.com/blogs/aws/new-port-forwarding-using-aws-system-manager-sessions-manager/

  • "... Tunnel through AWS Systems Manager to access my private VPC resources"

https://aws.amazon.com/premiumsupport/knowledge-center/systems-manager-ssh-vpc-resources/

Change video playback speed rate with javascript

Change video playback speed rate with javascript

You can run these commands in the

document.getElementsByTagName("video")[0].playbackRate = '1.00'
document.getElementsByTagName("video")[0].playbackRate = '1.50'
document.getElementsByTagName("video")[0].playbackRate = '1.75'
document.getElementsByTagName("video")[0].playbackRate = '2.00'
document.getElementsByTagName("video")[0].playbackRate = '2.50'

You can also save them as a bookmark link

sample with querySelector('video')

javascript: (function () {    document.querySelector('video').playbackRate = 1.00;})();
javascript: (function () {    document.querySelector('video').playbackRate = 1.50;})();
javascript: (function () {    document.querySelector('video').playbackRate = 1.75;})();
javascript: (function () {    document.querySelector('video').playbackRate = 2.00;})();
javascript: (function () {    document.querySelector('video').playbackRate = 2.50;})();

sample with getElementsByTagName("video")

javascript: (function () {    document.getElementsByTagName("video")[0].playbackRate = 1.00;})();
javascript: (function () {    document.getElementsByTagName("video")[0].playbackRate = 1.50;})();
javascript: (function () {    document.getElementsByTagName("video")[0].playbackRate = 1.75;})();
javascript: (function () {    document.getElementsByTagName("video")[0].playbackRate = 2.00;})();
javascript: (function () {    document.getElementsByTagName("video")[0].playbackRate = 2.50;})();

sample with getElementsByTagName("audio")

javascript: (function () {    document.getElementsByTagName("audio")[0].playbackRate = 1.00;})();
javascript: (function () {    document.getElementsByTagName("audio")[0].playbackRate = 1.50;})();
javascript: (function () {    document.getElementsByTagName("audio")[0].playbackRate = 1.75;})();
javascript: (function () {    document.getElementsByTagName("audio")[0].playbackRate = 2.00;})();
javascript: (function () {    document.getElementsByTagName("audio")[0].playbackRate = 2.50;})();