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
Submission: On October 10 via manual from US — Scanned from DE
Form analysis
1 forms found in the DOMGET 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 & 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