<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0"><channel><title>Pulumi Blog: Praneet Loke</title><link>https://www.pulumi.com/blog/author/praneet-loke/</link><description>Pulumi blog posts: Praneet Loke.</description><language>en-us</language><pubDate>Mon, 06 Feb 2023 00:00:00 +0000</pubDate><item><title>Organizing AWS Accounts With Pulumi</title><link>https://www.pulumi.com/blog/organizing-aws-accounts-with-pulumi/</link><pubDate>Mon, 06 Feb 2023 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/organizing-aws-accounts-with-pulumi/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/organizing-aws-accounts-with-pulumi/index.png" /&gt;
&lt;p&gt;In an enterprise organization, an IT self-service &amp;ldquo;vending machine&amp;rdquo; allows employees to quickly and easily request and receive access to pre-approved cloud resources. Behind the scenes, Pulumi programs may orchestrate any of the requisite resources. We will look at an example of using Pulumi to create an AWS child account, within an AWS Organization.&lt;/p&gt;
&lt;p&gt;One might envision a developer requesting a new AWS account to be added entirely through a Pull Request in a git repository either for their own use or on behalf of a team. This scenario is not just for enterprises, however. Teams of any size should organize their AWS accounts using the least-privileged access principle.&lt;/p&gt;
&lt;p&gt;Here’s the Organization structure we are looking to build with Pulumi. It just has one organizational unit (OU) with one member account under it to demonstrate how teams can construct the structure that works best for them or follow AWS’ recommendations on this topic. Depending on your team size you may want to keep this simple or you may need something that can handle multiple teams each with multiple accounts. The decision is yours.&lt;/p&gt;
&lt;p&gt;&lt;img src="org-structure.png" alt="Organization Structure"&gt;&lt;/p&gt;
&lt;p&gt;For the above organization structure, we want the following operational model:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The user accounts for developers will be provisioned (either manually or automatically through SSO depending on your HR systems) in the root account. Developers will only be able to assume a specific role in the target accounts that have a trust boundary with the root account.&lt;/li&gt;
&lt;li&gt;Developers will be added to a group and the group should be granted access to assume a role.&lt;/li&gt;
&lt;li&gt;An IAM user meant for automation (eg. CI/CD pipelines) in the root account should have access to assume a role in the target account in order to manage resources. No developer should have access to assume the role meant for the automation user.&lt;/li&gt;
&lt;li&gt;An org unit-level (OU) backup policy that backs-up resources tagged with a specific key/value pair.&lt;/li&gt;
&lt;li&gt;An org unit-level (OU) tagging policy that enforces tag-casing and the default tags that resources should have.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The component resources mentioned in this post are for demonstration and to show you how you can use the expressiveness found only in the Pulumi programming model. Some details are omitted in this post for brevity. Please see the &lt;a href="https://github.com/pulumi/examples/tree/master/aws-ts-organizations"&gt;source repository&lt;/a&gt; for the complete source code.
In order to modify the organization resources you’ll need credentials to an admin IAM user from your management account. Create an IAM user specifically to run this infrastructure app. These elevated credentials should not be used for anything else.&lt;/p&gt;
&lt;p&gt;Once the member accounts have been created, in order to operate in those accounts using your preferred CI/CD service, we’ll create an automation user that will specifically have the permissions to assume a role in the member account. So you should use the credentials of that user for any other resources the team would want to deploy. For example, the team might want to deploy a new ECS cluster, along with Managed Redis instances and perhaps an RDS cluster too. These are resources specific to the team and what they want to use the account for.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;If you are using one of the supported CI/CD services you might be able to use federated credentials using OIDC. So if you are going to use that auth mechanism, you can skip creation of the fixed automation user account since you will not need its
credentials.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="organizational-unit-ou"&gt;Organizational Unit (OU)&lt;/h2&gt;
&lt;p&gt;An org unit can represent anything. In our example it represents the development team. You could also have multiple OUs and even nest them to create sub-hierarchies, depending on your use-case.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;organizations&lt;/code&gt; module in the AWS provider package contains the resources we need in order to create an OU and an account.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// If you&amp;#39;ve already created an organization in your root account
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// and don&amp;#39;t want it to be managed by Pulumi then simply retrieve
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// it using the `getOrganization` function.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;organization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;organizations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getOrganization&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Otherwise, create an organization and let Pulumi manage it.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// If you are going to create the organization using the following
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// construction, you should remove the call to getOrganization above.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// const organization = new aws.organizations.Organization(&amp;#34;&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;devOrgUnit&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;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;organizations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OrganizationalUnit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;orgUnit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;parentId&lt;/span&gt;: &lt;span class="kt"&gt;organization.then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;roots&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="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Development&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;devAccount&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;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;organizations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;devAccount&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;DeveloperAccount&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;parentId&lt;/span&gt;: &lt;span class="kt"&gt;devOrgUnit.id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;email&lt;/span&gt;: &lt;span class="kt"&gt;devAccountEmailContact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// This role can be used by this Pulumi app to execute
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// an AssumeRole action on this new member account.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// This role is automatically created in every new
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// account created in an Organization. The name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// `OrganizationalAccountAccessRole` is the default
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// name. You may choose a different name.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_accounts_access.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;roleName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;OrganizationalAccountAccessRole&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// IMPORTANT! Set this to `false` if you do not wish to have
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// accounts closed when the account resource is removed from
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// your Pulumi app.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;closeOnDeletion&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// This flag tells Pulumi to protect this resource from being deleted
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// during a `pulumi destroy` operation. It also means you need to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// first unprotect it if you do wish to delete it using Pulumi.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// https://www.pulumi.com/docs/concepts/options/protect/
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;protect&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;An important note about the &lt;code&gt;Account&lt;/code&gt; resource and destroying them. Notice how we set the &lt;code&gt;closeOnDeletion&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;. Closing accounts on deletion will only succeed if you have not exceeded the quotas set by AWS for account closure. So set that flag accordingly. If you expect to be closing many accounts frequently (perhaps for an ephemeral use-case), you may want to set the flag to &lt;code&gt;false&lt;/code&gt; so you can close them manually or have some other sort of asynchronous automation do it for you. Otherwise, your Pulumi execution will fail when AWS returns an error code due to the quota being exceeded.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="developers-access"&gt;Developers’ Access&lt;/h2&gt;
&lt;p&gt;We’ll create an IAM group for developers and assign a group policy that allows its members to perform the &lt;code&gt;sts:AssumeRole&lt;/code&gt; on any AWS account but only using a specific role.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;devGroup&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;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;developers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;developers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GroupPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;developersGroupPolicy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;group&lt;/span&gt;: &lt;span class="kt"&gt;devGroup.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Allow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;sts:AssumeRole&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// This role will be created by the AccountPermissions component resource
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// introduced in the next section of this post.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Resource&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sb"&gt;`arn:aws:iam::*:role/DeveloperRole`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2012-10-17&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, we&amp;rsquo;ll create the IAM user that we’ll use for automation purposes. Again, you don’t need to do this if you plan to use OIDC federation for your CI/CD service.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;automationUser&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;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;automationUser&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cicd-automation&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UserPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;automationUserPolicy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Allow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;sts:AssumeRole&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// This role will be created by the AccountPermissions component resource
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// introduced in the next section of this post.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Resource&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sb"&gt;`arn:aws:iam::*:role/AutomationRole`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2012-10-17&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;user&lt;/span&gt;: &lt;span class="kt"&gt;automationUser.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="membertarget-account-permissions"&gt;Member/Target Account Permissions&lt;/h2&gt;
&lt;p&gt;We’ve created the base infrastructure in our root (aka management) account. We now need to create roles in the target account that allows users in the management account to assume.&lt;/p&gt;
&lt;p&gt;&lt;img src="target-account-permissions.png" alt="Target Account Permissions"&gt;&lt;/p&gt;
&lt;p&gt;We’ll use a component resource to set up the necessary roles and policies in the target account. If you recall, when the target account was created, we specified a role name. That role name is the initial role that AWS creates on our behalf in the brand new account with admin privileges. The credentials we are using currently to execute our Pulumi app is assumed to be an admin user in the root account since we are dealing with highly-privileged operations here. We will need to create an explicit provider for our target account that can assume that automatically-created role.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;devAccountProvider&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;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;devAccountProvider&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;allowedAccountIds&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;devAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;assumeRole&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;roleArn&lt;/span&gt;: &lt;span class="kt"&gt;pulumi.interpolate&lt;/span&gt;&lt;span class="sb"&gt;`arn:aws:iam::&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;devAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;:role/OrganizationalAccountAccessRole`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, whenever we want to modify resources in the target account in this app, we’ll use that provider. We’ll pass this provider to the component mentioned above, so that the roles and policies created by that component are performed using this provider instance. The component resource code is not included in this post for brevity. It provides a nice way to encapsulate the roles and policies we want to bootstrap our brand new account with. Of course, you can customize those roles and what permissions they get based on your use-case.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;devAccountPermissions&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;AccountPermissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;devAccountPermissions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;automationUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;managementAccountId&lt;/span&gt;: &lt;span class="kt"&gt;pulumi.Output.create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCallerIdentity&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// The prefix that will be used to name the child resources created by this component
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// since we expect to create a new instance of this component for every new member
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// account.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resourceNamesPrefix&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;dev&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;: &lt;span class="kt"&gt;devAccountProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="backup-policies"&gt;Backup Policies&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_backup.html"&gt;Backup policies&lt;/a&gt; are strictly not required in order to create new member accounts in an OU. However, many teams have a requirement to have a backup policy for certain resources. Aside from the compliance requirement, it’s a good idea to ensure that your DBs, EBS volumes etc. are properly backed-up. AWS Backup is a managed backup service that allows you to define backup plans and create vaults in primary (where your resources reside) and a secondary (backup/copy region). AWS will execute your backup plans and create backups in the vaults.&lt;/p&gt;
&lt;p&gt;We’ll once again use a component resource to encapsulate the creation of a backup vault in each of our member accounts. AWS recommends that we attach the backup policy to the organizational unit so that all member accounts inherit the policy implicitly.&lt;/p&gt;
&lt;p&gt;AWS needs to know which resources to target to perform the backup. We provide that information using the &lt;code&gt;selections&lt;/code&gt; property in the backup policy. The &lt;code&gt;selections&lt;/code&gt; property allows you to specify tags that can be used as backup targets. In other words, compatible resources that have that tag will be targeted by this backup policy. In our example, the tag key is &lt;code&gt;BackupType&lt;/code&gt; and the value is &lt;code&gt;MONTHLY&lt;/code&gt;. This tag is optional, of course, since we don&amp;rsquo;t need every resource to have this tag; just the ones that need to be backed-up. You can enforce required tags too, which is a nice segue to our next topic.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vault&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;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Vault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sb"&gt;`backupVault-&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;accountName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// We rely on the vault name staying consistent across AWS accounts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// for the purposes of the backup policy that is attached to the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// organizational unit.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&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="s2"&gt;&amp;#34;Default&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;: &lt;span class="kt"&gt;accountProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;: &lt;span class="kt"&gt;this&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Create the IAM role in the target account that allows AWS Backup to execute backup plans.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;backupPolicyRole&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;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;accountName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;BackupPolicyRole`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// This name has to stay consistent across all member accounts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// since we will reference this role in the actual backup policy.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;MyMonthlyBackupIamRole&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;assumeRolePolicy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Allow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;sts:AssumeRole&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Principal&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;backup.amazonaws.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2012-10-17&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;managedPolicyArns&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;: &lt;span class="kt"&gt;accountProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;: &lt;span class="kt"&gt;this&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The actual backup policy is a JSON document with a special syntax. In our example, the monthly plan looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;Monthly_Backup_Plan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;regions&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;@@assign&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&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;primaryRegions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Monthly&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;schedule_expression&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;@@assign&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cron(0 5 1 * ? *)&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;start_backup_window_minutes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@@assign&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;480&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;target_backup_vault_name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@@assign&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Default&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;lifecycle&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;move_to_cold_storage_after_days&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;@@assign&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;30&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;delete_after_days&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@@assign&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;365&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;copy_actions&lt;/span&gt;: &lt;span class="kt"&gt;backupVaultCopyAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;selections&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Backup_Assignment&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;iam_role_arn&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;@@assign&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sb"&gt;`arn:aws:iam::$account:role/&lt;/span&gt;&lt;span class="si"&gt;${&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;monthlyBackupPolicyIamRoleName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tag_key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@@assign&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;BackupType&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tag_value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@@assign&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;MONTHLY&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="tagging-policies"&gt;Tagging Policies&lt;/h2&gt;
&lt;p&gt;Similar to backup policies, &lt;a href="https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_tag-policies.html"&gt;tag policies&lt;/a&gt; are also not required to create member accounts in an OU. But it&amp;rsquo;s a good idea to define one. In keeping with our general theme here, we’ll encapsulate our tagging policy with yet another component resource so that we can easily include future org units. Similar to the backup policy syntax, the tag policy syntax uses JSON with some special placeholder variables.&lt;/p&gt;
&lt;p&gt;Let’s take a look at the consumer point-of-view for this component. We want users of this component to pass in a list of allowed cost centers for a certain org unit. Say, if a team wants to have multiple org units and therefore different cost centers for each of them, this model allows those teams to use the &lt;code&gt;TagPolicies&lt;/code&gt; component for each org unit separately and assign the allowed cost center values accordingly.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tagPolicies&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;TagPolicies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;tagPolicies&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;costCenters&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// The component accepts an array of allowed cost center
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// values that can be used as values in tags.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// This is just an example of how you can restrict what values
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// tags can be assigned.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;allowedCostCenters&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Development&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Testing&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;ou&lt;/span&gt;: &lt;span class="kt"&gt;devOrgUnit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;orgId&lt;/span&gt;: &lt;span class="kt"&gt;organization.then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;roots&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="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The tag policy for our example looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;TAG_POLICY&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;content&lt;/span&gt;: &lt;span class="kt"&gt;JSON.stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;CostCenter&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tag_value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// The allowed cost center values that we passed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// to the TagPolicy component as an arg.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;@@assign&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;costCenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allowedCostCenters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Add tags that are enforceable only to the OU.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Owner&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tag_key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;@@assign&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Owner&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Don&amp;#39;t allow any child policies from changing the key of this tag.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;@@operators_allowed_for_child_policies&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;@@none&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that’s about it as far as setting up the simple org unit and member account structure shown at the beginning of this post.
View the &lt;a href="https://github.com/pulumi/examples/tree/master/aws-ts-organizations"&gt;full source-code&lt;/a&gt; for the component resources in the &lt;code&gt;pulumi/examples&lt;/code&gt; repository.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how the stack looks once the organizational unit and the development AWS account in it have been created.&lt;/p&gt;
&lt;p&gt;&lt;img src="stack-overview.png" alt="Stack Overview"&gt;&lt;/p&gt;
&lt;p&gt;Suppose there is a need to add a new AWS account for a test account in addition to the development account.
We just need a new &lt;code&gt;Account&lt;/code&gt; resource, the backup policy and the permissions for it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testAccount&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;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;organizations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;testAccount&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;SharedTestAccount&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;parentId&lt;/span&gt;: &lt;span class="kt"&gt;devOrgUnit.id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;email&lt;/span&gt;: &lt;span class="kt"&gt;testAccountEmailContact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;roleName&lt;/span&gt;: &lt;span class="kt"&gt;initialRoleName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;closeOnDeletion&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;protect&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testAccountProvider&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;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;testAccountProvider&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;allowedAccountIds&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;testAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;assumeRole&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;roleArn&lt;/span&gt;: &lt;span class="kt"&gt;pulumi.interpolate&lt;/span&gt;&lt;span class="sb"&gt;`arn:aws:iam::&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;devAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;:role/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;initialRoleName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testAccountPermissions&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;AccountPermissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;testAccountPermissions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;automationUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;managementAccountId&lt;/span&gt;: &lt;span class="kt"&gt;pulumi.Output.create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCallerIdentity&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resourceNamePrefix&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;test&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;: &lt;span class="kt"&gt;testAccountProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And with those additions, we get this preview:&lt;/p&gt;
&lt;p&gt;&lt;img src="add-test-account.gif" alt="Add Shared Test Account"&gt;&lt;/p&gt;
&lt;p&gt;This post demonstrates how you could use the Pulumi programming model to encapsulate and account for the hierarchical organization structure that your team desires or is required to have for any number of reasons. While an enterprise organization might be interested in this sort of a setup to ensure multiple teams in the organization operate in a similar way, smaller teams should also strongly consider organizing their AWS accounts in a way that enforces the principle of least privileged access. Especially, if you are looking to get SOC2 certified and need to ensure strict isolation of resources that hold any kind of real-world customer data.&lt;/p&gt;
&lt;div class="rounded-lg bg-violet-50 p-6 my-8"&gt;
&lt;p class="heading-4 m-0 mb-3 flex items-center gap-1.5"&gt;Manage AWS accounts as code&lt;/p&gt;
&lt;div class="body-base m-0 text-gray-950"&gt;Use Pulumi component resources to provision AWS Organizations units, member accounts, and least-privilege roles in a repeatable way. Build a self-service account structure your team can request and review in a pull request.&lt;/div&gt;
&lt;a href="https://www.pulumi.com/docs/iac/concepts/components/" data-track="blog-body-cta" class="btn btn-primary mt-4"&gt;
Learn more
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular size-4" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-arrow-right-regular"/&gt;&lt;/svg&gt;
&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id="next-steps"&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;There’s so much more you can do with AWS Organizations and Pulumi.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn about &lt;a href="https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html"&gt;service control policies&lt;/a&gt; and how you can centrally control the maximum available permissions in a member account, for example.&lt;/li&gt;
&lt;li&gt;These Pulumi features could be combined to provide a powerful self-service mechanism for your organization: &lt;a href="https://www.pulumi.com/docs/using-pulumi/automation-api/"&gt;Automation API&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/using-pulumi/crossguard/get-started/"&gt;Policy-as-Code&lt;/a&gt; (similar in its principle to AWS SCPs but operates at the Pulumi resource-level so you can validate every resource created using Pulumi)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/organizations/latest/userguide/orgs_best-practices_mgmt-acct.html"&gt;Best practices for your management account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/organizations/latest/userguide/best-practices_member-acct.html"&gt;Best practices for your member accounts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Praneet Loke</author><category>aws</category><category>enterprise</category><category>components</category></item><item><title>Infrastructure CI/CD With Github Actions and Pulumi</title><link>https://www.pulumi.com/blog/infrastructure-ci-cd-with-github-actions-and-pulumi/</link><pubDate>Mon, 14 Dec 2020 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/infrastructure-ci-cd-with-github-actions-and-pulumi/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/infrastructure-ci-cd-with-github-actions-and-pulumi/index.png" /&gt;
&lt;p&gt;&lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt; help automate tasks within your software development life cycle. At Pulumi, we use GitHub Actions internally as part of every build/release cycle, and we run these tasks many, many times per day. This helps us to automate our CI/CD process and eliminate manual steps. Pulumi and many of our customers also deliver infrastructure resources as part of a CI/CD process: delivering infrastructure and applications in a single, integrated pipeline.&lt;/p&gt;
&lt;h2 id="better-automation-with-github-actions-and-pulumi"&gt;Better Automation with GitHub Actions and Pulumi&lt;/h2&gt;
&lt;p&gt;Today, we’re pleased to announce that Pulumi is available as a verified &lt;a href="https://github.com/marketplace/actions/pulumi-cli-action"&gt;GitHub Action in the GitHub Marketplace&lt;/a&gt;. It’s now easier than ever to start automating your infrastructure deployments with Pulumi and GitHub Actions. &lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/github-actions/"&gt;Our new guide shows you how to get started with GitHub Actions and Pulumi&lt;/a&gt;. Here are just a few great examples of how to use the Pulumi GitHub Action that will simplify your cloud engineering tasks:&lt;/p&gt;
&lt;h3 id="master-builds"&gt;Master Builds&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Pulumi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;master&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Update&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/checkout@v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pulumi/actions@v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;up&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PULUMI_ACCESS_TOKEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ secrets.PULUMI_ACCESS_TOKEN }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="pull-request-builds"&gt;Pull Request Builds&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Pulumi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;pull_request&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Preview&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/checkout@v2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pulumi/actions@v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;preview&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;PULUMI_ACCESS_TOKEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ secrets.PULUMI_ACCESS_TOKEN }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;IS_PR_WORKFLOW&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;COMMENT_ON_PR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="announcing-the-new-pulumi-cicd-integration-assistant"&gt;Announcing the New Pulumi CI/CD Integration Assistant&lt;/h2&gt;
&lt;p&gt;We often hear from developers who want to setup CI/CD automation for their stacks but don’t have the time to figure out how to configure a working pipeline. Today, we are happy to announce the launch of the &lt;a href="https://www.pulumi.com/docs/pulumi-cloud/deployments/ci-cd-integration-assistant/"&gt;CI/CD Integration Assistant&lt;/a&gt; to make setting up CI/CD automation more straightforward. You can easily get started using popular CI/CD services without the hassle of the initial setup.&lt;/p&gt;
&lt;p&gt;The integration assistant guides you with instructions based on your preferred CI/CD service and provides the customized pipeline configuration for CI/CD services that you can add to your Version Control System (VCS) repository.&lt;/p&gt;
&lt;p&gt;We are super excited to offer &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt; support as part of the CI/CD Integration Assistant and other popular tools like Azure Pipelines and more.
If you’d like to request support for more CI/CD services, please use &lt;a href="https://github.com/pulumi/ci-workflow-templates/issues/new?assignees=&amp;amp;labels=&amp;amp;template=ci-cd-request.md&amp;amp;title=%5BNEW+CI+REQUEST%5D"&gt;this convenient template&lt;/a&gt; on the Pulumi GitHub repo.&lt;/p&gt;
&lt;p&gt;&lt;img src="image1.png" alt="Integrations Console"&gt;&lt;/p&gt;
&lt;h2 id="managing-your-infrastructure-with-a-vcs"&gt;Managing Your Infrastructure with a VCS&lt;/h2&gt;
&lt;p&gt;You may already be familiar with Git-based services such as &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt;, Bitbucket, and GitLab. Adding your code to a central VCS allows you to secure your codebase against failures and boost team collaboration. When you add an automated CI/CD pipeline, your team will deliver software safely and efficiently by ensuring that automated tests are passed prior to every deployment. This process is valuable for application code and infrastructure code.&lt;/p&gt;
&lt;p&gt;The Assistant also goes beyond helping you get started with an automated pipeline. It works throughout the Pulumi Service providing hints for configuring a VCS for projects that are not already configured. It can also help identify updates to stacks that were not run in an automated pipeline (in the activity tab). These additions will help you quickly identify the stacks where best practices are not followed and take corrective actions.
You can access the Assistant in the Integrations option of your stack’s settings page to help you through the whole process of configuring a VCS to setting up a working automated pipeline.&lt;/p&gt;
&lt;p&gt;Learn more about the &lt;a href="https://www.pulumi.com/docs/pulumi-cloud/deployments/ci-cd-integration-assistant/"&gt;CI/CD Integration Assistant in our user guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We are eager to hear your feedback on how we can improve your experience with this feature. If you haven’t already signed up for our &lt;a href="https://slack.pulumi.com/"&gt;Community Slack&lt;/a&gt;, it’s quick and easy! You can join in on conversations you like and get help from other community members, as well as the Pulumi Team. That’s it for now! 👋&lt;/p&gt;</description><author>Paul Stack</author><author>Praneet Loke</author><author>Isaac Harris</author><category>github-actions</category></item><item><title>Amp-up GitLab Merge Requests With Pulumi</title><link>https://www.pulumi.com/blog/gitlab-project-integration/</link><pubDate>Wed, 26 Aug 2020 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/gitlab-project-integration/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/gitlab-project-integration/index.png" /&gt;
&lt;p&gt;We are excited to announce the launch of native support for integrating GitLab Merge Requests with Pulumi.
By integrating your GitLab Projects directly with Pulumi, you can now approve your merge requests
with confidence.&lt;/p&gt;
&lt;h2 id="new-to-pulumi-and-gitlab-cicd"&gt;New To Pulumi and GitLab CI/CD?&lt;/h2&gt;
&lt;p&gt;GitLab&amp;rsquo;s &lt;a href="https://docs.gitlab.com/ee/ci/pipelines/merge_request_pipelines.html"&gt;merge request pipelines&lt;/a&gt; runs a CI/CD workflow for building and testing your software.
Pulumi makes a great addition to it, by allowing you to preview any infrastructure changes as part of your merge request flow.&lt;/p&gt;
&lt;p&gt;Using the merge request pipeline feature with Pulumi can validate the changes to your infrastructure before they are applied.
Once validated and approved through a peer-review process, you can apply your changes quickly and continuously with confidence while doing so,
a process commonly referred to as GitOps for infrastructure.&lt;/p&gt;
&lt;p&gt;To leverage GitOps for your infrastructure, the Pulumi CLI offers two commands: &lt;code&gt;preview&lt;/code&gt; and &lt;code&gt;up&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Pulumi command&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Merge requests pipeline&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pulumi preview&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preview infrastructure changes to be merged.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Master branch pipeline&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pulumi up&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update your infrastructure with latest changes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Learn how to use &lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/gitlab-ci"&gt;Pulumi in GitLab CI/CD&lt;/a&gt; with merge request pipelines and how to configure the &lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/gitlab-app/"&gt;GitLab project integration with Pulumi&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="already-using-both"&gt;Already Using Both?&lt;/h2&gt;
&lt;p&gt;If you are already a user of either Pulumi and GitLab CI/CD, you
know the importance of merge request pipelines and running Pulumi within them.
With today&amp;rsquo;s announcement, you can now make any changes to your infrastructure in your merge
request front and center, so you don&amp;rsquo;t miss any of those changes.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a &lt;em&gt;preview&lt;/em&gt; of what that looks like 😉&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/gitlab-project-integration/pulumi_gitlab.png" alt="Merge Request Note"&gt;&lt;/p&gt;
&lt;p&gt;Head over to our docs to learn how to &lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/gitlab-app/"&gt;configure the GitLab integration&lt;/a&gt;, whether for
a single project or all of the projects under a GitLab Group.&lt;/p&gt;
&lt;p&gt;GitLab provides lots of tools for streamlining your application delivery, and the new integration with Pulumi makes things even better.
As always, we&amp;rsquo;d love to hear your feedback or suggestions for other improvements. Check out the &lt;a href="https://slack.pulumi.com"&gt;Pulumi Community Slack&lt;/a&gt;.&lt;/p&gt;</description><author>Praneet Loke</author><category>continuous-delivery</category><category>gitlab</category></item><item><title>Unlocking Spinnaker With Pulumi</title><link>https://www.pulumi.com/blog/unlocking-spinnaker-with-pulumi/</link><pubDate>Thu, 18 Jun 2020 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/unlocking-spinnaker-with-pulumi/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/unlocking-spinnaker-with-pulumi/index.png" /&gt;
&lt;p&gt;Spinnaker is an open source, multi-cloud continuous delivery platform for releasing software changes with high velocity and confidence.
This makes it a perfect fit for Pulumi to unleash the power of Spinnaker and its continuous delivery capabilities to all of the providers
that Pulumi supports today and in the future.&lt;/p&gt;
&lt;p&gt;We have written a developer &lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/spinnaker/"&gt;guide&lt;/a&gt; showing you how to install the &lt;a href="https://github.com/pulumi/spinnaker-preconfigured-job-plugin"&gt;plugin&lt;/a&gt; in your Spinnaker instance and start using it right away.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a brief overview of the plugin.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a new Spinnaker pipeline with the Pulumi stage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/unlocking-spinnaker-with-pulumi/pipeline-config.png" alt="Pulumi plugin config"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When you run a pipeline that has a Pulumi stage in it, you&amp;rsquo;ll be able to see the logs of the Pulumi CLI within your pipeline execution details window. Click the &lt;strong&gt;Console Output&lt;/strong&gt; to view the logs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/unlocking-spinnaker-with-pulumi/spinnaker-pulumi-preview.png" alt="Pulumi logs"&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a demo of the plugin:&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/V3FxNh6KQkE?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;If you have any questions or feedback about the plugin, please feel free to open an &lt;a href="https://github.com/pulumi/spinnaker-preconfigured-job-plugin/issues"&gt;issue&lt;/a&gt; in the repo or join the conversation on our &lt;a href="https://slack.pulumi.com"&gt;Community Slack&lt;/a&gt; as always.&lt;/p&gt;</description><author>Praneet Loke</author><category>continuous-delivery</category><category>spinnaker</category></item><item><title>Dynamic Providers</title><link>https://www.pulumi.com/blog/dynamic-providers/</link><pubDate>Thu, 16 Jan 2020 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/dynamic-providers/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/dynamic-providers/index.png" /&gt;
&lt;p&gt;Pulumi has many resource providers that allow you to interact with your favorite cloud or resource. There are times when a provider may not deliver on the specific task that you want to accomplish. Dynamic Providers can be a powerful tool to help accomplish your infrastructure tasks.&lt;/p&gt;
&lt;p&gt;A provider manages the CRUD (Create, Read, Update, Delete) life-cycle of a resource against some underlying service. The underlying service can be one of the public clouds or an on-premise service. For example, AWS, Azure, GCP, and Kubernetes have resource providers, which can manage resources by request.&lt;/p&gt;
&lt;h2 id="resource-provider"&gt;Resource Provider&lt;/h2&gt;
&lt;p&gt;A resource provider is made up of two different pieces:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A resource plugin, which is the binary used by the deployment engine to manage a resource. These plugins are stored in the plugin cache (located in &lt;code&gt;~/.pulumi/plugins&lt;/code&gt;) and can be managed using the &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_plugin/"&gt;&lt;code&gt;pulumi plugin&lt;/code&gt;&lt;/a&gt; set of commands.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An SDK which provides bindings for each type of resource the provider can manage.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/dynamic-providers/engine-block-diagram.png" alt="How Pulumi works"&gt;&lt;/p&gt;
&lt;p&gt;A resource provider is an extension of the API exposed by the respective cloud providers. As such, it can be the limiting factor. Thankfully, there is a solution to this. Since the Pulumi engine works with life-cycle callbacks handing control to the provider at appropriate times, it is easy to write a provider that implements custom logic in those callbacks.&lt;/p&gt;
&lt;p&gt;Learn more about how Pulumi works &lt;a href="https://www.pulumi.com/docs/concepts/how-pulumi-works/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="dynamic-resource-provider"&gt;Dynamic Resource Provider&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Dynamic providers are currently only supported in JavaScript, TypeScript, and Python.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pulumi provides appropriate life-cycle callbacks through the &lt;code&gt;pulumi.dynamic.ResourceProvider&lt;/code&gt; abstract class. While Pulumi does not know what sort of resources a Dynamic Provider will create, the life-cycle hooks must return data in specific formats, which Pulumi uses to call the appropriate callbacks.&lt;/p&gt;
&lt;p&gt;For example, if the user changes an input property to your dynamic resource, the &lt;code&gt;diff&lt;/code&gt; hook will be called with both the old (if applicable) and new inputs. You can compare then to see which input properties have changed and give hints to Pulumi as to whether &lt;code&gt;delete&lt;/code&gt; should be called or whether to call the &lt;code&gt;update&lt;/code&gt; hook.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;check&lt;/code&gt; life-cycle hook will be called before any other hook to let you validate the inputs and populate defaults, if necessary.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When a dynamic resource instance updates, the &lt;code&gt;delete&lt;/code&gt; hook will be called to allow you to perform any necessary cleanups before the dynamic resource is removed from your stack’s state.&lt;/p&gt;
&lt;h3 id="provider-credentials"&gt;Provider Credentials&lt;/h3&gt;
&lt;p&gt;If you need to use the credentials used by the rest of your Pulumi app, also known as the ambient provider credentials, you can access the relevant credentials (and other configuration) through the &lt;code&gt;&amp;lt;provider&amp;gt;.config&lt;/code&gt; where &lt;code&gt;provider&lt;/code&gt; is the imported provider module.&lt;/p&gt;
&lt;h2 id="sample-use-cases"&gt;Sample Use Cases&lt;/h2&gt;
&lt;p&gt;Dynamic providers can be used for almost any task. Since Pulumi uses general-purpose programming languages, you can do almost anything you would outside of your infrastructure app. You can even use libraries that are standard to the respective programming language.&lt;/p&gt;
&lt;p&gt;Here are some use cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run a command-line tool when a dependent resource is created.&lt;/li&gt;
&lt;li&gt;Copy files to a VM once the VM is created.&lt;/li&gt;
&lt;li&gt;Call REST APIs in each life-cycle hook (CRUD) to adopt an external resource under the cloud resource model.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="examples"&gt;Examples&lt;/h3&gt;
&lt;h4 id="enable-azure-storages-static-websites-feature"&gt;Enable Azure Storage&amp;rsquo;s Static Websites Feature&lt;/h4&gt;
&lt;p&gt;The Azure resource provider does not support enabling the &lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-static-website"&gt;static website&lt;/a&gt; feature for a storage account. However, there is a REST API that can be called to enable the feature, so we can easily call the API from within the dynamic provider.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/pulumi/examples/blob/5bcf9de17a660f17172ca05d4ca3f061456a99c5/azure-ts-static-website/staticWebsite.ts"&gt;Here&amp;rsquo;s&lt;/a&gt; the source for this example. The following is an excerpt from the &lt;a href="https://github.com/pulumi/examples/blob/e990699e03ff31af95bd62b08f31f8fb99b11ccb/azure-ts-static-website/index.ts"&gt;example&lt;/a&gt; where the dynamic provider is actually used. Note that the Azure Storage Account is created before using this dynamic provider.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Create a Storage Account for our static website
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storageAccount&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;azure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;websitesa&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resourceGroupName&lt;/span&gt;: &lt;span class="kt"&gt;resourceGroup.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;accountReplicationType&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;LRS&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;accountTier&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Standard&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;accountKind&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;StorageV2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;staticWebsite&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;StorageStaticWebsite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;website-static&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;accountName&lt;/span&gt;: &lt;span class="kt"&gt;storageAccount.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="add-a-custom-domain-to-an-azure-cdn-endpoint"&gt;Add A Custom Domain To An Azure CDN endpoint&lt;/h4&gt;
&lt;p&gt;Similar to the previous example, this is another example of a shortcoming of the regular Azure resource provider available in Pulumi. However, due to the availability of a REST API, we can easily add a custom domain to an Azure CDN resource using a dynamic provider.&lt;/p&gt;
&lt;p&gt;Along with adding a custom domain to the CDN endpoint, this dynamic provider also enables HTTPS provided by Azure&amp;rsquo;s one-click &lt;a href="https://docs.microsoft.com/en-us/azure/cdn/cdn-custom-ssl?tabs=option-1-default-enable-https-with-a-cdn-managed-certificate"&gt;HTTPS enablement&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As before, details such as the creation of the CDN profile and its endpoint are omitted for clarity. You can check out the full example &lt;a href="https://github.com/pulumi/examples/tree/846811de2c7faa4694454c64edc9bbcdb31d533e/classic-azure-ts-dynamicresource"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cdnEndpoint&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;azure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;cdnEndpoint&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * Specify a well-known name for the endpoint name,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * so you can add a CNAME record for your custom domain
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * pointing to this CDN endpoint to it.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * For example, the URL for this CDN endpoint when it is created
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * would be `my-cdn-endpoint.azureedge.net`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;my-cdn-endpoint&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resourceGroupName&lt;/span&gt;: &lt;span class="kt"&gt;resourceGroup.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;profileName&lt;/span&gt;: &lt;span class="kt"&gt;cdnProfile.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;isHttpsAllowed&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;isHttpAllowed&lt;/span&gt;: &lt;span class="kt"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;isCompressionEnabled&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;originHostHeader&lt;/span&gt;: &lt;span class="kt"&gt;storageAccount.primaryBlobHost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;contentTypesToCompresses&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;text/plain&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;text/html&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;application/x-javascript&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;application/javascript&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;application/xml&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;image/png&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;image/jpeg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;origins&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cdn-origin&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;hostName&lt;/span&gt;: &lt;span class="kt"&gt;storageAccount.primaryBlobHost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;httpsPort&lt;/span&gt;: &lt;span class="kt"&gt;443&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cdnCustomDomainResource&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;CDNCustomDomainResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;cdnCustomDomain&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resourceGroupName&lt;/span&gt;: &lt;span class="kt"&gt;resourceGroupName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Ensure that there is a CNAME record for mycompany.com
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// pointing to my-cdn-endpoint.azureedge.net.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// You would do that in your domain registrar&amp;#39;s portal.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;customDomainHostName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;mycompany.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;profileName&lt;/span&gt;: &lt;span class="kt"&gt;cdnProfileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;endpointName&lt;/span&gt;: &lt;span class="kt"&gt;cdnEndpointName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// This will enable HTTPS through Azure&amp;#39;s one-click
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// automated certificate deployment.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// The certificate is fully managed by Azure from provisioning
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// to automatic renewal at no additional cost to you.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;httpsEnabled&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;: &lt;span class="kt"&gt;cdnEndpoint&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="dynamic-providers-as-provisioners"&gt;Dynamic Providers As Provisioners&lt;/h4&gt;
&lt;p&gt;Provisioning a VM after it is created is a common problem. Developers have the option to run user-supplied scripts while creating the VM itself. For example, the AWS EC2 resource has a &lt;code&gt;userData&lt;/code&gt; parameter, that allows you to specify an inline script, which EC2 will run at instance startup.&lt;/p&gt;
&lt;p&gt;Scripts provided through the &lt;code&gt;userData&lt;/code&gt; parameter can be configured to run every time the instance is restarted. But what if you wanted to run the script every time the &lt;em&gt;script&lt;/em&gt; changes? To do that you could use SCP to transfer the file and then execute the script on the VM. This &lt;a href="https://github.com/pulumi/examples/tree/master/aws-ts-ec2-provisioners"&gt;example&lt;/a&gt; shows you how you can do that. Although the example uses TypeScript and is specific to AWS EC2, you can easily adapt this to other cloud providers.&lt;/p&gt;
&lt;p&gt;This snippet of the code shows how, the dynamic resources for copying a file and executing it, are used:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;host&lt;/span&gt;: &lt;span class="kt"&gt;server.publicIp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ec2-user&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// The EC2 instance is created with the corresponding SSH public key.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Read more here: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;privateKeyPassphrase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Copy a config file from the local filesystem to the instance.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cpConfig&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;provisioners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CopyFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;config&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;myapp.conf&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;myapp.conf&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dependsOn&lt;/span&gt;: &lt;span class="kt"&gt;server&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Execute a basic command on the instance.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;catConfig&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;provisioners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RemoteExec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;cat-config&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cat myapp.conf&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dependsOn&lt;/span&gt;: &lt;span class="kt"&gt;cpConfig&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;…&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Read more about dynamic providers in our &lt;a href="https://www.pulumi.com/docs/concepts/resources/dynamic-providers/"&gt;docs&lt;/a&gt;. Let us know what cool dynamic providers you create by dropping us a note on our community &lt;a href="https://slack.pulumi.com/"&gt;Slack&lt;/a&gt;!&lt;/p&gt;</description><author>Praneet Loke</author><category>features</category></item><item><title>GitHub &amp; Pulumi Join Forces To Ensure Pulumi Tokens Are Safe</title><link>https://www.pulumi.com/blog/github-token-scanning-service/</link><pubDate>Mon, 19 Aug 2019 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/github-token-scanning-service/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/github-token-scanning-service/index.png" /&gt;
&lt;p&gt;We are very excited to announce that we have partnered with GitHub to offer our users better protection for their &lt;a href="https://www.pulumi.com/docs/pulumi-cloud/accounts#access-tokens"&gt;Pulumi Access Tokens&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By default, Pulumi users manage the state of their cloud infrastructure deployments using &lt;a href="https://app.pulumi.com/signin"&gt;https://app.pulumi.com&lt;/a&gt;. This service provides state storage, concurrency control, audit history and access controls for both individuals and teams working with Pulumi. Each user and service account can generate one or more Pulumi Access Tokens to be used to authenticate with this service. These access tokens can be used on both local development machines, as well as in CI/CD systems for automated infrastructure deployments. These access tokens are sensitive secrets which should never be shared publicly, and in particular should never be committed to source control.&lt;/p&gt;
&lt;h2 id="how-github-token-scanning-works-for-pulumi-users"&gt;How GitHub Token Scanning Works for Pulumi Users&lt;/h2&gt;
&lt;p&gt;With the recent changes to integrate Pulumi with GitHub Token Scanning, GitHub now scans each commit you push to a &lt;strong&gt;public repo&lt;/strong&gt; on github.com for any files containing these tokens. When GitHub&amp;rsquo;s &lt;a href="https://developer.github.com/partnerships/token-scanning/"&gt;Token Scanning Service&lt;/a&gt; finds a potential match for our tokens, the service will call ours to have us verify the token. Only Pulumi Access Tokens generated after June 28, 2019 that contain the prefix &lt;code&gt;pul-&lt;/code&gt; will be matched by the scanning service.&lt;/p&gt;
&lt;p&gt;During the processing of the requests from the Token Scanning Service, if we find that the token belongs to a Pulumi account, we will use the primary email on the account to notify the user. We will not, however, revoke the token automatically. So ensure that your account&amp;rsquo;s email address is up-to-date by going to your &lt;a href="https://app.pulumi.com/account/profile"&gt;profile&lt;/a&gt; in the Pulumi Service.&lt;/p&gt;
&lt;p&gt;The whole process, from the check-in to the email notification, typically takes just a few seconds, minimizing the window of an accidental breach. Of course, best practice is to avoid checking in the token at all!&lt;/p&gt;
&lt;h2 id="avoid-checking-in-the-token-in-the-first-place"&gt;Avoid Checking-In The Token In The First Place&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/pulumi-cloud/accounts#access-tokens"&gt;Pulumi Access Tokens&lt;/a&gt; grant access to your stacks. They allow you to login into the CLI non-interactively and thus allow the CLI to access a stack’s configuration, which may in-turn &lt;a href="https://www.pulumi.com/blog/managing-secrets-with-pulumi/"&gt;contain other secrets&lt;/a&gt;. The token is typically used inside CI/CD environments. So you should never have to check-in a token to your source tree (public or otherwise.)&lt;/p&gt;
&lt;p&gt;Most CI/CD services have a way for you to specify secret environment variables that allow you to safely inject them into your build environment. We have written-up quite a few guides on &lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/"&gt;how to integrate Pulumi into your CI/CD&lt;/a&gt;. If you don&amp;rsquo;t see a guide for a CI/CD system that you are using, feel free to create an issue &lt;a href="https://github.com/pulumi/docs"&gt;here&lt;/a&gt;, or even better, raise a PR for it. We love community contributions! :)&lt;/p&gt;</description><author>Praneet Loke</author><category>security</category><category>github</category></item><item><title>CI/CD Made Easy with Pulumi and Azure Pipelines</title><link>https://www.pulumi.com/blog/cd-made-easy-with-pulumi-and-azure-pipelines/</link><pubDate>Mon, 06 May 2019 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/cd-made-easy-with-pulumi-and-azure-pipelines/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/cd-made-easy-with-pulumi-and-azure-pipelines/index.png" /&gt;
&lt;p&gt;Azure DevOps is very popular among teams that want a single place to
manage their development pipelines, Git repositories, builds, releases,
and test plans. Pulumi&amp;rsquo;s open-source tools are a great choice for
developers and operators deploying infrastructure as code on Azure. With
these two tools at hand, adopting CI and CD for your Azure
infrastructure is just a few steps away for you and your teams.&lt;/p&gt;
&lt;p&gt;To make it easy to use Pulumi with Azure, we are announcing an
open-source task extension for Azure Pipelines! The task extension will
manage the installation of the Pulumi CLI, and run the &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/"&gt;Pulumi
commands&lt;/a&gt; you specify against
your stack.&lt;/p&gt;
&lt;p&gt;You can install the task extension directly from the &lt;a href="https://marketplace.visualstudio.com/items?itemName=pulumi.build-and-release-task"&gt;Visual Studio
Marketplace&lt;/a&gt;.
Click the &lt;strong&gt;&amp;ldquo;Get It Free&amp;rdquo;&lt;/strong&gt; button to install the extension into your
Azure DevOps organization. If you do not have the permissions to add it
to your organization, please contact your org admin to have the
extension installed. The source code for the open source task extension
can be found on
&lt;a href="https://github.com/pulumi/pulumi-az-pipelines-task"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To use the Pulumi task extension in Azure Pipelines, there are two
options. The
full &lt;a href="https://github.com/pulumi/pulumi-az-pipelines-task/tree/master/examples"&gt;example&lt;/a&gt; is
in the source repo. For contrast, without this task extension,
&lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/azure-devops#using-scripts-manual-approach"&gt;here&amp;rsquo;s&lt;/a&gt; how
you would achieve the same, but with scripts.&lt;/p&gt;
&lt;h2 id="option-1-using-the-classic-editor-console"&gt;OPTION 1: Using the Classic Editor Console&lt;/h2&gt;
&lt;p&gt;Pasted below is a typical view of the Editor User Interface. Click on
the &lt;strong&gt;&amp;quot;+&amp;quot;&lt;/strong&gt; button next to the job. As visible in the screenshot, the
job is called &lt;strong&gt;&amp;ldquo;Agent job 1&amp;rdquo;&lt;/strong&gt;. The agent pool you choose does not
matter. The Pulumi task can run on both Linux as well as Windows
images.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/cd-made-easy-with-pulumi-and-azure-pipelines/classic-editor-console.png" alt="classic editor console"&gt;&lt;/p&gt;
&lt;p&gt;Search for the &lt;strong&gt;Pulumi&lt;/strong&gt; task by typing in the filter input on the right. Click the &lt;strong&gt;Add&lt;/strong&gt; button.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/cd-made-easy-with-pulumi-and-azure-pipelines/add-pulumi.png" alt="add Pulumi"&gt;&lt;/p&gt;
&lt;p&gt;Fill in the required information. You can learn about creating service connections for Azure
&lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/cd-made-easy-with-pulumi-and-azure-pipelines/configuration.png" alt="configuration"&gt;&lt;/p&gt;
&lt;p&gt;If you want to understand all the commands available with the Pulumi CLI, click on the information icon (&lt;strong&gt;i&lt;/strong&gt;)
next to &lt;strong&gt;Pulumi Command&lt;/strong&gt;, and click on the help link to go to our quick reference page.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/cd-made-easy-with-pulumi-and-azure-pipelines/output.png" alt="output"&gt;&lt;/p&gt;
&lt;h2 id="option-2-using-a-yaml-file"&gt;Option 2: Using a YAML File&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s an example of the Pulumi task extension defined in YAML configuration.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="nt"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Pulumi@0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;azureSubscription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;your-service-connection-name&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;up&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;--yes --skip-preview&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Replace this with your org&amp;#39;s name.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;lt;org-name&amp;gt;/pulumi-az-pipelines-task-example/dev&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="moving-to-production"&gt;Moving to Production&lt;/h2&gt;
&lt;p&gt;Once you&amp;rsquo;ve configured your Pulumi task extensions for your Azure Pipelines, you can now more
easily integrate Pulumi into your CI/CD pipeline, and take advantage of previews to infrastructure
changes in pull requests, push-to-deploy, and ultimately removing the friction for your DevOps.&lt;/p&gt;
&lt;p&gt;As always, we&amp;rsquo;d love to hear what you think. Say 👋 in the &lt;a href="https://slack.pulumi.com"&gt;Pulumi Community Slack&lt;/a&gt;
or &lt;a href="https://www.pulumi.com/contact/"&gt;drop us a line&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Want to learn more? Check out &lt;a href="https://www.pulumi.com/blog/level-up-your-azure-platform-as-a-service-applications-with-pulumi/"&gt;this post from Mikhail Shilkov&lt;/a&gt;
for a detailed look at deploying applications on Azure with Pulumi.
Also, keep an eye on our blog posts this week for more posts about Azure.&lt;/p&gt;</description><author>Praneet Loke</author><category>azure</category><category>continuous-delivery</category><category>features</category></item><item><title>Announcing Support for Email-based Identities</title><link>https://www.pulumi.com/blog/announcing-support-for-email-based-identities/</link><pubDate>Thu, 21 Mar 2019 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/announcing-support-for-email-based-identities/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/announcing-support-for-email-based-identities/index.png" /&gt;
&lt;p&gt;We have been hard at work the past few months providing our users with
more ways to connect to Pulumi. Here are some our past announcements
related to identities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/pulumi-now-supports-atlassian-identity/"&gt;Support for Atlassian identity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/connecting-multiple-identities-to-pulumi/"&gt;Connecting multiple identities to an existing Pulumi account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/welcoming-gitlab-users-to-pulumi/"&gt;Support for GitLab identity&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Today&lt;/strong&gt;, we are pleased to announce that we are launching support for
email-based identities. You no longer need to use a social identity to
sign-up for an account on Pulumi. Just fill out
the &lt;a href="https://app.pulumi.com/signup/email"&gt;signup&lt;/a&gt; form, and you are
ready to go.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/announcing-support-for-email-based-identities/email-signup.png" alt="Email Signup"&gt;&lt;/p&gt;
&lt;h2 id="quickstart"&gt;Quickstart&lt;/h2&gt;
&lt;p&gt;Get started quickly by creating a new &lt;a href="https://app.pulumi.com/site/new-project"&gt;template-based project&lt;/a&gt;.
This creates a project, and a &lt;a href="https://www.pulumi.com/docs/concepts/stack/"&gt;stack&lt;/a&gt; ready to be used by the Pulumi CLI.
The wizard also shows you the commands you need to run in the CLI.&lt;/p&gt;
&lt;p&gt;Haven&amp;rsquo;t setup your CLI for a specific cloud yet? Check out this docs page on how to do that.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/uploads/content/blog/announcing-support-for-email-based-identities/new-project-wizard.gif" alt="New Project Wizard"&gt;&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve deployed your first stack, the next step is up to you. You can refer to our documentation on integrating Pulumi into your CI/CD pipeline, setting up chat-ops workflows via Webhooks, or taking your Kubernetes solutions to the next level!&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;d love to hear what you&amp;rsquo;re up to. Say 👋 in the &lt;a href="https://slack.pulumi.com/"&gt;Pulumi Community Slack&lt;/a&gt;
or &lt;a href="https://www.pulumi.com/contact/"&gt;drop us a line&lt;/a&gt;.&lt;/p&gt;</description><author>Praneet Loke</author><category>announcements</category><category>features</category></item><item><title>Pulumi now supports Atlassian Identity</title><link>https://www.pulumi.com/blog/pulumi-now-supports-atlassian-identity/</link><pubDate>Wed, 30 Jan 2019 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-now-supports-atlassian-identity/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-now-supports-atlassian-identity/index.png" /&gt;
&lt;p&gt;Today we added support for yet another developer favorite product,
Atlassian Bitbucket. You can now sign-up for a Pulumi account with an
Atlassian identity. This also means you can connect your Atlassian
identity with an existing Pulumi account.&lt;/p&gt;
&lt;p&gt;This work follows on from the support for
&lt;a href="https://www.pulumi.com/blog/welcoming-gitlab-users-to-pulumi/"&gt;GitLab identity&lt;/a&gt;
and also the ability to
&lt;a href="https://www.pulumi.com/blog/connecting-multiple-identities-to-pulumi/"&gt;connect identities&lt;/a&gt;,
eliminating the need for users to create multiple accounts on Pulumi.&lt;/p&gt;
&lt;p&gt;This helps users with repos across the major version control systems to
seamlessly import their GitHub Organizations and GitLab Groups - and now
Atlassian Bitbucket Teams - into a single Pulumi account. Of course, you
don&amp;rsquo;t &lt;em&gt;need&lt;/em&gt; to connect identities. You can always create separate
account for each of your identities, if that&amp;rsquo;s what you want to do.&lt;/p&gt;
&lt;h2 id="creating-a-new-pulumi-account-using-your-atlassian-identity"&gt;Creating a new Pulumi account using your Atlassian identity&lt;/h2&gt;
&lt;p&gt;To get started using your Atlassian identity, you can navigate to
&lt;a href="https://app.pulumi.com/signin"&gt;app.pulumi.com&lt;/a&gt; and select the Atlassian button to authenticate.
If you are already logged-in to Pulumi, you should first logout and then
head back to the Pulumi Service.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/pulumi-now-supports-atlassian-identity/atlassian-1.png" alt="atlassian-1"&gt;&lt;/p&gt;
&lt;h2 id="connecting-an-existing-pulumi-account-to-your-atlassian-identity"&gt;Connecting an existing Pulumi account to your Atlassian identity&lt;/h2&gt;
&lt;p&gt;If you want to connect your Atlassian identity to an existing Pulumi
account, then navigate to &lt;a href="https://app.pulumi.com/signin"&gt;app.pulumi.com&lt;/a&gt; and once logged in,
head to Account Settings to choose the option to connect your Atlassian
identity.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/pulumi-now-supports-atlassian-identity/atlassian-2.png" alt="atlassian-2"&gt;&lt;/p&gt;
&lt;h2 id="bitbucket-team-backed-organizations"&gt;Bitbucket Team-backed Organizations&lt;/h2&gt;
&lt;p&gt;A &lt;a href="https://confluence.atlassian.com/bitbucket/teams-321853005.html"&gt;Bitbucket Team&lt;/a&gt;
helps you organize users into user groups and therefore, assign each of
them a permission to your repositories. By adding a Bitbucket
Team-backed organization, you can invite the same members to collaborate
on Pulumi.&lt;/p&gt;
&lt;p&gt;This allows you to set permissions on
&lt;a href="https://www.pulumi.com/docs/concepts/stack/"&gt;Stacks&lt;/a&gt; owned by your
organization. You can learn more about
&lt;a href="https://www.pulumi.com/docs/pulumi-cloud/access-management/teams/"&gt;Teams&lt;/a&gt;
in the Pulumi and how those permissions get applied too.&lt;/p&gt;
&lt;h2 id="ci-integration"&gt;CI Integration&lt;/h2&gt;
&lt;p&gt;Did you also know that the Pulumi CLI can be used in most, if not all,
CI/CD workflows? Check out our
&lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/"&gt;documentation&lt;/a&gt; for integrating
with several popular CI/CD systems. Get up and running with Pulumi in CI
on &lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/gitlab-ci/"&gt;GitLab&lt;/a&gt;,
&lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/travis/"&gt;Travis&lt;/a&gt;,
&lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/azure-devops/"&gt;Azure DevOps&lt;/a&gt; and more.
Don&amp;rsquo;t see docs for a particular CI system? Let us know or better yet
file an issue &lt;a href="https://github.com/pulumi/docs/issues"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Having trouble? Questions? Join our
&lt;a href="https://slack.pulumi.com/"&gt;community Slack&lt;/a&gt; or send us an email.&lt;/p&gt;</description><author>Praneet Loke</author><category>features</category><category>continuous-delivery</category></item><item><title>Connecting multiple identities to Pulumi</title><link>https://www.pulumi.com/blog/connecting-multiple-identities-to-pulumi/</link><pubDate>Fri, 14 Dec 2018 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/connecting-multiple-identities-to-pulumi/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/connecting-multiple-identities-to-pulumi/index.png" /&gt;
&lt;p&gt;Hot on the heels of our
&lt;a href="https://www.pulumi.com/blog/welcoming-gitlab-users-to-pulumi/"&gt;GitLab sign-in support&lt;/a&gt;,
we&amp;rsquo;ve just released support for multiple identities for a single Pulumi
account in the Pulumi Service. Previously, you could only sign-up
for a new Pulumi account using a GitHub or GitLab identity. Starting
today, you can connect your Pulumi account with additional identities,
beyond what you first signed-up with.&lt;/p&gt;
&lt;p&gt;For example, if you signed-in to Pulumi with your GitHub account, you
could only add GitHub organizations to the Pulumi Service, or
collaborate with other GitHub users. With multiple identities, you can
now also connect your Pulumi account to a GitLab identity too!&lt;/p&gt;
&lt;p&gt;To connect an identity, first sign-in as usual on
&lt;a href="https://app.pulumi.com/signin"&gt;https://app.pulumi.com&lt;/a&gt;, then go to your Profile page as shown below.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/connecting-multiple-identities-to-pulumi/multi-id.gif" alt="multi-id"&gt;&lt;/p&gt;
&lt;p&gt;Based on the example, on the Profile page, you would see a new button to
connect a GitLab account. Conversely, if you signed-up originally using
your GitLab account onto Pulumi, then you would see a button to connect
your GitHub account.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/connecting-multiple-identities-to-pulumi/multi-id-2.png" alt="multi-id-2"&gt;&lt;/p&gt;
&lt;p&gt;Connecting multiple identities to Pulumi has advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can then add your GitHub organizations or GitLab groups, to
collaborate with the respective members of those organizations using
Pulumi.&lt;/li&gt;
&lt;li&gt;A single Pulumi account connected to additional identities allows
for more ways to sign into the Pulumi Service.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, you don&amp;rsquo;t have to associate multiple identities with the same
Pulumi account. Whenever you sign-in with a new identity for the first
time on &lt;a href="https://app.pulumi.com/signup"&gt;app.pulumi.com&lt;/a&gt;, a new Pulumi account is created. You
can then choose to add additional identities at a later time.&lt;/p&gt;</description><author>Praneet Loke</author><category>continuous-delivery</category></item><item><title>Welcoming GitLab users to Pulumi</title><link>https://www.pulumi.com/blog/welcoming-gitlab-users-to-pulumi/</link><pubDate>Mon, 03 Dec 2018 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/welcoming-gitlab-users-to-pulumi/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/welcoming-gitlab-users-to-pulumi/index.png" /&gt;
&lt;p&gt;We are very pleased to announce that &lt;a href="https://www.pulumi.com/"&gt;Pulumi&lt;/a&gt; now
supports signing-in with your GitLab account. Don&amp;rsquo;t have an account on
GitLab yet? Head on over to &lt;a href="https://gitlab.com"&gt;https://gitlab.com&lt;/a&gt; and sign-up for an
account.&lt;/p&gt;
&lt;h2 id="why-gitlab"&gt;Why GitLab?&lt;/h2&gt;
&lt;p&gt;GitLab is a fully-integrated DevOps service that not only provides git
repository management but also allows you to collaborate using issue
boards, setup build and deployment pipelines. It provides an end-to-end
solution that starts from your code and ends with your customers, all
without ever having to leave GitLab.&lt;/p&gt;
&lt;p&gt;And with Pulumi on GitLab, you truly never have to leave GitLab, not
even to provision your infrastructure to run your services on the cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://about.gitlab.com/why/"&gt;Learn more about GitLab&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="login-and-create-a-gitlab-backed-pulumi-organization"&gt;Login and create a GitLab-backed Pulumi organization&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Log into &lt;code&gt;app.pulumi.com&lt;/code&gt; using the GitLab Sign-in.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click on the organizations dropdown menu and select &lt;strong&gt;Add an
organization&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the next page, you may select your GitLab group, based on which a
Pulumi organization will be created.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once the organization is created, you can create stacks in your
newly created organization, so that other members of your
organization can collaborate with you.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="inviting-members-in-your-gitlab-group-to-use-pulumi"&gt;Inviting members in your GitLab group to use Pulumi&lt;/h2&gt;
&lt;p&gt;Select the organization you created from the organization dropdown menu.
You should see a &lt;strong&gt;People&lt;/strong&gt; tab. Select the People tab.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;You will see the People tab if &lt;em&gt;you&lt;/em&gt; added the organization on
Pulumi or if you are an Owner of the GitLab group on
&lt;a href="https://gitlab.com"&gt;gitlab.com&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Members must have an active and valid role in your GitLab group,
so that you may invite them.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;From the People tab, you can invite additional members in your group to
also use Pulumi. By inviting members in your group to join Pulumi, you
can collaborate with them more easily and share stacks, just like you
would collaborate on a project on GitLab.&lt;/p&gt;
&lt;h2 id="running-pulumi-on-gitlab"&gt;Running Pulumi on GitLab&lt;/h2&gt;
&lt;p&gt;Pulumi can be run in &lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/"&gt;many CI/CD environments&lt;/a&gt;. Pulumi can be easily
integrated in your &lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/gitlab-ci/"&gt;CI pipeline on GitLab&lt;/a&gt;, too.&lt;/p&gt;
&lt;h2 id="deep-linking-to-your-gitlab-projects-branches-and-commits"&gt;Deep-linking to your GitLab projects, branches and commits&lt;/h2&gt;
&lt;p&gt;When you run Pulumi in a GitLab-based repo, the pulumi CLI recognizes
the correct metadata based on your repository&amp;rsquo;s &lt;code&gt;remote&lt;/code&gt; configuration
and uses that information to enhance your experience on
&lt;code&gt;app.pulumi.com&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example of a project hosted on
&lt;a href="https://gitlab.com"&gt;gitlab.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/welcoming-gitlab-users-to-pulumi/gl-3.png" alt="gl-3"&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the same project with some activity having links to the
commit-hash, and the branch in which this stack was updated.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/welcoming-gitlab-users-to-pulumi/gl-4.png" alt="gl-4"&gt;&lt;/p&gt;
&lt;h2 id="faq"&gt;FAQ&lt;/h2&gt;
&lt;h3 id="i-use-my-github-identity-to-login-into-gitlab-how-do-i-do-that-with-pulumi"&gt;I use my GitHub identity to login into GitLab. How do I do that with Pulumi?&lt;/h3&gt;
&lt;p&gt;Click the &lt;strong&gt;GitLab&lt;/strong&gt; sign-in button on &amp;lt;app.pulumi.com&amp;gt;, Pulumi
will redirect you to &lt;a href="https://gitlab.com"&gt;gitlab.com&lt;/a&gt; where GitLab will
present you with the sign-in options to login into your GitLab account.
At that point, you may choose any of the sign-in options GitLab provides
to sign-in.&lt;/p&gt;
&lt;h3 id="i-already-have-an-account-on-pulumi-will-signing-in-with-my-gitlab-identity-create-a-new-account"&gt;I already have an account on Pulumi. Will signing-in with my GitLab identity create a new account?&lt;/h3&gt;
&lt;p&gt;Yes. Signing-in with a GitLab account will create a new account. That
means, your stacks and activity will stay with the other account. You
can migrate them by performing a
&lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_stack_export"&gt;&lt;code&gt;pulumi stack export&lt;/code&gt;&lt;/a&gt;
from your source stack and then importing it using
&lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_stack_import"&gt;&lt;code&gt;pulumi stack import&lt;/code&gt;&lt;/a&gt;
in a new stack in your GitLab-based account.&lt;/p&gt;
&lt;p&gt;If you would like to add your GitLab identity to your &lt;em&gt;existing&lt;/em&gt; Pulumi account, you can
do so by connecting your GitLab identity from your Pulumi account&amp;rsquo;s profile page.&lt;/p&gt;
&lt;h3 id="how-do-i-login-into-the-pulumi-cli-on-my-local-machine-using-my-gitlab-backed-pulumi-account"&gt;How do I login into the pulumi CLI on my local machine using my GitLab-backed Pulumi account?&lt;/h3&gt;
&lt;p&gt;One of the benefits of using &amp;lt;app.pulumi.com&amp;gt; is to track the state of
your stacks. When you are running the pulumi CLI on your machine, you
can login into your account by typing &lt;code&gt;pulumi login&lt;/code&gt;. There are two
options for you to complete the login process. You can either create an
Access Token on &amp;lt;app.pulumi.com&amp;gt; or simply press &lt;strong&gt;ENTER&lt;/strong&gt; to let the
CLI launch the browser.&lt;/p&gt;
&lt;p&gt;If you would like to let the CLI launch the browser, ensure that you are
already signed-in using GitLab at &amp;lt;app.pulumi.com&amp;gt; using your machine&amp;rsquo;s
&lt;em&gt;default&lt;/em&gt; browser. This way, when the browser is launched by the CLI,
your Pulumi account based on your GitLab identity would be automatically
used.&lt;/p&gt;</description><author>Praneet Loke</author><category>continuous-delivery</category></item></channel></rss>