Showing posts with label iam. Show all posts
Showing posts with label iam. Show all posts

Friday, April 7, 2023

Crib Notes: Assuming a Role

Several of my current customers leverage AWS IAM's role-assumption capability. In particular, one of my customers leverages it for automating the execution of the Terragrunt-based IaC. For the automated-execution, they run the Terragrunt code from an EC2 that has an attached IAM role that allows code executed on the hosting-EC2 to assume roles in other accounts.

Sometimes, when writing updates to their Terragrunt code, it's helpful to be able to audit the target account's state before and after the execution, but outside the context of Terragrunt, itself. In these cases, knowing how to use the AWS CLI to switch roles can be quite handy. A quick one-liner template for doing so looks like:

$ eval "$(
  aws sts assume-role \
    --role-arn "arn:<AWS_PARTITION>:iam::<TARGET_ACCOUNT_NUMBEr>:role/<TARGET_ROLE_NAME>" \
    --role-session-name <userid> --query 'Credentials' | \
  awk '/(Key|Token)/{ print $0 }' | \
  sed -e 's/",$/"/' \
      -e 's/^\s*"/export /' \
      -e 's/": "/="/' \
      -e 's/AccessKeyId/AWS_ACCESS_KEY_ID/' \
      -e 's/SecretAccessKey/AWS_SECRET_ACCESS_KEY/' \
      -e 's/SessionToken/AWS_SESSION_TOKEN/'
)"

What the above does is:

  1. Opens a subshell to execute a series of commands in
  2. Executes `aws sts assume-role` to fetch credentials, in JSON format, for accessing the target AWS account as the target IAM role
  3. Uses `awk` to select which parts of the prior command's JSON output to keep (`grep` or others are likely more computationally-efficient, but you get the idea)
  4. Uses `sed` to convert the JSON parameter/value pair-strings into BASH-compatible environment-variable delcarations
  5. Uses `eval` to take the output of the subshell and read it into the current shell's environment
Once this is executed, your SHELL will grant you privileges to execute commands in the target account – be that using the AWS CLI or any other tool that understands the "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY" and "AWS_SESSION_TOKEN" environment variables.

Using `aws sts get-caller-identity` will allow you to see your new IAM role.

Wednesday, July 21, 2021

What Permissions Do I Need

 In recent months, I've been converting some automation I originally wrote under CloudFormation to instead work under Terraform. Ultimately, the automation I wrote is going to be used in a different account than I (re)developed it in. As part of the customer's "least-privileges" deployment model, I needed to be able to specify to them all of the specific AWS IAM permissions that my TerraForm-based automation would need. Since the development account I've been working in doesn't provide me CloudTrail or other similarly-useful access, I had to find another way. Turns out, that "another way" is effectively built into Terraform, itself!

