avatarTeri Radichel

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

11347

Abstract

js-keyword">policy</span> { "Role": { "Path": "/", "RoleName": "XacctWebAdminGroup", "RoleId": "AROAXW4B4T5FZFYHIOBHN", "Arn": "arn:aws:iam::222222222222:role/XacctWebAdminGroup", "CreateDate": "2023-06-07T03:56:05+00:00", "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::222222222222:user/WebAdmin" }, "Action": "sts:AssumeRole", "Condition": { "Bool": { "aws:MultiFactorAuthPresent": "true" } } } ] }, "Description": "", "MaxSessionDuration": <span class="hljs-number">3600</span>, "RoleLastUsed": {} } } Does the assume <span class="hljs-keyword">role</span> document (trust <span class="hljs-keyword">policy</span>) contain the ARN <span class="hljs-keyword">for</span> the <span class="hljs-keyword">user</span> that <span class="hljs-keyword">is</span> allowed <span class="hljs-keyword">to</span> assume the <span class="hljs-keyword">role</span>? Ctrl-C <span class="hljs-keyword">to</span> <span class="hljs-keyword">exit</span>. Enter <span class="hljs-keyword">to</span> <span class="hljs-keyword">continue</span>.</pre></div><p id="5d50"><i>Note: I should change the above to grep for the correct user but I’d have to switch to the user account role and then back to the account profile with the cross-account role. Maybe later. For now, you can see the ARN for the user in the user account above.</i></p><p id="2861">Get the account number where the user and group exists that can assume the cross account role.</p><div id="f3b6"><pre><span class="hljs-built_in">echo</span> <span class="hljs-string">"Get the account number of the account where the user and group exists"</span> useracctnum=(get_account_number <span class="hljs-variable">useraccountname</span>) <span class="hljs-built_in">echo</span> -e <span class="hljs-string">"The user account number is <span class="hljs-variable">useracctnum</span>.<span class="hljs-variable">m</span>"</span> <span class="hljs-built_in">read</span> ok</pre></div><p id="940e">Output:</p><div id="78e8"><pre>Get the account number of the account where the user and group exists The user account number is <span class="hljs-number">222222222222</span>. Ctrl-C to <span class="hljs-keyword">exit</span>. Enter to <span class="hljs-keyword">continue</span>.</pre></div><p id="4f91">Create a CLI Profile for that account that leverages the default AWS Organizations role.</p><div id="916e"><pre><span class="hljs-built_in">echo</span> <span class="hljs-string">"Create an AWS CLI Profile for the default Organization role in <span class="hljs-variable">useraccountname</span>"</span> <span class="hljs-built_in">echo</span> <span class="hljs-string">"Please wait..."</span> useracctprofile=(create_org_admin_role_profile <span class="hljs-variable">useraccountname</span>) cliprofile=(<span class="hljs-built_in">cat</span> ~/.aws/config | grep -i <span class="hljs-variable">useracctprofile</span> -A2) <span class="hljs-built_in">echo</span> -e <span class="hljs-variable">cliprofile</span> <span class="hljs-built_in">echo</span> -e <span class="hljs-string">"CLI profile created.<span class="hljs-variable">m</span>"</span> <span class="hljs-built_in">read</span> ok</pre></div><p id="d4a5">Output:</p><div id="39e3"><pre>Create an AWS CLI Profile <span class="hljs-keyword">for</span> the default Organization role <span class="hljs-keyword">in</span> Sandbox Please wait... [profile xxxxxx-Sandbox] region = xxxxxxxx output = json CLI profile created. Ctrl-C to <span class="hljs-keyword">exit</span>. Enter to <span class="hljs-keyword">continue</span>.</pre></div><p id="675f">Check that the user name exists which we are trying to use to assume the role.</p><div id="5d2a"><pre><span class="hljs-built_in">echo</span> <span class="hljs-string">"Check that user exists in the user account."</span> testuser=(aws iam list-users --profile <span class="hljs-variable">useracctprofile</span> --output text | grep <span class="hljs-variable">userToAssumeRole</span> | <span class="hljs-built_in">cut</span> -f2) <span class="hljs-keyword">if</span> [ <span class="hljs-string">"<span class="hljs-variable">testuser</span>"</span> == <span class="hljs-string">""</span> ]; <span class="hljs-keyword">then</span> <span class="hljs-built_in">echo</span> -e <span class="hljs-string">"<span class="hljs-variable">userToAssumeRole</span> does not exist.<span class="hljs-variable">m</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-built_in">echo</span> -e <span class="hljs-string">"<span class="hljs-variable">testuser</span> exists.<span class="hljs-variable">m</span>"</span> <span class="hljs-keyword">fi</span> <span class="hljs-built_in">read</span> ok</pre></div><p id="e840">Output:</p><div id="757c"><pre>Check that user exists <span class="hljs-keyword">in</span> the user account. arn:aws:iam::<span class="hljs-number">222222222222</span>:user/WebAdmin exists. Ctrl-C to <span class="hljs-keyword">exit</span>. Enter to <span class="hljs-keyword">continue</span>.</pre></div><p id="62e8">Check that the group exists that has permission to assume the role.</p><div id="3564"><pre><span class="hljs-built_in">echo</span> <span class="hljs-string">"Check that the group exits."</span> testgroup=(aws iam list-groups --profile <span class="hljs-variable">useracctprofile</span> --output text | grep <span class="hljs-variable">groupname</span> | <span class="hljs-built_in">cut</span> -f2) <span class="hljs-keyword">if</span> [ <span class="hljs-string">"<span class="hljs-variable">testgroup</span>"</span> == <span class="hljs-string">""</span> ]; <span class="hljs-keyword">then</span> <span class="hljs-built_in">echo</span> -e <span class="hljs-string">"Group: <span class="hljs-variable">groupname</span> does not exist in <span class="hljs-variable">useraccountname</span>.<span class="hljs-variable">m</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-built_in">echo</span> -e <span class="hljs-string">"Group: <span class="hljs-variable">testgroup</span> exists in <span class="hljs-variable">useraccountname</span>.<span class="hljs-variable">m</span>"</span> <span class="hljs-keyword">fi</span> <span class="hljs-built_in">read</span> ok</pre></div><p id="f5c5">Output:</p><div id="0b28"><pre>Check that the group exits. Group: arn:aws:iam::<span class="hljs-number">222222222222</span>:group/XacctWebAdmin exists <span class="hljs-keyword">in</span> Sandbox. Ctrl-C to <span class="hljs-keyword">exit</span>. Enter to <span class="hljs-keyword">continue</span>.</pre></div><p id="4cbf">Check that the user is in the group.</p><div id="563c"><pre><span class="hljs-built_in">echo</span> <span class="hljs-string">"Check that the user is in the group"</span> group=(aws iam list-groups-for-user --profile <span class="hljs-variable">useracctprofile</span> --user-name <span class="hljs-variable">userToAssumeRole</span> --output text | grep <span class="hljs-variable">groupname</span> | <span class="hljs-built_in">cut</span> -f2) <span class="hljs-keyword">if</span> [ <span class="hljs-string">"<span class="hljs-variable">group</span>"</span> == <span class="hljs-string">""</span> ]; <span class="hljs-keyword">then</span> <span class="hljs-built_in">echo</span> -e <span class="hljs-string">"Group not found for user.<span class="hljs-variable">m</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-built_in">echo</span> -e <span class="hljs-string">"User is in group: <span class="hljs-variable">group</span>.<span class="hljs-variable">m</span>"</span> <span class="hljs-keyword">fi</span> <span class="hljs-built_in">read</span> ok</pre></div><p id="33b2">Output:</p><div id="a15d"><pre><span class="hljs-keyword">Check</span> that the <span class="hljs-keyword">user</span> <span class="hljs-keyword">is</span> <span class="hljs-keyword">in</span> the <span class="hljs-keyword">group</span> <span class="hljs-keyword">User</span> <span class="hljs-keyword">is</span> <span class="hljs-keyword">in</span> <span class="hljs-keyword">group</span>: arn:aws:iam::<span class="hljs-number">222222222222</span>:<span class="hljs-keyword">group</span>/XacctWebAdmin. Ctrl-C <span class="hljs-keyword">to</span> <span class="hljs-keyword">exit</span>. Enter <span class="hljs-keyword">to</span> <span class="hljs-keyword">continue</span>.</pre></div><p id="293e">Check the policy with the expected name exists.</p><div id="7bcf"><pre><span class="hljs-string">policyname</span>=<span class="hljs-string">groupname</span><span class="hljs-string">'GroupPolicy'</span> <span class="hljs-string">echo</span> <span class="hljs-string">"Check that the group policy policyname exists."</span> <span class="hljs-string">echo</span> <span class="hljs-string">"Group policies:"</span> <span class="hljs-string">aws</span> <span class="hljs-string">iam</span> <span class="hljs-built_in">list-group-policies</span> <span class="hljs-built_in">--profile</span> <span class="hljs-string">useracctprofile</span> <span class="hljs-built_in">--group-name</span> <span class="hljs-string">groupname</span> <span class="hljs-built_in">--output</span> <span class="hljs-string">text</span> <span class="hljs-comment">#this code should really loop through all policies but I know I only add one policy to groups in this codebase</span> <span class="hljs-string">testpolicy</span>=(<span class="hljs-string">aws</span> <span class="hljs-string">iam</span> <span class="hljs-built_in">list-group-policies</span> <span class="hljs-built_in">--profile</span> <span class="hljs-string">useracctprofile</span> <span class="hljs-built_in">--group-name</span> <span class="hljs-string">groupname</span> <span class="hljs-built_in">--output</span> <span class="hljs-string">json</span> <span class="hljs-built_in">--query</span> <span class="hljs-string">'PolicyNames[0]'</span>) <span class="hljs-string">if</span> [ <span class="hljs-string">"testpolicy"</span> == <span class="hljs-string">"null"</span> ]; <span class="hljs-string">then</span> <span class="hljs-string">echo</span> -<span class="hljs-string">e</span> <span class="hljs-string">"Policy policyname does not exist for group: groupname.m"</span> <span class="hljs-string">else</span> <span class="hljs-string">echo</span> -<span class="hljs-string">e</span> <span class="hljs-string">"Policy testpolicy exists for group groupname.$m"</span> <span class="hljs-string">fi</span> <span class="hljs-string">read</span> <span class="hljs-string">ok</span></pre></div><p id="e9be">Output:</p><div id="344d"><pre>Check that the group policy XacctWebAdminGroupPolicy exists. Group policies: POLICYNAMES XacctWebAdminGroupPolicy Policy <span class="hljs-string">"XacctWebAdminGroupPolicy"</span> exists <span class="hljs-keyword">for</span> group XacctWebAdmin. Ctrl-C to <span class="hljs-keyword">exit</span>. Enter to <span class="hljs-keyword">continu

