<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nicolò Marchesi</title>
    <description>The latest articles on DEV Community by Nicolò Marchesi (@pethron).</description>
    <link>https://dev.to/pethron</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F459989%2F61d0f092-ee00-43ee-9426-517b941e53dd.jpg</url>
      <title>DEV Community: Nicolò Marchesi</title>
      <link>https://dev.to/pethron</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pethron"/>
    <language>en</language>
    <item>
      <title>IAM policies and Service Control Policies (SCPs): How to master and secure access and permissions in an AWS Landing Zone</title>
      <dc:creator>Nicolò Marchesi</dc:creator>
      <pubDate>Mon, 03 Apr 2023 13:51:11 +0000</pubDate>
      <link>https://dev.to/aws-builders/iam-policies-and-service-control-policies-scps-how-to-master-and-secure-access-and-permissions-in-an-aws-landing-zone-37f6</link>
      <guid>https://dev.to/aws-builders/iam-policies-and-service-control-policies-scps-how-to-master-and-secure-access-and-permissions-in-an-aws-landing-zone-37f6</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Hello cloud fellows! Today we’ll build up on the cloud landing zone series to explore a fascinating but often ignored context… Service Control Policies! SCPs are powerful, but there are a few caveats and tricks to make them work efficiently with every different kind of &lt;strong&gt;IAM policy&lt;/strong&gt;. In this blog post, we will see how the whole IAM ecosystem interacts and how we can effectively leverage the tools to deploy a strong IAM strategy in our Cloud Landing Zone.&lt;/p&gt;

&lt;p&gt;There is a lot of ground to cover, so let’s start immediately!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ I don’t want to bother you with all the details about AWS Organizations so that we can keep our focus on permissions. If that’s not the case, refer to one of the thousands of articles on the web or check &lt;a href="https://blog.leapp.cloud/aws-multi-account-structure-with-aws-organization"&gt;THIS&lt;/a&gt; one I wrote.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Policies
&lt;/h2&gt;