When one uses the TF_LOG=trace environment-variable, the activity-logging becomes very verbose. Burried amongst the storm of output is all of the IAM permissions that Terraform needs in order to perform its deployment, configuration and removal actions. Extracting it all was a matter of:

  1. Execute a `terraform apply` using:
      TF_LOG=trace terraform apply -autoapprove > apply.log
  2. Execute a `terraform apply` using:
      TF_LOG=trace terraform apply --autoapprove \
        -refresh-only > refresh.log
    `
  3. Execute a `terraform apply` using:
      TF_LOG=trace terraform destroy -autoapprove > destroy.log
Once each of the above completes successfully, one has three looooong output files. To extract the information (and put it in a format IAM administrators are more used to), a simple set of filters can be applied:

cat *.log | \
grep 'DEBUG: Request ' | \
sed -e 's/.*: Request//' \
    -e 's/ Details:.*$//' \
    -e 's#/#:#' | \
sort -u
This filter-set gives you a list that looks something like:
ec2:AuthorizeSecurityGroupEgress
 ec2:AuthorizeSecurityGroupIngress
 ec2:CreateSecurityGroup
 ec2:DescribeImages
 ec2:DescribeInstanceAttribute
 ec2:DescribeInstanceCreditSpecifications
 ec2:DescribeInstances
 ec2:DescribeSecurityGroups
 ec2:DescribeTags
 ec2:DescribeVolumes
 ec2:DescribeVpcs
 ec2:RevokeSecurityGroupEgress
 ec2:RunInstances
 elasticloadbalancing:AddTags
 elasticloadbalancing:CreateListener
 elasticloadbalancing:CreateLoadBalancer
 elasticloadbalancing:CreateTargetGroup
 elasticloadbalancing:DescribeListeners
 elasticloadbalancing:DescribeLoadBalancerAttributes
 elasticloadbalancing:DescribeLoadBalancers
 elasticloadbalancing:DescribeTags
 elasticloadbalancing:DescribeTargetGroupAttributes
 elasticloadbalancing:DescribeTargetGroups
 elasticloadbalancing:ModifyLoadBalancerAttributes
 elasticloadbalancing:ModifyTargetGroup
 elasticloadbalancing:ModifyTargetGroupAttributes
 elasticloadbalancing:SetSecurityGroups
 s3:GetObject
 s3:ListObjects
Which you can then pass on to the parties that set up your IAM roles.

Saturday, April 6, 2019

Crib-Notes: Tracing Permissions for an Instance Role That Uses Inline Policies

The rationale for this crib-note is essentially identical to that for the previous topic on tracing IAM permissions in instance-roles that use managed-policies. So I'm just going to crib the rest of the intro...

When working with AWS EC2 instances – particularly when automating the deployments and lifecycles thereof – it's common to make use of the AWS IAM system's Instance Role Policy feature. Occasionally, you might get asked, "what permissions have been given to that instance." To answer, you might use AWS's IAM web console or the IAM CLI. In the former case, to get the information to the requestor, you're left with the options of either taking screen-shots or trying to copy and paste the text from the UI to your email/slack/etc. reply. In the latter case, you can just dump out the JSON-formatted policy-document that enumerates the permissions.

Generally, I prefer the CLI option since I don't have to worry "what does the recipient need to do with the results". Just dumping a text file, I needn't worry about being yelled at that the contents of a screen-shot can't be used to easily create another, similar policy. It's also easy to simply redirect the output to a file and attach it to whatever media I'm responding to ...or, if mail is enabled within the CLI environment, simply pipe the output directly to a CLI-based email tool and save a step in the process (laziness for the win!).

But, how to go from "there's an instance in this account: what privileges does it have" to "here's what it can do?". Basically, it's a three-step process:

  1. Get the name of the Instance Role attached to the EC2 instance. This can be done with a method similar to:

    $ aws ec2 describe-instances --instance-id <INSTANCE_ID> \
          --query 'Reservations[].Instances[].IamInstanceProfile[].Arn[]' --out text | \
      sed 's/^.*arn:.*profile\///'

  2. Get th list of inline policies attached to role. This can be done with a method similar to:

    $ aws iam list-role-policies --role-name <OUPUT_FROM_PREVIOUS>

  3. Get the list of permissions associated with the instance role's inline policy/policies. This can be done with a method similar to:

    $ aws iam get-role-policy --role-name INSTANCE --policy-name <OUPUT_FROM_PREVIOUS>

The above steps will dump out the full IAM policy/permissions of the queried inline policy:

  • If the inline policy was the only policy attached to the role, the output will show all of the permissions the instance role grants any EC2s it is attached to.
  • If the inline policy was the not the only inline policy attached to the role, it will be necessary to iterate over the remaining policies attached to the role to get the aggregated permission-set.
To facilitate the iteration, one can use a script similar to the following to encapsulate the second and third steps from prior process description:


#!/bin/bash
#
# Script to dump out all permissions granted through an IAM role with multiple
# inline IAM policies attached.
###########################################################################

if [[ $# -eq 0 ]]
then
   echo "Usage: ${0} <instance-id>" >&2
   exit 1
fi

PROFILE_NAME=$( aws ec2 describe-instances --instance-id "${1}" \
   --query 'Reservations[].Instances[].IamInstanceProfile[].Arn' --out text | \
  tr '\t' '\n' | sort -u | sed 's/^.*arn:.*profile\///' )

POLICY_LIST_RAW=$( aws iam list-role-policies --role-name ${PROFILE_NAME} )
POLICY_LIST_CLN=($( echo ${POLICY_LIST_RAW} | jq .PolicyNames[] | sed 's/"//g' ))

for ITER in $( seq 0 $(( ${#POLICY_LIST_CLN[@]} - 1 )) )
do
  aws iam get-role-policy --role-name "${PROFILE_NAME}" \
    --policy-name "${POLICY_LIST_CLN[${ITER}]}"
done

Friday, April 5, 2019

Crib-Notes: Tracing Permissions for an Instance Role That Uses Managed Policies

When working with AWS EC2 instances – particularly when automating the deployments and lifecycles thereof – it's common to make use of the AWS IAM system's Instance Role Policy feature. Occasionally, you might get asked, "what permissions have been given to that instance." To answer, you might use AWS's IAM web console or the IAM CLI. In the former case, to get the information to the requestor, you're left with the options of either taking screen-shots or trying to copy and paste the text from the UI to your email/slack/etc. reply. In the latter case, you can just dump out the JSON-formatted policy-document that enumerates the permissions.

Generally, I prefer the CLI option since I don't have to worry "what does the recipient need to do with the results". Just dumping a text file, I needn't worry about being yelled at that the contents of a screen-shot can't be used to easily create another, similar policy. It's also easy to simply redirect the output to a file and attach it to whatever media I'm responding to ...or, if mail is enabled within the CLI environment, simply pipe the output directly to a CLI-based email tool and save a step in the process (laziness for the win!).

But, how to go from "there's an instance in this account: what privileges does it have" to "here's what it can do?" Basically, it's a four-step process:

  1. Get the name of the Instance Role attached to the EC2 instance. This can be done with a method similar to:
    $ aws ec2 describe-instances --instance-id <INSTANCE_ID> \
        --query 'Reservations[].Instances[].IamInstanceProfile[].Arn[]' --out text | \
      sed 's/^.*arn:.*profile\///'
    $ aws iam get-instance-profile --instance-profile-name <OUPUT_FROM_PREVIOUS> \
        --query 'InstanceProfile.Roles[].RoleName' --out text
     
  2. Get list of policies attached to role. This can be done with a method similar to:
    aws iam list-attached-role-policies --role-name <OUPUT_FROM_PREVIOUS> \
        --query 'AttachedPolicies[].PolicyArn[]' --out text
     
  3. Find current version of attached policy/policies. Thi can be done with a method similar to:
    aws iam get-policy --policy-arn <OUPUT_FROM_PREVIOUS> \
        --query 'Policy.DefaultVersionId' --out text
    
  4. Get contents of attached policy/policies active version. This can be done – using the outputs from steps #2 and #3 – with a method similar to:
    aws iam get-policy-version --policy-arn <OUPUT_FROM_STEP_2> \
         --version-id <OUPUT_FROM_STEP_3>
     
The above steps will dump out the full IAM policy/permissions of the queried managed-policy:
  • If the inline policy was the only policy attached to the role, the output will show all of the permissions the instance role grants any EC2s it is attached to.
  • If the inline policy was the not the only inline policy attached to the role, it will be necessary to iterate over the remaining policies attached to the role to get the aggregated permission-set.
To facilitate the iteration, one can use a script similar to the following to encapsulate the steps from prior process description:

#!/bin/bash
#
# Script to dump out all permissions granted through an IAM role with multiple
# managed IAM policies attached.
###########################################################################

if [[ $# -eq 0 ]]
then
   echo "Usage: ${0} <instance-id>" >&2
   exit 1
fi

PROFILE_NAME="$( aws ec2 describe-instances --instance-id "${1}" \
  --query 'Reservations[].Instances[].IamInstanceProfile[].Arn[]' \
  --out text | sed 's/^.*arn:.*profile\///' )"
ROLE_NAME="$( aws iam get-instance-profile \
  --instance-profile-name "${PROFILE_NAME}" \
  --query 'InstanceProfile.Roles[].RoleName' \
  --out text | sed 's/^.*arn:.*profile\///' )"
ATTACHED_POLICIES=($( aws iam list-attached-role-policies \
  --role-name "${ROLE_NAME}" --query 'AttachedPolicies[].PolicyArn[]' | \
  jq .[] | sed 's/"//g' ))

for ITER in $( seq 0 $(( ${#ATTACHED_POLICIES[@]} - 1 )) )
do
   POLICY_VERSION=$( aws iam get-policy --policy-arn \
     ${ATTACHED_POLICIES[${ITER}]} --query \
     'Policy.DefaultVersionId' --out text )
   aws iam get-policy-version --policy-arn ${ATTACHED_POLICIES[${ITER}]} \
     --version-id "${POLICY_VERSION}"
done