Options

e</span>.</pre></div><p id="7373">Check that the policy has the expect role ARN in the policy.</p><div id="20a0"><pre><span class="hljs-string">echo</span> <span class="hljs-string">"Evaluate the policy"</span> <span class="hljs-string">aws</span> <span class="hljs-string">iam</span> <span class="hljs-built_in">get-group-policy</span> <span class="hljs-built_in">--profile</span> <span class="hljs-string">useracctprofile</span> <span class="hljs-built_in">--policy-name</span> <span class="hljs-string">policyname</span> <span class="hljs-built_in">--group-name</span> <span class="hljs-string">groupname</span> <span class="hljs-string">testpolicy</span>=(<span class="hljs-string">aws</span> <span class="hljs-string">iam</span> <span class="hljs-built_in">get-group-policy</span> <span class="hljs-built_in">--profile</span> <span class="hljs-string">useracctprofile</span> <span class="hljs-built_in">--policy-name</span> <span class="hljs-string">policyname</span> <span class="hljs-built_in">--group-name</span> <span class="hljs-string">groupname</span> | <span class="hljs-string">grep</span> <span class="hljs-string">rolename</span>) <span class="hljs-string">if</span> [ <span class="hljs-string">"testpolicyrole"</span> == <span class="hljs-string">""</span> ]; <span class="hljs-string">then</span> <span class="hljs-string">echo</span> -<span class="hljs-string">e</span> <span class="hljs-string">"Role name rolename not found in policy.m"</span> <span class="hljs-string">else</span> <span class="hljs-string">echo</span> -<span class="hljs-string">e</span> <span class="hljs-string">"Role name rolename found in policy.$m"</span> <span class="hljs-string">fi</span> <span class="hljs-string">read</span> <span class="hljs-string">ok</span></pre></div><p id="8f83">This is where I found my error. The ARN in my group policy was not correct.</p><h1 id="1d9d">❌ ❗ ️‼️ ⚠️</h1><p id="2c6b">Incorrect Output ~ it shows that the ARN in this policy does not have the correct group name. I had to modify the code that creates the GroupPolicy or more accurately the code that passes the role name to the GroupPolicy CloudFormation Template.</p><div id="c1cc"><pre>Evaluate the policy { <span class="hljs-string">"GroupName"</span>: <span class="hljs-string">"XacctWebAdmin"</span>, <span class="hljs-string">"PolicyName"</span>: <span class="hljs-string">"XacctWebAdminGroupPolicy"</span>, <span class="hljs-string">"PolicyDocument"</span>: { <span class="hljs-string">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>, <span class="hljs-string">"Statement"</span>: [ { <span class="hljs-string">"Condition"</span>: { <span class="hljs-string">"Bool"</span>: { <span class="hljs-string">"aws:MultiFactorAuthPresent"</span>: <span class="hljs-string">"true"</span> } }, <span class="hljs-string">"Action"</span>: <span class="hljs-string">"sts:AssumeRole"</span>, <span class="hljs-string">"Resource"</span>: <span class="hljs-string">"arn:aws:iam::222222222222:role/XacctWebAdmin"</span>, <span class="hljs-string">"Effect"</span>: <span class="hljs-string">"Allow"</span> } ] } } Role name XacctWebAdminGroup not found <span class="hljs-keyword">in</span> policy. Ctrl-C to <span class="hljs-keyword">exit</span>. Enter to <span class="hljs-keyword">continue</span>.</pre></div><p id="bed3">The first thing I did was create an init_vars.sh file and moved all the variables used by different scripts to one place to a.) reduce code and b.) ensure the assignments were consistent.</p><figure id="7940"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*G-4ZEdtehChDTQ3Ec5FkzA.png"><figcaption></figcaption></figure><p id="777c">That simplified my two scripts that create the IAM user, group, and cross-account role.</p><figure id="d139"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*u8aQw_WHU1GyrngGXoM9VQ.png"><figcaption></figcaption></figure><figure id="063a"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*yzrzO-YyLJWiSfdR1mP9aw.png"><figcaption></figcaption></figure><p id="1eec">I modified the deploy_group function to pass in an account number if deploying cross-account role and pass it through when deploying the policy.</p><figure id="5bc0"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*DGy7SxPObz0wEFnqLBLCPA.png"><figcaption></figcaption></figure><p id="6f2a">The group policy function passes the account number, if it exists, as a parameter to the template.</p><figure id="a6ea"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*ta7NHSsBLDY3GmlRb-1IHA.png"><figcaption></figcaption></figure><p id="be10">The group policy template now users the remote account number in the ARN if it is provided.</p><figure id="e386"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*gYjpo6hjqb940oJ7xFgm6Q.png"><figcaption></figcaption></figure><p id="2d3a">Along the way I spent way too long on this:</p><div id="1e3a" class="link-block"> <a href="https://readmedium.com/grep-not-found-results-in-error-condition-b141395954a2"> <div> <div> <h2>grep not found results in error condition</h2> <div><h3>This one bites hard</h3></div> <div><p>medium.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*4oxP4LXk8l8c3mpRvO7ejg.png)"></div> </div> </div> </a> </div><p id="86ea">After getting that working, I ran my test again.</p><p id="303e">Output:</p><div id="1cd5"><pre>OK: Role name XacctWebAdminGroup found <span class="hljs-keyword">in</span> policy. Ctrl-C to <span class="hljs-keyword">exit</span>. Enter to <span class="hljs-keyword">continue</span>.