&lt;p&gt;So, let’s get the foundations covered (for the laziest of you, skip after the graph, there’s a neat bullet-point recap). Before jumping directly to the interactions, we need to understand what we have at our disposal in our IAM strategy and all the different kind of tools in IAM to make it work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identity-based policies&lt;/strong&gt; are the most common type of policy. They are tied to IAM (Identity and Access Management) users, groups, and roles and specify what actions those entities can perform on certain AWS services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource-based policies&lt;/strong&gt;, on the other hand, are policies that are directly associated with an AWS resource, such as an S3 bucket or an EC2 instance. Resource-based policies specify who has access to the resource and what actions they can take. Not all AWS services support them (for a comprehensive list, check the &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html"&gt;AWS services that work with IAM&lt;/a&gt; page), and they are usually used for very specific scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permission boundaries (PBs)&lt;/strong&gt; are policies that define the maximum permissions that an IAM entity can have. These policies limit an entity's permissions, ensuring they cannot perform actions that exceed their authorized scope. Permission boundaries are also written in AWS policy language and can be attached to IAM entities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service control policies (SCPs)&lt;/strong&gt; enforce restrictions on AWS accounts within an AWS organization. SCPs are hierarchical policies applied to the entire organization or specific organizational units. SCPs can be used to limit the actions that an AWS account can perform, preventing them from performing activities that are outside their authorized scope.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session policies&lt;/strong&gt; are applied to temporary credentials created by IAM roles. Session policies limit the permissions of a temporary credential set, ensuring that it cannot perform actions that exceed its authorized scope. However, they primarily work like PBs and SCPs: they do not grant permissions and are applied only for the duration of the token. For the sake of simplicity, we’ll introduce this only at the end, so for now, let’s not consider it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The caveat
&lt;/h2&gt;

&lt;p&gt;As you may be starting to get, there is a fundamental difference between those policies, and it's laid out in the diagram by the action that connects the policy to the actual permissions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Permission boundaries and Service control policies do NOT grant ANY permission&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An Identity can access a Resource only through Identity-based and Resource-based policies. Permission boundaries and SCPs can only &lt;strong&gt;limit&lt;/strong&gt; the aforementioned permissions. That means we need an Identity-based or Resource-based policy that &lt;strong&gt;explicitly allows&lt;/strong&gt; permission to let the policy evaluation engine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DzytYzwi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qs01e97361jc8mliua2d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DzytYzwi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qs01e97361jc8mliua2d.png" alt="Image description" width="880" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In short, Identity-based and Resource-based policies define who can access resources and what actions they can perform. Permission boundaries and Service Control Policies limit the scope of those permissions, ensuring that entities cannot perform unauthorized actions. &lt;/p&gt;

&lt;h2&gt;
  
  
  A visual representation of policy interaction
&lt;/h2&gt;

&lt;p&gt;So let’s get a visual representation of our policies: start by seeing how it works in a single account, and then see how things change by adding AWS Organizations to the equation.&lt;/p&gt;

&lt;p&gt;Yeah, I know the icons differ from the AWS framework but bear with me; I want to highlight the differences and that we’re working with fundamentally different policies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Single account (without Organizations)
&lt;/h3&gt;

&lt;p&gt;As you can see, the three elements we can leverage are Identity-based, Resource-based policies, and Permission boundaries:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0cpdDYOz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/620xz3u8sfzolsvp12ea.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0cpdDYOz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/620xz3u8sfzolsvp12ea.png" alt="Image description" width="880" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that while the policies going in and out of the Identity and the Resource grants access, the Permission Boundaries limit that set of permission instead.&lt;/p&gt;

&lt;p&gt;It’s impossible to grant additional permissions through the use of Permission Boundaries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Organization structure
&lt;/h3&gt;

&lt;p&gt;When integrating the AWS Organization service, we gain the ability to use Service control policies to have better control over our environment:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Jskmri_H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tr9z0qyhxg6qxdjukgy4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Jskmri_H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tr9z0qyhxg6qxdjukgy4.png" alt="Image description" width="880" height="709"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The behavior is practically the same as Permission Boundaries, but we’ll see soon that it has a slight difference. So, to briefly recap:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS Identity-based policies:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Most common policy type in AWS.&lt;/li&gt;
&lt;li&gt;Attached to IAM entities (users, groups, and roles)&lt;/li&gt;
&lt;li&gt;Specify actions that entities can execute on specific AWS resources&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Goes from Identity to Resource&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Resource-based policies:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Attached to an AWS resource (e.g., S3 bucket or EC2 instance)&lt;/li&gt;
&lt;li&gt;Determine which users have access to the resource&lt;/li&gt;
&lt;li&gt;Define what actions the authorized users can perform on the resource&lt;/li&gt;
&lt;li&gt;Not all AWS services support them&lt;/li&gt;
&lt;li&gt;Used in &lt;strong&gt;very specific&lt;/strong&gt; scenarios&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Goes from Resource to Identity&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permission boundaries:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Attached to IAM entities.&lt;/li&gt;
&lt;li&gt;Defining maximum permissions for an IAM entity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limits&lt;/strong&gt; the entity's permissions to the authorized scope&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service control policies (SCPs):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Hierarchical policies for AWS accounts in an Organization&lt;/li&gt;
&lt;li&gt;Used to restrict the actions of AWS accounts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limits&lt;/strong&gt; activities outside the scope of permissions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session policies:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Used with identity-based policies and permission boundaries&lt;/li&gt;
&lt;li&gt;Applied to temporary credentials of IAM roles&lt;/li&gt;
&lt;li&gt;Limits the permissions of temporary credentials&lt;/li&gt;
&lt;li&gt;Ensures authorized scope is not exceeded&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  The policy evaluation flow
&lt;/h1&gt;

&lt;p&gt;Behind all these definitions, a policy evaluation engine goes through all the policies we have seen before and evaluates if the specific action performed has to be allowed or denied.&lt;/p&gt;

&lt;p&gt;Here I condensed the logic to understand the decision flow better:&lt;/p&gt;

&lt;p&gt;It’s interesting to note that  Resource and Identity-based permissions are evaluated at the center of the evaluation flow. Around them, SCPs and PBs are evaluated, which we clustered in control policies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EjPLMg97--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mu3y0fsj1rmpcm8w42w4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EjPLMg97--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mu3y0fsj1rmpcm8w42w4.png" alt="Image description" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aside from Resource-based and Session policies, it turns out that it’s pretty straightforward; the trick here is to focus on the edge cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  With resource-based policies
&lt;/h3&gt;

&lt;p&gt;Resource-based policies result in a deny when the Principal making the request is different than the Principal we’re granting access to through the Resource-based policy.&lt;br&gt;
I’ve highlighted the affected case in the schema proposed by AWS at this &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CjKwXLmb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94uuwctfn91331el9o7b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CjKwXLmb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94uuwctfn91331el9o7b.png" alt="Image description" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  With session policies
&lt;/h3&gt;

&lt;p&gt;Even in this case, it’s simpler than it looks. Session policies kick in only when they are present.&lt;/p&gt;

&lt;p&gt;If you’re not using them in your request, you shouldn't care, but when the time comes that you’re leveraging them, you need to remember the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;there is no allow → implicit deny&lt;/li&gt;
&lt;li&gt;there is no explicit deny → implicit deny&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  A side note on cross-account access
&lt;/h2&gt;

&lt;p&gt;Until now, we’ve considered only access within the same account, but what would happen if we need to evaluate also cross-account access? It’s simpler than it looks: request is evaluated on policies and permission from the perspective of both the trusted and trusting account and allowed only if both are evaluated as an allow!&lt;/p&gt;

&lt;p&gt;If you think about this, it’s more restrictive than single access. Since AWS permission starts with an implicit deny, you must explicitly set the permissions on both accounts before evaluating the request as an allow.&lt;/p&gt;
&lt;h2&gt;
  
  
  Permission intersections
&lt;/h2&gt;

&lt;p&gt;After understanding what is involved in deciding when a request is allowed, we can move on to how they interact.&lt;/p&gt;

&lt;p&gt;This led to two practical scenarios, one with and one without Resource-based policies. The main point here is to understand that &lt;strong&gt;the only case in which one’s effective permissions can exceed that of the whole intersection is when Resource-based policies are involved.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9_e9nyCT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r9t9f8dcz6y66zbgyhq0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9_e9nyCT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r9t9f8dcz6y66zbgyhq0.png" alt="Image description" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When Resource-based policies are involved, if they evaluate as an allow, you’re taking the final decision before the policy evaluation flow would evaluate Identity-based, Permission Boundaries, and Session policies. This results in permissions granted that can exceed the ones explicitly allowed by those policies.&lt;/p&gt;
&lt;h2&gt;
  
  
  About SCPs inheritance
&lt;/h2&gt;

&lt;p&gt;The last thing to say is about Service Control Policies and the fact that they can be inherited.&lt;/p&gt;

&lt;p&gt;Strangely, this doesn’t work as one should expect (but it’s for the better, trust me).&lt;/p&gt;

&lt;p&gt;When one thinks about inheritance, usually in programming, but even in other fields, one thinks about getting the parent's configurations to the child. If we apply this to SCPs, Organizational Units, and accounts, one can define the SCPs at the root level and then inherit everything. Well, that’s NOT how it works. &lt;/p&gt;

&lt;p&gt;Since DENY statements are evaluated first, in practice, &lt;strong&gt;only DENY statements are inherited&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you deny a service in an SCP, there is no way to grant it in a lower-level OU or Account.&lt;/p&gt;

&lt;p&gt;So, when an SCP is evaluated, there are actually only two SCPs that concur with the outcome:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The parent SCP — it’s the SCP evaluated of the next higher-level SCP; this needs to be navigated to the Root to the Organization, so it just needs to add the next layer, one step at a time&lt;/li&gt;
&lt;li&gt;The current SCP — the SCP which is currently being evaluated&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HCvTAHry--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h0ei3vhcxpcpypwl3xxl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HCvTAHry--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h0ei3vhcxpcpypwl3xxl.png" alt="Image description" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From this perspective, you can see that ALLOW statements are not inherited but need to be explicitly set in the SCP of the Account or Organization Unit. This is for security purposes, as we want to explicitly set the boundaries of accounts and organizational units to avoid implicit significant permissions.&lt;/p&gt;
&lt;h3&gt;
  
  
  Deny strategy
&lt;/h3&gt;

&lt;p&gt;With a deny strategy, actions are allowed by default through a FullAccess SCP managed directly by AWS. You attach that SCP to all Accounts and OU and you need to specify what services and actions are prohibited:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q02rBulz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/etznty7nazdc9w9u6kob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q02rBulz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/etznty7nazdc9w9u6kob.png" alt="Image description" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the default configuration of AWS Organizations so that account admins can delegate all services and actions until you create and attach an SCP that denies a specific service.&lt;/p&gt;

&lt;p&gt;The benefit of this approach is that &lt;strong&gt;deny statements require less maintenance&lt;/strong&gt; because you don't need to update them when AWS adds new services, and it’s supported out of the box. You can also restrict access to specific resources or define conditions for when SCPs are in effect.&lt;/p&gt;

&lt;p&gt;This is a great way to start for smaller organizations that need to act fast and don’t have strict requirements over governance and security.&lt;/p&gt;
&lt;h3&gt;
  
  
  Allow strategy
&lt;/h3&gt;

&lt;p&gt;With an allow strategy, you must remove the AWS-managed FullAWSAccess SCP. Now all actions for all services are implicitly denied, and you need to create an SCP that explicitly permits only those services and actions you want to allow. This case is the same schema as the inheritance evaluation.&lt;/p&gt;

&lt;p&gt;The benefit of this approach is that &lt;strong&gt;you have more control over what is allowed&lt;/strong&gt;. Since everything is implicitly denied, this way is easier to scope down the actual boundaries of an account. Since deny permissions are inherited, you don’t have to specify it everywhere.&lt;/p&gt;

&lt;p&gt;However, it requires more maintenance since you have to manually allow each service (and this includes new services). And it comes with some limitations on the allow statements: &lt;strong&gt;Resource elements can only have a ”*” entry,&lt;/strong&gt; and they &lt;strong&gt;can't have a Condition.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This approach's value shines when services may not be needed by a large portion of the organization but may still be required for specific use cases. In this scenario, it’s simpler to elevate permissions and satisfy security and governance concerns while allowing flexibility and exceptions.&lt;/p&gt;
&lt;h2&gt;
  
  
  Just a few examples
&lt;/h2&gt;

&lt;p&gt;So let’s see those SCPs in action; here, I put some examples so you can better picture what an SCP looks like in a real-world scenario.&lt;/p&gt;
&lt;h3&gt;
  
  
  Pipeline only account
&lt;/h3&gt;

&lt;p&gt;In this case, we’ve created an SCP to deny everything except changes that run through pipelines. The use case is to create an automation-only account where no manual action is allowed, but changes are always deployed through pipelines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DenyAllExceptPipelines"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Deny"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"NotAction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"codepipeline:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"codebuild:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"codecommit:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"codedeploy:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"codestar:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"cloudformation:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"iam:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"s3:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"logs:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"cloudwatch:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"cloudtrail:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"codestar:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"codestar-notification:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"codeartifact:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"kms:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"tag:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"access-analyzer:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"codestar-connections:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ssm:GetParameter*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"sts:*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"events:*"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"StringNotLike"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"aws:PrincipalArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::MY-ACCOUNT-ID:role/MY-ROLE"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Backup protection
&lt;/h3&gt;

&lt;p&gt;In this SCP, we implemented a way to protect all backups made through AWS backup by deletion. Notice that both S3 and Backup vaults are protected and the service cannot be turned down.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DenyS3BackupDelete"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:DeleteObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:DeleteObjectVersion"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:DeleteObjectTagging"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:DeleteBucket"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::MY-S3-BACKUP*/*"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Deny"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DenyBackupDelete"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"backup:DeleteBackupVault"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"backup:DeleteBackupVaultAccessPolicy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"backup:PutBackupVaultAccessPolicy"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:backup:*:*:backup-vault:MY-BACKUP-VAULT"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Deny"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"StringNotLike"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"aws:PrincipalARN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::*:role/MY-EXECUTION-ROLE"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DenyBackupTurnoffService"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"backup:UpdateRegionSettings"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Deny"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"StringNotLike"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"aws:PrincipalARN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::*:role/MY-EXECUTION-ROLE"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations, you’ve managed to get to the end of the blog post! We’ve gone from the policy evaluation flow to the actual implementation of SCPs, passing through the understanding of all the details that concur in policy and boundary interaction.&lt;/p&gt;

&lt;p&gt;From seeing the SCP examples, as with any governance tool, their implementation is extremely tied to how your organization is structured and works. So I truly believe this knowledge should be well internalized and widely understood within the organization.&lt;/p&gt;

&lt;p&gt;Now you’re on your way to mastery; see you next time, and let me know how your cloud journey is going!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're curious about my open-source project visit the &lt;a href="https://github.com/Noovolari/leapp"&gt;Leapp GitHub repository&lt;/a&gt; (be sure to drop a star if you like it!) or read more about IAM and Cloud Access Management on our &lt;a href="https://blog.leapp.cloud/"&gt;blog&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>aws</category>
      <category>identity</category>
      <category>security</category>
    </item>
    <item>
      <title>AWS multi-account strategy explained</title>
      <dc:creator>Nicolò Marchesi</dc:creator>
      <pubDate>Fri, 16 Dec 2022 09:54:03 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-multi-account-strategy-explained-2nh9</link>
      <guid>https://dev.to/aws-builders/aws-multi-account-strategy-explained-2nh9</guid>
      <description>&lt;p&gt;If you ever wanted to understand how an AWS multi-account strategy works, you’re in the right place! In this blog post, we’ll explore a bottom-up approach where we’ll see how to secure your single AWS account and then move to a multi-account organization with a fun take.&lt;/p&gt;

&lt;h3&gt;
  
  
  One box to rule them all
&lt;/h3&gt;

&lt;p&gt;So, first of all, we need to understand what is an AWS account and let’s deep dive into the topic with a definition:&lt;/p&gt;

&lt;p&gt;💡 &lt;em&gt;An AWS account acts as a resource container and resource isolation boundary.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The two essential keywords here are &lt;strong&gt;container&lt;/strong&gt; and &lt;strong&gt;isolation&lt;/strong&gt; &lt;strong&gt;boundary,&lt;/strong&gt; and I don’t know about you, but to me, they both contribute to forming a pretty clear image:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wdx5GXHz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s4d4olurnhqy962f34wk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wdx5GXHz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s4d4olurnhqy962f34wk.png" alt="Image description" width="225" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Disappointed? You were thinking of something more sturdy, right? Don’t you worry now; we’ll get there eventually. So, what can you do with this box? You can put things inside, and… that’s it.&lt;/p&gt;

&lt;p&gt;The container, by itself, acts like any other container: to keep things from being scattered around. It can still be wet by a sudden flood, gnawed by rodents, or stolen by someone else!&lt;/p&gt;

&lt;p&gt;We must make a little effort to make it more &lt;strong&gt;robust&lt;/strong&gt; and &lt;strong&gt;secure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And everything because of the &lt;strong&gt;shared responsibility model&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The shared responsibility model
&lt;/h3&gt;

&lt;p&gt;As you may already know, when moving to the cloud, you stop thinking about things like managing the low-level components, such as the host operating system and virtualization layer, and down to the physical security of the facilities where the service operates. But not everything goes away.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tm_8ATV---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fbo0rx80syvaqe82sldk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tm_8ATV---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fbo0rx80syvaqe82sldk.jpg" alt="Image description" width="880" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You are responsible for the &lt;strong&gt;security&lt;/strong&gt; of your workloads, and where does our brittle cardboard box we just discussed fit in? Precisely! That’s your job to keep it safe.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making the box sturdy: let’s secure it
&lt;/h3&gt;

&lt;p&gt;So let’s start by making your AWS account more secure. The magic happens in the AWS Identity and Access Management (IAM) service, where you can tell anyone in your organization what they can access. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gpC-ih3Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o5kdkb2dso43o0s5bq6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gpC-ih3Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o5kdkb2dso43o0s5bq6g.png" alt="Image description" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Given that we’re talking about a single account structure, there is a high chance of a &lt;strong&gt;root user&lt;/strong&gt; in your account, the one identity with complete access to all AWS services and resources. The very first thing you should do is to &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#id_root-user_manage_mfa"&gt;activate multi-factor authentication (MFA) on the AWS account root user&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Aside from that, the actions you should always take are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Activate MFA to any users with interactive access to AWS IAM&lt;/li&gt;
&lt;li&gt;Limit AWS account root user access to your resources&lt;/li&gt;
&lt;li&gt;Use AWS IAM roles and learn about granular permissions&lt;/li&gt;
&lt;li&gt;Enable CloudTrail monitoring for your account and its resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But this is just the starting point; from there on, you’re embarking on a &lt;strong&gt;journey&lt;/strong&gt; where it’s up to you to understand how to define your security policies. The essential takeaway is that there will always be new things to look out for, so integrate them into your cloud operations process.&lt;/p&gt;

&lt;p&gt;At least the box looks more like this now!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--We46UKjY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hvcebxjaaanztl86gg9p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--We46UKjY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hvcebxjaaanztl86gg9p.png" alt="Image description" width="271" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  More boxes! Scaling out your accounts
&lt;/h2&gt;

&lt;p&gt;Now that we’ve learned how to safeguard a single account, why should we ever move away? Let’s continue with the boxes example to know how. So right now, we have made our box sturdy and safe, but a few things could happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;I need more space!&lt;/strong&gt; Yeah, the box could virtually expand indefinitely (we’re still talking Cloud here, remember?), or I could purchase a giant box, but at some point, it will become a mess to organize. Ever tried moving to a new house and using just one box for all your belongings? Yeah, that’s not pretty.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I need to share&lt;/strong&gt; the box's content with someone else; I trust myself since I know well how I manage my secret code, but what about others? A burglar could steal everything from the box if he knew the code, regardless of who got it from.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think you’re starting to get the point. The isolation of our single AWS account can let us leverage the two essential concepts of &lt;strong&gt;organization&lt;/strong&gt; and &lt;strong&gt;privilege.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And AWS Organization is the thing that ties everything together. You don’t have to implement this, but you can leverage it for the best benefits with the least friction.&lt;/p&gt;

&lt;p&gt;To sum up what you can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create new AWS accounts using a hierarchy pattern;&lt;/li&gt;
&lt;li&gt;Put out-of-order AWS accounts that aren’t used anymore;&lt;/li&gt;
&lt;li&gt;Cluster accounts with your logic and apply the same set of rules to them;&lt;/li&gt;
&lt;li&gt;Manage fine-grained permission and access to single accounts or collections;&lt;/li&gt;
&lt;li&gt;View all your accounts billing in one place.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Let’s get organized
&lt;/h3&gt;

&lt;p&gt;If you try to fit everything in one AWS account, you could have problems differentiating your workloads, while the AWS account itself poses boundaries on the content you decide to put in.  Want to distinguish between development and production? Sure! Have you a machine learning division? Give them their account! Want to deploy some microservices? Here you are!&lt;/p&gt;

&lt;p&gt;But how should you get organized? That’s one of the most common questions I hear in this field, and for sure, there isn’t a single true answer because it depends on what you’re trying to achieve.&lt;/p&gt;

&lt;p&gt;What AWS suggest in their best practices is to organize based on function. This means that instead of trying to mirror the actual organization that you have, you should group based on &lt;strong&gt;security&lt;/strong&gt; and &lt;strong&gt;operational needs&lt;/strong&gt;. With &lt;a href="https://aws.amazon.com/organizations/"&gt;AWS Organization&lt;/a&gt;, you can cluster accounts into Organizational Units (OUs) and make them follow the same rules. Also, it’s possible to use a hierarchy to make child accounts inherit the same rules with the same Service Control Policies (SCPs) as their parent. Like this, securing things down the line is more manageable if you allow specific services from the top.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6htksfrg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vb0515fcu6x7lu8b7ul9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6htksfrg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vb0515fcu6x7lu8b7ul9.png" alt="Image description" width="880" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s share access
&lt;/h3&gt;

&lt;p&gt;After getting organized into a beautiful pattern we choose, we still need a  way to get our colleagues in. We don’t want to do all the work by ourselves, no?&lt;/p&gt;

&lt;p&gt;When managing access, AWS best practices tell us that you should always &lt;strong&gt;prefer a federated access method&lt;/strong&gt;, leaving us with &lt;strong&gt;&lt;a href="https://aws.amazon.com/iam/identity-center/"&gt;AWS Identity Center (former AWS SSO)&lt;/a&gt;&lt;/strong&gt; or a &lt;strong&gt;SAML-based&lt;/strong&gt; approach. Which one to pick largely depends on how you usually set up accounts and organizational units, so let's overview the two.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;AWS Identity Center&lt;/strong&gt; to work, you need to enable it with your AWS Organization's root account. Once enabled, you can manage all directory users from the AWS SSO portal and give access to single persons or groups through roles. You can use the internal user directory of AWS SSO or link an external guide with some third-party identity provider.&lt;/p&gt;

&lt;p&gt;AWS SSO can be the most straightforward way to access your multi-account environment if you have relatively few accounts and users. It's easy to use, takes minutes to set up, and has a neat integration with the AWS CLI to impersonate your roles directly from your local environment.&lt;/p&gt;

&lt;p&gt;But it's when you reach a certain amount of users and accounts you start to have some problems in management, and it becomes increasingly hard to keep up with that amount of resources. In my opinion, that threshold is reached at 20-30 accounts and users, at which point AWS SSO can't keep up with everything, and you need another solution.&lt;/p&gt;

&lt;p&gt;On the opposite side, the &lt;strong&gt;SAML-based&lt;/strong&gt; approach is the manual way of doing AWS SSO. This approach's downside is setting up the federation process and syncing between your user directory and roles. You have strict control over your identity provider and AWS accounts and less &lt;em&gt;magic on the&lt;/em&gt; advantage side. And you &lt;strong&gt;don't need access to your AWS Organization root account&lt;/strong&gt; because all setup can be done in IAM.&lt;/p&gt;

&lt;h2&gt;
  
  
  And now, starting operations in AWS
&lt;/h2&gt;

&lt;p&gt;Still, there is an elementary problem that we need to address, and it’s more on the operational side of things. Once we secured and implemented a tremendous multi-account strategy, how do people access AWS accounts? It turns out there is a fantastic open-source tool that lets you handle that with no effort, and its name is &lt;a href="https://github.com/Noovolari/leapp"&gt;Leapp&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since there wasn’t a tool that solved the full spectrum of the complexity of this problem, my team and I implemented it. Leapp is designed to rotate temporary, short-lived credentials generated from sensitive data encrypted in your local system vault; and for you to use with any AWS-compatible tools (i.e., AWS CLI, Terraform, CDK, etc.) and access your AWS console too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;Now that we’ve started implementing our multi-account structure with AWS Organizations, our situation looks more like this. Seems a lot better now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PvKZq1aE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gd0rlkmpvjbu5hz10d1s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PvKZq1aE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gd0rlkmpvjbu5hz10d1s.png" alt="Image description" width="620" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, to recap everything we’ve seen today: we’ve used the AWS account definition to navigate the critical concepts of isolation and security; the first for organizing your account structure and the second to understand who is responsible for its security. Then we have seen a few best practices and learned that &lt;strong&gt;account security is a journey rather than a few spot actions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then we scaled out to apply the same model to multiple AWS accounts and saw an implementation for organizing and sharing through AWS Organizations. We’ve learned about Service Control Policies to define boundaries and Organizational Units to structure the accounts hierarchy, reaching our ultimate goal for the implementation of a great multi-account strategy.&lt;/p&gt;

&lt;p&gt;I hope this was interesting to read; we can go more in-depth next time.&lt;/p&gt;

&lt;p&gt;Is automating processes also your thing? Do you like to find solutions to your everyday problems and want to share them with others? Then join &lt;a href="https://join.slack.com/t/noovolari/shared_invite/zt-opn8q98k-HDZfpJ2_2U3RdTnN~u_B~Q"&gt;our community&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Until next time! Thanks for reading, and have a great day!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>security</category>
    </item>
    <item>
      <title>Leapp and the Windows Certificate expiry</title>
      <dc:creator>Nicolò Marchesi</dc:creator>
      <pubDate>Thu, 09 Jun 2022 14:28:49 +0000</pubDate>
      <link>https://dev.to/pethron/leapp-and-the-windows-certificate-expiry-3npc</link>
      <guid>https://dev.to/pethron/leapp-and-the-windows-certificate-expiry-3npc</guid>
      <description>&lt;p&gt;In the last two weeks, we had a few problems with the Windows certificate of our open-source project &lt;a href="https://www.leapp.cloud/"&gt;Leapp&lt;/a&gt;. In the spirit of complete transparency, I'll try to highlight what went wrong and why.&lt;/p&gt;

&lt;p&gt;Many thanks to &lt;a href="https://twitter.com/Balubor"&gt;Alessandro Gaggia&lt;/a&gt; for the support in writing this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;As many of you are aware, Windows implements a security system named User Account Controls (UAC) that requires the administrator access token must prompt for consent. To pass UAC on Windows and results as a verified application, one must sign its executables with a .p12 (.pfx) code signing certificate. This goes for the installer, app, and uninstaller as well.&lt;/p&gt;

&lt;p&gt;These certificates are issued by specific companies that have the authority to validate your company and your Brand from a legal perspective, ensuring that you are what you declare to be and that the software is not malevolent.&lt;/p&gt;

&lt;p&gt;In our case, we used Sectigo, formerly Comodo, as our certification authority. But, as you may guess, the journey was a bit bumpy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 1: Generating .p12 certificate
&lt;/h3&gt;

&lt;p&gt;Every year we renew our code signing certificate, typically in &lt;strong&gt;May.&lt;/strong&gt; What are the steps to acquire a new certificate? Let's start by obtaining a new .crt certificate:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_Ek0pXlD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2A6pJveNUcLiUJ6BP7tBH2-g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_Ek0pXlD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2A6pJveNUcLiUJ6BP7tBH2-g.png" alt="https://cdn-images-1.medium.com/max/1200/1*6pJveNUcLiUJ6BP7tBH2-g.png" width="880" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We register and log in to our certificate authority website (sectigo in our case)&lt;/li&gt;
&lt;li&gt;Inside your dashboard is a voice called certificates: Go to the "code signing" sub-item.&lt;/li&gt;
&lt;li&gt;Here you'll eventually find the old certificates and a green button to buy a new one&lt;/li&gt;
&lt;li&gt;On the new page, we need the first type of certificate, also known as the "legacy type certificate" or OV (organization validated) certificate. Currently, we are not using &lt;a href="https://en.wikipedia.org/wiki/Extended_Validation_Certificate"&gt;EV (Extended Validation) certificates&lt;/a&gt;, but we're opting to change the next time we'll have to renew.&lt;/li&gt;
&lt;li&gt;After completing the order, you'll find the new certificate requested in your account's certificate section. And now the fun part begins.&lt;/li&gt;
&lt;li&gt;You must also &lt;strong&gt;generate a CSR (&lt;a href="https://it.wikipedia.org/wiki/Certificate_Signing_Request"&gt;certificate signing request&lt;/a&gt;) on your machine when requesting the certificate.&lt;/strong&gt; When asked, use "Generate CSR" under the personal info form (which will do via your default browser). This is very important as it contains the certificate's public key and your organization information and is used to request your new certificate.&lt;/li&gt;
&lt;li&gt;After "generate CRT", we waited for validation. And here started the delays.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Phase 2: Speeding up validation
&lt;/h3&gt;

&lt;p&gt;When we requested our certificate, we didn't do anything particular the first days, believing that the process would have gone by itself; however, after a few days, we saw that the process was stuck. What did we miss?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We had to verify our organization's identity by passing two critical things to the form that comes with the receipt email and that tracks the validation process:&lt;/li&gt;
&lt;li&gt;the organization DUNS' number&lt;/li&gt;
&lt;li&gt;A document that demonstrates the existence of the company. We chose the &lt;strong&gt;Chamber of Commerce registration document. However&lt;/strong&gt;, we needed to contact the support team 2 times to make them accept this document. For reference, in many countries with a good volume of imports/exports with Italy, some places can validate this document, even abroad.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After wasting six days of back and forth, we managed to make them accept our document but still, we needed a photo of the face of one of us with our ID card near us for validation. So we needed to take the picture, upload it and wait another day for it to be accepted. And this was another silly problem: the first time, the ID card was not near enough to our colleague's face, which was invalidated. We had to retake a picture, and we wasted another day.&lt;/p&gt;

&lt;p&gt;After another call with the support team, we obtained the certificate, which was already in .p12 format and could be renamed to .pfx (they are the same except for the extension name). Finally, we had a certificate to be used to sign the window executable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Side thoughts on what happened
&lt;/h3&gt;

&lt;p&gt;During this process, we felt primarily pressured by the delays of the supplier but also by our user base. The sudden problems with the application meant that we were flooded with reports and requests to fix this problem for about two weeks.&lt;/p&gt;

&lt;p&gt;Mind me; I try to see this in the brightest light: people were so much in pain not being able to use Leapp that they forgot that the project is entirely free and open-source (and they can build and fully utilize the application themselves). Luckily, when we arrived at the thought of buying another certificate, we resolved the issue. But what pained me the most was that few requests weren't exceptionally polite.&lt;/p&gt;

&lt;p&gt;We have a company support program that can take care of like-wise situations. We strongly suggest adhering to it if organizations and companies rely heavily on Leapp to manage their access. The support program is designed to take into account situations like this and gives us the margin to continue providing for the community and free users. Everybody wins.&lt;/p&gt;

&lt;p&gt;Also, you get to have a privileged interaction with the development team along with ours and the community's gratitude :)&lt;/p&gt;

</description>
      <category>security</category>
      <category>opensource</category>
      <category>windows</category>
    </item>
    <item>
      <title>Top 10 uncommon DevOps tools you should know</title>
      <dc:creator>Nicolò Marchesi</dc:creator>
      <pubDate>Thu, 24 Mar 2022 10:43:00 +0000</pubDate>
      <link>https://dev.to/aws-builders/top-10-uncommon-devops-tools-you-should-know-7ed</link>
      <guid>https://dev.to/aws-builders/top-10-uncommon-devops-tools-you-should-know-7ed</guid>
      <description>&lt;p&gt;Hello everyone! You clicked here to take a laugh at yet another boring list, right? I’ll try to surprise you with a list of unique tools that you probably still don’t know! I know you already know about Git, Terraform, Jenkins, and so on, so let’s focus on the &lt;strong&gt;tiny pearls&lt;/strong&gt; you can find out there! I’ve chosen only open-source tools to spread some love; if you find anything helpful, you can contribute back.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Chaostoolkit
&lt;/h3&gt;

&lt;p&gt;As a DevOps (and software engineer), I find chaos engineering one of the most relevant and thrilling topics to study right now. &lt;a href="http://chaostoolkit.org/" rel="noopener noreferrer"&gt;Chaostoolkit&lt;/a&gt; it’s a perfect way to introduce into this world through a straightforward and flexible command-line tool and a way to define experiments with declarative files that you can version.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Insomnia
&lt;/h3&gt;

&lt;p&gt;I bet you all know Postman for API design, right? I prefer &lt;a href="http://insomnia.rest/" rel="noopener noreferrer"&gt;Insomnia.rest&lt;/a&gt; since they’ve taken the extra mile to open-source the complete application and integrations through their &lt;a href="https://insomnia.rest/plugins" rel="noopener noreferrer"&gt;plugin hub&lt;/a&gt;. I know it’s a bit more popular nowadays, but I started using this when there were just a few thousand stars, and it got better and better over the years. I think the trend will keep up.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Leapp
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/Noovolari/leapp" rel="noopener noreferrer"&gt;Leapp&lt;/a&gt; is my go-to tool for accessing my cloud accounts. I was fed up with manually managing local development and operations credentials, so I automated everything most securely. I can’t count how much time it saved me over the years.&lt;/p&gt;

&lt;p&gt;It integrates with nearly any development tool (Terraform, CDK, etc.) and some excellent additions like connecting directly to SSM. Like Insomnia, it’s completely open-source, and the repository and slack channel are very active if you want to come around. Also, the tool is getting better at each release, and there is an excellent &lt;a href="https://roadmap.leapp.cloud/tabs/4-in-progress" rel="noopener noreferrer"&gt;roadmap&lt;/a&gt; to keep up with what’s new.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8fbkc69ixg41wfamwm0o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8fbkc69ixg41wfamwm0o.png" alt="Leapp"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Gitea
&lt;/h3&gt;

&lt;p&gt;If you don’t live under a rock, you already know about mainstream git repository software like GitHub and GitLab. But what if a highly lightweight, community-driven, and self-hosted alternative exists? That’s &lt;a href="http://gitea.io/" rel="noopener noreferrer"&gt;gitea.io&lt;/a&gt;. It’s not as full-fledged as its counterparts, but it’s highly promising and painless to install and use and has a very active and welcoming community.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Hubot
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://hubot.github.com/" rel="noopener noreferrer"&gt;Hubot&lt;/a&gt; is kind of old (at least in software terms!), but I’m amazed at how few people know about the ChatOps model. From 10000 thousand feet perspective, it’s just automation through your go-to chat software (discord, slack, rocketchat, mattermost, etc.), and Hubot paved the way to other similar tools. Maybe it’s less relevant today, but I find an interesting concept nonetheless (I love automation in any form it can take) that can solve a few issues, especially for less technical people.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Mkdocs-material
&lt;/h3&gt;

&lt;p&gt;I love markdown, and MkDocs is my go-to tool for writing documentation, but it’s pretty bare. &lt;a href="https://squidfunk.github.io/mkdocs-material/" rel="noopener noreferrer"&gt;mkdocs-material&lt;/a&gt; is a template that you can put mkdocs on… except it packs a whole world of additional features: versioning your documentation, a native cookie consent solution, rich search previews, and a truckload of other things… seriously give the guy 10$ a month to get supporters-only features, and you’ll get the only documentation tool you will ever need. (for instance, the &lt;a href="https://aws.github.io/copilot-cli/" rel="noopener noreferrer"&gt;AWS Copilot CLI&lt;/a&gt; docs were written with this, see for yourself, that’s amazing).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgptflvyyqwxr958j4ihd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgptflvyyqwxr958j4ihd.png" alt="Mkdocs-material"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Podman
&lt;/h3&gt;

&lt;p&gt;I’ve actively used Docker for almost all my container needs, but I’m always happy to take a look at new and emerging technologies. What got me into Podman was the daemonless architectural pattern, and nowadays, I like where the project is going. However, it’s still rough around the edges (especially the docs). Still, when I tried it out the first time, I was able to drop it in the middle of my Dockerfile, and everything just worked.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Sshuttle
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/sshuttle/sshuttle" rel="noopener noreferrer"&gt;Sshuttle&lt;/a&gt; is an excellent tool that acts as a “poor man” VPN, allowing you to create a VPN connection from your machine to any remote server you can connect to via ssh. The exciting part is that it is not precisely a VPN and not exactly port forwarding. Internally it assembles the TCP stream locally, multiplexes it statefully over an ssh session, and disassembles it back into packets at the other end to achieve data-over-TCP, which is safe. Useful if your VPN breaks down.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Infracost
&lt;/h3&gt;

&lt;p&gt;If you’re a Terraform fan, you’ll love this one. What if I tell you you can couple your infrastructure as code with bill forecasting? Sounds fantastic, huh? That’s what &lt;a href="http://infracost.io/" rel="noopener noreferrer"&gt;infracost.io&lt;/a&gt; is all about: it will scan through your Terraform files when you commit some changes to git and estimate the resulting billing of your changes! Pretty handy to have before getting unpleasant surprises.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4ksc7i23d5wdrqk7fb4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4ksc7i23d5wdrqk7fb4.png" alt="Infracost"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Checkov
&lt;/h3&gt;

&lt;p&gt;Ok, here’s the final pearl. &lt;a href="http://checkov.io/" rel="noopener noreferrer"&gt;Checkov.io&lt;/a&gt; is a static code analysis tool for checking infrastructure as code misconfiguration. I cannot express how much this one can help find and fix the most basic (and advanced) security problems in your cloud infrastructure, and it comes with support to a whole world of different IaC tools. I also love it because you can run it from the command line.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final thoughts
&lt;/h3&gt;

&lt;p&gt;I hope this was useful to delve a bit more into the technical tools of the DevOps and cloud world. I honestly think that newcomers and experts would benefit as there is always something more to experiment on and learn. Do you think something is missing? Write a comment or send me a DM and I’ll be sure to check them out and include them on the next post, see you next time!  &lt;/p&gt;

</description>
      <category>devops</category>
      <category>tooling</category>
      <category>cloud</category>
      <category>aws</category>
    </item>
    <item>
      <title>How to access AWS and Azure in Terraform</title>
      <dc:creator>Nicolò Marchesi</dc:creator>
      <pubDate>Thu, 04 Nov 2021 10:23:55 +0000</pubDate>
      <link>https://dev.to/aws-builders/how-to-access-aws-and-azure-in-terraform-g8h</link>
      <guid>https://dev.to/aws-builders/how-to-access-aws-and-azure-in-terraform-g8h</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Being a cloud developer can be hard but there are tons of tools and resources to help smooth the hard edges. One of the tools at our disposal is Terraform, an open-source infrastructure as a code software tool that provides a consistent CLI workflow to manage hundreds of cloud services. But how exactly Terraform is able to connect to those services and create our infrastructure? And can we find the best way to manage our resources? Let's see it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you shouldn't do!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Specifying credentials in provider's block
&lt;/h3&gt;

&lt;p&gt;For the love of everything that is good, please don't ever do this if you don't want to quickly find out a new world of grief and pain:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qo6qSEw---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rnjobdgw49thcn02q5e0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qo6qSEw---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rnjobdgw49thcn02q5e0.png" alt="Hardcoded credentials" width="880" height="461"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In AWS and Azure documentation, you will find some warning with mild words and a funny little warning block saying &lt;em&gt;this is not recommended&lt;/em&gt;; this doesn't even start to convey how much bad practice is hardcoding credentials, so I'll tell you more bluntly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔥 DON'T. NEVER. EVER. HARDCODE. CREDENTIALS! 🔥&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The internet is full of horror stories of people lazy or careless enough to find themselves with big surprises in their next cloud provider bill. In the most recent one, &lt;a href="https://www.reddit.com/r/aws/comments/qgr9jh/was_billed_60k_with_a_free_tier/"&gt;a guy found out a 65k bill because he "&lt;em&gt;handled source code with hardcoded credentials to other devs&lt;/em&gt;"&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Do you want to become part of this group? There are better ways to connect your Terraform with your cloud accounts, so let's follow best practices, shall we?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U2Fj6KC8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fyo4kdj19cj9h26ynugk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U2Fj6KC8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fyo4kdj19cj9h26ynugk.jpg" alt="Hardcoded Credentials Pain Meme" width="750" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What you should handle with care
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Putting credentials in environment variables
&lt;/h3&gt;

&lt;p&gt;The first thing you can do to connect Terraform with your providers is to leverage environment variables. You need to export all the data needed to connect into the default environment variables and you're good to go. Just declare an empty provider and Terraform will automatically pick them up and run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;ARM_SUBSCRIPTION_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;00000000-0000-0000-0000-000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;ARM_TENANT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;00000000-0000-0000-0000-000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;ARM_CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;00000000-0000-0000-0000-000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;ARM_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;00000000-0000-0000-0000-000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000000000000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;AWS_DEFAULT_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-east-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;azurerm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;features&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Only downside of this approach is that managing this environment variables manually is a real pain. How cool would be to have an automated way to handling this? ;)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔥 Refrain from exporting directly in your &lt;em&gt;.bash_rc&lt;/em&gt;, &lt;em&gt;.profile&lt;/em&gt; or any other automatically sourced configuration files. Those file are not encrypted you it's a very similar situation as the hardcoded credentials. &lt;strong&gt;Forewarned is forearmed.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  What you should do! (finally)
&lt;/h2&gt;

&lt;p&gt;Here things will split a bit for AWS and Azure, but I'll try to keep them as consistent as possible. We'll mostly look at interactive ways so keep that in mind.&lt;/p&gt;
&lt;h2&gt;
  
  
  On Azure
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Logging through the CLI
&lt;/h3&gt;

&lt;p&gt;This is the default and most secure method for interactively working with Terraform. By running the az login command on the Azure CLI it will export the parameters needed to work into environment variables. The only problem you can incur is by having multiple tenants; in this case, you need to specify in the Terraform Azure provider the one you will use.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;azuread&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;tenant_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;00000000-0000-1111-1111-111111111111&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Using service principals
&lt;/h3&gt;

&lt;p&gt;Service Principal authentication is usually more suitable for automated workflows like for CI/CD or running application scenarios. This type of authentication decouples the authentication process from any specific user login and allows for managed access control.&lt;/p&gt;

&lt;p&gt;We can see them as the Azure counterpart of IAM Roles in AWS, and one trivial advantage would be that it can be shared between people without having to resort to groups or tie directly to an identity. In essence, by using a Service Principal, you avoid creating fake users in Azure AD to manage authentication when you need to access resources.&lt;/p&gt;
&lt;h2&gt;
  
  
  On AWS
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Assuming Roles
&lt;/h3&gt;

&lt;p&gt;Assuming a role is the single most simple and secure way to interact with your cloud resources through Terraform. It comes easy as defining the assume_role parameter in the provider and filling out the role you want to assume, the name of the session (it will be handy if you need to trace calls through monitoring systems such as CloudTrail), and an optional external_id that serves as a secret.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;assume_role&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;role_arn&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;session_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SESSION_NAME&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;external_id&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EXTERNAL_ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Overall is a good method but it suffers the same problem as the hardcoded credentials in the sense that when you commit it into your repository anyone can put their hands on this and manage your account.&lt;/p&gt;
&lt;h3&gt;
  
  
  Shared Credentials file
&lt;/h3&gt;

&lt;p&gt;You can also make all those information external by telling terraform to look up a shared credential file. The default location is &lt;code&gt;$HOME/.aws/credentials&lt;/code&gt; on Linux and macOS, or &lt;code&gt;"%USERPROFILE%\.aws\credentials"&lt;/code&gt; on Windows. This way the only information you need to exchange with Terraform is the name of the named profile and the CLI will automatically perform the assume role for you.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt;                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-west-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;shared_credentials_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/Users/tf_user/.aws/creds&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;profile&lt;/span&gt;                 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;customprofile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This can be further enhanced by using multiple named profiles. &lt;/p&gt;
&lt;h3&gt;
  
  
  No MFA support, Leapp to the rescue!
&lt;/h3&gt;

&lt;p&gt;Currently, Terraform doesn't support the &lt;code&gt;mfa_serial&lt;/code&gt; while assuming roles according to this issue:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/hashicorp/terraform-provider-aws/issues/2420"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--i3JOwpme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg"&gt;
      &lt;span class="issue-title"&gt;
        Doesn't ask MFA token code when using assume_role with MFA required
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#2420&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jsi-p"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--bzn7QRHC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars.githubusercontent.com/u/11882778%3Fv%3D4" alt="jsi-p avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jsi-p"&gt;jsi-p&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/hashicorp/terraform-provider-aws/issues/2420"&gt;&lt;time&gt;Nov 23, 2017&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;When using multiple AWS accounts it's good practice to only allow access via AssumeRole from a master account. This can be done with or without requiring MFA. Terraform supports assume_role with s3 state file and aws provider configurations, but doesn't seem to ask the MFA token code when one is required. This prevents using AssumeRole for credentials when MFA is required.&lt;/p&gt;
&lt;p&gt;AWS documentation describing MFA with cross account AssumeRole: &lt;a href="http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_configure-api-require.html#MFAProtectedAPI-cross-account-delegation" rel="nofollow"&gt;http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_configure-api-require.html#MFAProtectedAPI-cross-account-delegation&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Terraform Version&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;$ terraform --version
Terraform v0.11.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Affected Resource(s)&lt;/h3&gt;
&lt;p&gt;Both of these support assume_role, so they should also support asking for MFA token code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;S3 backend configuration&lt;/li&gt;
&lt;li&gt;AWS provider configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Terraform Configuration Files&lt;/h3&gt;
&lt;div class="highlight highlight-source-terraform js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;terraform&lt;/span&gt; {
  &lt;span class="pl-en"&gt;backend&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;s3&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; {
    bucket &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;terraform-state-bucket&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
    key &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;tf-state&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
    region &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;eu-west-1&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
    role_arn &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;arn:aws:iam::916005212345:role/OrganizationAccountAccessRole&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
  }
}
&lt;span class="pl-k"&gt;provider&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;aws&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; {
  region &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;eu-west-1&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
  &lt;span class="pl-en"&gt;assume_role&lt;/span&gt; {
    role_arn &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;arn:aws:iam::916005212345:role/OrganizationAccountAccessRole&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
    session_name &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;terraform-session&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
  }
}&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Actual Behavior (with DEBUG)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;$ TF_LOG=debug terraform init
2017/11/23 13:36:12 [INFO] Terraform version: 0.11.0  
2017/11/23 13:36:12 [INFO] Go runtime version: go1.9.2
2017/11/23 13:36:12 [INFO] CLI args: []string{"/usr/local/Cellar/terraform/0.11.0/bin/terraform", "init"}
2017/11/23 13:36:12 [DEBUG] Attempting to open CLI config file: /Users/***/.terraformrc
2017/11/23 13:36:12 [DEBUG] File doesn't exist, but doesn't need to. Ignoring.
2017/11/23 13:36:12 [INFO] CLI command args: []string{"init"}
2017/11/23 13:36:12 [DEBUG] command: loading backend config file: /Users/***

Initializing the backend...
2017/11/23 13:36:12 [WARN] command: backend config change! saved: 16375281725947963338, new: 2383462577283113429
Backend configuration changed!

Terraform has detected that the configuration specified for the backend
has changed. Terraform will now reconfigure for this backend. If you didn't
intend to reconfigure your backend please undo any changes to the "backend"
section in your Terraform configuration.


2017/11/23 13:36:12 [INFO] Building AWS region structure
2017/11/23 13:36:12 [INFO] Building AWS auth structure
2017/11/23 13:36:12 [INFO] Setting AWS metadata API timeout to 100ms
2017/11/23 13:36:13 [INFO] Ignoring AWS metadata API endpoint at default location as it doesn't return any instance-id
2017/11/23 13:36:13 [INFO] Attempting to AssumeRole arn:aws:iam::***:role/OrganizationAccountAccessRole (SessionName: "", ExternalId: "", Policy: "")
2017/11/23 13:36:13 [INFO] AWS Auth provider used: "SharedCredentialsProvider"
2017/11/23 13:36:13 [DEBUG] plugin: waiting for all plugin processes to complete...
Error initializing new backend: 
Error configuring the backend "s3": The role "arn:aws:iam::***:role/OrganizationAccountAccessRole" cannot be assumed.

  There are a number of possible causes of this - the most common are:
    * The credentials used in order to assume the role are invalid
    * The credentials do not have appropriate permission to assume the role
    * The role ARN is not valid

Please update the configuration in your Terraform files to fix this error
then run this command again.
&lt;/code&gt;&lt;/pre&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/hashicorp/terraform-provider-aws/issues/2420"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Leapp can work around this specific scenario by performing the assume role, prompting for the MFA token, and injecting into the credentials file the temporary credentials and tokens to let you use Terraform without further interaction. Nice, isn't it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i3JOwpme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Noovolari"&gt;
        Noovolari
      &lt;/a&gt; / &lt;a href="https://github.com/Noovolari/leapp"&gt;
        leapp
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Leapp is the DevTool to access your cloud
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Leapp&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://lgtm.com/projects/g/Noovolari/leapp/context:javascript" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/aa3af19b630084b8944635611edf990f79c585da0fb9f109df6172fd02083535/68747470733a2f2f696d672e736869656c64732e696f2f6c67746d2f67726164652f6a6176617363726970742f672f4e6f6f766f6c6172692f6c656170702e7376673f6c6f676f3d6c67746d266c6f676f57696474683d3138" alt="Language grade: JavaScript"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://www.leapp.cloud/" rel="nofollow"&gt;leapp.cloud&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Documentation Website: &lt;a href="https://docs.leapp.cloud/" rel="nofollow"&gt;docs.leapp.cloud&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Roadmap: &lt;a href="https://github.com/Noovolari/leapp/discussions/178"&gt;Roadmap&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Chat with us: &lt;a href="https://join.slack.com/t/noovolari/shared_invite/zt-opn8q98k-HDZfpJ2_2U3RdTnN~u_B~Q" rel="nofollow"&gt;Slack&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Noovolari/leapp.github/images/README-1.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KoRNG_jC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/Noovolari/leapp.github/images/README-1.png" alt="logo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Leapp is a Cross-Platform Cloud access App, built on top of &lt;a href="https://github.com/electron/electron"&gt;Electron&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The App is designed to &lt;strong&gt;manage and secure Cloud Access in multi-account environments.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://user-images.githubusercontent.com/9497292/114399348-1e942f80-9ba1-11eb-8b4a-74b60bd29189.jpeg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cSyWyw_i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/9497292/114399348-1e942f80-9ba1-11eb-8b4a-74b60bd29189.jpeg" alt="Securing aws Credentials on DevOps machines 001"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
Key features&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;We Strongly believe that access information to Cloud in &lt;code&gt;~/.aws&lt;/code&gt; or &lt;code&gt;~/.azure&lt;/code&gt; files are not safe, and &lt;strong&gt;&lt;a href="https://docs.leapp.cloud/contributing/system_vault/" rel="nofollow"&gt;we prefer to store that information in an encrypted file managed by the system.&lt;/a&gt;&lt;/strong&gt;
Credentials will be hourly rotated and accessible in those files only when they are needed, so only when Leapp is active.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Switch Cloud Profile in a click&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://docs.leapp.cloud/contributing/system_vault/" rel="nofollow"&gt;Secure&lt;/a&gt; repository for your access data&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Multiple Cloud-Access &lt;a href="https://docs.leapp.cloud/use-cases/intro/" rel="nofollow"&gt;strategies&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://docs.leapp.cloud/concepts/" rel="nofollow"&gt;No long-lived&lt;/a&gt; credentials&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Generate and use sessions directly from &lt;a href="https://docs.leapp.cloud/use-cases/aws_sso/" rel="nofollow"&gt;your aws Organization&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Connect EC2 instances straight away&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All the covered access methods can be found &lt;a href="https://docs.leapp.cloud/use-cases/intro/" rel="nofollow"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Noovolari/leapp.github/images/Leapp-animation.gif"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hL4O1sHM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://github.com/Noovolari/leapp.github/images/Leapp-animation.gif" alt="Leapp App animation"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
Installation&lt;/h1&gt;
&lt;p&gt;Get &lt;a href="https://www.leapp.cloud/releases" rel="nofollow"&gt;here&lt;/a&gt; the latest release.&lt;/p&gt;
&lt;h1&gt;
Contributing&lt;/h1&gt;
&lt;p&gt;Please read through our &lt;a href="https://github.com/Noovolari/leapp.github/CONTRIBUTING.md"&gt;contributing guidelines&lt;/a&gt; and &lt;a href="https://github.com/Noovolari/leapp.github/CODE_OF_CONDUCT.md"&gt;code of&lt;/a&gt;…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Noovolari/leapp"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;As we've seen there are a lot of ways to interact with Terraform for both AWS and Azure. When choosing our access methods we should always think about the security concerns and avoid at all costs manual interactions with the configurations file. For all of this, &lt;strong&gt;Leapp is the best tool to achieve both security and automation&lt;/strong&gt;, abstracting away all underlying interactions and letting cloud developers focus on their tasks.&lt;/p&gt;

&lt;p&gt;If you found this interesting, have any questions or you just want to drop a DM and connect you can &lt;a href="https://twitter.com/NicoloMarchesi"&gt;find me on twitter&lt;/a&gt; or &lt;a href="https://join.slack.com/t/noovolari/shared_invite/zt-opn8q98k-HDZfpJ2_2U3RdTnN~u_B~Q"&gt;join our slack community&lt;/a&gt;. See you soon!&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>aws</category>
      <category>azure</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Road to Noovolari</title>
      <dc:creator>Nicolò Marchesi</dc:creator>
      <pubDate>Wed, 30 Jun 2021 08:35:19 +0000</pubDate>
      <link>https://dev.to/pethron/road-to-noovolari-92l</link>
      <guid>https://dev.to/pethron/road-to-noovolari-92l</guid>
      <description>&lt;h2&gt;
  
  
  The journey to tech startup
&lt;/h2&gt;

&lt;p&gt;What drives a person, team, or company to reach its potential? How do you discover the right approach to achieve it? And why it's critical to find motivation and define aspiration? Those are questions that our team, Noovolari, asked several times in the wandering of finding our path.&lt;/p&gt;

&lt;p&gt;I bet that many of you will think that they are abstract, convoluted, and probably meaningless, only useful in some third-rate marketing strategy. Trust me; they are not. Taking the time to understand who you are and why you are doing what you are doing is central to achieve complete fulfillment, both personal and in business.&lt;/p&gt;

&lt;p&gt;Don't get me wrong; it's an incredibly challenging ride with many blurred answers. Still, it's a trail we've been following for the last seven years, and today we will shed some light on what we did to achieve this formidable goal (spoiler: yes, we did it!); from how everything started and how we changed along the way up to discovering and embracing our true vision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A safe haven to return at when in doubt.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The first steps
&lt;/h2&gt;

&lt;p&gt;It's impossible to talk about &lt;em&gt;Noovolari&lt;/em&gt; without starting from &lt;em&gt;beSharp&lt;/em&gt;, one of the first companies in Italy to focus and train in cloud computing expertise.&lt;/p&gt;

&lt;p&gt;BeSharp started as a university spinoff. Everyone shared the passion for solving problems with a deep technical approach, expanding and polishing the skills needed in every technology aspect involving the cloud.&lt;/p&gt;

&lt;p&gt;Since day one, most people in beSharp were focused on becoming advanced AWS consulting partners for business, architecting and developing cloud infrastructures, and hand-crafted solutions for customers.&lt;/p&gt;

&lt;p&gt;Instead, my team focused on research and development to learn and bring innovation to the whole company. We always had freedom in aiding our consulting associates and their customers as we saw fit; that's why we never focused on a single cloud provider. Instead, we explored the whole cloud landscape to create new and more broad solutions. Our projects ranged in vastly different cloud areas, from adaptive pipelines for genomic high-performance computing to application consistent backup and disaster recovery. Our team's name, &lt;em&gt;Noovolari&lt;/em&gt;, was a pun involving the word "cloud" in Italian (&lt;strong&gt;e.d. nuvola&lt;/strong&gt;), and the famous racing driver Tazio Nuvolari; meant that we wanted to go fast in the cloud.&lt;/p&gt;

&lt;p&gt;We explored a little bit of everything, but we soon realized that the best results came from improving our internal processes. Our knowledge and understanding of the underlying platforms gave us an unfair advantage in creating new developer tools. Despite our small team and endless stream of work, we were able to free many of our colleagues' burdens to make them focus on what really mattered to them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Our mission was to put to good use our skills at scale.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Growing together
&lt;/h2&gt;

&lt;p&gt;It was by chance that we started showing our work to people on the outside. In our chase to give our colleagues the best tools they could have, we started putting a bit more effort into the user experience. As a result, they started using our product during meetings in front of customers... and the feedback was astounding. People started asking to use our software, and we realized that we weren't solving problems just for us but also for many people. That was a perfect opportunity to put our expertise to good use.&lt;/p&gt;

&lt;p&gt;One of the most crucial moments was our first database rollback in production. One of our customers had a major disruption on their workloads. Since they were using our software to manage their entire backup lifecycle, it felt natural to support them. It was our first test drive, and we couldn't stop thinking about what would happen if something went wrong. And in a few minutes, the application was working as if no problem ever came up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We were able to solve a real problem for a real customer.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep calm and stop
&lt;/h2&gt;

&lt;p&gt;Things were going well at that moment. We were getting acknowledged and building more and more awesome features. We started making arrangements to offer the software as a service, subscribed our software to several marketplaces, and plan our commercial offering. So we felt on the edge of starting our journey as a product company. But we never took off.&lt;/p&gt;

&lt;p&gt;Aside from few customers directed to us by our colleagues, very few people came after our solution through other channels. As this situation persisted until the beginning of 2020, we started wondering what was wrong with our project despite all our work. We were confident about our solution, but still, customers didn't flock at us as we expected. Why?&lt;/p&gt;

&lt;p&gt;We thought the best way was to gather the courage and contact someone who already walked the path we were trailing on. We asked more successful entrepreneurs to give us some feedback on our strategy, but it was painstaking. We were scared of what they could tell us and how that could affect our morale. After some weeks of attempts, we finally found a person willing to help. And just a few minutes into the meeting, he said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Let me guess... are you all engineers?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That was it.&lt;/p&gt;

&lt;p&gt;At that moment, it flashed the idea that our situation was more common than we thought. The problem with engineers is that we think only in terms of features and development cycles. We thought that making the best technical product was enough for people to come by themselves, and we just had confirmation that this wasn't the case. We were really naive.&lt;/p&gt;

&lt;p&gt;This brief call opened pandora's box, and we started to see the fallacies in our process. From focusing all our efforts on the next big feature to the grave lack of communications with our potential customers and the small and biased customer feedback we collected. We just weren't aware of the several things needed to make a successful product. And diving deeper into the hole just popped out more and more questions... it seems as if there was no end to it.&lt;/p&gt;

&lt;p&gt;That was one of our hardest moments. We felt overwhelmed by the things we took for granted, but we couldn't go on without a plan or answers. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We decided to stop everything and go back to the fundamentals.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Time for questions
&lt;/h2&gt;

&lt;p&gt;The first thing on the agenda was a retrospective of the last year of development. We focused on the creative process and feature proposal up to the customer feedback because we felt that something was off in the decision-making and feature selection. So we first examined the backlog and roadmap to find out why we chose to develop some specific features.&lt;/p&gt;

&lt;p&gt;Up to that point, we used a scoring system based on reach, impact, confidence, and effort to value all our potential features. Each element of the scoring system had some internal weights that could tweak the overall score in favor of our current goal. For example, lower technical debt, catch up to competitors or develop new features in the market. So far, so good, we even thought that we did a pretty good job!&lt;/p&gt;

&lt;p&gt;But the most affected phases were &lt;em&gt;validation, feedback,&lt;/em&gt; and &lt;em&gt;custom development&lt;/em&gt;. We assumed that our choices were objective because of the multiple steps involved, but we missed the point in disregarding the work at the top or the bottom of the process. We prioritized things based on what our colleagues doing consultancy needed at that moment, and their necessities swayed their feedback. Moreover, we offered to integrate custom features for our current customers. Trying to fit those features as generally available increased the technical debt. In the long run, it slowed us down to the point where new features required complete code refactoring.&lt;/p&gt;

&lt;p&gt;After focusing inside, we shifted the perspective on the outside. We already had a market and competitor analysis, but after a review, we found out its main goal was to &lt;em&gt;find features to bridge the gap&lt;/em&gt; or &lt;em&gt;find features that could set us apart&lt;/em&gt; from the competition. We didn't make a broader analysis to find out what was setting us apart from the competition. So we started from scratch and tried to build a clear understanding of the whole market and, more importantly, where we could belong. &lt;/p&gt;

&lt;p&gt;First, we drew a &lt;em&gt;competitive landscape&lt;/em&gt;, a visual representation of each market segment, and where all our competitors belonged in that space. Next, we went into an in-depth analysis of each competitor's features to determine the gap between us and discover their strengths and weaknesses. It was a lengthy process that needed few iterations, and it proved invaluable to have a visual aid for discussion since the amount of data to deal with was huge, and not everyone was focused on this task. Putting everything together required a lot of effort and brainstorming, but we emerged with some answers, and most of our fears and doubts materialized. &lt;/p&gt;

&lt;p&gt;We always thought we could manage to find our niche by creating the best possible technical solution, but we had difficulty explaining how exactly that could find its place in the landscape. It seemed that we lacked a proper area that set us aside from the competition. Moreover, the gap with our competitors was too wide. As a team of barely four people, there was no way we could catch up to their latest features.&lt;/p&gt;

&lt;p&gt;Last but not least, we went into a thorough analysis of our marketing strategy, and we realized that we needed to take the matter into our hands. We relied too much on internal feedback and word of mouth; we needed to build an online presence. But based on what? We still didn't have a unique identity. Things were looking pretty grim, but still, we didn't want to give in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We just needed to tackle the problem from a different perspective.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Back to why
&lt;/h2&gt;

&lt;p&gt;Despite all the analysis and work we did, we were still far from finding our place. Again the help came in the unexpected form of a simple yet powerful phrase that's been my guiding principle since then:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When in doubt, be yourself&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It may seem trivial, but it's easy to wander and lose focus when you're trying to do something very complex. What works really well is to have somewhere to return to, so you don't need to waste precious resources thinking about what's wrong. We focused on the process, analytics, markets, and business development, but we weren't sure what were the reasons that brought us together and why. We lacked a safe haven.&lt;/p&gt;

&lt;p&gt;What helped us get going was the famous golden circle:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4YRDhCxJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i2q6xwo7rf7b3hjss7q4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4YRDhCxJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i2q6xwo7rf7b3hjss7q4.png" alt="GoldenCircle"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The method is super inspiring and challenges the status quo at its core for identifying your purpose for what you want to do in business and life. So many people think about this only in marketing terms, but we've relied on it as a framework to find our deepest meaning, and it has really served us well.&lt;/p&gt;

&lt;p&gt;We had many brainstorming sessions filling on post-it notes what were the reasons we started, what we wanted to achieve, and what was driving us forward. In other words, the reasons we were doing what we were doing.&lt;/p&gt;

&lt;p&gt;As you can guess, the "what" and "how" were pretty straightforward and slightly deviated from the average answer. Still, it was important to start with setting some common ground. Unfortunately, the "why" part was countless times more difficult. Although I know this sounds like an easy task, we got a different answer to every question, and they started piling up pretty fast.&lt;/p&gt;

&lt;p&gt;It was important to use physical support to have a quick overview, so we put every note on a wall. We then started clustering our notes and give a general meaning to each cluster. Finally, each reason was put in a thorough examination and distilled into something we all agreed upon. I'll spare you the details about this, but it required a lot of meetings and talking.&lt;/p&gt;

&lt;p&gt;In the end, this is what emerged:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Imagine a future where the public cloud will be the key to opening the doors of innovation to your business. What could we do if the complexity of the workloads in multi-cloud environments did not allow our users to focus on their core business? And how extraordinary would it be to accomplish all of this day after day, thanks to a work that inspires us, makes us happy, and makes us feel fulfilled?&lt;/p&gt;

&lt;p&gt;We create products that revolutionize the way we work in complex multi-cloud environments, allowing our customers to achieve their business goals through the unification, centralization, and facilitation of cloud processes following best practices. We want to be a beacon for companies seeking a standard for complex processes in multi-cloud environments.&lt;/p&gt;

&lt;p&gt;We believe in a world where everyone can contribute to evolve and innovate faster; we believe that all digital products should be open to contributions. We want to grow as people and be aware of the extraordinary goals that we can achieve, thanks to mutual trust and teamwork.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Get to the how and what
&lt;/h2&gt;

&lt;p&gt;We had done it. 3 months had passed, but we finally had our compass.&lt;/p&gt;

&lt;p&gt;Now it was about fitting our vision into the market... and it came unexpectedly easy. One of the few things that came up during brainstorming was that &lt;em&gt;we believe in a world where everyone can contribute to evolve and innovate faster.&lt;/em&gt; Of course, that ringed a bell with &lt;strong&gt;open-source&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As software engineers, we had previous experience in that area, but we never really thought about it in business terms. So we were again back at square one, but with a viable option in mind, that could really set us apart. So in the next few weeks, we dedicated ourselves to learning everything we could about making open-source products and make them sustainable through commercial offerings. And we loved what we saw.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It was the perfect union of our beliefs and how to reach them.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Nowadays
&lt;/h2&gt;

&lt;p&gt;This brings us more or less to one year ago, so now you're probably wondering what we've been up to since today? We've stopped the projects that didn't perfectly align with our vision; the effort to change them on the run was too high to be reasonable. But the good news is that we are not short of ideas.&lt;/p&gt;

&lt;p&gt;We had a developer's tool to grant easy and secure access to our large numbers of accounts during all this time. We created it out of the necessity of increasing the number of our cloud accounts to comply with the best practice to segregate cloud workloads. It was nothing fancy, but we realized that it became a standard for our whole company in no time. Also, like before, a few of our consultancy associates' customers are starting to ask about it in detail.&lt;/p&gt;

&lt;p&gt;But now we are prepared... well... at least more prepared than before!&lt;/p&gt;

&lt;p&gt;We spent the rest of last year making it an open-source tool, built for cloud developers like us. And now it goes by the name of &lt;a href="https://www.leapp.cloud/"&gt;Leapp&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'd really like to delve into the full details about how we did it, including how we structured our internal process, how we built the product roadmap, the development methodology, the go-to market strategy, how we have structured the commercial offering, and so on... but this will require at least a couple more articles.&lt;/p&gt;

&lt;p&gt;We're still early on our journey, but things are moving as never seen before. We're about to reach 450 stars on &lt;a href="https://github.com/Noovolari/leapp"&gt;Github repository&lt;/a&gt;, about 750 stable downloads at each release, and offer &lt;a href="https://www.leapp.cloud/support.html"&gt;our first commercial support plan&lt;/a&gt;. We have even a few surprises waiting for you in the next months. As a little spoiler, we are planning another software specifically built for teams on top of Leapp. But we'll make a big reveal in due time!&lt;/p&gt;

&lt;p&gt;Meanwhile, if you'd like to join us to have a chat, discuss some new features, or keep up with the news, join our community on Slack and Github.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We are Noovolari and we'll do wonderful things together.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>startup</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Enhanced Serverless GitHub Metrics</title>
      <dc:creator>Nicolò Marchesi</dc:creator>
      <pubDate>Thu, 11 Mar 2021 13:37:53 +0000</pubDate>
      <link>https://dev.to/pethron/enhanced-serverless-github-metrics-1ec2</link>
      <guid>https://dev.to/pethron/enhanced-serverless-github-metrics-1ec2</guid>
      <description>&lt;p&gt;Since we started &lt;a href="https://github.com/Noovolari/leapp"&gt;Leapp&lt;/a&gt; a few months ago, we wanted to steadily improve our open-source project to engage better all people interested in working fast and safely in the cloud.&lt;/p&gt;

&lt;p&gt;But to improve on something, you need to be aware of what you want to improve. So the first thing we noticed was the Insight page inside our GitHub repository. You can find a ton of useful information there, but it's limited to 1 month of data, so my thought was: let's fix that!&lt;/p&gt;

&lt;h2&gt;
  
  
  Meanwhile...
&lt;/h2&gt;

&lt;p&gt;What better chance to learn something new? Since the project was simple enough, I decided to take a little extra time to study and research new technologies that could come in handy for future projects. I like to learn new things consistently to keep up with our ever-changing world... and while having fun too!&lt;/p&gt;

&lt;p&gt;I wanted to share the whole process and my takeout at the end, so if you're searching for inspiration, I hope you're in the right place!&lt;/p&gt;

&lt;h1&gt;
  
  
  Requisites
&lt;/h1&gt;

&lt;p&gt;So, before writing even a few code lines, I want to have a clear overview of how I would build my project. Here's my thought process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the framework and language
&lt;/h2&gt;

&lt;p&gt;My drive here is to do some research to evaluate technologies for other projects to use in production. Since this is an easy goal, it's perfect to avoid incurring major technical issues while having the opportunity to dive deep enough to discover any significant flaws I can encounter in the future.&lt;/p&gt;

&lt;p&gt;For a few months, I wanted to try out &lt;strong&gt;TypeScript&lt;/strong&gt; and check if the Twitter hype was right for once, while for infrastructure as code (IaC), I never had the chance to research &lt;strong&gt;Terraform&lt;/strong&gt;. In the end, this was an excellent use-case to finally do some serious research and development with a clear goal.&lt;/p&gt;

&lt;p&gt;As for deployment and data persistence, I want to use something that I'm confident in; since I'm already adding uncertainty with a new programming language and deployment frameworks, it's better to stop here with the novelty and avoid delays.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the data-persistence layer
&lt;/h2&gt;

&lt;p&gt;For this, I need something inexpensive and with good filtering capabilities since I'm going to query for dates. Moreover, I don't want to pay for idle, so the choice is between DynamoDB and Aurora Serverless. Since I don't forecast to access this data a lot, I think DynamoDB is a better fit. For the filtering part, I learned the hard way that it's always better to devise your queries first; I took some time to forecast what kind of questions I would run to retrieve my data, and i's something like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many GitHub stars did we have on that date?&lt;/li&gt;
&lt;li&gt;How many Contributors did we have on that date?&lt;/li&gt;
&lt;li&gt;Plot all Stargazers that were present between those dates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's pretty clear that I wanted all data divided by date, so I designed the table to have the date set as my primary key. Unfortunately, the date range query was applicable only in two scenarios: secondary indexes or scans. But the data I'm expecting to store and search for is tiny, so I can safely ignore the mantra "&lt;strong&gt;never use scans"&lt;/strong&gt; and use the date as my primary key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other considerations
&lt;/h2&gt;

&lt;p&gt;Since I want complete automation and daily granularity, the best thing to do is fire off my Lambda on a daily cron job. To maintain the serverless spirit, CloudWatch Alarms is a perfect fit for that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final choice
&lt;/h2&gt;

&lt;p&gt;So, with the final choice, I went with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Platform: &lt;strong&gt;AWS Lambda&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Language: &lt;strong&gt;TypeScript&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Infrastructure as Code: &lt;strong&gt;Terraform&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Data Persistence: &lt;strong&gt;DynamoDB&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Events: &lt;strong&gt;CloudWatch Alarm&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Developing
&lt;/h1&gt;

&lt;p&gt;Once settled with the whole technology stack, it was time to do some testing and development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extracting data
&lt;/h2&gt;

&lt;p&gt;The first thing I did was use the GitHub SDK with Octokit to query for data and start defining the data structure. I will later save this to DynamoDB.&lt;/p&gt;

&lt;p&gt;This thing would be as fast as lightning to implement, but I made an encounter with the most dreaded thing of the whole JavaScript engine... the Promise! Octokit only provides a client that could be interacted only with asynchronous interfaces.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise"&gt;Thanks to MDN for the clear explanation.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, it was pretty easy. Put await in front of each promise to make them synchronous and extract a bunch of data to store in an Object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;scrape&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Metrics&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get_social&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get_issues_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IssueState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Closed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;opc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get_pulls_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IssueState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get_pulls_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IssueState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Closed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get_releases&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Globals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;closed_issues_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;closed_pulls_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;forks_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forks_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;open_issues_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open_issues_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;open_pulls_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;opc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;stargazers_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stargazers_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;subscribers_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribers_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;total_issues_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cic&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open_issues_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;total_pulls_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cpc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;opc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;watchers_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;watchers_count&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;releases&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, I divided the metrics into &lt;strong&gt;globals&lt;/strong&gt; and &lt;strong&gt;releases.&lt;/strong&gt; The first contains all data tied to the repository (Stars, Contributors, Traffic, etc.), while the latter will store all releases versions and the number of times each file has been downloaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing data
&lt;/h2&gt;

&lt;p&gt;The writing part was the most tricky... guess why? Again the Promise!&lt;/p&gt;

&lt;p&gt;Since I already created the Lambda handler, it took me few attempts to return the Promise to be resolved.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DynamoDB&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Metrics&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./scrape/dto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metrics&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;calendar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;calendar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;globals&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dynamo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DynamoDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DocumentClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2012-08-10&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eu-west-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dynamo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;put&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The lambda handler
&lt;/h2&gt;

&lt;p&gt;And here, for the sake of completeness, the handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Scraper&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./scrape/scrape&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;write&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./writer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scraper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Scraper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OWNER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REPO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AUTH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;scraper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrape&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TABLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since the handler is a Promise, and the Lambda runtime environment has a wrapper that resolves it, you don't need to wait for the write function to complete before returning it. I'm returning the Promise directly from the DynamoDB put operation.&lt;/p&gt;

&lt;p&gt;I know it's pretty dry, but I like to have &lt;em&gt;slim handlers to focus on the business logic&lt;/em&gt; without worrying about how they will run in the Lambda environment.&lt;/p&gt;

&lt;h1&gt;
  
  
  Building the infrastructure
&lt;/h1&gt;

&lt;p&gt;After making everything work on the development side, I went to build and create the infrastructure. I set up everything in a folder named &lt;a href="https://github.com/pethron/serverless-github-metrics/tree/master/terraform"&gt;terraform&lt;/a&gt; to generate a file for each infrastructure element. Something like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terraform

&lt;ul&gt;
&lt;li&gt;cloudwatch&lt;/li&gt;
&lt;li&gt;dynamo&lt;/li&gt;
&lt;li&gt;iam&lt;/li&gt;
&lt;li&gt;lambda&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The variables
&lt;/h2&gt;

&lt;p&gt;Since I want to consistently work between the local and cloud environments and always prefer to generalize and reuse my code when possible, I always start by forecasting the variables I need to pass to the function. Since I'm using CloudWatch Alarms to fire off Lambda those variables will be later transformed into environment variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_region&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-west-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vertical&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stack&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;project&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;owner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;repo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_region&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;current&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_caller_identity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;current&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I would need the &lt;em&gt;owner&lt;/em&gt; and &lt;em&gt;repo&lt;/em&gt; to configure the data source and the &lt;em&gt;auth&lt;/em&gt; token to establish the connection. Since I'm using &lt;a href="https://github.com/Noovolari/leapp"&gt;Leapp&lt;/a&gt; to manage access to the cloud account, I've configured the &lt;em&gt;aws_profile&lt;/em&gt; to pick it up from default.&lt;/p&gt;

&lt;h2&gt;
  
  
  The .env
&lt;/h2&gt;

&lt;p&gt;As we have previously seen, I want to populate the variables for Terraform automatically. For this, I think the &lt;a href="https://github.com/motdotla/dotenv#readme"&gt;dotenv project&lt;/a&gt; is helpful. Set up a .env file to store your variables and, if there isn't an integration or you're a purist (like me), you can source the file and run any command you want like this: "&lt;em&gt;source .env &amp;amp;&amp;amp; terraform plan."&lt;/em&gt; It will export all variables, and Terraform will pick them up and assign them to the elements defined in the &lt;em&gt;variables&lt;/em&gt; file.&lt;/p&gt;

&lt;p&gt;The only downside here was to export manually with TF_VAR prepended to each variable. But you know, it should take about 10 seconds to do that. I think I can live with it. **&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;VERTICAL&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;my-vertical&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;STACK&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;my-stack&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;PROJECT&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;my-project&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;OWNER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;noovolari
&lt;span class="nv"&gt;REPO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;leapp
&lt;span class="nv"&gt;AUTH&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;my-github-token&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;TABLE&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;eddie-metrics-global-table&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;AWS_SDK_LOAD_CONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true

export &lt;/span&gt;&lt;span class="nv"&gt;TF_VAR_vertical&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$VERTICAL&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TF_VAR_stack&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$STACK&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TF_VAR_project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PROJECT&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TF_VAR_owner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$OWNER&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TF_VAR_repo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$REPO&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TF_VAR_auth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$AUTH&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TF_VAR_table&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$TABLE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The locals
&lt;/h2&gt;

&lt;p&gt;Here I put the local variable I will consistently use on my whole stack to avoid repeating them and clog the configuration files.&lt;/p&gt;

&lt;p&gt;The vertical, stack and project variables are a 3-tier set of constants used to group and identify projects by name. I have defined a composite variable named &lt;em&gt;full&lt;/em&gt; to avoid composing the full project name in the &lt;em&gt;locals&lt;/em&gt; file.&lt;/p&gt;

&lt;p&gt;Moreover setting the &lt;em&gt;tags&lt;/em&gt; like a dictionary let me use them directly as a variable and forget completely about them, but still have them consistent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;locals &lt;span class="o"&gt;{&lt;/span&gt;
  lambda_memory &lt;span class="o"&gt;=&lt;/span&gt; 128
  full        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.vertical&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.stack&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.project&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  tags &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    Vertical    &lt;span class="o"&gt;=&lt;/span&gt; var.vertical
    Stack       &lt;span class="o"&gt;=&lt;/span&gt; var.stack
    Project     &lt;span class="o"&gt;=&lt;/span&gt; var.project
    Name        &lt;span class="o"&gt;=&lt;/span&gt; local.full
    ManagedBy   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The DynamoDB table
&lt;/h2&gt;

&lt;p&gt;I'm cheating a bit because I had already set up the DynamoDB table with Terraform... but it's really tiny so let's just ignore that. As you can see, the &lt;em&gt;tags&lt;/em&gt; variables it is really handy!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_dynamodb_table&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dynamodb_table&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${local.full}-table&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;billing_mode&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PROVISIONED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;read_capacity&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
  &lt;span class="nx"&gt;write_capacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
  &lt;span class="nx"&gt;hash_key&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

  &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;S&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Lambda
&lt;/h2&gt;

&lt;p&gt;Here I'll break down things a bit to better explain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Archive Files
&lt;/h3&gt;

&lt;p&gt;The archive files are just zip files that contain the function and the node_modules folders. The main things to notice here are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;While there is a convenient function in Terraform that does the packaging for you, I needed a more custom approach, and thus there are two commands in the &lt;em&gt;package.json&lt;/em&gt; for building the Lambda and the layer. They copy and zip a folder.&lt;/li&gt;
&lt;li&gt;Never forget to add the &lt;em&gt;source_code_hash&lt;/em&gt; and the sha256 fingerprint! It allows Terraform to put a fingerprint on the package and automatically create new versions of the layer only if something is changed.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;data &lt;span class="s2"&gt;"archive_file"&lt;/span&gt; &lt;span class="s2"&gt;"function_archive"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;type&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"zip"&lt;/span&gt;
  source_dir  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.module&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/../dist/lambda"&lt;/span&gt;
  output_path &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.module&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/../dist/lambda/lambda.zip"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

resource &lt;span class="s2"&gt;"aws_lambda_layer_version"&lt;/span&gt; &lt;span class="s2"&gt;"layer"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  filename            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.module&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/../dist/layers/layers.zip"&lt;/span&gt;
  layer_name          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.full&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-layer"&lt;/span&gt;
  compatible_runtimes &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"nodejs12.x"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  source_code_hash    &lt;span class="o"&gt;=&lt;/span&gt; filebase64sha256&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.module&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/../dist/layers/layers.zip"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The function
&lt;/h3&gt;

&lt;p&gt;The function again is pretty primary. As you can see, I have referenced the data archives containing the Lambda and the lambda layer resource name. I added the environmental variables to let me configure the function from Terraform. If I need to deploy this to track another GitHub repository, I only need to change the variables in the &lt;em&gt;.env&lt;/em&gt; file, and everything will run the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resource &lt;span class="s2"&gt;"aws_lambda_function"&lt;/span&gt; &lt;span class="s2"&gt;"lambda"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  filename      &lt;span class="o"&gt;=&lt;/span&gt; data.archive_file.function_archive.output_path
  function_name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.full&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-lambda"&lt;/span&gt;
  role          &lt;span class="o"&gt;=&lt;/span&gt; aws_iam_role.lambda_role.arn
  handler       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"index.handler"&lt;/span&gt;

  &lt;span class="c"&gt;# Lambda Runtimes can be found here: https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html&lt;/span&gt;
  layers &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;aws_lambda_layer_version.layer.arn]
  runtime     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"nodejs12.x"&lt;/span&gt;
  &lt;span class="nb"&gt;timeout&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"30"&lt;/span&gt;
  memory_size &lt;span class="o"&gt;=&lt;/span&gt; local.lambda_memory

  environment &lt;span class="o"&gt;{&lt;/span&gt;
    variables &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      OWNER &lt;span class="o"&gt;=&lt;/span&gt; var.owner
      REPO &lt;span class="o"&gt;=&lt;/span&gt; var.repo
      AUTH &lt;span class="o"&gt;=&lt;/span&gt; var.auth
      TABLE &lt;span class="o"&gt;=&lt;/span&gt; aws_dynamodb_table.dynamodb_table.name
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  R&amp;amp;D conclusions
&lt;/h1&gt;

&lt;p&gt;Here are my conclusion of my R&amp;amp;D on TypeScript and Terraform&lt;/p&gt;

&lt;p&gt;TypeScript is a potent language. I've always had some problems with JavaScript and its lack of types, and with TypeScript, it feels like a complete experience. I still need to wrap my head around the async/await paradigm and Promise class on the downsides. It's not that they don't work, but, in my opinion, it adds unnecessary overhead while programming. Since TypeScript was an extension of JavaScript, which was designed for asynchronous operations and frontend, I think it's normal to shine in these environments. For backend, synchronous operations, and scripting, I think there are better choices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terraform was mind-blowing.&lt;/strong&gt; What I conservatively forecast to take at least a day to get up and running was done in about an hour. The tooling was great, the documentation was clear, many examples around the internet and on the git repository... what more could I have to ask for?&lt;/p&gt;

&lt;p&gt;There were some minor inconsistencies with the state management, though; just once something went wrong and generating the plan threw an unrecoverable error (probably due to my inexperience). In the end, I resolved pretty quickly by tearing all down and re-creating it, so no-big-deal.&lt;/p&gt;

&lt;h1&gt;
  
  
  And what about metrics?
&lt;/h1&gt;

&lt;p&gt;After some research around the best metrics to track for open-source projects, I set everything up to save:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open/Closed issues and pull requests&lt;/li&gt;
&lt;li&gt;Forks, Stargazers, Watchers, and Subscribers&lt;/li&gt;
&lt;li&gt;Total issues and pull requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea was to get an overall feeling if we are sparking interest in other people and contributing with code or just with issues and enhancements. Those metrics proved very useful and gave us some insight, but after few months of running and reviewing them, we feel that something is missing along the lines.&lt;/p&gt;

&lt;p&gt;Nonetheless, I'm happy we started collecting those metrics and weekly review them.&lt;/p&gt;

&lt;p&gt;It's the drive to do better and improve our community and project.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>typescript</category>
      <category>terraform</category>
      <category>github</category>
    </item>
    <item>
      <title>
Thoughts on Ruby 3?</title>
      <dc:creator>Nicolò Marchesi</dc:creator>
      <pubDate>Sat, 26 Dec 2020 10:42:11 +0000</pubDate>
      <link>https://dev.to/pethron/thoughts-on-ruby-3-51ie</link>
      <guid>https://dev.to/pethron/thoughts-on-ruby-3-51ie</guid>
      <description>&lt;p&gt;&lt;a href="https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/"&gt;Ruby 3 was released&lt;/a&gt; yesterday on Christmas 2020.&lt;/p&gt;

&lt;p&gt;What do you think of the new features?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>ruby</category>
    </item>
    <item>
      <title>AWS multi-account structure with AWS Organization</title>
      <dc:creator>Nicolò Marchesi</dc:creator>
      <pubDate>Wed, 23 Dec 2020 14:25:48 +0000</pubDate>
      <link>https://dev.to/pethron/aws-multi-account-structure-with-aws-organization-412i</link>
      <guid>https://dev.to/pethron/aws-multi-account-structure-with-aws-organization-412i</guid>
      <description>&lt;p&gt;Welcome back to the second part of &lt;strong&gt;how to access your AWS accounts&lt;/strong&gt;. Noticed the final "s" on accounts? Yeah, today I will write about multi-account strategies. We laid the foundations with the previous article on &lt;a href="https://blog.pethron.me/how-to-access-your-aws-account" rel="noopener noreferrer"&gt;how to access your AWS account&lt;/a&gt; by seeing the various strategies at our disposal and when they're a good fit. The good thing is that everything still applies, but we must look at this from the perspective of multiple accounts and organizations.&lt;/p&gt;

&lt;p&gt;Because sooner or later, one AWS account will not be enough to contain all your resources in an organized manner, and nowadays, that moment will come pretty fast too!&lt;/p&gt;

&lt;h1&gt;
  
  
  The evolution of an AWS account
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwopi6dr43lxgvo1k2klg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwopi6dr43lxgvo1k2klg.gif" alt="AccountGIF"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Looks familiar?&lt;/strong&gt; This is more or less the evolution of the AWS account when I started using AWS. The thing is that when you begin extensively using a public cloud provider for development and production workloads, everything will escalate pretty quickly. There are just too many services and resources to keep track of while proceeding at a fast pace. More than ever, if you cramp them in a single AWS account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-account and consolidated billing
&lt;/h2&gt;

&lt;p&gt;By the time I started working with AWS in 2014, there was already the well-established pattern of using consolidated billing to group multiple AWS accounts under a single credit card. That solved a slightly annoying process of keeping track in your AWS bill's central place, but there wasn't any way to centralize the governance.&lt;/p&gt;

&lt;p&gt;We did solve this kind of problem by creating a &lt;strong&gt;root account&lt;/strong&gt; with billing information where only a few people had privileged access. In the root account, only one person had permission to view billing, and few other ones could create roles and manage permissions for everyone else.&lt;/p&gt;

&lt;p&gt;But we still needed a way to tie the corporate identities to the roles to enable single sign-on to the web console and APIs for our developers. We set up the federation process between the root account roles and the users in our user directory. On which, by the way, I've published another thorough tutorial here on &lt;a href="https://blog.pethron.me/how-to-saml-federate-your-aws-account-with-g-suite" rel="noopener noreferrer"&gt;how to SAML federate your AWS account with G Suite&lt;/a&gt;. Check it out if you're curious about the process.&lt;/p&gt;

&lt;p&gt;The nice thing was that we solved the governance problem at the first step. We could define who could access what. The "downside" was that we had to set up a trust relationship with the root account to let people assume the other account's role from the role in the root one. And there wasn't a way to centrally restrict permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS Organization to the rescue
&lt;/h2&gt;

&lt;p&gt;In 2017 AWS announced &lt;strong&gt;AWS Organization&lt;/strong&gt;, which was a big step in standardizing how to govern your AWS accounts. With AWS Organization, we can create and manage AWS accounts via Console and APIs and restrict AWS services with Service Control Policies (SCP).&lt;/p&gt;

&lt;p&gt;It even enabled further organizing the accounts under the organization in Organizational Units (OU) that can share different configurations. On the account management notice, it still lacks the account deletion API, so the process of creating and deleting an account can't be entirely automated.&lt;/p&gt;

&lt;p&gt;The other main feature of the AWS Organization is &lt;strong&gt;Service Control Policies&lt;/strong&gt;. With these, you can enable or disable APIs on an account or OU basis, and I think it's the most underused and essential feature of the whole AWS Organization. Coupled with Permission Boundaries let other people than super-admins manage IAM, which is by definition the most sensitive service in an entire AWS account, without worrying too much that they can cause problems.&lt;/p&gt;

&lt;p&gt;With this graph, you have a quick summary of how much you can restrict your AWS account access. Correctly identifying the permissions that it's safe to give by default and the ones that need some governance escalation to get can increase teams' velocity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft80571udexfhnfbs8pun.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft80571udexfhnfbs8pun.png" alt="Permission intersection"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Multi-account access
&lt;/h1&gt;

&lt;p&gt;Once you have gone to the length of set up your AWS Organization, you need to let other people access the accounts. And at this point, it's usually tough to only rely on IAM users and roles.&lt;/p&gt;

&lt;p&gt;With an AWS Organization, you should &lt;strong&gt;prefer a federated access method&lt;/strong&gt;, and that leaves us with AWS SSO or a SAML based approach. Which one to pick largely depends on how you usually set up accounts and organizational units, so let's take an overview of the two with this perspective.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS SSO
&lt;/h2&gt;

&lt;p&gt;This is the default way suggested by AWS, and it comes with a lot of outstanding features like auditing SSO activity across applications and AWS accounts and multi-factor authentication.&lt;/p&gt;

&lt;p&gt;For AWS SSO to work, you need to enable it with your AWS Organization's root account. Once enabled, you can manage all directory users from the AWS SSO portal and give access to single persons or groups through roles. You can both use the internal user directory of AWS SSO or link an external directory with some third-party identity provider.&lt;/p&gt;

&lt;p&gt;If you have "relatively" few accounts and users, AWS SSO can be the most straightforward way to access your multi-account environment. It's easy to use, it's managed, takes minutes to set up, and has a neat integration with the AWS CLI v2 to impersonate your roles directly from your local environment.&lt;/p&gt;

&lt;p&gt;But it's when you reach hundreds of users and accounts that begin to have some difficulties in management, and it becomes more and more difficult can't keep up with that amount of resources. In my opinion, there's a point at which AWS SSO can't keep up with everything and need a dedicated external solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  SAML Approach
&lt;/h2&gt;

&lt;p&gt;The SAML approach is the manual way of doing AWS SSO. This approach's downside is that you need to set up the federation process and sync between your user directory and roles. You have strict control over your identity provider and AWS accounts and less &lt;em&gt;magic on the&lt;/em&gt; advantage side*.* And you &lt;strong&gt;don't need access to your AWS Organization root account&lt;/strong&gt; because all setup can be done in IAM.&lt;/p&gt;

&lt;p&gt;But you can still divide your whole organization, as I've previously explained: into multiple federated root accounts where you can govern the other chaining directly from IAM. You lose the single-centralized place for user and permission management of AWS SSO, but in fact, you gain multiple areas better to segregate your users, roles, and permission. It's just a matter of getting the segregation right.&lt;/p&gt;

&lt;h1&gt;
  
  
  And if we change the organization?
&lt;/h1&gt;

&lt;p&gt;Right now, we have two strategies at our disposal with our AWS Organization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Centralize everything in AWS SSO&lt;/li&gt;
&lt;li&gt;Split into multiple root accounts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But there is some variable that we can change? We are keeping fixed just one thing, and that is using a single AWS Organization. What happens if we start adding more AWS Organizations instead of relying on only one?&lt;/p&gt;

&lt;h3&gt;
  
  
  Consolidated billing
&lt;/h3&gt;

&lt;p&gt;Off we go with the first &lt;strong&gt;apparent&lt;/strong&gt; downside. We will no longer have a single place to check how much our AWS bill amounts, and instead, we are again on tracking on multiple places.&lt;/p&gt;

&lt;p&gt;But is it a downside? Indeed, we have now split our bills in multiple places. Still, if we segregated the numerous AWS Organizations with some sense (e.g., business units that span across the company or entire departments), we now can have a better view of the single organization's spending. It depends on the use case, but I think it's both a downside and an improvement depending on the perspective.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multiple AWS SSO
&lt;/h3&gt;

&lt;p&gt;Remember we had to have access to the AWS Organization root account to set up AWS SSO? It's a shame not to leverage its features because we have too many accounts and users. But wait, having multiple AWS Organizations should mean having fewer accounts and resources to manage from a single root account and having an overall better management experience on AWS SSO. To me, this is a significant improvement.&lt;/p&gt;

&lt;h3&gt;
  
  
  SAML federation
&lt;/h3&gt;

&lt;p&gt;It doesn't change much on this aspect since it's a manual approach to accessing your accounts. You still need to manually configure your identity provider and account, only with fewer people. I think it's safe to say that it's a draw on this.&lt;/p&gt;

&lt;h3&gt;
  
  
  SCPs
&lt;/h3&gt;

&lt;p&gt;Like having multiple AWS SSO, we can now better tailor our SCPs to the need of that single AWS Organization without having to worry about making some disruptive changes to workloads not related to them. This can lead to some inconsistencies and replication on governance policies if not managed correctly, but overall I think it is an improvement!&lt;/p&gt;

&lt;h3&gt;
  
  
  Reduced blast-radius
&lt;/h3&gt;

&lt;p&gt;In the scenario where some malicious person takes over an AWS Organization root account, if everything is inside just one organization, the blast-radius will be merely devastating. Being in control of the AWS Organization root account lets you access all accounts linked to it and delete resources and backups, not something I'd like to see even in my worst nightmares.&lt;/p&gt;

&lt;p&gt;Having multiple AWS Organizations increases the surface attack, but it shouldn't change much if we're following security best-practices. What is changing is that our other AWS Organizations are safe in the unlikely event of a security breach. It's a bit of a tradeoff, but I think it's again an improvement.&lt;/p&gt;

&lt;h1&gt;
  
  
  To sum up
&lt;/h1&gt;

&lt;p&gt;We covered a little more ground and presented a few ways to handle things at the organization level with multiple AWS Organizations.&lt;/p&gt;

&lt;p&gt;Using a single Organization is the default way to go, but I think it will need dedicated solutions to manage a vast amount of resources in the long run.&lt;/p&gt;

&lt;p&gt;As an alternative, we can shift to a multi-organization environment where each AWS Organization has extensive power and works in very segregated silos. This is a good thing but needs some aggregation tool to view and manage everything centralized.&lt;/p&gt;

&lt;p&gt;Only remember there is no right or wrong since you decide based on your use-case and how your company is structured.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpcdqaup5seymp8s6a062.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpcdqaup5seymp8s6a062.png" alt="Single vs. multi organization"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>security</category>
    </item>
    <item>
      <title>How to access your AWS account</title>
      <dc:creator>Nicolò Marchesi</dc:creator>
      <pubDate>Fri, 04 Dec 2020 14:16:03 +0000</pubDate>
      <link>https://dev.to/pethron/how-to-access-your-aws-account-4ng3</link>
      <guid>https://dev.to/pethron/how-to-access-your-aws-account-4ng3</guid>
      <description>&lt;p&gt;Hey there. You just created your first AWS account, and you can't wait to dive into all the exciting services and technologies that AWS has to offer you to start to build the next big thing. But, wait for a second... are you going to log-in with your root account credentials? Or it's better to generate a new user? Or maybe use a role?&lt;/p&gt;

&lt;p&gt;Slow down a minute, and by the end of the blog post, I promise you will be able to choose the &lt;strong&gt;best way to access your AWS account securely&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Beware, though, we will consider access to a single aws account as we will cover multi-account strategies the next time. We need to walk before we can run, right?&lt;/p&gt;

&lt;h1&gt;
  
  
  Accounts and Resources
&lt;/h1&gt;

&lt;p&gt;Each incredible journey with AWS starts with accounts and resources, and an account is just like an empty box.&lt;/p&gt;

&lt;p&gt;The things you can put inside your account can be anything related to AWS's services, for example, networks, virtual machines, containers, and so on.&lt;/p&gt;

&lt;p&gt;But the most crucial part is that by default, no account shares any resource so that nothing can go in or out between two different AWS account. And this is great to divide your workloads and be sure that only the right people access everything.&lt;/p&gt;

&lt;h1&gt;
  
  
  IAM — Identity &amp;amp; Access Management
&lt;/h1&gt;

&lt;p&gt;Within each account, IAM is there to protect the resources inside your account by managing which entities can perform some actions on those resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;WHO — which identities&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WHAT — can do some actions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WHERE — on some resources&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HOW — and met some conditions&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I define these as the &lt;strong&gt;4W&lt;/strong&gt;, and for now, we will need to focus only on the first 3.&lt;/p&gt;

&lt;h2&gt;
  
  
  In the beginning — the root user
&lt;/h2&gt;

&lt;p&gt;When you logged-in after you created the AWS account, you used that account &lt;strong&gt;root user&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is different from the other ones you can create because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Created on the account registration&lt;/li&gt;
&lt;li&gt;You can sign in using the email address and password that you used to create the account&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You can access the billing information&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It has unrestricted access to all resources in your account&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This user is super important, and you should protect it in the best way you can. It's a super-administrator on steroids since it's able to view the billing information along with being able to do everything with all your resources.&lt;/p&gt;

&lt;p&gt;So, the first thing to do should be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable multi-factor authentication (MFA) and save the QR code in a secure place&lt;/li&gt;
&lt;li&gt;Delete all access keys related to this user to disable programmatic access (you wouldn't need this anyway!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;And the very next thing should be to decide how you will access this account from now on.&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  From inside AWS
&lt;/h1&gt;

&lt;p&gt;Let's focus for now on what AWS gives us without relying on 3rd parties. This is especially useful if we focus on this single account because we need to master the three IAM building blocks: user, groups, and roles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LNbadMkE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1606989583888/S9TFFdWeS.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LNbadMkE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1606989583888/S9TFFdWeS.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Users
&lt;/h2&gt;

&lt;p&gt;Remember the root user? IAM users are the same type of entity but differently from the root user. They don't have default billing permissions and administrator access (unless you give them... which you shouldn't).&lt;/p&gt;

&lt;p&gt;With a user, we can create an entity that can log-in to the AWS web console or with programmatic access through a set of credentials (an access key and a secret access key) that are fixed and will not change over time. Along with SSH/HTTPS keys for AWS CodeCommit, or Credentials for Amazon Keyspaces (for Apache Cassandra)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sign-in credentials for the web console&lt;/li&gt;
&lt;li&gt;Access and secret key credentials for programmatic access for APIs, CLI, and SDK&lt;/li&gt;
&lt;li&gt;SSH/HTTPS keys for AWS CodeCommit&lt;/li&gt;
&lt;li&gt;Credentials for Amazon Keyspaces (for Apache Cassandra)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Granular access
&lt;/h3&gt;

&lt;p&gt;It's entirely possible with an IAM user to enable one or more access keys depending on how you want that user to behave. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A data-analyst that needs to check only the analytics on the web console but without needing programmatic access&lt;/li&gt;
&lt;li&gt;A serverless DevOps which need to perform actions on the console and use the CLI to provide some resources will need both of these access&lt;/li&gt;
&lt;li&gt;A developer working on a single repository and doesn't need to interact with AWS resources will have SSH/HTTPS keys for AWS CodeCommit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be aware that &lt;strong&gt;sharing&lt;/strong&gt; IAM user credentials &lt;strong&gt;is a big no-no,&lt;/strong&gt; as it's the first step to lose credentials and governance and lay yourself open to security threats.&lt;/p&gt;

&lt;p&gt;You don't want your production account completely erased in favor of a full set of bitcoin miners, do you?&lt;/p&gt;

&lt;h3&gt;
  
  
  Enforce security
&lt;/h3&gt;

&lt;p&gt;Another cool feature of AWS IAM users is to be able to enforce password complexity (which is by default pretty high with a length between 8-128 characters, a minimum of 3 special characters, and to not be identical to your AWS account name or email address) and password expiration time to ensure that after a certain time your users will change the password.&lt;/p&gt;

&lt;p&gt;On top of that, you can enable MFA with various devices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A virtual MFA device with an authenticator app installed on your mobile device or computer&lt;/li&gt;
&lt;li&gt;A U2F security key like a YubiKey or any other compliant U2F device&lt;/li&gt;
&lt;li&gt;Another hardware MFA device like the Gemalto token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general, there is a granular approach as you can have specific means for each IAM user.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use
&lt;/h3&gt;

&lt;p&gt;If you have &lt;strong&gt;very few users&lt;/strong&gt; (between 1-5) with precise permissions tied to each one, IAM users can save some time on the initial configuration and console access. &lt;strong&gt;Beware of static credentials&lt;/strong&gt; because they are substantial security issues, so handle with extreme care. Or use the AWS CLI get-session-token to generate temporary credentials out of static ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Groups
&lt;/h2&gt;

&lt;p&gt;Not an entity per se, but IAM Groups are there to bundle IAM users together and give the same set of permissions to a group of users. This smooth a little the rough edges of IAM users, but overall the same things we have seen for IAM users apply.&lt;/p&gt;

&lt;p&gt;A nice thing to keep in mind is that an IAM user can still have personal policies while associated with a group, with the resulting permission equals the merge of the group and personal ones.&lt;/p&gt;

&lt;p&gt;This should be more the exception than the typical workflow. With too many individual permissions, we create many unmaintainable policies and lose the overall overview of the permissions in the account.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use
&lt;/h3&gt;

&lt;p&gt;If you have &lt;strong&gt;few users&lt;/strong&gt; (between 5-15), IAM Groups can save some of the hassles of managing and configuring each IAM user. But the same consideration as IAM users applies, so if possible, avoid them unless you are just working on a single account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roles
&lt;/h2&gt;

&lt;p&gt;And here we are to AWS roles. IAM roles can have permissions (just like users) and log to the console (again like users...). Instead of being uniquely associated with one person, anyone who needs it can &lt;strong&gt;assume&lt;/strong&gt; a role.&lt;/p&gt;

&lt;p&gt;So a person &lt;strong&gt;wears the cap&lt;/strong&gt; of the role which he wants to assume, and&lt;/p&gt;

&lt;p&gt;The IAM role logo just gained a lot more sense, right?&lt;/p&gt;

&lt;h3&gt;
  
  
  Temporary Credentials
&lt;/h3&gt;

&lt;p&gt;Another key difference from IAM users is that IAM roles don't have static credentials. When someone assumes the roles, a set of &lt;strong&gt;temporary credentials&lt;/strong&gt; is generated and given. It's possible to customize how long those credentials will last and further restrict access if needed.&lt;/p&gt;

&lt;p&gt;Time can be set from 900 seconds (15 minutes) up to 12 hours, but in my opinion, setting one-hour-long expiration is the best tradeoff between security and performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  CloudTrail monitoring
&lt;/h3&gt;

&lt;p&gt;I'll mention this because some people don't use roles because they think that they can't audit what roles can do. The truth is that you can, and you should. By enabling Cloudtrail monitoring, you can see all actions performed inside your account, so you can always know what's going on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cross Account
&lt;/h3&gt;

&lt;p&gt;This will be discussed in more detail in another blog post, as we are focusing on single accounts, but for now, be aware that IAM roles can be used to give access to other IAM roles or IAM users.&lt;/p&gt;

&lt;p&gt;And that's incredibly useful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entry-point required
&lt;/h3&gt;

&lt;p&gt;And now for the downsides. Unfortunately, you can't give direct access to the console and temporary credentials to an IAM role. First, you need to have set up a user or a federated role (more on this in a few paragraphs) to give access to an IAM role.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Always.&lt;/strong&gt; The sole fact that IAM roles are not tied with static credentials makes them the best way to access your cloud. Combine them with the ability to monitor IAM roles actions and enforce security even with MFA. The only downside is that it a little more configuration, but it's a low price to pay in my opinion.&lt;/p&gt;

&lt;h1&gt;
  
  
  From outside AWS
&lt;/h1&gt;

&lt;p&gt;And now, let's see what we can do when we go into the field of corporate identities. I'm referring to use an Identity Provider as an Identities source and log-in in with our corporate email and password.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b-NwTrMq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1606989619547/GVvPK4WQe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b-NwTrMq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1606989619547/GVvPK4WQe.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Federation
&lt;/h2&gt;

&lt;p&gt;But what do we mean by federation? On one side, we have the identity provider. These systems contain a directory of users and some software that can communicate through specific federation protocols. All the data of our users reside as &lt;strong&gt;Identities&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On the other side, there is your AWS Account as an &lt;strong&gt;Identity Consumer&lt;/strong&gt;. It maintains a reference to the identities without saving them. On this side, we generally have much more granular authorization levels (thanks, IAM!).&lt;/p&gt;

&lt;p&gt;So the &lt;strong&gt;federation&lt;/strong&gt; is the relationship of trust that makes the Identity Consumer able to reference the Identities in the Identity Provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  SAML Federation
&lt;/h2&gt;

&lt;p&gt;The most common definition for Security Assertion Markup Language (SAML) is an open standard for exchanging authentication and authorization data between parties. This means that we can use our Identities to log in to AWS and even get temporary credentials by assuming roles. It's a generalistic approach you can apply to nearly all Identity Providers.&lt;/p&gt;

&lt;h3&gt;
  
  
  The trust relationship
&lt;/h3&gt;

&lt;p&gt;To set up the federation between the two parties, we need to create and manage an &lt;strong&gt;IAM Identity Provider&lt;/strong&gt;. This is necessary because it represents the real Identity Provider and holds the shared secret that lets the two parties communicate. Moreover, inside each role that we want our users to assume, we will define a &lt;strong&gt;trust policy&lt;/strong&gt; to allows entities related to the IAM Identity Provider to assume the role:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oexNMd9U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1606989662460/6A_UlKzRB.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oexNMd9U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1606989662460/6A_UlKzRB.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom management
&lt;/h3&gt;

&lt;p&gt;The thing is that managing the federation by yourself can be challenging and time-consuming at first. There are some concepts to understand well, and you need to create a bunch of entities, relations, and custom things to make this happen. To get an idea, you can find a complete tutorial example &lt;a href="https://blog.pethron.me/how-to-saml-federate-your-aws-account-with-g-suite"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use
&lt;/h3&gt;

&lt;p&gt;In general, this is an excellent and battle-tested approach that will work in nearly all cases. Still, the custom management of identities can be difficult and time consuming for inexperienced people.&lt;/p&gt;

&lt;p&gt;Typical use-cases are if you want to manage this yourself for security or compliance purposes. You don't have access to your AWS Organization, or AWS SSO does not yet support your Identity Provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS SSO
&lt;/h2&gt;

&lt;p&gt;This is the cloud-based and managed SSO service that lets you connect your Identity Provider with your AWS account.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS Organization
&lt;/h3&gt;

&lt;p&gt;To set up AWS SSO, you will need to configure AWS Organizations, and for now, you can think of it to manage multiple AWS accounts. To keep things brief, you need to know that setting up an AWS Organization needs extensive permissions (namely the root user).&lt;/p&gt;

&lt;h3&gt;
  
  
  Internal Identity Storage
&lt;/h3&gt;

&lt;p&gt;By default, AWS SSO provides a directory to store your user information and credentials to serve as Identity Provider directly. It's great if you don't already have an Identity Provider or don't want to go to the trouble of setup one.&lt;/p&gt;

&lt;h3&gt;
  
  
  External Identity Storage
&lt;/h3&gt;

&lt;p&gt;But suppose your organization already uses some User directory, like Microsoft Active Directory. In that case, you can connect it to AWS SSO, eliminating the need to maintain two distinct directories with &lt;strong&gt;automatic provisioning&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Beware, though, that this feature is supported only on a limited set of Identity Providers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/azure-ad-idp.html"&gt;Azure AD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/okta-idp.html"&gt;Okta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/onelogin-idp.html"&gt;OneLogin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/pingidentity.html"&gt;Ping Identity&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Multi-factor authentication
&lt;/h3&gt;

&lt;p&gt;With AWS SSO, you can configure an MFA device for your users inside the service. Right now, it supports Authenticator apps like Google Authenticator and security keys like the Yubikey. The internal solution is exciting, but it lacks MFA support if set up on an external Identity Provider side.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use
&lt;/h3&gt;

&lt;p&gt;It's the standard suggested by AWS, and it can be the default way to go if unsure how to proceed. Still, there are at least a couple of requirements that you need to tick make the most out of this solution:&lt;/p&gt;

&lt;p&gt;you've already set up your AWS Organization, &lt;strong&gt;and&lt;/strong&gt; you have access to the root account. You want to keep your Identities within AWS SSO or use an identity provider supported by automatic provisioning.&lt;/p&gt;

&lt;h1&gt;
  
  
  Final Notes
&lt;/h1&gt;

&lt;p&gt;So, we have laid out the foundations to access a single AWS account, and now you should have the elements to choose the best method for your specific use-case. We will use this to cover the ground to multi-account management and AWS Organizations in the next blog post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leapp
&lt;/h2&gt;

&lt;p&gt;I advise developers to use some tool that helps them store all the data needed to connect to their AWS account. My team and I are developing an open-source tool that supports all these use-cases, so feel free to check out:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Noovolari"&gt;
        Noovolari
      &lt;/a&gt; / &lt;a href="https://github.com/Noovolari/leapp"&gt;
        leapp
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Leapp is the tool to access your cloud;  It securely stores your access information and generates temporary credential sets to access your cloud ecosystem from your local machine.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Leapp&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://github.com/Noovolari/leapp/releases/latest"&gt;&lt;img src="https://camo.githubusercontent.com/e762f8e1ffabfc84fb01c98ab628b76b84652f18316ad394bddbe945f5ed81cf/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f6e6f6f766f6c6172692f6c656170702f6c61746573742f746f74616c" alt="Github All Releases"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://www.leapp.cloud/" rel="nofollow"&gt;https://www.leapp.cloud/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Roadmap: &lt;a href="https://github.com/Noovolari/leapp/projects/1"&gt;Roadmap&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Tutorials: &lt;a href="https://raw.githubusercontent.com/Noovolari/leapp/master/#tutorials"&gt;Tutorials&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Chat with us: &lt;a href="https://discord.gg/wHh2kyK" rel="nofollow"&gt;Discord&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://raw.githubusercontent.com/Noovolari/leapp/master/.github/images/README-1.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iv7fw7dU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/Noovolari/leapp/master/.github/images/README-1.png" alt="logo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Leapp is your everyday companion to access your cloud; designed to work with Cloud Providers APIs, CLIs, and SDKs
It's a software that securely stores your access information and generates temporary credential sets to access your cloud ecosystem from your local machine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For example, while using the AWS CLI it may become annoying to switch to a different profile or use the --profile argument before issuing every command.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Leapp lets you have a new set of credentials and give access to that account with a click.&lt;/p&gt;
&lt;p&gt;Leapp also will manage Federated access through Identity Provides.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://raw.githubusercontent.com/Noovolari/leapp/master/.github/images/Leapp-Keynote-pitch.001.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ebB6sevg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/Noovolari/leapp/master/.github/images/Leapp-Keynote-pitch.001.png" alt="Leapp App"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
Key features&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Switch account with a click&lt;/strong&gt;: collect all your cloud accounts access data in a single place and connect straight away. Leverage cloud RBAC to impersonate your roles in a click, and don’t waste time manually manage or edit your credentials file.&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Noovolari/leapp"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>aws</category>
      <category>security</category>
    </item>
    <item>
      <title>How to update in bulk G Suite users custom attributes with Google Admin SDK</title>
      <dc:creator>Nicolò Marchesi</dc:creator>
      <pubDate>Mon, 09 Nov 2020 09:53:37 +0000</pubDate>
      <link>https://dev.to/pethron/how-to-update-in-bulk-g-suite-users-custom-attributes-with-google-admin-sdk-4l6e</link>
      <guid>https://dev.to/pethron/how-to-update-in-bulk-g-suite-users-custom-attributes-with-google-admin-sdk-4l6e</guid>
      <description>&lt;h1&gt;
  
  
  A scenario to use Google APIs to enable continuous management of AWS SAML federation in Python
&lt;/h1&gt;

&lt;p&gt;In my  &lt;a href="https://blog.pethron.me/how-to-saml-federate-your-aws-account-with-g-suite" rel="noopener noreferrer"&gt;previous blog post&lt;/a&gt;, we discussed in-depth how to set-up a federation between AWS and G Suite to enable developers to log-in to the AWS Console through single sign-on (SSO) and generate short-lived local credentials with &lt;a href="https://github.com/Noovolari/leapp" rel="noopener noreferrer"&gt;Leapp&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While discussing in the Reddit forum, one exciting question came out:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if I add a new AWS IAM role that I want lots of users to assume from G Suite – would I have to add them to each user manually, or is there a better way?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thing is... there is! And I'll show you how to do that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attention please!
&lt;/h3&gt;

&lt;p&gt;You can &lt;strong&gt;scroll down to the TL;DR section&lt;/strong&gt; for the busiest people who don't need to dive deep into how the script works and prerequisites. I suggest you at least take a look at the configuration part.&lt;/p&gt;

&lt;p&gt;Be aware that we will programmatically change data with extensive permissions, but there is no other way to accomplish the same thing so be careful. I suggest you try this on a test environment before changing anything on your real users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't make the sysadmin team angry!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a Google Cloud Platform Project&lt;/li&gt;
&lt;li&gt;Enable the Admin SDK&lt;/li&gt;
&lt;li&gt;Create the OAuth Consent Screen&lt;/li&gt;
&lt;li&gt;Create the OAuth Client&lt;/li&gt;
&lt;li&gt;Configure the script&lt;/li&gt;
&lt;li&gt;Run the script&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A G Suite subscription with an admin account&lt;/li&gt;
&lt;li&gt;A Google Cloud Platform account&lt;/li&gt;
&lt;li&gt;The custom schema definition&lt;/li&gt;
&lt;li&gt;A list of users we want to update&lt;/li&gt;
&lt;li&gt;Account number, role names and provide names to give access to&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ — if you don't have already, you can follow &lt;a href="https://blog.pethron.me/how-to-saml-federate-your-aws-account-with-g-suite" rel="noopener noreferrer"&gt;this guide&lt;/a&gt; to set up the federation between AWS and G Suite&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  1. Create a Google Cloud Platform Project
&lt;/h1&gt;

&lt;p&gt;First of all, you need to create a GCP Project, so head to &lt;a href="https://console.cloud.google.com/projectcreate" rel="noopener noreferrer"&gt;https://console.cloud.google.com/projectcreate&lt;/a&gt; and:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Give a name to the project&lt;/strong&gt; — use a meaningful name. For example &lt;strong&gt;test-update-user-ca&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Select the organization&lt;/strong&gt; —  choose the one on which your users resides&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681016327%2FxdqcVh4-r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681016327%2FxdqcVh4-r.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just wait a few seconds for GCP to provision your project and once it's ready, select it from the drop-down menu and proceed to the next step.&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Enable the Admin SDK
&lt;/h1&gt;

&lt;p&gt;G Suite offers in the &lt;a href="https://admin.google.com/ac/users" rel="noopener noreferrer"&gt;Google Admin User Console&lt;/a&gt; a way to bulk update the users, but unfortunately, it &lt;strong&gt;does not allow to change their custom SAML attribute values&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For this, you have to use the Google Admin SDK and programmatically update users. But in order to do so you first need to enable the Admin APIs for this project. From the menu, select &lt;strong&gt;API &amp;amp; Services, Library.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681682737%2FILTyS9DZT.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681682737%2FILTyS9DZT.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From here, type in the search box &lt;strong&gt;admin&lt;/strong&gt; and click on the first search result: &lt;strong&gt;Admin SDK&lt;/strong&gt;. Just click on the ENABLE button, and you're good to go.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681288984%2FMhrYGhzYO.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681288984%2FMhrYGhzYO.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Create the OAuth consent screen
&lt;/h1&gt;

&lt;p&gt;For the next steps, we will use the OAuth client authentication and authorization method. For security purposes, service accounts and credentials can't be used to access the Admin SDK, so we are forced to use the OAuth client flow.&lt;/p&gt;

&lt;p&gt;But before we can create the OAuth client, we need to set up the OAuth consent screen. From the menu, select &lt;strong&gt;API &amp;amp; Services, OAuth consent screen.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681322002%2Fq-82qX2x7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681322002%2Fq-82qX2x7.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google will prompt you to select the application type since we use it only for internal purposes (we don't intend to make available the application to everyone). Select &lt;strong&gt;internal&lt;/strong&gt; and click &lt;strong&gt;create&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681350529%2FPRSOEzG5C.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681350529%2FPRSOEzG5C.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give any name you want to the consent screen, fill in the email needed for contact information, and then set the &lt;strong&gt;scopes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To correctly set up the application and don't get some warnings during the script execution, we have to tell the application the scope we are requesting. Basically our script will require access to the Admin APIs, and here we will set that we are granting that access.&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;add or remove scopes&lt;/strong&gt; and, at the end of the page, manually add a scope to &lt;a href="https://www.googleapis.com/auth/admin.directory.user" rel="noopener noreferrer"&gt;https://www.googleapis.com/auth/admin.directory.user&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681375851%2FV2zihuQD2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681375851%2FV2zihuQD2.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;add to table&lt;/strong&gt; and &lt;strong&gt;update&lt;/strong&gt; to commit your changes.&lt;/p&gt;

&lt;p&gt;Review your work and proceed to the next step.&lt;/p&gt;

&lt;h1&gt;
  
  
  4. Create the OAuth client
&lt;/h1&gt;

&lt;p&gt;Before we can dive into the code, the last step is to enable our code to interact with the Google Admin APIs. For this, we need to create an OAuth client with secrets shared between our script and Google.&lt;/p&gt;

&lt;p&gt;From the menu, select &lt;strong&gt;API &amp;amp; Services, Credentials.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681418692%2FfDajG5eLh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681418692%2FfDajG5eLh.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;create credentials&lt;/strong&gt; and select &lt;strong&gt;OAuth client ID&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681433649%2F-5r-Y8Jgc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681433649%2F-5r-Y8Jgc.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill in the information about the client and click on &lt;strong&gt;create&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681451287%2FSR16S_rYw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681451287%2FSR16S_rYw.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you have created the client, you will be shown the client secret and client id. We don't need to copy them from here but download the .json file from the credentials dashboard. So close the pop-up and click on the download button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681468341%2Fh0G1okyXK.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604681468341%2Fh0G1okyXK.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you have downloaded the file, rename it &lt;strong&gt;credentials.json&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  5. Configure the script
&lt;/h1&gt;

&lt;p&gt;Let's review the most important part of the script and how do they work, but before going deep, let's quickly review how the script is set up and works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses poetry (&lt;a href="https://python-poetry.org/" rel="noopener noreferrer"&gt;https://python-poetry.org/&lt;/a&gt;) as package and project management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;credentials.json&lt;/strong&gt; — place the file we downloaded before at the root of the project&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;custom-schema.yaml&lt;/strong&gt; — contains how you configured the custom schema, change it accordingly to your settings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;federation.yaml&lt;/strong&gt; — contains the list of users, together with a list of federations to apply to the custom schema fields&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ — the script supports only a multi-value field for the federated role; check the &lt;a href="https://blog.pethron.me/how-to-saml-federate-your-aws-account-with-g-suite" rel="noopener noreferrer"&gt;previous guide&lt;/a&gt; for more info about it&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  a. Clone the repository
&lt;/h2&gt;

&lt;p&gt;I have already set up the whole project on a Github repo:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/pethron" rel="noopener noreferrer"&gt;
        pethron
      &lt;/a&gt; / &lt;a href="https://github.com/pethron/gsuite-custom-schema-update" rel="noopener noreferrer"&gt;
        gsuite-custom-schema-update
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;A scenario to use Google APIs to enable continuous management of AWS SAML federation in Python.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/pethron/gsuite-custom-schema-update" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;You need to clone or head to the repository and download and unzip the archive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/pethron/gsuite-custom-schema-update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  b. Install dependencies
&lt;/h2&gt;

&lt;p&gt;I use poetry (&lt;a href="https://python-poetry.org/" rel="noopener noreferrer"&gt;https://python-poetry.org/&lt;/a&gt;) as package and project management, so you will be able to install all dependencies in a managed virtual environment by just running:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you prefer other methods, the &lt;strong&gt;requirements.txt&lt;/strong&gt; file is present, so you can still run:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  c. The custom schema file
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;custom-schema.yaml&lt;/strong&gt; file tells the script how to correctly create the custom attribute structure to be pushed on the user; the default attributes are the same used in the previous guide, so change it according to your environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt; — the name you give to the custom schema&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;session&lt;/strong&gt; — the name you give to the attribute representing the &lt;strong&gt;session duration&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;role&lt;/strong&gt; — the name you give to the attribute representing the &lt;strong&gt;federated role&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS SAML&lt;/span&gt;
&lt;span class="na"&gt;session&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SessionDuration&lt;/span&gt;
&lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;FederationRole&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  d. The federation file
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;federation.yaml&lt;/strong&gt; file tells the script the values that need to be pushed on the user (I choose to use the YAML notation as I think it's a lot more readable than JSON).&lt;/p&gt;

&lt;p&gt;At the document root, we have a list of users with their emails. For each user, there is a &lt;strong&gt;federations&lt;/strong&gt; field containing a list of the data used to create the string to update the custom schema:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;email&lt;/strong&gt; — the email of the user to change the custom schema attributes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;account&lt;/strong&gt; — the account number where the IAM Identity Provider and IAM Role resides&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;role&lt;/strong&gt; — the federated role name (the script will derive the ARN)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;provider&lt;/strong&gt; — the provider name (again, the script will derive the ARN)
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;john.doe@mydomain.net&lt;/span&gt;
  &lt;span class="na"&gt;federations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;account&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;123456789123&lt;/span&gt;
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fooRole&lt;/span&gt;
      &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fooProvider&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;account&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;123456789123&lt;/span&gt;
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;barRole&lt;/span&gt;
      &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fooProvider&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;account&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;345678912345&lt;/span&gt;
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;foobarRole&lt;/span&gt;
      &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;barProvider&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h1&gt;
  
  
  6. Run the script
&lt;/h1&gt;

&lt;p&gt;To run the script, change directory to the project root folder and type:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cli.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  a. Get Credentials
&lt;/h2&gt;

&lt;p&gt;This is the first thing that will run in our script (after loading the custom-schema and federations files). It will obtain a set of credentials to call the Google Admin Directory APIs.&lt;/p&gt;

&lt;p&gt;On the first run, the browser will pop-up asking you to authenticate and accept the consent screen we configured before. Next, it will store the token needed to authenticate the API calls in a file named &lt;strong&gt;token.pickle&lt;/strong&gt;, and every time the token expires, the browser will pop-up to let you authenticate again. &lt;/p&gt;

&lt;p&gt;Notice that we are requesting exactly access to the same API we configured earlier in the consent screen: &lt;a href="https://www.googleapis.com/auth/admin.directory.user" rel="noopener noreferrer"&gt;https://www.googleapis.com/auth/admin.directory.user&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_credentials&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;creds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;token.pickle&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;token.pickle&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;creds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pickle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;creds&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;creds&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expired&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;refresh_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;flow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;InstalledAppFlow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_client_secrets_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;credentials.json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://www.googleapis.com/auth/admin.directory.user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;creds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_local_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Save the credentials for the next run
&lt;/span&gt;        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;token.pickle&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;pickle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;creds&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  b. Build the service client and retrieve users
&lt;/h2&gt;

&lt;p&gt;Here is the first step of our main script. It builds the service client and fires a query to list the users in our organization. We can further filter the users using our Organizational Units through the query parameter in case.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ — the maximum number of user retrieved is 5, and the API can retrieve at most 500 users. Change the number to your needs once tested.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;creds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_credentials&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;admin&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;directory_v1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Call the Admin SDK Directory API
&lt;/span&gt;    &lt;span class="c1"&gt;# If need change like "orgUnitPath='/&amp;lt;my organizational unit&amp;gt;'"
&lt;/span&gt;    &lt;span class="n"&gt;orgPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;orgUnitPath=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;users&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my_customer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                   &lt;span class="n"&gt;projection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;full&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                   &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;orgPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                   &lt;span class="n"&gt;maxResults&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# max value is 500
&lt;/span&gt;                                   &lt;span class="n"&gt;orderBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;users&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  c. Iterate and find users to change
&lt;/h2&gt;

&lt;p&gt;This small snippet of code is just a quick and dirty way to compare the users we retrieved with the ones defined in the &lt;strong&gt;federation.yaml&lt;/strong&gt; file, and &lt;strong&gt;apply changes only to them&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# A user can have multiple defined emails 
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;emails&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="c1"&gt;# Let's iterate over all users defined in federation.yaml
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;federation&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;federations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Apply changes only if current user is found in federation.yaml
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;federation&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;address&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Update user {0} with the following custom schemas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;address&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="n"&gt;userUpdated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;update_saml_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema_config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;federation&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;federations&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{0} {1} {2}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;primaryEmail&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;userUpdated&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  d. Update the SAML attributes and preserve the others
&lt;/h2&gt;

&lt;p&gt;And finally to the function that generates the new custom schema. As you can see, we will generate an array of custom schema roles, so &lt;strong&gt;it will work only if you choose a multi-value field for the federated role field&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The neat thing is that by copying the current version of all the custom schemas, we can preserve all other custom schemas we defined and apply changes only to the one defined in the &lt;strong&gt;custom-schema.yaml&lt;/strong&gt; file.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_saml_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema_config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;federations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session_duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;28800&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;custom_schema_roles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;federation&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;federations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;custom_schema_roles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;work&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:iam::{0}:role/{1},arn:aws:iam::{0}:saml-provider/{2}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;federation&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;account&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;federation&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;federation&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;provider&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;current_schemas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;customSchemas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;customSchemas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;schema_config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;schema_config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;session&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;session_duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;schema_config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;custom_schema_roles&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;customSchemas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;current_schemas&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;users&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;customSchemas&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I set a default value for session duration of 28800; which means that the session will expire after 8 hours. Change to fit your use-case if needed.&lt;/p&gt;
&lt;h2&gt;
  
  
  e. Manually update the roles on the AWS accounts
&lt;/h2&gt;

&lt;p&gt;After you made changes, you need to add the IAM roles' trust relationship to allow the user to assume the role after logging in with G Suite. Again you can find extensive information on how to do that in my previous blog post.&lt;/p&gt;
&lt;h1&gt;
  
  
  [PRO TIP] Configure Leapp
&lt;/h1&gt;

&lt;p&gt;After those two tutorials, you have deepened your knowledge on how to set up SSO federation for your G Suite users to AWS accounts role, and update more easily the cloud accounts on which your developers, sysadmins, and DevOps can access.&lt;/p&gt;

&lt;p&gt;A good next step is to ease the process of accessing your cloud accounts.&lt;/p&gt;

&lt;p&gt;We have developed an open-source tool for easily storing your cloud accounts access data and generating temporary credentials to access your cloud accounts from the local environment.&lt;/p&gt;

&lt;p&gt;Head to the repository to find everything on how to configure and use it.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Noovolari" rel="noopener noreferrer"&gt;
        Noovolari
      &lt;/a&gt; / &lt;a href="https://github.com/Noovolari/leapp" rel="noopener noreferrer"&gt;
        leapp
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Leapp is the DevTool to access your cloud
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/Noovolari/leapp.github/images/README-1.png#gh-dark-mode-only"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FNoovolari%2Fleapp.github%2Fimages%2FREADME-1.png%23gh-dark-mode-only" alt="Leapp" height="150"&gt;&lt;/a&gt;
    &lt;a rel="noopener noreferrer" href="https://github.com/Noovolari/leapp.github/images/README-1-dark.png#gh-light-mode-only"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FNoovolari%2Fleapp.github%2Fimages%2FREADME-1-dark.png%23gh-light-mode-only" alt="Leapp" height="150"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Leapp&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;
  &lt;a href="https://www.leapp.cloud" rel="nofollow noopener noreferrer"&gt;Website&lt;/a&gt; |
  &lt;a href="https://roadmap.leapp.cloud/tabs/4-in-progress" rel="nofollow noopener noreferrer"&gt;Roadmap&lt;/a&gt; |
  &lt;a href="https://medium.com/leapp-cloud" rel="nofollow noopener noreferrer"&gt;Blog&lt;/a&gt; |
  &lt;a href="https://join.slack.com/t/noovolari/shared_invite/zt-opn8q98k-HDZfpJ2_2U3RdTnN~u_B~Q" rel="nofollow noopener noreferrer"&gt;TOPS community&lt;/a&gt; |
  &lt;a href="https://docs.leapp.cloud" rel="nofollow noopener noreferrer"&gt;Documentation&lt;/a&gt; |
  &lt;a href="https://docs.leapp.cloud/latest/troubleshooting/app-data/" rel="nofollow noopener noreferrer"&gt;Troubleshooting&lt;/a&gt;
&lt;/h4&gt;
&lt;/div&gt;

&lt;p&gt;
  &lt;a href="https://github.com/Noovolari/leapp/blob/master/LICENSE" rel="noopener noreferrer"&gt;&lt;img alt="License" src="https://camo.githubusercontent.com/17dbabd356010721fd158a5cb844cfe0d41314e02926fb4ad7fd088488cbdcc0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6e6f6f766f6c6172692f6c65617070"&gt;&lt;/a&gt;
  &lt;a href="https://join.slack.com/t/noovolari/shared_invite/zt-opn8q98k-HDZfpJ2_2U3RdTnN~u_B~Q" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cdb9967c52736ff057d5000dd749a3ac0f738c01afb41eb74bd46815dd5c2ead/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f736c61636b2d6f6e6c696e652d677265656e" alt="Slack"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/dea373660641792617e07cc71f7d93ca86e4b394f8cbb11aebd5f68186dcda4e/68747470733a2f2f64336f35396173613875646371392e636c6f756466726f6e742e6e65742f636f7665726167652d6261646765732f636f72652d6261646765732e737667"&gt;&lt;img src="https://camo.githubusercontent.com/dea373660641792617e07cc71f7d93ca86e4b394f8cbb11aebd5f68186dcda4e/68747470733a2f2f64336f35396173613875646371392e636c6f756466726f6e742e6e65742f636f7665726167652d6261646765732f636f72652d6261646765732e737667"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/6c3b56aa94fd3131166acbb45f1fa91f4e04c60e7f11322636e43f1470df7927/68747470733a2f2f64336f35396173613875646371392e636c6f756466726f6e742e6e65742f636f7665726167652d6261646765732f636c692d6261646765732e737667"&gt;&lt;img src="https://camo.githubusercontent.com/6c3b56aa94fd3131166acbb45f1fa91f4e04c60e7f11322636e43f1470df7927/68747470733a2f2f64336f35396173613875646371392e636c6f756466726f6e742e6e65742f636f7665726167652d6261646765732f636c692d6261646765732e737667"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;⚡ Lightning Fast, Safe, Desktop App for Cloud credentials managing and generation&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leapp&lt;/strong&gt; is a Cross-Platform Cloud access App, built on top of &lt;a href="https://github.com/electron/electron" rel="noopener noreferrer"&gt;Electron&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The App is designed to &lt;strong&gt;manage and secure Cloud Access in multi-account environments,&lt;/strong&gt; and it is available for MacOS, Windows, and Linux.&lt;/p&gt;

&lt;p&gt;For more information about features go to &lt;a href="https://docs.leapp.cloud/" rel="nofollow noopener noreferrer"&gt;our documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/Noovolari/leapp.github/images/Leapp-animation.gif"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FNoovolari%2Fleapp.github%2Fimages%2FLeapp-animation.gif" alt="Web interface gif"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;✨ Features&lt;/h1&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cloud credentials generation in 1 click&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data &lt;a href="https://docs.leapp.cloud/latest/security/system-vault/" rel="nofollow noopener noreferrer"&gt;stored locally encrypted&lt;/a&gt; in the OS System Vault&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multiple Cloud-Access supported &lt;a href="https://docs.leapp.cloud/latest/configuration/" rel="nofollow noopener noreferrer"&gt;strategies&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic &lt;a href="https://docs.leapp.cloud/latest/security/credentials-generation/aws/" rel="nofollow noopener noreferrer"&gt;short-lived credentials rotation&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic provisioning of &lt;a href="https://docs.leapp.cloud/latest/sessions/" rel="nofollow noopener noreferrer"&gt;Sessions&lt;/a&gt; from &lt;a href="https://docs.leapp.cloud/latest/configuring-integration/configure-aws-single-sign-on-integration/" rel="nofollow noopener noreferrer"&gt;AWS Single Sign-on&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Open multiple AWS console from different AWS accounts in &lt;a href="https://addons.mozilla.org/it/firefox/addon/leapp-multi-console-extension/" rel="nofollow noopener noreferrer"&gt;Firefox&lt;/a&gt; and &lt;a href="https://docs.leapp.cloud/0.16.2/built-in-features/multi-console/#chrome-edge-and-other-chromium-based-browsers" rel="nofollow noopener noreferrer"&gt;Chrome&lt;/a&gt; web extensions!&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connect to EC2 instances straight away&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Managing Leapp with its &lt;a href="https://docs.leapp.cloud/latest/cli/" rel="nofollow noopener noreferrer"&gt;CLI&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.leapp.cloud/0.14.1/plugins/plugins-introduction/" rel="nofollow noopener noreferrer"&gt;Create your own Leapp plugin&lt;/a&gt;&lt;/strong&gt; to customize the App functionalities from the &lt;a href="https://github.com/Noovolari/leapp-plugin-template" rel="noopener noreferrer"&gt;template&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the covered access methods can be found &lt;a href="https://docs.leapp.cloud/latest/configuration/" rel="nofollow noopener noreferrer"&gt;here&lt;/a&gt;…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Noovolari/leapp" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h1&gt;
  
  
  TL;DR
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Configure Google Project&lt;/li&gt;
&lt;li&gt;Clone the repository and install dependencies&lt;/li&gt;
&lt;li&gt;Change the &lt;strong&gt;custom-schema.yaml&lt;/strong&gt; according to the template:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt; — the name you give to the custom schema&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;session&lt;/strong&gt; — the name you give to the attribute representing the &lt;strong&gt;session duration&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;role&lt;/strong&gt; — the name you give to the attribute representing the &lt;strong&gt;federated role&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Change the &lt;strong&gt;federation.yaml&lt;/strong&gt; according to the template:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;email&lt;/strong&gt; — the email of the user to change the custom schema attributes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;account&lt;/strong&gt; — the account number where the IAM Identity Provider and IAM Role resides&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;role&lt;/strong&gt; — the federated role name (the script will derive the ARN)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;provider&lt;/strong&gt; — the provider name (the script will derive the ARN)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Run the script&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Wrap-up
&lt;/h1&gt;

&lt;p&gt;At this point, you will be able to change the federation between your AWS accounts and G Suite users through this script by just changing the &lt;strong&gt;federation.yaml&lt;/strong&gt; file. While it's convenient, it somewhat limited to some scenarios:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The script works for only one custom schema at a time.&lt;/strong&gt; If you need to federate multiple accounts and go with the multiple custom schema route because you won't compromise about security, you need to modify the script accordingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It will not take into account the complete removal of the custom schema from a user.&lt;/strong&gt; Means that if you leave the user in the federation.yaml file but remove everything in the federations field; the script will break. That's because Google will not understand an empty custom schema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You still have to add the trust relationship to the role&lt;/strong&gt;. So after you made changes, you need to log in to your AWS account and manually change the role trust relationship to allow the user to assume the role after logging in through SSO.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The user list call can retrieve 500 users at max&lt;/strong&gt;. You need to modify the source code and make a recursive method to retrieve all the users if you want to apply to more than 500 users.&lt;/p&gt;

&lt;p&gt;Many improvements can be made, like adding the CLI configuration or make-up for the non-supported scenarios. But apart from that, I think it's a great foundation to work upon, and you will surely find it handy.&lt;/p&gt;

&lt;p&gt;I hope you found this guide useful, and as always, let me know what you think about it, and feel free to ask anything. Cheers!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>google</category>
      <category>python</category>
      <category>sso</category>
    </item>
    <item>
      <title>How to SAML federate your AWS account with G Suite</title>
      <dc:creator>Nicolò Marchesi</dc:creator>
      <pubDate>Tue, 20 Oct 2020 10:23:28 +0000</pubDate>
      <link>https://dev.to/pethron/how-to-saml-federate-your-aws-account-with-g-suite-3a6n</link>
      <guid>https://dev.to/pethron/how-to-saml-federate-your-aws-account-with-g-suite-3a6n</guid>
      <description>&lt;h1&gt;
  
  
  The SAML Federation
&lt;/h1&gt;

&lt;p&gt;Isn't a bother always to remember or securely store access data to log into your AWS console or run some local command from the CLI?&lt;/p&gt;

&lt;p&gt;AWS has many means to authenticate to their accounts, and they range from federating users with identity providers to give direct access through credentials.&lt;/p&gt;

&lt;p&gt;This blog post will run you through all the steps to federate your G Suite account with an AWS account so that you will be able to access the AWS console and generate security credentials with your G Suite identity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You will never have to remember your access credentials again!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not use AWS Single Sign-on?
&lt;/h2&gt;

&lt;p&gt;AWS Single Sign-on (AWS SSO from now on) is a great way to achieve the same results, but it comes with some prerequisites that not always can be met;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have set up AWS Organizations.&lt;/li&gt;
&lt;li&gt;Have enabled &lt;strong&gt;all features&lt;/strong&gt; in the AWS Organizations (this should always be true!).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sign-in with the AWS Organizations master account.&lt;/strong&gt; You cannot set up AWS SSO while signed in with credentials from an Organization’s member account.&lt;/li&gt;
&lt;li&gt;It only works with AWS CLI v2.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Long story short... to set-up AWS SSO, you need &lt;strong&gt;a lot&lt;/strong&gt; of permissions.&lt;/p&gt;

&lt;p&gt;This is actually a good thing if coupled with all security best practices that come with AWS SSO, but it can't be implemented in some cases.&lt;/p&gt;

&lt;p&gt;Mind that, while in the context of AWS and G Suite, &lt;strong&gt;this is a generic approach that leverages SAML&lt;/strong&gt;. It will be different for other Identity Providers and Service Providers, but the overall process is the same. &lt;strong&gt;Know one to master them all.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus
&lt;/h2&gt;

&lt;p&gt;As a bonus track, I'll show you how to configure our open-source tool Leapp to leverage SAML Federation to generate AWS credentials through SSO, to use in your local development environment.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Noovolari" rel="noopener noreferrer"&gt;
        Noovolari
      &lt;/a&gt; / &lt;a href="https://github.com/Noovolari/leapp" rel="noopener noreferrer"&gt;
        leapp
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Leapp is the DevTool to access your cloud
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Spoiler:&lt;/strong&gt; we'll be adding &lt;strong&gt;AWS SSO support&lt;/strong&gt; to Leapp very soon.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Here's the rundown of the actions needed to get your federation up and running&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a custom user attribute category&lt;/li&gt;
&lt;li&gt;
Create a SAML application

&lt;ol&gt;
&lt;li&gt;IdP Metadata&lt;/li&gt;
&lt;li&gt;Service provider details&lt;/li&gt;
&lt;li&gt;Attribute mapping&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Create an AWS SAML IdP in AWS IAM&lt;/li&gt;

&lt;li&gt;Create an IAM federated role&lt;/li&gt;

&lt;li&gt;Fill custom SAML attributes for a user&lt;/li&gt;

&lt;li&gt;Enable the SAML app&lt;/li&gt;

&lt;/ol&gt;

&lt;h3&gt;
  
  
  Bonus
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Get SSO link&lt;/li&gt;
&lt;li&gt;Configure &lt;a href="https://github.com/Noovolari/leapp" rel="noopener noreferrer"&gt;Leapp&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A G Suite subscription with an admin account&lt;/li&gt;
&lt;li&gt;An AWS account with IAM permissions&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Tutorial
&lt;/h1&gt;

&lt;p&gt;So let's dive into the tutorial to set everything in place and get your shiny new federation on.&lt;/p&gt;

&lt;p&gt;For the sake of simplicity, we will consider that you already have a suitable user on your G Suite subscription on which to enable the federation.&lt;/p&gt;

&lt;p&gt;This schema simplifies the flow of the authentication process. You will federate AWS with G Suite to call the &lt;em&gt;AssumeRoleWithSAML&lt;/em&gt; call and retrieve a set of credentials associated with the IAM role that we set up during the process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1602759004355%2FTke_TnsNL.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1602759004355%2FTke_TnsNL.png" alt="AWS_FEDERATED_ACCESS_SCHEMA(1).png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Legend
&lt;/h3&gt;

&lt;p&gt;You will find some callout to highlight some aspects better; here is the meaning behind them:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✋ - &lt;strong&gt;ACTION REQUIRED&lt;/strong&gt; — Act for later use.&lt;/p&gt;

&lt;p&gt;💡 - &lt;strong&gt;INFO&lt;/strong&gt; — Further insights or customization for experienced people.&lt;/p&gt;

&lt;p&gt;💣 - &lt;strong&gt;WARNING&lt;/strong&gt; — Be aware of the security implications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;1. Create a custom user attribute category
&lt;/h2&gt;

&lt;p&gt;First of all, we have to add custom attributes to our users. When our Identity Provider (Google) will communicate the user's identity during login, it will transmit additional information to the Service Provider (AWS) in the form of custom attributes.&lt;/p&gt;

&lt;p&gt;The custom attributes are &lt;strong&gt;FederationRole&lt;/strong&gt; and &lt;strong&gt;SessionDuration&lt;/strong&gt;. After everything is set up, we can fill in each user a set of these attributes. These will be passed to enable AWS to automatically generate a set of credentials with an &lt;a href="https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role-with-saml.html" rel="noopener noreferrer"&gt;AssumeRoleWithSAML&lt;/a&gt; API call of the duration of the &lt;strong&gt;SessionDuration&lt;/strong&gt; parameter.&lt;/p&gt;

&lt;p&gt;So from the admin dashboard, head to the user directory by choosing &lt;strong&gt;Users&lt;/strong&gt;. From the top right corner in the user dashboard, choose &lt;strong&gt;Manage User Attributes&lt;/strong&gt; and &lt;strong&gt;Add Custom Category&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Type &lt;strong&gt;AWS SAML&lt;/strong&gt; in the category name with and proceed to fill the attributes data with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Attribute name&lt;/strong&gt; — FederationRole, Text, Visible to users and admin, Multi-Value&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attribute name&lt;/strong&gt; — SessionDuration, Whole number, Visible to users and admin, Single-Value&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 — You can use any name you want for the category and attribute names. When we later map each attribute name to an attribute recognized by AWS to enable the federation, so feel free to use the names that better suits you and your environment.&lt;/p&gt;

&lt;p&gt;💡 — We are using a multi-value field for FederationRole to federate multiple accounts simultaneously. If you choose a single-value, you will need to create a new category of custom attributes for each AWS account that you want to federate. Feel free to do it if you know what you are doing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092047075%2FmTgSRB96m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092047075%2FmTgSRB96m.png" alt="CUSTOM_CATEGORY"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;2. Create a SAML application
&lt;/h2&gt;

&lt;p&gt;Now, to set up your SAML SSO, we need to create a custom application in the G Suite management console. The application will represent your AWS accounts in the G Suite environment and will hold all security data to make AWS and G Suite establish a secure connection. We will obtain this by sharing the secret generated during the creation of the custom application with the AWS account.&lt;/p&gt;

&lt;p&gt;Again, from your G Suite admin dashboard, choose &lt;strong&gt;Apps, SAML Apps&lt;/strong&gt;. From here, choose the big yellow plus icon (&lt;strong&gt;+&lt;/strong&gt;) and select &lt;strong&gt;SETUP MY OWN CUSTOM APP&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;2.a. IdP Metadata
&lt;/h3&gt;

&lt;p&gt;This will present you with the google identity provider information and some download options. Download the &lt;strong&gt;IDP Metadata (option 2)&lt;/strong&gt;  and keep it close; we will need this file soon.&lt;/p&gt;

&lt;p&gt;This file contains an XML that contains some configuration parameters and the most important &lt;strong&gt;X.509 certificate&lt;/strong&gt;. The certificate is the entity on which the trust relationship between IdP and SP is based on.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💣 — Keep your X.509 certificate in a secure place and don't disclose it's contents for any reason. &lt;strong&gt;The security of the entire solution relies on keeping the content of this file confidential.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;2.b. Service provider details
&lt;/h3&gt;

&lt;p&gt;We continue the configuration by mapping the SAML entity known as  (that is, the user will be presented to the AWS console with their email address as their unique identifier).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ACS URL&lt;/strong&gt; — &lt;a href="https://signin.aws.amazon.com/saml" rel="noopener noreferrer"&gt;https://signin.aws.amazon.com/saml&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entity ID&lt;/strong&gt; — &lt;a href="https://signin.aws.amazon.com/saml" rel="noopener noreferrer"&gt;https://signin.aws.amazon.com/saml&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signed Response  —&lt;/strong&gt; leave unchecked&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name ID —&lt;/strong&gt; Primary Email&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name ID Format —&lt;/strong&gt; Email&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092154229%2FJiANIw6nj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092154229%2FJiANIw6nj.png" alt="SERVICE_PROVIDER_DETAILS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;2.c. Attribute mapping
&lt;/h3&gt;

&lt;p&gt;Now it's time to make AWS understand our custom attributes. This is done by mapping our G Suite custom attributes with specifically designed parameters on AWS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application attribute&lt;/strong&gt; — &lt;strong&gt;&lt;a href="https://aws.amazon.com/SAML/Attributes/RoleSessionName" rel="noopener noreferrer"&gt;https://aws.amazon.com/SAML/Attributes/RoleSessionName&lt;/a&gt;&lt;/strong&gt;, Basic Information, Primary Email&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application attribute&lt;/strong&gt; — &lt;strong&gt;&lt;a href="https://aws.amazon.com/SAML/Attributes/Role" rel="noopener noreferrer"&gt;https://aws.amazon.com/SAML/Attributes/Role&lt;/a&gt;&lt;/strong&gt;, AWS SAML, FederationRole&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application attribute&lt;/strong&gt; — &lt;strong&gt;&lt;a href="https://aws.amazon.com/SAML/Attributes/SessionDuration" rel="noopener noreferrer"&gt;https://aws.amazon.com/SAML/Attributes/SessionDuration&lt;/a&gt;&lt;/strong&gt;, AWS SAML, SessionDuration&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 — If you used another name for the custom category, choose accordingly.&lt;/p&gt;

&lt;p&gt;💡 — You can still change the mapping after creating the SAML application. From the admin dashboard, go to the &lt;strong&gt;Apps,&lt;/strong&gt; &lt;strong&gt;SAML Apps&lt;/strong&gt;, and choose the application that wants to modify. Here select &lt;strong&gt;Choose Attribute Mapping&lt;/strong&gt; to edit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092439415%2FKysZtgLDy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092439415%2FKysZtgLDy.png" alt="ATTRIBUTE_MAPPING"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;3. Create an AWS SAML IdP in AWS IAM
&lt;/h2&gt;

&lt;p&gt;We need to create some way to make AWS aware that we are using G Suite as an identity provider. This is pretty simple, but it needs the &lt;strong&gt;X.509 certificate&lt;/strong&gt; that we saved earlier.&lt;/p&gt;

&lt;p&gt;Log in to the AWS console, open the &lt;strong&gt;IAM&lt;/strong&gt; section, and from the left-side column, select &lt;strong&gt;Identity Providers&lt;/strong&gt;. Here click on &lt;strong&gt;Create Provider.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Provider Type&lt;/strong&gt; — SAML&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt; — GSuiteSAML (if you don't like it, change as you wish)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata Document&lt;/strong&gt; — choose the file downloaded when creating the SAML app&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;✋ — Select your newly created identity provider ARN, copy it, and set it aside.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092637561%2FZVyp4NHLT.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092637561%2FZVyp4NHLT.jpeg" alt="AWS_IDP"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;4. Create an IAM federated role
&lt;/h2&gt;

&lt;p&gt;We need to create a role that will be automatically assumed when our corporate user will access the console. In IAM, go to &lt;strong&gt;Roles, Creare role&lt;/strong&gt;. Here choose the SAML 2.0 federation and select from the dropdown the SAML provider created earlier; the other fields will be automatically selected. Next, assign the correct set of permission, and you're good to go!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✋ — Select your newly created user ARN, copy it, and set it aside.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092739802%2F5bKUmCUBE.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092739802%2F5bKUmCUBE.png" alt="IAM_ROLE"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This procedure will create a &lt;strong&gt;trust-relationship&lt;/strong&gt; with a &lt;strong&gt;condition&lt;/strong&gt;. This basically means "If someone is authenticated through the G Suite Identity Provider, and G Suite says that they can assume this role, then they are allowed to do so".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092779989%2FIl6nWmm92.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092779989%2FIl6nWmm92.png" alt="TRUST_RELATIONSHIP"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This policy can be further tweaked to let &lt;strong&gt;only specific users access the role&lt;/strong&gt;. We can add more conditions to reach our goal; for example, this role will be accessed only by this user. You can mix and match all conditions to achieve your desired logic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092815212%2F_S7y7XeJR.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092815212%2F_S7y7XeJR.png" alt="CONDITION"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;5. Fill custom SAML attributes for a user
&lt;/h2&gt;

&lt;p&gt;Now, remember the custom attribute category that we created at the very start of the tutorial? Now it's time to fill in the info for our users. From your G Suite dashboard, choose &lt;strong&gt;Users&lt;/strong&gt;, select the user you want to federate, and choose ** User Information** in the &lt;strong&gt;User details&lt;/strong&gt; page.&lt;/p&gt;

&lt;p&gt;Scroll down until you see the category with &lt;strong&gt;AWS SAML&lt;/strong&gt; (or whatever name you used) and click on it. You will see the two values of the custom category and fill them with: ****&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FederationRole&lt;/strong&gt; — This is a comma-separated string with the IAM role ARN and IdP ARN in the following format: &lt;code&gt;&amp;lt;Role-ARN&amp;gt;,&amp;lt;IDP-ARN&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SessionDuration&lt;/strong&gt; — This is the maximum time in seconds that the session will be active. Fill in &lt;strong&gt;28800&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💣 — As we have enabled MFA for all our users, we usually choose to have 1 working day-long sessions (8 hours) or 28800 seconds. Feel free to reduce the time or increase it, but mind that it cannot be longer than 12 hours and shorter than 1 hour.&lt;/p&gt;

&lt;p&gt;💣 — As we have used a multi-part value for the &lt;strong&gt;FederationRole&lt;/strong&gt;, we can add more values for roles and Identity Providers in different accounts so that you can manage everything from your G Suite user. Mind that you need to use the same IdP metadata to create the IAM Identity Provider in AWS. &lt;strong&gt;This is a tradeoff between security and ease of management&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;💡 — Alternatively, you can create multiple SAML apps, one for each account you want to federate. Like this, the metadata file will be different for each federation process. In case of a security breach and disclosure of the metadata file, the only account affected will be the one that gets disclosed. &lt;strong&gt;While this process is more secure, it also increases the management overhead and needs to keep track of everything&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;6. Enable the SAML app
&lt;/h2&gt;

&lt;p&gt;We need to enable the SAML app to make everything work and leverage our G Suite SSO to the AWS console. Choose the SAML application from the &lt;strong&gt;Apps&lt;/strong&gt; dashboard. On the details page, choose the one that fits you best:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ON for everyone&lt;/strong&gt; to turn on the app for every user in your G Suite account&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On for some&lt;/strong&gt; to turn on the app for a selective organization under your G Suite account&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;7. Test the SAML app
&lt;/h2&gt;

&lt;p&gt;Now you can test the federation by choosing the SAML apps from the Google Apps menu and clicking on it. You may have to choose &lt;strong&gt;More&lt;/strong&gt; to see the SAML app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092916824%2FcEkwGtba7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092916824%2FcEkwGtba7.png" alt="GAPPS_MENU"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt; — We named our SAML app &lt;strong&gt;Amazon Web Services&lt;/strong&gt;, but here you will see the apps with the names you have chosen earlier. Select accordingly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Bonus
&lt;/h1&gt;

&lt;p&gt;We use the same configuration at our company, and during the years, we developed an internal tool that we open-sourced under the name of &lt;a href="https://github.com/Noovolari/leapp" rel="noopener noreferrer"&gt;Leapp&lt;/a&gt;. As we have many accounts from different cloud providers, we collect all our cloud access data and switch between accounts. It supports both federated and simpler access credentials.&lt;/p&gt;

&lt;p&gt;I'll show you how to configure Leapp for this use-case.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;1. Get SSO link
&lt;/h2&gt;

&lt;p&gt;Right-click on the SAML all on your Google Apps menu and &lt;strong&gt;Copy Link Location&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092976184%2Fb45RV22fb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603092976184%2Fb45RV22fb.png" alt="GET_SSO"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;2. Configure Leapp
&lt;/h2&gt;

&lt;p&gt;Open Leapp. &lt;a href="https://github.com/Noovolari/leapp/releases/latest" rel="noopener noreferrer"&gt;Here's the link to the latest release&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Click on the &lt;strong&gt;top-left menu&lt;/strong&gt;, select &lt;strong&gt;Options&lt;/strong&gt;, and fill in the &lt;strong&gt;URL&lt;/strong&gt; you just copied.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603093002863%2FzZAztDgTW.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603093002863%2FzZAztDgTW.png" alt="CONFIGURE_LEAPP"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;3. Create a Federated Account
&lt;/h2&gt;

&lt;p&gt;On the home page, click on the big green (+) icon and select &lt;strong&gt;AWS&lt;/strong&gt; and &lt;strong&gt;Federated&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here you will fill in the information you got before:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Account Alias&lt;/strong&gt; — A name to recognize this set of accounts and roles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Account Number&lt;/strong&gt; — The account number of your federated role AWS account.
You can get it from the role ARN or log in to the AWS console and click on your name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role&lt;/strong&gt; — Your role name. Not the ARN, just the last part after the backslash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IdP ARN&lt;/strong&gt; — Your AWS IAM Identity Provider ARN.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603093079208%2FqN6BMciVl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1603093079208%2FqN6BMciVl.png" alt="CREATE_FEDERATED"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;4. Start your session
&lt;/h2&gt;

&lt;p&gt;Now you can click on the newly created entry and start your session so you can use both programmatic and console access through SSO.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/BKAD7OYIvWI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  Two Cents on Security
&lt;/h1&gt;

&lt;p&gt;There are still a couple of things that you can do to ensure the highest level of security.&lt;/p&gt;

&lt;p&gt;You may want to consider enforcing MFA on your Identity Provider (G Suite). This lowers the risk of someone’s account being compromised and an attacker gaining access to multiple systems.&lt;/p&gt;

&lt;p&gt;The other thing is that AWS has a neat service called &lt;a href="https://aws.amazon.com/cloudtrail/" rel="noopener noreferrer"&gt;CloudTrail&lt;/a&gt;, where you can log, monitor, and retain account activity related to actions and events across your AWS infrastructure. While we are using roles for gaining access to our AWS account, the user identity is brought along with every API call, meaning that you can still monitor what actions the federated user is performing on the account.&lt;/p&gt;

&lt;h1&gt;
  
  
  Final Notes
&lt;/h1&gt;

&lt;p&gt;In this blog post, we covered all the steps necessary to SAML federate your G Suite and AWS accounts and shared some technical insights. It may seem like a lot to get going, and it is a fair amount of work to get set up, but if you don't want to commit to AWS SSO or want to understand better what is involved in the process of SAML federation, it's totally worth your time.&lt;/p&gt;

&lt;p&gt;If you are interested in those topics, follow us on our &lt;a href="https://medium.com/leapp-cloud" rel="noopener noreferrer"&gt;medium publication&lt;/a&gt; for the third article of this series, coming next week. &lt;/p&gt;

</description>
      <category>aws</category>
      <category>gsuite</category>
      <category>sso</category>
    </item>
  </channel>
</rss>
