<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andrew Ogburn</title>
    <description>The latest articles on DEV Community by Andrew Ogburn (@aoggz).</description>
    <link>https://dev.to/aoggz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F182020%2F7dc11748-78c3-4d3a-84bd-eff0760406e8.jpeg</url>
      <title>DEV Community: Andrew Ogburn</title>
      <link>https://dev.to/aoggz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aoggz"/>
    <language>en</language>
    <item>
      <title>Deploying to AWS with runway &amp; SSM</title>
      <dc:creator>Andrew Ogburn</dc:creator>
      <pubDate>Wed, 09 Oct 2019 17:11:06 +0000</pubDate>
      <link>https://dev.to/aoggz/deploying-to-aws-with-runway-ssm-1gmn</link>
      <guid>https://dev.to/aoggz/deploying-to-aws-with-runway-ssm-1gmn</guid>
      <description>&lt;p&gt;Deploying to AWS with the Serverless Framework is a snap. Deploying to AWS with Terraform is not quite as easy as with Serverless, but it's pretty straightforward. Deploying infrastructure that's composed of both Terraform &amp;amp; Serverless configurations? That's crazy talk. Bash scripts, branches, and CLI output parsing will be needed to manage that mess. Right? Not quite...&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter runway
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/onicagroup/runway"&gt;Runway&lt;/a&gt; is...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A lightweight wrapper around linting (e.g. yamllint) &amp;amp; infrastructure deployment tools (e.g. CloudFormation, Terraform, Serverless) to ease management of per-environment configs &amp;amp; deployment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In short, runway is good at making deployments consistent between the various Infrastructure-as-Code tools.&lt;/p&gt;

&lt;p&gt;Runway is a layer of abstraction between your pipeline and configurations therein. Those configurations can be implemented in &lt;a href="https://www.terraform.io"&gt;Terraform&lt;/a&gt;, &lt;a href="https://serverless.com"&gt;Serverless&lt;/a&gt;, &lt;a href="https://github.com/cloudtools/stacker"&gt;Stacker&lt;/a&gt; (&lt;a href="https://aws.amazon.com/cloudformation/"&gt;CloudFormation&lt;/a&gt;), or &lt;a href="https://aws.amazon.com/cdk/"&gt;cdk&lt;/a&gt;. Runway knows how to inject variables into each framework, configure backends (in the case of terraform), specify stages/workspaces/environments, etc.&lt;/p&gt;

&lt;p&gt;For the purposes of this post, I'm just going to focus on Terraform and Serverless.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple example
&lt;/h2&gt;

&lt;p&gt;This simple runway.yml file defines a deployment of a Serverless app and a Terraform configuration (in that order). The deployment will occur in us-east-1, and the dev and prod environments are enabled (but have no specific configuration associated with either).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;deployments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;myapp.sls&lt;/span&gt;                &lt;span class="c1"&gt;# directory w/ Serverless stack&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;infrastructure.terraform&lt;/span&gt; &lt;span class="c1"&gt;# directory w/ terraform configuration&lt;/span&gt;
    &lt;span class="na"&gt;regions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;
    &lt;span class="na"&gt;environments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;prod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To deploy this to prod, you could run DEPLOY_ENVIRONMENT=prod &amp;amp;&amp;amp; runway deploy. You can also use Git branch names or folder names to specify the environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  A little more real-world
&lt;/h2&gt;

&lt;p&gt;This slightly more complicated example shows how you can specify unique variables &amp;amp; values into each module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;deployments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp.sls&lt;/span&gt;
        &lt;span class="na"&gt;environments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;api_gateway_custom_domain_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev.my-api.com&lt;/span&gt;
          &lt;span class="na"&gt;prod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;api_gateway_custom_domain_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-api.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;infrastructure.terraform&lt;/span&gt;
        &lt;span class="na"&gt;environments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
            &lt;span class="na"&gt;golden_image_ami&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ami-zyx123456&lt;/span&gt;
          &lt;span class="na"&gt;prod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;golden_image_ami&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ami-zyx654321&lt;/span&gt;
    &lt;span class="na"&gt;regions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here I'm providing new values in the environments property for each module. These variables will be passed into the module deployments via syntax native to each deployment tool. This makes it very easy to build the multi-stack configuration in one place and maintaining native variable reference syntax within each configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSM: cross-configuration glue
&lt;/h2&gt;

&lt;p&gt;For values that needs to cross configurations, my team has made heavy use of &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html"&gt;AWS Systems Manager Parameter Store&lt;/a&gt; parameters. We've found that this is the easiest construct (to use in AWS) that all of the infrastructure-as-code tools that we use can natively understand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terraform
&lt;/h3&gt;

&lt;p&gt;You can use an &lt;code&gt;aws_ssm_parameter&lt;/code&gt; data source to import an SSM parameter set somewhere else.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_ssm_parameter"&lt;/span&gt; &lt;span class="s2"&gt;"foo"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/foo/${terraform.workspace}/value"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To create an SSM parameter, add an &lt;code&gt;aws_ssm_parameter&lt;/code&gt; resource to the configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_ssm_parameter"&lt;/span&gt; &lt;span class="s2"&gt;"foo"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/foo/${terraform.workspace}/lb-access-key-secret"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SecureString"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_access_key&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lb&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secret&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Serverless
&lt;/h3&gt;

&lt;p&gt;Referencing SSM parameters from a Serverless stack is a little more straightforward. You can use their native syntax to reference variables stored in SSM like this...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;${ssm:/foo/${self:provider.stage}/value}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To create an SSM parameter, add a Cloudformation resource to the &lt;code&gt;Resources&lt;/code&gt; section of the template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::SSM::Parameter&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
        &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/foo/${self:provider.stage}/lb-access-key-secret"&lt;/span&gt;
        &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SecureString&lt;/span&gt;
        &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${self:custom.secret_value}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Runway is a great option to use if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want a common CLI to use for multiple Infrastructure-as-Code tools&lt;/li&gt;
&lt;li&gt;You have multiple configurations and want to deploy them in one go&lt;/li&gt;
&lt;li&gt;You'd like to standardize the deploy jobs of your CI pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It has certainly helped the productivity of my team in many ways. I could talk about it more than I have, but I'd love to hear your feedback! What would you like to hear more about? What could use some more explanation?&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>terraform</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