Check <span class="hljs-keyword">for</span> acctnum <span class="hljs-keyword">in</span> policy OK: Correct account number found <span class="hljs-keyword">in</span> policy. Ctrl-C to <span class="hljs-keyword">exit</span>. Enter to <span class="hljs-keyword">continue</span>.

Check <span class="hljs-keyword">for</span> ARN <span class="hljs-keyword">in</span> policy. OK: Policy contains correct ARN. Ctrl-C to <span class="hljs-keyword">exit</span>. Enter to <span class="hljs-keyword">continue</span>.</pre></div><p id="94cb">The policy passes validation.</p><p id="c572">Now I can run the code that has the WebAdmin assume the new cross account role in SandBox-Web and creates a CLI profile.</p><div id="c887"><pre><span class="hljs-built_in">echo</span> <span class="hljs-string">"Create a cross account CLI Profile for <span class="hljs-variable">rolename</span>"</span> create_cross_account_role_profile <span class="hljs-variable">targetacctnum</span> <span class="hljs-variable">rolename</span> <span class="hljs-variable">roleprofile</span> cliprofile=(<span class="hljs-built_in">cat</span> ~/.aws/config | grep -i <span class="hljs-variable">roleprofile</span> -A2) <span class="hljs-built_in">echo</span> -e <span class="hljs-variable">cliprofile</span> <span class="hljs-built_in">echo</span> -e <span class="hljs-string">"CLI profile created.<span class="hljs-variable">m</span>"</span> <span class="hljs-built_in">read</span> ok

