blog.revolve.team Open in urlscan Pro
13.32.121.33  Public Scan

URL: https://blog.revolve.team/2023/09/21/5-things-about-aws-iam/
Submission: On October 10 via manual from US — Scanned from DE

Form analysis 1 forms found in the DOM

GET https://blog.revolve.team/

<form action="https://blog.revolve.team/" method="get">
  <input type="text" name="s" class="form-control" value="" placeholder="Taper votre recherche &amp; appuyez sur entrer...">
</form>

Text Content

 * Automation
 * Data/ML
 * Sécurité
 * People
 * Migration
 * Références
 * Contact
 * Site web




5 THINGS YOU MAY NOT KNOW ABOUT AWS IAM

 * 21 septembre 2023
 * Jérémie Rodon
 * Sécurité

Temps de lecture : 12 minutes

When it comes to AWS IAM I recall a time, after less than 2 years of experience,
when I told myself: “that’s it, I have nothing more to learn about how it
works”. And since then, I learned new things and told myself the exact same
thing over and over again.

AWS IAM is the gift that keeps on giving, so here are the TOP5 IAM facts that
took me ages to figure out! And you, do you know them all?

NB: In this blog post, I assume that you already have a good working knowledge
of AWS IAM. Terms like identity-based policies, resource-based policies, Service
Control Policies (SCP), Statements, etc… will be thrown around with little to no
explanation.


SCPS ARE NOT INHERITED LIKE YOU WOULD EXPECT THEM TO BE

I learned this one the hard way: by breaking 200+ AWS accounts of my company’s
AWS Organization, a few years ago, during the 25 very long minutes it took me to
figure out my mistake.

As an illustrative example, imagine you want AWS accounts of your organisation
to use only the EC2 service, except for some AWS accounts that can also use S3.
Given this use case, you could be tempted to use a SCP allowing only EC2 at the
root of your AWS Organization, with an Organizational Unit (OU) allowing S3
(with the appropriate SCP), like that:

NB: DO NOT do that

After all, the AWS Organizations console seems to make it very clear that there
is inheritance between the OUs. After creating this configuration (please
don’t), you look at the Service Control Policies of ou-allow-s3 and you see
that:

Apparently, ou-allow-s3 inherits the only-ec2 SCP from Root, as expected. So you
can legitimately assume that any account placed inside this OU (such as AWS
account #3) will have access to both EC2 and S3, right?

But the reality is that you have access to neither:

In fact, you don’t have any access at all in this account. As often, the console
display is misleading: in reality, there is no inheritance at all, that is just
not how SCP works.

The evaluation of AWS Organizations Service Control Policies works as follows:

 1. For any given API call, consider all the SCP directly attached to the AWS
    account itself and verify that the call is allowed; then
 2. Consider all the SCP directly attached to the parent OU and verify that the
    call is allowed; then
 3. Repeat until there is no more parent (the root of the Organization has been
    reached).

Given that evaluation process, we understand why no service is accessible in the
AWS account #3 of our example schema:

 * If we try to access something that is not S3, the call is denied because at
   the level of ou-allow-s3 only S3 is allowed by the SCP;
 * If we try to access something that is not EC2, the call is denied because at
   the level of the root only EC2 is allowed by the SCP.

And of course, any AWS API call will fall either into the “not S3” and/or the
“not EC2” category and therefore will be denied.

If you really want this use-case to work, you must restrict services as you go
down in the hierarchy, which is very counter-intuitive:

But intuitive or not, this is just how AWS Organizations SCP works.

Note that you now understand why AWS automatically directly attaches the default
FullAWSAccess SCP to every AWS accounts and every OU of your AWS Organizations
and then asks you to work by only adding SCP that Deny things: it forces you to
conceive your AWS Organization by thinking “further down further restrict”;
which is the only way it can work anyway.


RESOURCE POLICIES CAN GIVE PERMISSIONS BY THEMSELVES

You have an AWS account with an IAM Role and a S3 bucket. The IAM role is called
role-without-policy and does not have any policy attached or inlined. The S3
bucket has a bucket policy that gives role-without-policy the permission to call
s3:GetObject.

Question: in that situation, can you successfully perform a GetObject on the
bucket using the role?

In that particular case, yes you can!

But if I ask in general if a resource-based policy alone can give permissions,
it depends. If you look at the IAM evaluation process in the AWS documentation,
you find this schema:

It is not very helpful for our question because an “Allow” inside a
Resource-based policy leads to an orange box. The AWS documentation provides a
confusing table to explain this “orange box”, which can be translated into this
decision flowchart:

First note that the behaviour depends on whether or not the Principal making the
request is in the same AWS account as the Resource.

If the Principal and the Resource are in different AWS accounts, the
resource-based policy of the Resource is necessary but not sufficient to give
permissions.

But when the Principal and the Resource are in the same AWS account, things get
interesting and depend on the nature of the Principal (IAM User, Role session or
Federated session) and how it is referenced in the resource-based policy (what
Principal ARN is written in the policy). If the resource-based policy references
an IAM User or an IAM Session (assumed-role for example), it will even bypass
the boundary and session policies evaluation!


NOTPRINCIPAL EVALUATION MAY NOT DO WHAT YOU EXPECT

You have a S3 bucket example-bucket filled with security information and you
want to ensure that only the IAM role role-security is allowed to access that
bucket. As you are an advanced AWS IAM user, you know about the possibility to
use NotPrincipal in a policy statement, so you write a bucket policy saying:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "NotPrincipal": {
        "AWS": [
          "arn:aws:iam::123456789012:role/role-security"
        ]
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::example-bucket/*"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::123456789012:role/role-security"
        ]
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::example-bucket/*"
    }
  ]
}



Seems legit, right? But when you try to perform a GetObject using the
role-security role, it fails with an explicit deny.

Well, when evaluating permissions for a Session (an assumed-role), the IAM
engine checks for two distinct Principal ARNs:

 * The role ARN: arn:aws:iam::<account>:role/<role-name>

 * The session ARN:
   arn:aws:sts::<account>:assumed-role/<role-name>/<session-name>

Therefore, the Deny statement of the bucket policy with:

"NotPrincipal": {
  "AWS": [
    "arn:aws:iam::123456789012:role/role-security"
  ]
}

ignores the Role ARN, as expected, but matches the Session ARN and applies.
That’s why it does not work!

If you want this use-case to work, you must choose in advance a session name,
let’s say secu, and write the following bucket policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "NotPrincipal": {
        "AWS": [
          "arn:aws:iam::123456789012:role/role-security",
          "arn:aws:sts::123456789012:assumed-role/role-security/secu"
        ]
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::example-bucket/*"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::123456789012:role/role-security"
        ]
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::example-bucket/*"
    }
  ]
}

As long as you assume the role with secu as session name, it will work as
expected. Of course, it is not convenient to have to set the session name in
advance, but unfortunately wildcards are not allowed in Principals so there is
no alternative.


A PERMISSION CAN BE GRANTED BY A COMBINATION OF STATEMENTS

In order to introduce the concept, let’s begin with a question. You are using an
IAM role which only has this policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ec2:RunInstances",
      "Resource": "arn:aws:ec2:*:*:instance/*"
    }
  ]
}

Can you use RunInstances to launch a new EC2 instance?

Since I asked, you probably guessed that there is a catch! No, you can’t launch
an EC2 instance with this policy alone. If we read the AWS documentation on EC2
actions, we can see for each action what resources are expected and which ones
are mandatory (they end with a star). For RunInstances, there are multiple
mandatory resources:

 * image
 * instance
 * network-interface
 * security-group
 * subnet
 * volume

In order for a policy to grant the RunInstances permission, it must allow it on
each of these resources, therefore our previous example is not complete.

In order to grant RunInstances, the three following policies are valid:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ec2:RunInstances",
      "Resource": "*"
    }
  ]
}

Of course, simply using a wildcard as Resource will work, as it matches all
resource types.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ec2:RunInstances",
      "Resource": [
        "arn:aws:ec2:*:*:instance/*",
        "arn:aws:ec2:*:*:image/*",
        "arn:aws:ec2:*:*:network-interface/*",
        "arn:aws:ec2:*:*:security-group/*",
        "arn:aws:ec2:*:*:subnet/*",
        "arn:aws:ec2:*:*:volume/*"
      ]
    }
  ]
}

Also, listing every mandatory resources ARN format will work.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ec2:RunInstances",
      "Resource": [
        "arn:aws:ec2:*:*:instance/*",
        "arn:aws:ec2:*:*:image/*",
        "arn:aws:ec2:*:*:network-interface/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "ec2:RunInstances",
      "Resource": [
        "arn:aws:ec2:*:*:security-group/*",
        "arn:aws:ec2:*:*:subnet/*",
        "arn:aws:ec2:*:*:volume/*"
      ]
    }
  ]
}

And finally, listing mandatory resource ARNs in different statements also works!
You could argue that this last one is just a pointless curiosity, but there is a
family of use-cases where it is unavoidable: tags conditions!

Let’s imagine you want to allow RunInstances if and only if the AMI is tagged
“ccoe-approved: true”. You could naively write this policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ec2:RunInstances",
      "Resource": "*",
      "Condition": {
        "StringEquals": {
           "aws:ResourceTag/ccoe-approved": "true"
        }
      }
    }
  ]
}

But it will fail! For this statement to apply, you would need to tag with
“ccoe-approved: true” every mandatory resources for RunInstances (the subnet,
the security group, etc…), but that is not what you want. You want the tag to be
required only on the AMI. Therefore you have to write this policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ec2:RunInstances",
      "Resource": "arn:aws:ec2:*:*:image/*",
      "Condition": {
        "StringEquals": {
           "aws:ResourceTag/ccoe-approved": "true"
        }
      }
    },
    {
      "Effect": "Allow",
      "Action": "ec2:RunInstances",
      "Resource": [
        "arn:aws:ec2:*:*:instance/*",
        "arn:aws:ec2:*:*:network-interface/*",
        "arn:aws:ec2:*:*:security-group/*",
        "arn:aws:ec2:*:*:subnet/*",
        "arn:aws:ec2:*:*:volume/*"
      ]
    }
  ]
}

And it works as expected! You need to split the permission in two separate
statements:

 * one with a condition to allow RunInstances on the image resource only if it
   is adequately tagged;
 * one to allow RunInstances on the other mandatory resources without condition.

Of course, more advanced use-cases could require to split the permission into
even more statements.


KMS GRANTS ARE LIKE DETACHED RESOURCE POLICY STATEMENTS

There is a particular use-case that is very enlightening on the profound nature
of KMS grants. Before we dive into it, let’s do a quick reminder about grants.

Imagine that you have an EC2 instance with an EBS volume encrypted by some KMS
key. I suppose you know that you must have permissions on the KMS key in order
to start the instance. But there is something strange here: it is not really you
who will decrypt the EBS volume, it is the EC2 instance, right? So how does it
work?

When you use StartInstances, the EC2 service will forward a request to KMS in
your name. But not a Decrypt: a CreateGrant! By starting the EC2 instance, you
will also create a KMS Grant for the instance, giving it the permission to call
Decrypt, and then the instance itself will call Decrypt. This sequence is
clearly visible in CloudTrail:

It is also possible to list currently existing grants on a KMS key, but only
through the CLI (or some SDK). We can see the resulting grant from the
CreateGrant of the previous screenshot:

GranteePrincipal is the Principal being granted the Operations, here the EC2
instance is granted the permission to Decrypt, with a constraint on the
EncryptionContext (grant constraints are like statement conditions).

Also note there is a RetiringPrincipal that has the permission to remove the
grant, here it is the EC2 service.

There is also info about the IssuingAccount, which is just my account here. We
will come back to this one

Now it is time to dive into a specific use-case. You have a KMS key in the
Security account, and you want to use it to protect EBS volumes in the Project
account for EC2 instances launched by an Autoscaling Group (ASG).

Note that it is not even far fetched: KMS keys centralization in a central
security account is not a recommendation I would make, but it is reasonably
common nonetheless; and ASGs are of course used a lot, with good reasons.

So, how do we make it work? KMS Keys have a resource-based policy: the Key
policy. We can use it to give permissions to the Project account, but we are in
a cross-account scenario: a resource-based policy cannot give permissions by
itself, the identity-based policy of the ASG in Project account must also allow
KMS operations. And there we got a problem: autoscaling groups use an IAM
service-role that does not have any KMS permission and we cannot change its
policies! What can we do? Grant.

Here is how we do it with the Security account being 111122223333 and the
Project account 444455556666:

First, we use the Key policy to allow the Project account to manage grants on
the key by adding this statement:

{
  "Sid": "Allow grant",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::444455556666:root"
  },
  "Action": [
    "kms:CreateGrant",
    "kms:RevokeGrant",
    "kms:ListGrants"
  ],
  "Resource": "*"
}

NB: We only need CreateGrant, but List/Revoke eases the cleanup after your test.

Then, we use a CLI AccessKey/SecretKey of an IAM User or Role inside the Project
account that also has the CreateGrant permission on its identity-based policy.
We are able to use CreateGrant cross-account because both our identity-based
policy and the resource-based policy of the key allow it.

Our CLI interaction looks like that:

$># We are in the Project account
$> aws sts get-caller-identity
{
    "UserId": "AIDAEXAMPLEEXAMPLE",
    "Account": "444455556666",
    "Arn": "arn:aws:iam::444455556666:user/jrodon"
}
$># From the Project account we create the grant
$> aws kms create-grant --key-id arn:aws:kms:eu-west-1:111122223333:key/51b0ad7a-aaaa-bbbb-cccc-dddddddddddd --grantee-principal arn:aws:iam::444455556666:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling --operations "Decrypt" "GenerateDataKeyWithoutPlaintext" "DescribeKey" "CreateGrant"
{
    "GrantToken": "<blablabla>",
    "GrantId": "aabbccddeeff"
}
$># We can see it
$> aws kms list-grants --key-id arn:aws:kms:eu-west-1:111122223333:key/51b0ad7a-aaaa-bbbb-cccc-dddddddddddd
{
  "Grants": [
    {
      "KeyId": "arn:aws:kms:eu-west-1:111122223333:key/51b0ad7a-aaaa-bbbb-cccc-dddddddddddd",
      "GrantId": "aabbccddeeff",
      "Name": "",
      "CreationDate": "2023-07-25T14:16:43+02:00",
      "GranteePrincipal": "arn:aws:iam::444455556666:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling",
      "IssuingAccount": "arn:aws:iam::444455556666:root",
      "Operations": [
        "Decrypt",
        "GenerateDataKeyWithoutPlaintext",
        "CreateGrant",
        "DescribeKey"
      ]
    }
  ]
}

Pay attention to the IssuingAccount of the grant: because we created it using a
principal of the Project account, the IssuingAccount is the Project Account!
Therefore, from the grant perspective, it is no longer a cross-account scenario:
the principal being granted is in the same AWS account as the grant itself! And
that’s it: as long as this grant exists, it is sufficient to give the ASG role
permissions to use the KMS key (and launch encrypted EC2 instances), even if the
role itself does not have any KMS permissions!

And that was my TOP5 non-obvious facts about AWS IAM!



COMMENTAIRES :



A LIRE ÉGALEMENT SUR LE SUJET :

NE PARTEZ PAS AVEC MES DONNÉES: JE VOUS RET...

 * 20 juillet 2020

Un article spécial RH, commerciaux et publicitaires aujourd’hui. En effet, il
a...

COMMENT FAIRE PASSER SON SITE WEB HÉBERGÉ S...

 * 28 mai 2018

Ce matin c’est la panique dans le bureau, Jean-René de l’équipe commerciale a
la...

LA SOUVERAINETÉ DANS LE CLOUD PAR LE CHIFFR...

 * 03 novembre 2022

Dans la première partie de cette série d'articles, nous avons considéré
Soverei...

AWS RE:INFORCE, LA SÉCURITÉ AU COEUR DU CLO...

 * 22 juillet 2019

Si la sécurité du Cloud a toujours fait partie de l’agenda d’AWS, le sujet
béné...

A PROPOS DE L'AUTEUR

JÉRÉMIE RODON

Passionné de sciences en général et particulièrement de physique et
d'astronomie, Jérémie baigne dans l'informatique depuis l'âge de 12 ans. Son
background d'administration système et de scripting en Powershell l'a
naturellement amené vers le cloud AWS. Jérémie est également AWS Community Hero
et formateur AWS.


LE BLOG REBIRTH

Nous luttons contre les raccourcis intellectuels, proposons des alternatives,
challengeons les pratiques, partageons nos expériences et provoquons une
réaction. En ce sens nous ENTREPRENONS et révélons les singularités.




ARTICLES RÉCENTS

 * Allowing a Gitlab project pipeline to pull another project
 * Revolve Job Zero : la revue de presse sécurité – Octobre 2023
 * Explorons les boucles CloudFormation
 * Deeptimize : une infrastructure full serverless sur le Cloud AWS pour booster
   l’analyse vidéo du sport par l’IA
 * 5 things you may not know about AWS IAM
 * Securing remote work with AWS Appstream


We use cookies on our website to give you the most relevant experience by
remembering your preferences and repeat visits. By clicking “Accept All”, you
consent to the use of ALL the cookies. However, you may visit "Cookie Settings"
to provide a controlled consent.
Cookie SettingsAccept All
Manage consent
Fermer

PRIVACY OVERVIEW

This website uses cookies to improve your experience while you navigate through
the website. Out of these, the cookies that are categorized as necessary are
stored on your browser as they are essential for the working of basic
functionalities of the ...
Necessary
Necessary
Toujours activé
Necessary cookies are absolutely essential for the website to function properly.
These cookies ensure basic functionalities and security features of the website,
anonymously.

CookieDuréeDescriptioncookielawinfo-checkbox-analytics11 monthsThis cookie is
set by GDPR Cookie Consent plugin. The cookie is used to store the user consent
for the cookies in the category "Analytics".cookielawinfo-checkbox-functional11
monthsThe cookie is set by GDPR cookie consent to record the user consent for
the cookies in the category "Functional".cookielawinfo-checkbox-necessary11
monthsThis cookie is set by GDPR Cookie Consent plugin. The cookies is used to
store the user consent for the cookies in the category
"Necessary".cookielawinfo-checkbox-others11 monthsThis cookie is set by GDPR
Cookie Consent plugin. The cookie is used to store the user consent for the
cookies in the category "Other.cookielawinfo-checkbox-performance11 monthsThis
cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the
user consent for the cookies in the category
"Performance".viewed_cookie_policy11 monthsThe cookie is set by the GDPR Cookie
Consent plugin and is used to store whether or not user has consented to the use
of cookies. It does not store any personal data.

Functional
Functional
Functional cookies help to perform certain functionalities like sharing the
content of the website on social media platforms, collect feedbacks, and other
third-party features.
Performance
Performance
Performance cookies are used to understand and analyze the key performance
indexes of the website which helps in delivering a better user experience for
the visitors.
Analytics
Analytics
Analytical cookies are used to understand how visitors interact with the
website. These cookies help provide information on metrics the number of
visitors, bounce rate, traffic source, etc.
Advertisement
Advertisement
Advertisement cookies are used to provide visitors with relevant ads and
marketing campaigns. These cookies track visitors across websites and collect
information to provide customized ads.
Others
Others
Other uncategorized cookies are those that are being analyzed and have not been
classified into a category as yet.
Enregistrer & appliquer





Nous travaillons en partenariat avec les Directions Informatiques pour les
accompagner dans leur transformation numérique. Spécialistes du Cloud et du
Devops, nos consultantes et consultants travaillent en équipe parce que
favoriser l’intelligence collective est le meilleur moyen de faire bouger les
lignes. Les équipes Revolve posent ainsi les bases de nouvelles méthodes de
travail et de collaboration au travers des prestations d'adoption des
technologies Cloud et BigData.

NOS LIENS UTILES

 * Site Devoteam Revolve
 * Devoteam Revolve sur Twitter
 * Revolve Toulouse sur Twitter
 * Formations AWS
 * Nos offres d'emploi
 * Téléchargez notre eBook "Data & Machine Learning"

NOS DERNIERS ARTICLES

ALLOWING A GITLAB PROJECT PIPELINE TO PULL ANOTHER PROJECT

 * 05 octobre 2023

EXPLORONS LES BOUCLES CLOUDFORMATION

 * 28 septembre 2023

NUAGE DE TAGS

automation automatisation AWS AWS Lambda big data cloud cloud AWS cloud native
continuous delivery continuous deployment data science dev devops icelab
itinéraire consultant machine learning people RH sécurité TIAD TIAD Paris
événements

En poursuivant votre navigation sur ce site, vous acceptez l’utilisation de
Cookies pour réaliser des statistiques de visites anonymes. OK