<span class="hljs-comment">#<span class="hljs-doctag">TODO:</span> need a mechanism to remove the role profile</span></pre></div><p id="dc5e">Output:</p><div id="651e"><pre>Create a cross account CLI Profile <span class="hljs-keyword">for</span> XacctWebAdminGroup Enter mfa token XXXXXX XacctWebAdminGroup [profile XacctWebAdminGroup] region = xxxxxx output = json CLI profile created. Ctrl-C to <span class="hljs-keyword">exit</span>. Enter to <span class="hljs-keyword">continue</span>.</pre></div><p id="4cb6">I have two other functions to test but this took long enough. These functions add the credentials to environment variables instead of a role profile. The second function removes the environment variables so those credentials don’t override others when the user is done using a particular role.</p><div id="9922"><pre>### TEST ASSUME ROLE WITH ENVIRONMENT VARS ### #assume a role and add the credentials <span class="hljs-keyword">as</span> environment vars assume_cross_account_role accountname roleprofile echo <span class="hljs-string">"Assume role and add credentials to environent vars ok? Ctrl-C to exit."</span> read ok</pre></div><div id="2bae"><pre><span class="hljs-comment">#remove credentials from env vars or they will override other auth methods</span> stop_assume_cross_account_role <span class="hljs-built_in">echo</span> <span class="hljs-string">"Have the credentials been removed from environment variables?"</span> <span class="hljs-built_in">echo</span> <span class="hljs-string">"Done."</span></pre></div><p id="6603">Output: I still need to thest this one.</p><p id="e45a">Phew!</p><p id="190f">Here’s the whole script as it stands at the time of this writing.</p><figure id="5fc8"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*fSB6g3fpuB12mEVTamy0qg.png"><figcaption></figcaption></figure><figure id="042c"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*QYC20ic9_SEF6SmjhM2FrA.png"><figcaption></figcaption></figure><figure id="dc83"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*HfD2ZKqZBe5yrBSb1oX-TQ.png"><figcaption></figcaption></figure><p id="7762">I’ll check it in after I finish testing those last two role assumption functions.</p><p id="5ff9">Follow for updates.</p><p id="4a3a">Teri Radichel | <i>© <a href="https://2ndsightlab.com/?source=post_page---------------------------">2nd Sight Lab</a> 2023</i></p><div id="8b5f"><pre><span class="hljs-section">About Teri Radichel:

⭐️ Author: Cybersecurity Books
⭐️ Presentations: Presentations by Teri Radichel
⭐️ Recognition: SANS Award, AWS Security Hero, IANS Faculty
⭐️ Certifications: SANS ~ GSE 240
⭐️ Education: BA Business, Master of Software Engineering, Master of Infosec
⭐️ Company: Penetration Tests, Assessments, Phone Consulting ~ 2nd Sight Lab</pre></div><div id="caae"><pre><span class="hljs-section">Need Help With Cybersecurity, Cloud, or Application Security?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
🔒 Request a penetration test or security assessment
🔒 Schedule a consulting call
🔒 Cybersecurity Speaker for Presentation</pre></div><div id="5a42"><pre>Follow <span class="hljs-keyword">for</span> more stories like <span class="hljs-keyword">this</span>:

❤️ Sign Up my Medium Email List ❤️ Twitter: <span class="hljs-meta">@teriradichel</span> ❤️ LinkedIn: https:<span class="hljs-comment">//www.linkedin.com/in/teriradichel</span> ❤️ Mastodon: <span class="hljs-meta">@teriradichel</span><span class="hljs-meta">@infosec</span>.exchange ❤️ Facebook: 2nd Sight Lab ❤️ YouTube: @2ndsightlab</pre></div><figure id="faf5"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*H9Ew1KCl-29nZiPR.jpeg"><figcaption></figcaption></figure></article></body>

Test Script For Cross-Account Roles

ACM.230 Troubleshooting why a cross account role is not working

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

⚙️ Check out my series on Automating Cybersecurity Metrics | Code.

🔒 Related Stories: AWS Security | IAM | Cloud Governance

💻 Free Content on Jobs in Cybersecurity | ✉️ Sign up for the Email List

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I’ve been working through creating some reusable functions to create and assume cross-account IAM roles. Let’s just say they can be tricky.

😳

I initially created the functions here as an initial test:

I tried to use the functions again here to create a user that can remotely administer website resources in another account.

That’s when I discovered a few errors which I fix below.

The cross-account role test script

Here’s the script I wrote to help me test and find problems with cross-account roles. I’m going to walk through the script one step at a time and show you what I did. I’ll likely revise and improve this script in the future.

Note: This code presumes that you’re using my codebase in the GitHub repository above with an AWS Organization created by my code that has an SSM Parameter containing the OrgPrefix used in the default AWS Organizations role names and a CLI profile named OrgRoot with permissions in the Organizations Root account to query the parameter and assume the default cross account organization role with the expected name. It also uses my functions to create role profiles and assume roles.

Warning: This is long! Jump to the end to see the full script.

I modified the accounts in the output:

  • Account with the cross-account role: 111111111111
  • Account with the user and group: 22222222222

First I source the files that have the functions I need.

source shared_functions.sh
source assume_role.sh

I get the base path for my code as I use it to switch directories to call functions in other directories.

#get the root directory for this code base
cd ../
base_path=$(pwd)

I set the other variables used by the script. You can change these to your own test values.

#role that has permission to assume cross account roles
#and query IAM
profile="OrgRoot"
targetaccountname='Sandbox-Web'
rolename="XacctWebAdminGroup"
userToAssumeRole="WebAdmin"
useraccountname='Sandbox'
groupname='XacctWebAdmin'
m="\nCtrl-C to exit. Enter to continue."

#name of the role profile you want to create in your AWS CLI configuration.
#I'm using the role name as the AWS CLI profile name here
#Once created run commands like this: aws s3 ls --profile $roleprofile

Change to the Organizations directory and set the profile variable to the OrgRoot profile so we can run some code that requires permissions the role that profile assumes has.

echo "Change to Organization directory and use OrgRoot AWS CLI profile"
change_dir "Organization" $base_path "OrgRoot"
echo ""

Output:

Change to Organization directory and use OrgRoot AWS CLI profile
change dir Organization

Get the account number for the account with the Cross-Account Role.

echo "Get the account number of the account where the role exists"
acctnum=$(get_account_number $targetaccountname)
echo -e "The target account number is $acctnum.$m"
read ok

Output:

Get the account number of the account where the role exists
The target account number is 111111111111.
Ctrl-C to exit. Enter to continue.

Create a role profile for the AWS CLI for that account number.

echo "Create an AWS CLI Profile for the default Organization role in $targetaccountname"
echo "Please wait..."
remoteprofile=$(create_org_admin_role_profile $targetaccountname)
cliprofile=$(cat ~/.aws/config | grep -i $remoteprofile -A2)
echo -e $cliprofile
echo -e "CLI profile created.$m"
read ok

Output:

Create an AWS CLI Profile for the default Organization role in Sandbox-Web
Please wait...
[profile xxxxxx-Sandbox-Web] region = xxxxxxx output = json
CLI profile created.
Ctrl-C to exit. Enter to continue.

List the roles and make sure the Cross Account role exists.

echo "List the roles in the target account using profile: $remoteprofile" 
role=$(aws iam list-roles --profile $remoteprofile --output text | grep $rolename | cut -f2)
if [ "$role" != "" ]; then
  echo -e "Role exists: $role.$m"
else
  echo -e "Role does not exist.$m"
fi
read ok

Output:

List the roles in the target account using profile: xxxxxxx-Sandbox-Web
Role exists: arn:aws:iam::111111111111:role/XacctWebAdminGroup.
Ctrl-C to exit. Enter to continue.

Evaluate the trust policy. We need to make sure the user ARN that is allowed to assume the role is correct.

echo "Evalute the role trust policy"
aws iam get-role --role-name $rolename --profile $remoteprofile
echo -e "Does the assume role document (trust policy) contain the ARN for the user that is allowed to assume the role?$m"
read ok

Output:

Evalute the role trust policy
{
    "Role": {
        "Path": "/",
        "RoleName": "XacctWebAdminGroup",
        "RoleId": "AROAXW4B4T5FZFYHIOBHN",
        "Arn": "arn:aws:iam::222222222222:role/XacctWebAdminGroup",
        "CreateDate": "2023-06-07T03:56:05+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": "arn:aws:iam::222222222222:user/WebAdmin"
                    },
                    "Action": "sts:AssumeRole",
                    "Condition": {
                        "Bool": {
                            "aws:MultiFactorAuthPresent": "true"
                        }
                    }
                }
            ]
        },
        "Description": "",
        "MaxSessionDuration": 3600,
        "RoleLastUsed": {}
    }
}
Does the assume role document (trust policy) contain the ARN for the user that is allowed to assume the role?
Ctrl-C to exit. Enter to continue.

Note: I should change the above to grep for the correct user but I’d have to switch to the user account role and then back to the account profile with the cross-account role. Maybe later. For now, you can see the ARN for the user in the user account above.

Get the account number where the user and group exists that can assume the cross account role.

echo "Get the account number of the account where the user and group exists"
useracctnum=$(get_account_number $useraccountname)
echo -e "The user account number is $useracctnum.$m"
read ok

Output:

Get the account number of the account where the user and group exists
The user account number is 222222222222.
Ctrl-C to exit. Enter to continue.

Create a CLI Profile for that account that leverages the default AWS Organizations role.

echo "Create an AWS CLI Profile for the default Organization role in $useraccountname"
echo "Please wait..."
useracctprofile=$(create_org_admin_role_profile $useraccountname)
cliprofile=$(cat ~/.aws/config | grep -i $useracctprofile -A2)
echo -e $cliprofile
echo -e "CLI profile created.$m"
read ok

Output:

Create an AWS CLI Profile for the default Organization role in Sandbox
Please wait...
[profile xxxxxx-Sandbox] region = xxxxxxxx output = json
CLI profile created.
Ctrl-C to exit. Enter to continue.

Check that the user name exists which we are trying to use to assume the role.

echo "Check that user exists in the user account."
testuser=$(aws iam list-users --profile $useracctprofile --output text | grep $userToAssumeRole | cut -f2)
if [ "$testuser" == "" ]; then
  echo -e "$userToAssumeRole does not exist.$m"
else
  echo -e "$testuser exists.$m"
fi
read ok

Output:

Check that user exists in the user account.
arn:aws:iam::222222222222:user/WebAdmin exists.
Ctrl-C to exit. Enter to continue.

Check that the group exists that has permission to assume the role.

echo "Check that the group exits."
testgroup=$(aws iam list-groups --profile $useracctprofile --output text | grep $groupname | cut -f2)
if [ "$testgroup" == "" ]; then
  echo -e "Group: $groupname does not exist in $useraccountname.$m"
else
  echo -e "Group: $testgroup exists in $useraccountname.$m"
fi
read ok

Output:

Check that the group exits.
Group: arn:aws:iam::222222222222:group/XacctWebAdmin exists in Sandbox.
Ctrl-C to exit. Enter to continue.

Check that the user is in the group.

echo "Check that the user is in the group"
group=$(aws iam list-groups-for-user --profile $useracctprofile --user-name $userToAssumeRole --output text | grep $groupname | cut -f2)
if [ "$group" == "" ]; then
  echo -e "Group not found for user.$m"
else
  echo -e "User is in group: $group.$m"
fi
read ok

Output:

Check that the user is in the group
User is in group: arn:aws:iam::222222222222:group/XacctWebAdmin.
Ctrl-C to exit. Enter to continue.

Check the policy with the expected name exists.

policyname=$groupname'GroupPolicy'
echo "Check that the group policy $policyname exists."
echo "Group policies:"
aws iam list-group-policies --profile $useracctprofile --group-name $groupname --output text
#this code should really loop through all policies but I know I only add one policy to groups in this codebase
testpolicy=$(aws iam list-group-policies --profile $useracctprofile --group-name $groupname --output json --query 'PolicyNames[0]')
if [ "$testpolicy" == "null" ]; then
  echo -e "Policy $policyname does not exist for group: $groupname.$m"
else
  echo -e "Policy $testpolicy exists for group $groupname.$m"
fi
read ok

Output:

Check that the group policy XacctWebAdminGroupPolicy exists.
Group policies:
POLICYNAMES     XacctWebAdminGroupPolicy
Policy "XacctWebAdminGroupPolicy" exists for group XacctWebAdmin.
Ctrl-C to exit. Enter to continue.

Check that the policy has the expect role ARN in the policy.

echo "Evaluate the policy"
aws iam get-group-policy --profile $useracctprofile --policy-name $policyname --group-name $groupname
testpolicy=$(aws iam get-group-policy --profile $useracctprofile --policy-name $policyname --group-name $groupname | grep $rolename)
if [ "$testpolicyrole" == "" ]; then
  echo -e "Role name $rolename not found in policy.$m"
else
  echo -e "Role name $rolename found in policy.$m"
fi
read ok

This is where I found my error. The ARN in my group policy was not correct.

❌ ❗ ️‼️ ⚠️

Incorrect Output ~ it shows that the ARN in this policy does not have the correct group name. I had to modify the code that creates the GroupPolicy or more accurately the code that passes the role name to the GroupPolicy CloudFormation Template.

Evaluate the policy
{
    "GroupName": "XacctWebAdmin",
    "PolicyName": "XacctWebAdminGroupPolicy",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Condition": {
                    "Bool": {
                        "aws:MultiFactorAuthPresent": "true"
                    }
                },
                "Action": "sts:AssumeRole",
                "Resource": "arn:aws:iam::222222222222:role/XacctWebAdmin",
                "Effect": "Allow"
            }
        ]
    }
}
Role name XacctWebAdminGroup not found in policy.
Ctrl-C to exit. Enter to continue.

The first thing I did was create an init_vars.sh file and moved all the variables used by different scripts to one place to a.) reduce code and b.) ensure the assignments were consistent.

That simplified my two scripts that create the IAM user, group, and cross-account role.

I modified the deploy_group function to pass in an account number if deploying cross-account role and pass it through when deploying the policy.

The group policy function passes the account number, if it exists, as a parameter to the template.

The group policy template now users the remote account number in the ARN if it is provided.

Along the way I spent way too long on this:

After getting that working, I ran my test again.

Output:

OK: Role name XacctWebAdminGroup found in policy.
Ctrl-C to exit. Enter to continue.

Check for acctnum in policy
OK: Correct account number found in policy.
Ctrl-C to exit. Enter to continue.

Check for ARN in policy.
OK: Policy contains correct ARN.
Ctrl-C to exit. Enter to continue.

The policy passes validation.

Now I can run the code that has the WebAdmin assume the new cross account role in SandBox-Web and creates a CLI profile.

echo "Create a cross account CLI Profile for $rolename"
create_cross_account_role_profile $targetacctnum $rolename $roleprofile
cliprofile=$(cat ~/.aws/config | grep -i $roleprofile -A2)
echo -e $cliprofile
echo -e "CLI profile created.$m"
read ok

#TODO: need a mechanism to remove the role profile

Output:

Create a cross account CLI Profile for XacctWebAdminGroup
Enter mfa token
XXXXXX
XacctWebAdminGroup
[profile XacctWebAdminGroup] region = xxxxxx output = json
CLI profile created.
Ctrl-C to exit. Enter to continue.

I have two other functions to test but this took long enough. These functions add the credentials to environment variables instead of a role profile. The second function removes the environment variables so those credentials don’t override others when the user is done using a particular role.

### TEST ASSUME ROLE WITH ENVIRONMENT VARS ###
#assume a role and add the credentials as environment vars
assume_cross_account_role $accountname $roleprofile
echo "Assume role and add credentials to environent vars ok? Ctrl-C to exit."
read ok
#remove credentials from env vars or they will override other auth methods
stop_assume_cross_account_role
echo "Have the credentials been removed from environment variables?"
echo "Done."

Output: I still need to thest this one.

Phew!

Here’s the whole script as it stands at the time of this writing.

I’ll check it in after I finish testing those last two role assumption functions.

Follow for updates.

Teri Radichel | © 2nd Sight Lab 2023

About Teri Radichel:
~~~~~~~~~~~~~~~~~~~~
⭐️ Author: Cybersecurity Books
⭐️ Presentations: Presentations by Teri Radichel
⭐️ Recognition: SANS Award, AWS Security Hero, IANS Faculty
⭐️ Certifications: SANS ~ GSE 240
⭐️ Education: BA Business, Master of Software Engineering, Master of Infosec
⭐️ Company: Penetration Tests, Assessments, Phone Consulting ~ 2nd Sight Lab
Need Help With Cybersecurity, Cloud, or Application Security?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
🔒 Request a penetration test or security assessment
🔒 Schedule a consulting call
🔒 Cybersecurity Speaker for Presentation
Follow for more stories like this:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
❤️ Sign Up my Medium Email List
❤️ Twitter: @teriradichel
❤️ LinkedIn: https://www.linkedin.com/in/teriradichel
❤️ Mastodon: @teriradichel@infosec.exchange
❤️ Facebook: 2nd Sight Lab
❤️ YouTube: @2ndsightlab
Cross Account Role
AWS
Troubleshooting
Testing
Iam
Recommended from ReadMedium