<?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: Sean Ziegler</title>
    <description>The latest articles on DEV Community by Sean Ziegler (@sean_ziegler).</description>
    <link>https://dev.to/sean_ziegler</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%2F376151%2Fee4fcbd9-3755-4e98-8dd1-894b81bb7c08.jpg</url>
      <title>DEV Community: Sean Ziegler</title>
      <link>https://dev.to/sean_ziegler</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sean_ziegler"/>
    <language>en</language>
    <item>
      <title>Learning AWS on your own? 10 services you need to know</title>
      <dc:creator>Sean Ziegler</dc:creator>
      <pubDate>Wed, 02 Sep 2020 13:01:31 +0000</pubDate>
      <link>https://dev.to/sean_ziegler/learning-aws-on-your-own-10-services-you-need-to-know-3nie</link>
      <guid>https://dev.to/sean_ziegler/learning-aws-on-your-own-10-services-you-need-to-know-3nie</guid>
      <description>&lt;p&gt;As of January 2020, there are approximately 190 AWS services. Even if you study full time, that's a lot if you're trying to learn AWS on your own. Fortunately, you can build full-featured applications after learning a small set of the core AWS services. These core services will form the foundation of the vast majority of applications built on AWS.&lt;/p&gt;

&lt;h2 id="0-can-you-learn-aws-on-your-own"&gt;Can you learn AWS on your own?&lt;/h2&gt;

&lt;p&gt;Yes, absolutely, you don't need any formal training or even an online course to learn AWS. How hard will it be? Well, that depends on your past experience in the IT / software industry. If you consider yourself a pro, you might not struggle very much. For IT beginners, AWS might not be the best starting point. Ultimately, it is possible to learn AWS on your own and you have to decide for yourself (based on your goals and experience) what path is best for you.&lt;/p&gt;

&lt;h2 id="1-study-the-most-important-aws-services-first"&gt;Study the most important AWS services first&lt;/h2&gt;

&lt;p&gt;Before you get caught up in the AWS machine learning section, consider getting a solid grasp of the fundamental services. It will make you a better engineer in the long run, I promise. I consider these the ten most important AWS services. Obviously, this is just my opinion. This list will change depending on who you ask and what they do in the cloud. &lt;/p&gt;

&lt;p&gt;Start with this list and once you have a basic understanding of AWS, branch out to the services specific to your needs.&lt;/p&gt;

&lt;p&gt;I highly recommend reading the Getting Started guide and FAQ for each service. After, research the key topics to deepen your understanding.  If you can do that, you're well on your way to a solid AWS foundation and maybe even an entry level certification. &lt;/p&gt;

&lt;h2 id="2-amazon-ec2-elastic-cloud-compute"&gt;Amazon EC2 - (Elastic Cloud Compute)&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Rh6PRM1s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-EC2%404x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rh6PRM1s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-EC2%404x.png" alt="" class="wp-image-1234" width="225" height="225"&gt;&lt;/a&gt;&lt;strong&gt;Amazon EC2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html"&gt;What is EC2?&lt;/a&gt; | &lt;a href="https://aws.amazon.com/ec2/faqs/"&gt;FAQ&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Amazon EC2 provides virtual servers, called instances, in the cloud. These are the cloud replacement for server racks in a data center. You can provision as many instances as you need and only pay for what you use. EC2 instances are available on-demand and can automatically scale up or down depending on your needs. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Key topics to understand&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instance types&lt;/li&gt;
&lt;li&gt;Regions &amp;amp; Availability zones&lt;/li&gt;
&lt;li&gt;User-data&lt;/li&gt;
&lt;li&gt;Instance store volumes (EBS)&lt;/li&gt;
&lt;li&gt;Autoscaling &amp;amp; Scaling policies&lt;/li&gt;
&lt;li&gt;Security groups&lt;/li&gt;
&lt;li&gt;SSH keypairs&lt;/li&gt;
&lt;li&gt;Public / Private / Elastic IPs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="3-aws-iam-identity-and-access-management"&gt;AWS IAM - (Identity and Access Management)&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hFi14o8S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/AWS-Identity-and-Access-Management_IAM%404x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hFi14o8S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/AWS-Identity-and-Access-Management_IAM%404x.png" alt="" class="wp-image-1236" width="225" height="225"&gt;&lt;/a&gt;&lt;strong&gt;AWS IAM&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html"&gt;What is IAM?&lt;/a&gt; | &lt;a href="https://aws.amazon.com/iam/faqs/"&gt;FAQ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS IAM allows you to restrict access to your cloud resources. With IAM, you can specify exactly who (or what) can interact with each of your AWS resources. IAM enables you to give the right people access to the right areas of your AWS account and enforce security policies as you see fit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Key topics to understand&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users and groups&lt;/li&gt;
&lt;li&gt;Service roles&lt;/li&gt;
&lt;li&gt;Trust relationships&lt;/li&gt;
&lt;li&gt;Identity federation&lt;/li&gt;
&lt;li&gt;Managed and inline policies&lt;/li&gt;
&lt;li&gt;Security tokens (STS)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="4-amazon-s3-simple-storage-service"&gt;Amazon S3 - (Simple Storage Service)&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B3tIcddx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-Simple-Storage-Service-S3_light-bg%404x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B3tIcddx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-Simple-Storage-Service-S3_light-bg%404x.png" alt="" class="wp-image-1237" width="225" height="225"&gt;&lt;/a&gt;&lt;strong&gt;AWS S3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/Welcome.html"&gt;What is S3?&lt;/a&gt; | &lt;a href="https://aws.amazon.com/s3/faqs/"&gt;FAQ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;S3 is low-cost highly scalable data storage for the cloud. S3 enables you to store your data in folders called buckets that are cost efficient, high performing, and reliable. You can upload and retrieve objects via the AWS SDK, CLI, or management interface. S3 is one of AWS's oldest and most popular services because it is so versatile. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Key topics to understand&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storage classes and retrieval times&lt;/li&gt;
&lt;li&gt;Lifecycle mangement&lt;/li&gt;
&lt;li&gt;Multi-part uploads&lt;/li&gt;
&lt;li&gt;Data consistency model &lt;/li&gt;
&lt;li&gt;Cross region replication&lt;/li&gt;
&lt;li&gt;CORS&lt;/li&gt;
&lt;li&gt;Static website hosting&lt;/li&gt;
&lt;li&gt;Pre-signed URLs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="5-amazon-rds-relational-database-service"&gt;Amazon RDS - (Relational Database Service)&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uB2XsAjT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-RDS%404x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uB2XsAjT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-RDS%404x.png" alt="" class="wp-image-1238" width="225" height="225"&gt;&lt;/a&gt;&lt;strong&gt;Amazon RDS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html"&gt;What is RDS?&lt;/a&gt; | &lt;a href="https://aws.amazon.com/rds/faqs/"&gt;FAQ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RDS provides databases in the cloud. RDS supports most of the major database engines and can scale up or down depending on the load. It automates many of the common tasks associated with database management such as software patching, backups, and recovery. RDS is a transactional database, in contrast &lt;a href="https://aws.amazon.com/dynamodb/"&gt;DynamoDB&lt;/a&gt; is Amazon's serverless NoSQL offering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Key topics to understand&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database engine options&lt;/li&gt;
&lt;li&gt;Database instance types&lt;/li&gt;
&lt;li&gt;Multi-AZ deployments&lt;/li&gt;
&lt;li&gt;Read replicas&lt;/li&gt;
&lt;li&gt;Auto-scaling &lt;/li&gt;
&lt;li&gt;Encryption options&lt;/li&gt;
&lt;li&gt;Backups and restores&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="6-amazon-route53"&gt;Amazon Route53&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ip-8ydd0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-Route-53%404x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ip-8ydd0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-Route-53%404x.png" alt="" class="wp-image-1239" width="225" height="225"&gt;&lt;/a&gt;&lt;strong&gt;Amazon&lt;/strong&gt; &lt;strong&gt;Route 53&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/Welcome.html"&gt;What is Route53?&lt;/a&gt; | &lt;a href="https://aws.amazon.com/route53/faqs/"&gt;FAQ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Route53 manages DNS within the AWS ecosystem. Route53 serves three major functions: registering domains, DNS routing, and health checking. It is highly available by default and can support high traffic out of the box. You can use any DNS registrar with AWS, but there are some advantages to staying within the AWS eco-system (health checks and alias records to name a few).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;strong&gt;Key topics to understand&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Domain concepts - domain name, registrars, TLDs&lt;/li&gt;
&lt;li&gt;DNS record types&lt;/li&gt;
&lt;li&gt;Health checks&lt;/li&gt;
&lt;li&gt;Routing policies&lt;/li&gt;
&lt;li&gt;DNS failover&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="7-amazon-elb-elastic-load-balancer"&gt;Amazon ELB - (Elastic Load Balancer)&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3Jp2sP2L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Elastic-Load-Balancing%404x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3Jp2sP2L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Elastic-Load-Balancing%404x.png" alt="" class="wp-image-1240" width="225" height="225"&gt;&lt;/a&gt;&lt;strong&gt;Amazon ELB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/userguide/what-is-load-balancing.html"&gt;What is ELB? &lt;/a&gt;| &lt;a href="https://aws.amazon.com/route53/faqs/"&gt;FAQ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ELB provides load balancers which distribute incoming traffic across multiple resources inside of AWS, like EC2 servers or ECS nodes. If your traffic is too much for one server or you want to make your application highly available, you need a load balancer. ELB increases your applications reliability by handling SSL, health checks, and traffic routing so your application servers can focus on their primary task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key topics to understand&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Health checks&lt;/li&gt;
&lt;li&gt;Stickiness&lt;/li&gt;
&lt;li&gt;CLB vs. NLB vs. ALB&lt;/li&gt;
&lt;li&gt;Cross AZ load balancing&lt;/li&gt;
&lt;li&gt;Connection draining&lt;/li&gt;
&lt;li&gt;SSL Certificates&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="8-amazon-cloudfront"&gt;Amazon CloudFront&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P9xE0v3---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-CloudFront_light-bg%404x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P9xE0v3---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-CloudFront_light-bg%404x.png" alt="" class="wp-image-1241" width="225" height="225"&gt;&lt;/a&gt;&lt;strong&gt;Amazon CloudFront&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html"&gt;What is CloudFront?&lt;/a&gt; | &lt;a href="https://aws.amazon.com/cloudfront/faqs/"&gt;FAQ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CloudFront is Amazon's CDN offering. CloudFront serves static files like HTML, CSS, JS, and images through a worldwide network of edge locations. Using CloudFront edge locations serves your website's static assets from locations that are physically closer to the user. CloudFront adds speed and reliability while reducing costs and taking some work off more expensive compute resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key topics to understand&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edge locations&lt;/li&gt;
&lt;li&gt;Origins&lt;/li&gt;
&lt;li&gt;Signed URLs&lt;/li&gt;
&lt;li&gt;CORS&lt;/li&gt;
&lt;li&gt;Origin Access Identities &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="9-amazon-vpc-virtual-private-cloud"&gt;Amazon VPC  - (Virtual Private Cloud)&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jo52n0EQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-VPC%404x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jo52n0EQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-VPC%404x.png" alt="" class="wp-image-1242" width="225" height="225"&gt;&lt;/a&gt;&lt;strong&gt;Amazon&lt;/strong&gt; &lt;strong&gt;VPC&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html"&gt;What is Amazon VPC?&lt;/a&gt; | &lt;a href="https://aws.amazon.com/vpc/faqs/"&gt;FAQ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VPCs are a tricky topic. With a VPC, you can define the network that your resources use to communicate. Strictly, a VPC is not a service, but it's something that you need to understand because it forms the backbone of networking in AWS. VPCs form the backbone of AWS solutions and can even link-up on-premises and cloud resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key topics to understand&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public vs. private IPs&lt;/li&gt;
&lt;li&gt;Subnets&lt;/li&gt;
&lt;li&gt;Route tables&lt;/li&gt;
&lt;li&gt;Access control lists and security groups&lt;/li&gt;
&lt;li&gt;Internet &amp;amp; NAT gateways&lt;/li&gt;
&lt;li&gt;VPC Peering&lt;/li&gt;
&lt;li&gt;VPC Endpoints&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="10-aws-lambda"&gt;AWS Lambda&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6Y1vCtDU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/AWS-Lambda%404x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6Y1vCtDU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/AWS-Lambda%404x.png" alt="" class="wp-image-1243" width="225" height="225"&gt;&lt;/a&gt;&lt;strong&gt;AWS Lambda&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/welcome.html"&gt;What is AWS Lambda?&lt;/a&gt; | &lt;a href="https://aws.amazon.com/lambda/faqs/"&gt;FAQ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS Lambda is one of my favorite AWS services. Lambda functions are small functions that only run while they are being executed. Lambda functions are serverless and scale easily, which means you only pay for what you use and can handle heavy traffic out of the box. If no one is using your website or application, you don't pay.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key topics to understand&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supported runtimes&lt;/li&gt;
&lt;li&gt;Function execution limits&lt;/li&gt;
&lt;li&gt;Triggers and integrations&lt;/li&gt;
&lt;li&gt;Lambda@Edge&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="11-amazon-api-gateway"&gt;Amazon API Gateway&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xkPPScmq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-API-Gateway%404x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xkPPScmq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/07/Amazon-API-Gateway%404x.png" alt="" class="wp-image-1244" width="225" height="225"&gt;&lt;/a&gt;&lt;strong&gt;API Gateway&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html"&gt;What is API Gateway?&lt;/a&gt; | &lt;a href="https://aws.amazon.com/api-gateway/faqs/"&gt;FAQ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Amazon designed API Gateway for building APIs at scale. API Gateway enables you to build APIs that directly return responses or act as a proxy for other AWS services. API Gateway includes features for managing API caching, API keys and usage plans, request / response transformation and much more. Serverless applications commonly rely on an API gateway proxying requests to an array of Lambda functions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key topics to understand&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;REST vs. HTTP APIs&lt;/li&gt;
&lt;li&gt;Resources and methods&lt;/li&gt;
&lt;li&gt;Triggers and integrations&lt;/li&gt;
&lt;li&gt;Stages, versioning, and deployments&lt;/li&gt;
&lt;li&gt;API keys and usage plans&lt;/li&gt;
&lt;li&gt;Lambda custom authentication &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="12-bonus-aws-cli-and-sdk"&gt;Bonus: AWS CLI and SDK&lt;/h2&gt;

&lt;p&gt;Usually, people start learning AWS using the console, but you'll quickly realize you also need a method of interacting with the services through code and the command line. Many amateurs who learn AWS on their own work solely with the web interface, but most professionals primarily use the CLI. I encourage you to research the AWS CLI and the AWS SDK that corresponds to the language you're most comfortable with. &lt;/p&gt;

&lt;h3 id="13-aws-cli"&gt;AWS CLI&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html"&gt;What is the AWS CLI?&lt;/a&gt; | &lt;a href="http://docs.aws.amazon.com/cli/latest/reference/"&gt;CLI Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The AWS CLI (Command Line Interface) is exactly what it sounds like. Instead of clicking buttons on a GUI in a web browser,  you can install the AWS CLI and manage all your AWS resources from a terminal. Many professionals prefer the AWS CLI because it is more powerful, and personally, I agree with them.&lt;/p&gt;

&lt;h3 id="14-aws-sdk"&gt;AWS SDK&lt;/h3&gt;

&lt;p&gt;The AWS SDKs (Software Development Kits) are Amazon's solution for interacting with AWS resources inside of code. If you want to store images in S3 with a Python script, you'll need the Python SDK. Similarly, if you want to store records in an RDS database with PHP, you'd need the PHP SDK. I suggest getting familiar with at least one of these, you'll probably be needing it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;C++&lt;/li&gt;
&lt;li&gt;Go&lt;/li&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;.NET&lt;/li&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;PHP&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Ruby&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="15-where-to-go-next"&gt;Where to go next&lt;/h2&gt;

&lt;p&gt;After you've learned the first 10 services, where do you go next? You should decide what you want to build and focus on the services that will enable you to do that. Learning an AWS specialty on your own can take your career to an even higher level. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Serverless&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lambda&lt;/li&gt;
&lt;li&gt;Step Functions&lt;/li&gt;
&lt;li&gt;SQS&lt;/li&gt;
&lt;li&gt;SNS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;DevOps&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CloudPipeline&lt;/li&gt;
&lt;li&gt;CloudFormation&lt;/li&gt;
&lt;li&gt;ECS&lt;/li&gt;
&lt;li&gt;EKS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Monitoring and administration&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CloudWatch&lt;/li&gt;
&lt;li&gt;CloudTrail&lt;/li&gt;
&lt;li&gt;Systems Manager&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Data workloads&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Athena&lt;/li&gt;
&lt;li&gt;EMR&lt;/li&gt;
&lt;li&gt;Kinesis&lt;/li&gt;
&lt;li&gt;Elastic search&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Machine learning&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sagemaker&lt;/li&gt;
&lt;li&gt;Lex &lt;/li&gt;
&lt;li&gt;Polly&lt;/li&gt;
&lt;li&gt;Textract&lt;/li&gt;
&lt;li&gt;Transcribe&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hopefully, this article helped you decide where to start learning AWS. Learning AWS on your own can be a very challenging task, but I promise it's well worth it!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>beginners</category>
      <category>devops</category>
    </item>
    <item>
      <title>How to build an API with AWS Lambda and the Serverless Application Model (SAM)</title>
      <dc:creator>Sean Ziegler</dc:creator>
      <pubDate>Sun, 05 Jul 2020 11:16:39 +0000</pubDate>
      <link>https://dev.to/sean_ziegler/how-to-build-an-api-with-aws-lambda-and-the-serverless-application-model-sam-hji</link>
      <guid>https://dev.to/sean_ziegler/how-to-build-an-api-with-aws-lambda-and-the-serverless-application-model-sam-hji</guid>
      <description>&lt;p&gt;Designing an API on AWS is hard. Designing a reliable API on AWS is even harder. The &lt;a href="https://aws.amazon.com/serverless/sam/"&gt;AWS Serverless Application Model (SAM)&lt;/a&gt; is an open source framework that makes deploying serverless resources much easier. SAM extends CloudFormation, so you can use all the usual CloudFormation resources inside of a SAM template. SAM can deploy serverless functions, databases, and APIs. &lt;br&gt;&lt;/p&gt;

&lt;p&gt;In this post I’ll be covering the basics of using the AWS SAM template language, the AWS SAM CLI, and some advanced features like usage plans and API keys.&lt;/p&gt;

&lt;h2 id="0-the-sam-template-language-and-the-sam-cll"&gt;The SAM template language and the SAM CLI&lt;/h2&gt;

&lt;p&gt;SAM is composed of two parts, the &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy.html"&gt;SAM template language&lt;/a&gt; and the &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-command-reference.html"&gt;SAM CLI.&lt;/a&gt; The SAM template language provides a method of describing serverless resources in JSON or YAML blocks. The SAM template language provides seven resource types.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS::Serverless::Api&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AWS::Serverless::Application&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AWS::Serverless::Function&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AWS::Serverless::HttpApi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AWS::Serverless::LayerVersion&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AWS::Serverless::SimpleTable&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AWS::Serverless::StateMachine&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, I can define a Lambda function using an &lt;code&gt;AWS::Serverless::Function&lt;/code&gt; block. Here I’ve created a Lambda function using &lt;code&gt;python3.6&lt;/code&gt; and SAM will store the code in an S3 bucket. &lt;/p&gt;

&lt;pre class="wp-block-code lang-yaml"&gt;&lt;code&gt;Type: AWS::Serverless::Function
Properties:
  Handler: index.handler
  Runtime: python3.6
  CodeUri: s3://bucket/key&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The SAM CLI provides a command-line interface for building, testing, and deploying the serverless resources described by your SAM templates. The SAM CLI has eight commands.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sam build&lt;/code&gt; - Processes your template file, prepares code and dependencies for deployment&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam deploy&lt;/code&gt; - Deploys resources described in SAM template&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam init&lt;/code&gt; - Initializes a new SAM project&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam local&lt;/code&gt; - Creates local version of serverless resources for easier testing and debugging&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam logs&lt;/code&gt; - Show your resources's logs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam package&lt;/code&gt; - Creates a zip and uploads an artifact to S3&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam validate&lt;/code&gt; - Validates template file is valid CloudFormation syntax&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam publish&lt;/code&gt; - Publishes an application to the Serverless Application Repository&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="1-start-a-sam-project-with-the-sam-cli"&gt;Start a SAM project with the SAM CLI&lt;/h2&gt;

&lt;p&gt;Let's get started building a simple API that takes two URL parameters, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, and returns their &lt;code&gt;product&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;AWS SAM has a CLI that makes creating a new project simple. &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html"&gt;Install the AWS SAM CLI&lt;/a&gt; and then use &lt;code&gt;sam init&lt;/code&gt; to start a new project. I like to use the quick start templates to get a project going quickly, but you can also select &lt;code&gt;2&lt;/code&gt; for a Custom Template Location and give it a filepath or URL.&lt;/p&gt;

&lt;pre class="wp-block-code language-bash"&gt;&lt;code&gt;sam init

Which template source would you like to use?
    1 - AWS Quick Start Templates
    2 - Custom Template Location

Choice: 1&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Choose a language for your project's runtime. I'll be using &lt;code&gt;python3.6&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="wp-block-code language-bash"&gt;&lt;code&gt;Which runtime would you like to use?
    1 - nodejs12.x
    2 - python3.8
    3 - ruby2.7
    4 - go1.x
    5 - java11
    6 - dotnetcore3.1
    7 - nodejs10.x
    8 - python3.7
    9 - python3.6
    10 - python2.7
    11 - ruby2.5
    12 - java8
    13 - dotnetcore2.1
    14 - dotnetcore2.0
    15 - dotnetcore1.0
Runtime: 9&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Name the project and select the Hello World template. This will generate a sample project with a Lambda function and a template for an API Gateway resource. &lt;/p&gt;

&lt;pre class="wp-block-code language-bash"&gt;&lt;code&gt;Project name [sam-app]: SAMdemo

Cloning app templates from https://github.com/awslabs/aws-sam-cli-app-templates.git

AWS quick start application templates:
    1 - Hello World Example
    2 - EventBridge Hello World
    3 - EventBridge App from scratch (100+ Event Schemas)
    4 - Step Functions Sample App (Stock Trader)
    5 - Elastic File System Sample App
Template selection: 1

-----------------------
Generating application:
-----------------------
Name: SAMdemo
Runtime: python3.6
Dependency Manager: pip
Application Template: hello-world
Output Directory: .

Next steps can be found in the README file at ./SAMdemo/README.md&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;SAM generates a bunch of boilerplate code and a few folders for you. There are four main parts to know. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;template.yaml&lt;/code&gt; - Defines your SAM resources&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hello_world/&lt;/code&gt; - Directory for Lambda function code &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/&lt;/code&gt; - Directory for unit tests for your function, run using Pytest&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;events/&lt;/code&gt; - Mocked events for testing functions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="2-create-a-lambda-function"&gt;Create a Lambda function&lt;/h2&gt;

&lt;p&gt;We need to create a function that can take in two URL parameters and return a product. I will reuse the &lt;code&gt;hello_world&lt;/code&gt; function the SAM CLI generated by renaming the &lt;code&gt;hello_world&lt;/code&gt; folder &lt;code&gt;multiply&lt;/code&gt; and editing the &lt;code&gt;app.py&lt;/code&gt; file inside it.&lt;/p&gt;

&lt;pre class="wp-block-code language-bash"&gt;&lt;code&gt;mv hello_world/ multiply/
vim multiply/app.py&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;app.py&lt;/code&gt; file defines the Lambda function. This function will take in two integers, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, as URL parameters and return their product. We can access the URL parameters through the &lt;code&gt;event&lt;/code&gt; variable. &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-services.html"&gt;The &lt;code&gt;event&lt;/code&gt; variable&lt;/a&gt; contains data about the API Gateway event that triggered this Lambda function.  &lt;/p&gt;

&lt;pre class="wp-block-code language-python"&gt;&lt;code&gt;import json

def lambda_handler(event, context):
    '''&amp;lt;snip&amp;gt;'''

    a = event["queryStringParameters"]['a']
    b = event["queryStringParameters"]['b']

    product = int(a) * int(b)

    return {
        "statusCode": 200,
        "body": json.dumps({
            "product": product,
        }),
    }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Lambda functions must return a JSON response, so I've chosen to just dump the &lt;code&gt;product&lt;/code&gt; result into the &lt;code&gt;body&lt;/code&gt; of the response.&lt;/p&gt;

&lt;h2 id="3-define-an-api-gateway-using-a-sam-template"&gt;Define an API Gateway using a SAM template&lt;/h2&gt;

&lt;p&gt;SAM also generated a file called &lt;code&gt;template.yaml&lt;/code&gt;. I will tell SAM that I want to deploy a Lambda function by including an &lt;code&gt;AWS::Serverless:Function&lt;/code&gt; block inside the SAM template.&lt;/p&gt;

&lt;pre class="wp-block-code language-yaml"&gt;&lt;code&gt;AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Function and API for multiplying two numbers

Resources:
  MultiplyFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: multiply/
      Handler: app.lambda_handler
      Runtime: python3.6
      Events:
         Multiply:
           Type: Api
           Properties:
             Path: /multiply
             Method: POST
             RestApiId:
               Ref: MultiplyApi
Outputs:
  MultiplyApi:
    Description: "API Gateway endpoint URL for Prod stage for Multiply function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/multiply/"
  MultiplyFunction:
    Description: "Multiply Lambda Function ARN"
    Value: !GetAtt MultiplyFunction.Arn
  MultiplyFunctionIamRole:
    Description: "Implicit IAM Role created for Multiply function"
    Value: !GetAtt MultiplyFunctionRole.Arn&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This template will deploy a Lambda function backed by the code in the &lt;code&gt;multiply&lt;/code&gt; folder. After the deployment, the &lt;code&gt;Outputs&lt;/code&gt; section will return an API Gateway Endpoint, a Lambda function ARN, and an IAM role for the function.&lt;/p&gt;

&lt;h2 id="4-deploy-the-sam-template-with-the-sam-cli"&gt;Deploy the SAM template with the SAM CLI&lt;/h2&gt;

&lt;p&gt;It is time to deploy the SAM template. &lt;code&gt;sam deploy --guided&lt;/code&gt; starts an interactive session which guides you through the deployment process. &lt;/p&gt;

&lt;pre class="wp-block-code language-bash"&gt;&lt;code&gt;~/SAMdemo ❯ sam deploy --guided                                                         

Configuring SAM deploy
======================

    Looking for samconfig.toml :  Not found

    Setting default arguments for 'sam deploy'
    =========================================
    Stack Name [sam-app]: SAMDemo
    AWS Region [us-east-1]: 
    #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
    Confirm changes before deploy [y/N]: N
    #SAM needs permission to be able to create roles to connect to the resources in your template
    Allow SAM CLI IAM role creation [Y/n]: Y
    MultiplyFunction may not have authorization defined, Is this okay? [y/N]: Y
    Save arguments to samconfig.toml [Y/n]: Y
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After you finish the guided process, SAM will generate a change set (Just like CloudFormation) and deploy your resources. You will see the &lt;code&gt;outputs&lt;/code&gt; from &lt;code&gt;template.yaml&lt;/code&gt; printed onto the screen. &lt;/p&gt;

&lt;pre class="wp-block-code language-bash"&gt;&lt;code&gt;CloudFormation outputs from deployed stack
-------------------------------------------------------------------------------------------------
Outputs
-------------------------------------------------------------------------------------------------
Key                 MultiplyFunctionIamRole
Description         Implicit IAM Role created for Multiply function
Value               arn:aws:iam::&amp;lt;snip&amp;gt;

Key                 MultiplyFunction
Description         Multiply Lambda Function ARN
Value               arn:aws:lambda:us-east-1:&amp;lt;snip&amp;gt;
Key                 MultiplyApi
Description         API Gateway endpoint URL for Prod stage for Multiply function
Value               https://&amp;lt;snip&amp;gt;.execute-api.us-east-1.amazonaws.com/Prod/multiply/
-------------------------------------------------------------------------------------------------

Successfully created/updated stack - SAMDemo in us-east-1&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="5-testing-the-api-with-generated-events"&gt;Testing the API with generated events&lt;/h2&gt;

&lt;p&gt;SAM provides a method for testing your API locally prior to deployment. First, let's generate a mock API Gateway event. The command &lt;code&gt;sam local generate-event apigateway aws-proxy &amp;gt; events/multiply.json&lt;/code&gt; will generate a fake API event and save it to a JSON file. Change the &lt;code&gt;queryStringParameters&lt;/code&gt; in &lt;code&gt;multiply.json&lt;/code&gt; to some integers for &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;. &lt;/p&gt;

&lt;pre class="wp-block-code language-json"&gt;&lt;code&gt;"queryStringParameters": {
    "foo": "bar"
  },&lt;/code&gt;&lt;/pre&gt;

&lt;pre class="wp-block-code language-json"&gt;&lt;code&gt;  "queryStringParameters": {
    "a": "5",
    "b": "3"
  }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now lets use &lt;code&gt;sam local invoke&lt;/code&gt; to invoke the Lambda function and provide it the &lt;code&gt;multiply&lt;/code&gt; event.&lt;/p&gt;

&lt;pre class="wp-block-code language-bash"&gt;&lt;code&gt;sam local invoke -e multiply.json

Invoking app.lambda_handler (python3.8)

Fetching lambci/lambda:python3.8 Docker container image......
Mounting /Users/seanziegler/Coding/SAMdemo/multiply as /var/task:ro,delegated inside runtime container
START RequestId: a17fdb0c-15bc-1cb0-c8a5-836299856b0c Version: $LATEST
END RequestId: a17fdb0c-15bc-1cb0-c8a5-836299856b0c
REPORT RequestId: a17fdb0c-15bc-1cb0-c8a5-836299856b0c  Init Duration: 93.96 ms Duration: 2.85 ms   Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 25 MB

{"statusCode":200,"body":"{\"product\": 15}"}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The function returned &lt;code&gt;product: 15&lt;/code&gt; which is what we expected. You can use &lt;code&gt;sam local generate event&lt;/code&gt; to generate mock events for many services including S3, APIGateway, DynamoDB, SQS, and more. Generating events and testing locally is a great pattern for ensuring your serverless functions are reliable.&lt;/p&gt;

&lt;h2 id="6-configuring-an-api-key-and-usage-plan-"&gt;Configuring an API Key and usage plan &lt;/h2&gt;

&lt;p&gt;Adding API keys and a usage plan to an API is a straightforward process. It's possible to set up both using the &lt;code&gt;Auth&lt;/code&gt; object on &lt;code&gt;AWS::Serverless::Api&lt;/code&gt;. &lt;br&gt;&lt;/p&gt;

&lt;p&gt;On the Multiply route I will require an API key, limit requests to 500 per day, and limit requests to 5 requests per second. &lt;/p&gt;

&lt;pre class="wp-block-code language-yaml"&gt;&lt;code&gt;MultiplyApi:
     Type: AWS::Serverless::Api
     Properties:
       StageName: Prod
       Auth:
         ApiKeyRequired: true
         UsagePlan:
           CreateUsagePlan: PER_API
           Quota:
             Limit: 500
             Period: DAY
           Throttle:
             RateLimit: 5&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let's make a request and see what happens. &lt;/p&gt;

&lt;pre class="wp-block-code lang-bash"&gt;&lt;code&gt;curl -X POST https://&amp;lt;snip&amp;gt;.execute-api.us-east-1.amazonaws.com/Prod/multiply?a=3&amp;amp;b=1

{"message": "Missing Authentication Token"}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Okay, that didn't work because I didn't supply an API key. &lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let's try it again with an API key I generated for myself earlier.&lt;/p&gt;

&lt;pre class="wp-block-code lang-bash"&gt;&lt;code&gt;curl -X POST -H "x-api-key:&amp;lt;API KEY&amp;gt;" https://&amp;lt;snip&amp;gt;.execute-api.us-east-1.amazonaws.com/Prod/multiply?a=5&amp;amp;b=3

{"product": 15}&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="7-conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;That's all it takes to build a small API using SAM. You can extend this API by adding more routes and functions as resource declarations in the &lt;code&gt;template.yaml&lt;/code&gt; file. The &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy.html"&gt;SAM template language reference&lt;/a&gt; and the &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-command-reference.html"&gt;SAM CLI reference&lt;/a&gt; are your friends.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>aws</category>
      <category>tutorial</category>
      <category>howto</category>
    </item>
    <item>
      <title>A complete guide to using the AWS Systems Manager Parameter Store in your cloud applications</title>
      <dc:creator>Sean Ziegler</dc:creator>
      <pubDate>Sun, 24 May 2020 13:06:56 +0000</pubDate>
      <link>https://dev.to/sean_ziegler/a-complete-guide-to-using-the-aws-systems-manager-parameter-store-44ed</link>
      <guid>https://dev.to/sean_ziegler/a-complete-guide-to-using-the-aws-systems-manager-parameter-store-44ed</guid>
      <description>&lt;p&gt;Environment variables are used by nearly every developer. They are great for setting parameters that change based on the environment of the system. Unfortunately, they don't scale well. Sure, I agree, there are ways to do it, but it isn't a fun process. AWS offers a product I think can take the place of environment variables (or at least reduce your reliance on them). The AWS Systems Manager Parameter Store is a perfect solution for building modern cloud applications.&lt;/p&gt;

&lt;h2 id="0-what-is-aws-systems-manager-parameter-store"&gt;What is AWS Systems Manager Parameter Store?&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/systems-manager/features/"&gt;AWS Systems Manager &lt;/a&gt;is a product designed to help you manage large groups of servers deployed into the cloud. For instance, it provides a remote connection to systems, security and patch updates, remote command execution, and other administration tasks at scale.&lt;/p&gt;

&lt;p&gt;It also provides a feature called the Parameter Store. The parameter store is a superb place to store centralized data like API keys, database strings, passwords, and other configuration data. &lt;/p&gt;

&lt;h2 id="1-why-use-the-aws-systems-manager-parameter-store"&gt;Why use the AWS Systems Manager Parameter Store?&lt;/h2&gt;

&lt;p&gt;The Parameter Store is a great way to make your application less stateful and improve your ability to deploy across several environments. The parameter store has a few advantages over other methods of managing variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to update from a central interface&lt;/li&gt;
&lt;li&gt;Hierarchy structure&lt;/li&gt;
&lt;li&gt;Supports encryption to store secrets like passwords&lt;/li&gt;
&lt;li&gt;Supports versioning and roll back of parameters&lt;/li&gt;
&lt;li&gt;Allows access control, both for IAM users and roles&lt;/li&gt;
&lt;li&gt;Ability to audit parameter access using CloudTrail&lt;/li&gt;
&lt;li&gt;Supports throughput of 1,000 transactions per second (must be increased in your settings)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I choose parameters over environment variables because I can update the parameter in one location and the changes are instantly available to any code using the parameter. &lt;/p&gt;

&lt;h2 id="2-hierarchy-structure"&gt;Hierarchy Structure&lt;/h2&gt;

&lt;p&gt;Perhaps the most interesting thing about the Parameter Store is the hierarchy structure. Hierarchies are parameters that start with a slash. They are a great way to organize parameters in a manageable fashion. I often create parameters for dev, test, and prod.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;/dev/API_KEY
/dev/DB_STRING
/test/API_KEY
/test/DB_STRING
/prod/API_KEY
/prod/DB_STRING
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is a painless way to separate and manage parameters even when you have thousands of them. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uySb1L8F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/05/ParameterStoreGraphic.jpg%3Ffit%3D1024%252C358%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uySb1L8F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/05/ParameterStoreGraphic.jpg%3Ffit%3D1024%252C358%26ssl%3D1" alt="" class="wp-image-874"&gt;&lt;/a&gt;Even with multiple environments, each part of your application can request the data it needs using the hierarchy structure.&lt;/p&gt;

&lt;h2 id="3-parameter-types"&gt;Parameter Types&lt;/h2&gt;

&lt;p&gt;A parameter is a piece of data stored within AWS Systems Manager Parameter Store. AWS provides no validation on any parameters (with one exception covered later).&lt;/p&gt;

&lt;p&gt;There are three types of Parameter Store parameters (and a fourth kinda-weird bonus type).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;String&lt;/li&gt;
&lt;li&gt;StringList&lt;/li&gt;
&lt;li&gt;SecureString&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="4--string-"&gt;&lt;strong&gt;String&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Strings are exactly what you expect. Strings are any block of text such as &lt;code&gt;Hello World&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, or &lt;code&gt;wow this is a great blog post&lt;/code&gt;. &lt;/p&gt;

&lt;h3 id="5--stringlist-"&gt;&lt;strong&gt;StringList&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;StringList is, again, rather intuitive. A StringList is a collection of strings separated by a comma. For example, &lt;code&gt;Cat,Dog,Rabbit&lt;/code&gt; and &lt;code&gt;Mercury,Mars,Melons&lt;/code&gt; are two examples of string lists.&lt;/p&gt;

&lt;h3 id="6--securestring-"&gt;&lt;strong&gt;SecureString&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;SecureString is used for sensitive data like passwords and API Keys. Data stored in a SecureString parameter are encrypted using keys managed by the AWS Key Management Service. You should know that these parameters are free to use, but AWS will charge you for the Key Management Service as usual. &lt;/p&gt;

&lt;h3 id="7-subtype---ami-datatype"&gt;Subtype - AMI Datatype&lt;/h3&gt;

&lt;p&gt;There is one strange "bonus" type you should know. When using a string attribute, you can use an additional parameter &lt;code&gt;--data-type&lt;/code&gt; and then specify an Amazon machine image resource number.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm put-parameter &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\a&lt;/span&gt;&lt;span class="s2"&gt;mis&lt;/span&gt;&lt;span class="se"&gt;\l&lt;/span&gt;&lt;span class="s2"&gt;inux&lt;/span&gt;&lt;span class="se"&gt;\g&lt;/span&gt;&lt;span class="s2"&gt;olden-ami"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--type&lt;/span&gt; &lt;span class="s2"&gt;"String"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--data-type&lt;/span&gt; &lt;span class="s2"&gt;"aws:ec2:image"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"ami-12345abcdeEXAMPLE"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The parameter store will validate that the AMI image is valid, then you'll be able to use the AMI in other services by referencing the parameter.&lt;/p&gt;

&lt;h2 id="8-parameter-tiers"&gt;Parameter Tiers&lt;/h2&gt;

&lt;p&gt;There are two types of parameters: standard parameters and advanced parameters. Advanced parameters support parameter policies which can set parameter expiration, notify you if parameters expire, and let you know if a parameter hasn't changed in a while.&lt;/p&gt;

&lt;p&gt;You can upgrade parameters to advanced parameters, but you can never downgrade to a standard parameter. There's really no reason to use an advanced parameter unless you run up against one of the limits below or you need the advanced policies they offer for notifications.&lt;/p&gt;

&lt;h3 id="9--standard-parameters-"&gt;&lt;strong&gt;Standard Parameters&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Free&lt;/li&gt;
&lt;li&gt;Max of 10,000 parameters (per region)&lt;/li&gt;
&lt;li&gt;4KB max size&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="10--advanced-parameters-"&gt;&lt;strong&gt;Advanced Parameters&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Paid&lt;/li&gt;
&lt;li&gt;Max of 100,000 parameters (per region)&lt;/li&gt;
&lt;li&gt;8KB max size&lt;/li&gt;
&lt;li&gt;Supports parameter policies&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="11-intelligent-tiering"&gt;Intelligent Tiering&lt;/h3&gt;

&lt;p&gt;This option is a blend of the two standard options. When you select intelligent tiering, the parameter store will inspect each parameter to see if requires advanced features. If it does, the store automatically upgrades the parameter to the advanced tier. &lt;/p&gt;

&lt;p&gt;Intelligent tiering helps control cost and prevent failures because you hit the limit on standard parameters or tried to store a key larger than 4KB. If you don't mind spending the money on advanced parameters, it's worth considering.&lt;/p&gt;

&lt;h2 id="12-managing-parameters-using-the-aws-cli"&gt;Managing Parameters using the AWS CLI&lt;/h2&gt;

&lt;p&gt;You'll need to install and configure the &lt;a href="https://aws.amazon.com/cli/"&gt;AWS CLI&lt;/a&gt; if you haven't already.&lt;/p&gt;

&lt;p&gt;Creating parameters is very easy. There's a built in command to create parameters.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm put-parameter &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/test/email/liscence"&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt; &lt;span class="s2"&gt;"String"&lt;/span&gt; &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"XM56HE1I9M2AC9W30UM1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To create a SecureString, add a &lt;code&gt;--Key-Id&lt;/code&gt; and specify a KMS Key ARN. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm put-parameter &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/test/email/password"&lt;/span&gt; &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"4G00DPA&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;W0RD"&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt; &lt;span class="s2"&gt;"SecureString"&lt;/span&gt; &lt;span class="nt"&gt;--key-id&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:kms:us-east-2:123456789012:key/1a2b3c4d-1a2b-1a2b-1a2b-1a2b3c4d5e"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Getting parameters is even more fun. To get a parameter by name, use &lt;code&gt;get-parameters&lt;/code&gt;.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm get-parameters &lt;span class="nt"&gt;--names&lt;/span&gt; &lt;span class="s2"&gt;"/dev/API_KEY"&lt;/span&gt; &lt;span class="s2"&gt;"/test/API_KEY"&lt;/span&gt; &lt;span class="s2"&gt;"/prod/API_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;SecureString parameters require a &lt;code&gt;--with-decryption&lt;/code&gt; flag. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm get-parameters &lt;span class="nt"&gt;--names&lt;/span&gt; &lt;span class="s2"&gt;"/prod/API_KEY"&lt;/span&gt; &lt;span class="nt"&gt;--with-decryption&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can get all the parameters in hierarchy&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm get-parameters-by-path &lt;span class="nt"&gt;--path&lt;/span&gt; &lt;span class="s2"&gt;"/dev"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and use &lt;code&gt;describe-parameters&lt;/code&gt; to query parameters by type. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm describe-parameters &lt;span class="nt"&gt;--filters&lt;/span&gt; &lt;span class="s2"&gt;"Key=Type,Values=StringList"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2 id="13-parameter-versioning"&gt;Parameter Versioning&lt;/h2&gt;

&lt;p&gt;Versioning is another great feature of the parameter store.  If you overwrite a parameter that already exists, the parameter's version will increment. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm put-parameter &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/test/email/liscence"&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt; &lt;span class="s2"&gt;"String"&lt;/span&gt; &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"XM56HE1I9M2AC9W30UM1"&lt;/span&gt;

aws ssm put-parameter &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/test/email/liscence"&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt; &lt;span class="s2"&gt;"String"&lt;/span&gt; &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"XM56HE1I000000000000"&lt;/span&gt; &lt;span class="nt"&gt;--overwrite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Lets inspect the parameter's history. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;aws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ssm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;get-parameter-history&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;--name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/test/email/liscence"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;91&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/test/email/liscence"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"String"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"LastModifiedDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2020-05-22T16:25:04.303000-04:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"LastModifiedUser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::&amp;amp;lt;redacted&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"XM56HE1I9M2AC9W30UM1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Labels"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;91&lt;/span&gt;&lt;span class="err"&gt;;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Tier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Standard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Policies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;91&lt;/span&gt;&lt;span class="err"&gt;;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/test/email/liscence"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"String"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"LastModifiedDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2020-05-22T16:25:38.281000-04:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"LastModifiedUser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::&amp;amp;lt;redacted&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"XM56HE1I000000000000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Labels"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;91&lt;/span&gt;&lt;span class="err"&gt;;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Tier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Standard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Policies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;91&lt;/span&gt;&lt;span class="err"&gt;;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2 id="14-parameter-policies"&gt;Parameter Policies&lt;/h2&gt;

&lt;p&gt;Parameter polices allow you to set expirations for parameters, get notified when a parameter expires, and also get notified if a parameter hasn't changed in a while. Don't ask me why policies are only good for these three things, but that's how it works. Maybe AWS will add more options. &lt;/p&gt;

&lt;p&gt;You can set an expiration time with policies.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Expiration"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Attributes"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2018-12-02T21:34:33.000Z"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can set up notifications if a parameter is expiring.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"ExpirationNotification"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Attributes"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Before"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"15"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Days"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And finally, you can set up notifications if a parameter has &lt;em&gt;not &lt;/em&gt;changed in a set time period.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"NoChangeNotification"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"Attributes"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"After"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"20"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Days"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Assigning a parameter policy with the AWS CLI is relatively straightforward.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm put-parameter   
    &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/dev/apikey"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"XM56HE1I9M2AC9W30UM1"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--type&lt;/span&gt; &lt;span class="s2"&gt;"String"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--overwrite&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;   
    &lt;span class="nt"&gt;--policies&lt;/span&gt; &lt;span class="s2"&gt;"&amp;amp;#91;{policies-enclosed-in-brackets-and-curly-braces}]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2 id="15-setting-up-service-roles-for-ec2"&gt;Setting up service roles for EC2&lt;/h2&gt;

&lt;p&gt;If you want to use the Parameter Store with other services (you probably do), you'll need to grant that service access via a service role.&lt;/p&gt;

&lt;p&gt;I've included a role here which will give you access to the Parameter Store for whatever service assumes the role (Just don't forget to attach this to your service role). &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;91&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AllowSSMAccess"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;91&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ssm:PutParameter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ssm:DeleteParameter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ssm:GetParameterHistory"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ssm:GetParametersByPath"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ssm:GetParameters"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ssm:GetParameter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ssm:DescribeParameters"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ssm:DeleteParameters"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:ssm:*:*:parameter/*"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you require more strict access control, you can limit access to read-only or only allow access to certain parameters.&lt;/p&gt;

&lt;h2 id="16-using-boto3-to-interact-with-the-parameter-store"&gt;Using Boto3 to interact with the Parameter Store&lt;/h2&gt;

&lt;p&gt;Obviously, no service would be complete with a way to interact with it from code and the Parameter Store is no exception. The &lt;a href="https://aws.amazon.com/tools/"&gt;AWS SDK&lt;/a&gt;, in my case &lt;a href="https://boto3.amazonaws.com/v1/documentation/api/latest/index.html"&gt;Boto3&lt;/a&gt; since I use python, offers a straightforward way to interface with the Parameter Store.&lt;/p&gt;

&lt;p&gt;For example, in the code below I access three different prefixes based on a single environment variable set on the host (you can do this with &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html"&gt;EC2 user data&lt;/a&gt; or a Dockerfile) and then my application knows which set of parameters to retrieve. I use it to a variety of things including API keys, log file locations, ports, debug status, and more. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;## PIP
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;

&lt;span class="n"&gt;ssm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'ssm'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'us-east-1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'env'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Select SSM parameters based on the 'env' environment variable
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'DEV'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'/&amp;amp;lt;project&amp;gt;-dev/'&lt;/span&gt;

&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'TEST'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'/&amp;amp;lt;project&amp;gt;-test/'&lt;/span&gt;

&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'PROD'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'/&amp;amp;lt;project&amp;gt;-prod/'&lt;/span&gt;

&lt;span class="c1"&gt;# If env is not set, raise error to stop server from starting
&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;AttributeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'No value set for environment type (env)'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;secrets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'ENV'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'DEBUG'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'DEBUG'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#91;'Parameter']&amp;amp;#91;'Value'],
&lt;/span&gt;    &lt;span class="s"&gt;'PORT'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'PORT'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#91;'Parameter']&amp;amp;#91;'Value'],
&lt;/span&gt;    &lt;span class="s"&gt;'FLASK_SECRET_KEY'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'FLASK_SECRET_KEY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WithDecryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#91;'Parameter']&amp;amp;#91;'Value'],
&lt;/span&gt;
    &lt;span class="s"&gt;'COGNITO_ID'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'COGNITO_ID'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WithDecryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#91;'Parameter']&amp;amp;#91;'Value'],
&lt;/span&gt;    &lt;span class="s"&gt;'CLIENT_ID'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'CLIENT_ID'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WithDecryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#91;'Parameter']&amp;amp;#91;'Value'],
&lt;/span&gt;    &lt;span class="s"&gt;'INVOKE_API'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'INVOKE_API'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WithDecryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#91;'Parameter']&amp;amp;#91;'Value'],
&lt;/span&gt;    &lt;span class="s"&gt;'API_GATEWAY_KEY'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'API_GATEWAY_KEY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WithDecryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#91;'Parameter']&amp;amp;#91;'Value'],
&lt;/span&gt;    &lt;span class="s"&gt;'SNS_CONTACT_ARN'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'SNS_CONTACT_ARN'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#91;'Parameter']&amp;amp;#91;'Value'],
&lt;/span&gt;
    &lt;span class="s"&gt;'RAINFOREST_API_KEY'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'RAINFOREST_API_KEY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WithDecryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#91;'Parameter']&amp;amp;#91;'Value'],
&lt;/span&gt;
    &lt;span class="s"&gt;'LOG_FILE'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'LOG_FILE'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#91;'Parameter']&amp;amp;#91;'Value']
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Don't forget to add the service role for any machine that will run code that accesses the Parameter Store!&lt;/p&gt;

&lt;h2 id="17-conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;That's everything that you need to know about how to integrate the AWS Systems Manager Parameter Store. Hopefully, you learned how to use the AWS Parameter Store a little better and can incorporate it into your future work.&lt;/p&gt;

&lt;p&gt;If you enjoyed this content, follow me on Twitter to see more like this!&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/sean_ziegler?ref_src=twsrc%5Etfw" class="twitter-follow-button"&gt;Follow @Sean_Ziegler&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>python</category>
    </item>
    <item>
      <title>How to build a free static resume site with AWS S3, Cloudfront, and Route 53</title>
      <dc:creator>Sean Ziegler</dc:creator>
      <pubDate>Thu, 14 May 2020 20:59:11 +0000</pubDate>
      <link>https://dev.to/sean_ziegler/how-to-build-a-free-static-resume-site-with-aws-s3-cloudfront-and-route-53-2hpn</link>
      <guid>https://dev.to/sean_ziegler/how-to-build-a-free-static-resume-site-with-aws-s3-cloudfront-and-route-53-2hpn</guid>
      <description>&lt;p&gt;&lt;a href="https://forrestbrazeal.com/"&gt;Forrest Brazeal&lt;/a&gt;, an AWS Serverless Hero who I follow on Twitter, recently tweeted about a #CloudResumeChallenge to build a resume site using AWS. In return, Forrest would use his network to help everyone who completed the challenge land a job. An awesome deal! I already have IT experience (which disqualifies me) but I thought it would be fun to build the site anyway and write up a post about how I did it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/forrestbrazeal/status/1254822417203113986?s=20"&gt;He tweeted about it here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The challenge set some rules for the website:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resume must be written in HTML and styled with CSS&lt;/li&gt;
&lt;li&gt;Deployed as an Amazon S3 static website&lt;/li&gt;
&lt;li&gt;Should be accessible via HTTPS&lt;/li&gt;
&lt;li&gt;Have a custom domain name&lt;/li&gt;
&lt;li&gt;Include a Javascript visitor counter&lt;/li&gt;
&lt;li&gt;Visitor count stored on DynamoDB&lt;/li&gt;
&lt;li&gt;The site must communicate with DynamoDB via Lambda and API Gateway&lt;/li&gt;
&lt;li&gt;Lambda and API Gateway should be deployed with AWS SAM CLI&lt;/li&gt;
&lt;li&gt;Website automatically updates on push to GitHub&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id="0-setting-up-the-site-content"&gt;Setting up the site content&lt;/h4&gt;

&lt;p&gt;All right, let's start with the content. Since I'm not in this for the networking, I didn't think it made much sense to develop another personal site for this challenge. I did it on &lt;a href="https://en.wikipedia.org/wiki/Alan_Turing"&gt;Alan Turing&lt;/a&gt; instead. Why? Because he's cool, and none of us would be looking at this without him. &lt;/p&gt;

&lt;p&gt;Anyway, create an empty Git repo.&lt;/p&gt;

&lt;pre class="wp-block-code language-bash"&gt;&lt;code&gt;git clone git@github.com:seanziegler/AlanTuringResume.git&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I hate HTML and CSS so I stole a nice little resume template from this &lt;a href="https://css-tricks.com/one-page-resume-site/"&gt;CSS-Tricks article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Originally, it was based on Cthulu which.... was a little strange, but okay. After some Wikipedia research and a little front-end stumbling, I had a clean one-page resume site about Alan Turing developed. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NtANSvn9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/05/AlanTuringResumeSite-1024x983.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NtANSvn9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/05/AlanTuringResumeSite-1024x983.png" alt="" class="wp-image-793" width="508" height="486"&gt;&lt;/a&gt;Well, this makes my resume look weak.&lt;/p&gt;

&lt;h4 id="1-create-an-s3-static-site"&gt;Create an S3 Static Site&lt;/h4&gt;

&lt;p&gt;Okay, on to the more interesting part, the back-end. The first requirement of the site is it should be a static site hosted by AWS S3. &lt;/p&gt;

&lt;p&gt;First thing we need is an S3 bucket. You'll need to configure the AWS CLI if you haven't done so already.&lt;/p&gt;

&lt;pre class="wp-block-code language-bash"&gt;&lt;code&gt;aws s3 mb s3://turingresume&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Copy all the files for your website into the bucket. The root page of your website (often index.html) should be at the root level of the S3 bucket.&lt;/p&gt;

&lt;pre class="wp-block-code language-bash"&gt;&lt;code&gt;aws s3 cp &amp;lt;project_dir&amp;gt; s3://turingresume --recursive&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Last, tell S3 that this should be a static website, not a normal bucket.&lt;/p&gt;

&lt;pre class="wp-block-code language-bash"&gt;&lt;code&gt;aws s3 website s3://turingresume --index index.html&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Check to see if your website is available. You can access it at &lt;code&gt;http://"bucketname".s3-website-"bucketregion".amazonaws.com/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you can see your website, you've successfully deployed the static site using S3. Let's work on making it easier to reach your site since that S3 website URL isn't exactly memorable.  &lt;/p&gt;

&lt;h4 id="2-purchase-a-domain-"&gt;Purchase a domain &lt;/h4&gt;

&lt;p&gt;We're off to Route 53 where you can purchase a domain from inside the AWS console. Unfortunately, AlanTuring.com wasn't available, so I went with the much friendlier heyitsalan.com. I realized later that it looks a lot like "hey its Satan" which is unfortunate, but I already paid for the domain and I'm not made of money.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GmvefghM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Buying-Domain-Name-Route53.png%3Ffit%3D1024%252C169%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GmvefghM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Buying-Domain-Name-Route53.png%3Ffit%3D1024%252C169%26ssl%3D1" alt="" class="wp-image-802"&gt;&lt;/a&gt;All right, it's not the best domain, but it works.&lt;/p&gt;

&lt;p&gt;Ok, that's all we can do in Route53 for now. &lt;/p&gt;

&lt;h4 id="3-create-an-ssl-certificate-in-acm"&gt;Create an SSL certificate in ACM&lt;/h4&gt;

&lt;p&gt;Since we will serve the site over HTTPS, we will need an SSL certificate. Fortunately, the AWS Certificate Manager makes it simple to generate a certificate. &lt;/p&gt;

&lt;p&gt;Make sure you request a certificate for *.yourdomain.com so it covers all sub-domains (especially the www and non-www versions of your URL).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uWQOg_f3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Creating-SSL-Cert-ACM.png%3Ffit%3D1024%252C705%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uWQOg_f3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Creating-SSL-Cert-ACM.png%3Ffit%3D1024%252C705%26ssl%3D1" alt="" class="wp-image-803" width="580" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll need to add a TXT record to the DNS records of your domain to prove that you own it. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dhOrklMN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/05/Select-DNS-validation-Route53.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dhOrklMN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/05/Select-DNS-validation-Route53.png" alt="" class="wp-image-805" width="385" height="219"&gt;&lt;/a&gt;DNS Validation proves you own the domain covered by the SSL certificate.&lt;/p&gt;

&lt;p&gt;If you bought your domain on Route53 like I did, you can just click the "Add DNS Records to Route53" button. If you're on a different host, you'll have to look at their documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2K8HQIze--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/05/Create-DNS-Records-Route53-1024x819.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2K8HQIze--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/05/Create-DNS-Records-Route53-1024x819.png" alt="" class="wp-image-806" width="512" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once AWS Certificate Manager sees the DNS record and knows you own the domain, it will issue your SSL certificate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LlNXgIjl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/05/ACM-Issued-SSL-Cert.png%3Ffit%3D1024%252C147%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LlNXgIjl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/05/ACM-Issued-SSL-Cert.png%3Ffit%3D1024%252C147%26ssl%3D1" alt="" class="wp-image-807" width="512" height="74"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4 id="4-create-a-cloudfront-distribution"&gt;Create a CloudFront Distribution&lt;/h4&gt;

&lt;p&gt;We're ready to tie everything together and get this domain name tied up. All we need to do is create a HTTPS CloudFront Distribution and with our S3 website as its origin. After that, we'll point the domain name to the CloudFront distribution to finish. Start by creating a CloudFront distribution. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jbK_eCOd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Create-CloudFront-Distribution-1.png%3Ffit%3D1024%252C972%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jbK_eCOd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Create-CloudFront-Distribution-1.png%3Ffit%3D1024%252C972%26ssl%3D1" alt="" class="wp-image-812" width="512" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll also need to add your domain as an alternate CNAME in the CloudFront distribution and import the SSL certificate you generated earlier. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AaYV4EyM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/05/CloudFront-SSL-Setup-1.png%3Ffit%3D1024%252C829%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AaYV4EyM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/05/CloudFront-SSL-Setup-1.png%3Ffit%3D1024%252C829%26ssl%3D1" alt="" class="wp-image-814" width="512" height="415"&gt;&lt;/a&gt;Don't forget to add * in front of your domain so all sub-domains redirect here.&lt;/p&gt;

&lt;p&gt;Fire up Route53 and head to the DNS records for the domain you registered. We will add CNAME alias record, which points to the domain name for the CloudFront distribution created earlier. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KM8HlK0I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/05/Route53-CNAME-for-CloudFront.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KM8HlK0I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/05/Route53-CNAME-for-CloudFront.png" alt="" class="wp-image-837" width="446" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you can test your domain and see if it works (although you might need to wait a few minutes for the site to propagate through the CloudFront edge locations).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_N7JObTK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/05/SSL-on-domain.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_N7JObTK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/05/SSL-on-domain.png" alt="" class="wp-image-816" width="296" height="66"&gt;&lt;/a&gt;Another requirement down.&lt;/p&gt;

&lt;h4 id="5-deploy-a-dynamodb-table-with-cloudformation"&gt;Deploy a DynamoDB table with CloudFormation&lt;/h4&gt;

&lt;p&gt;Since our problem statement calls for a DynamoDB table to hold the visitor count, I will use CloudFormation. CloudFormation is an excellent product for deploying AWS resources and makes life so much easier when you need to update or manage your resources later.&lt;/p&gt;

&lt;p&gt;This is a super simple DynamoDB table. In all honestly, I'm not convinced this is a good use of DynamoDB, but the problem statement calls for it, so who am I to argue?&lt;/p&gt;

&lt;pre class="wp-block-code language-yaml"&gt;&lt;code&gt;AWSTemplateFormatVersion: "2010-09-09"
Resources: 
  TuringResumeCounterDynamodb: 
    Type: AWS::DynamoDB::Table
    Properties: 
      AttributeDefinitions: 
        - 
          AttributeName: "Site"
          AttributeType: "N"
      KeySchema: 
        - 
          AttributeName: "Site"
          KeyType: "HASH"
      ProvisionedThroughput: 
        ReadCapacityUnits: "1"
        WriteCapacityUnits: "1"
      TableName: "turingresumecounter"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Deploying this is a single AWS CLI command (I love CloudFormation!).&lt;/p&gt;

&lt;pre class="wp-block-code language-bash"&gt;&lt;code&gt;aws cloudformation deploy --template-file dynamodb.yml --stack-name turingresumecounter&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I will create a single attribute to hold the visitor count.&lt;/p&gt;

&lt;pre class="wp-block-code language-bash"&gt;&lt;code&gt;aws dynamodb put-item --table-name turingresumecounter --item '{"Site":{"N":"0"}, "Visits": {"N": "0"}}'&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Great, now I can read and write from this attribute to keep track of the visitor count. I don't think this is a good solution if you are running in a production setup, so I might re-factor this later. &lt;/p&gt;

&lt;h4 id="6-deploy-a-serverless-api-with-lambda-and-api-gateway"&gt;Deploy a serverless API with Lambda and API Gateway&lt;/h4&gt;

&lt;p&gt;The site still needs some interface to communicate with DynamoDB. I'm going to implement this with Lambda and API Gateway since they are the de facto standard for serverless APIs on AWS. I'm a big fan of API Gateway because it makes it a breeze to set up rate limits, throttling, and other usage plan metrics for your API.&lt;/p&gt;

&lt;p&gt;CloudFormation is great, but it can be a bear to use when deploying serverless resources. AWS makes a companion product called the &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-command-reference.html"&gt;SAM CLI&lt;/a&gt;. The SAM CLI designed to make deploying serverless assets easier and is perfect for our use case. &lt;/p&gt;

&lt;p&gt;The first step is to create another YAML file that describes the deployment. &lt;/p&gt;

&lt;pre class="wp-block-code language-yaml"&gt;&lt;code&gt;AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  Counter:
    Type: AWS::Serverless::Function
    Properties:
      Handler: function.handler
      Runtime: python3.8
      Policies: AmazonDynamoDBFullAccess
      Events:
        HttpGet:
          Type: Api
          Properties:
            Path: '/counter'
            Method: get&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;Handler: function.handler&lt;/code&gt; line above tells SAM that we will provide the lambda function in a file named &lt;code&gt;function.py&lt;/code&gt; with a function named &lt;code&gt;handler&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;handler&lt;/code&gt; function uses the AWS SDK for Python called &lt;a href="https://boto3.amazonaws.com/v1/documentation/api/latest/index.html"&gt;boto3&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote class="wp-block-quote"&gt;&lt;p&gt;UPDATE: After talking to Forrest, we decided it would be best if future participants had to design these parts on their own. Good luck :)&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Great, now when we send a GET request to the API Gateway URL we will see the visitor count. Now, let's work that into the site itself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b25HwDQx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/05/HTTP-Endpoint-Response.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b25HwDQx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seanjziegler.com/wp-content/uploads/2020/05/HTTP-Endpoint-Response.png" alt="" class="wp-image-840" width="336" height="177"&gt;&lt;/a&gt;Wow, someone call Google, this API is HOT!&lt;/p&gt;

&lt;h4 id="7-add-the-visitor-counter-to-the-site"&gt;Add the visitor counter to the site&lt;/h4&gt;

&lt;p&gt;The site needs an element to display the visitor counter. I'm going to create some HTML to display the visitor count and add it to the bottom of the page.  &lt;/p&gt;

&lt;pre class="wp-block-code language-html"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
    &amp;lt;p style = "text-align: center;"&amp;gt;
    Visits: &amp;lt;span id="visits"&amp;gt;0&amp;lt;/span&amp;gt;
    &amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yes, I know inline CSS is bad. Sue me. Let's add some Javascript magic to the footer. This function sends a GET request to the API gateway endpoint every time the page is refreshed. Technically, this is a counter of page views not visitors, but I digress. &lt;/p&gt;

&lt;blockquote class="wp-block-quote"&gt;&lt;p&gt;UPDATE: After talking to Forrest, we decided it would be best if future participants had to design these parts on their own. Good luck :)&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Cool, let's check the page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6QWaw1lI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Visit-Counter.png%3Ffit%3D1024%252C380%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6QWaw1lI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Visit-Counter.png%3Ffit%3D1024%252C380%26ssl%3D1" alt="" class="wp-image-841" width="512" height="190"&gt;&lt;/a&gt;Looking good.&lt;/p&gt;

&lt;h4 id="8-create-a-pipeline-for-automated-deployments"&gt;Create a pipeline for automated deployments&lt;/h4&gt;

&lt;p&gt;We are nearing the finish line! All that's left is creating a pipeline in CodePipeline to deploy our code to the S3 bucket when we push to Git. I already wrote about &lt;a href="https://seanjziegler.com/deploying-code-from-github-to-aws-ec2-with-codepipeline/"&gt;how to deploy from GitHub to EC2&lt;/a&gt;, but since we're going to S3 this time, let's do a quick overview. &lt;/p&gt;

&lt;p&gt;Setup a pipeline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GaYTpYuh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Pipeline-Settings.png%3Ffit%3D1024%252C813%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GaYTpYuh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Pipeline-Settings.png%3Ffit%3D1024%252C813%26ssl%3D1" alt="" class="wp-image-844" width="512" height="407"&gt;&lt;/a&gt;I usually allow AWS to create the service role - much easier that way.&lt;/p&gt;

&lt;p&gt;Make the Git repo your source.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KCHBmpA5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Pipeline-Source-Stage.png%3Ffit%3D1024%252C944%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KCHBmpA5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Pipeline-Source-Stage.png%3Ffit%3D1024%252C944%26ssl%3D1" alt="" class="wp-image-845" width="512" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Setup a deployment stage which pushes the files to your S3 bucket. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BuLqbVCi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Successful-Deployment-.png%3Ffit%3D868%252C1024%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BuLqbVCi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Successful-Deployment-.png%3Ffit%3D868%252C1024%26ssl%3D1" alt="" class="wp-image-846" width="434" height="512"&gt;&lt;/a&gt;Finally done.&lt;/p&gt;

&lt;p&gt;That's all there is to do! You've got a fully functional static S3 that updates on Git push and is served over HTTPs, all for essentially free. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JGKscRAH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Final-Product.png%3Ffit%3D1024%252C444%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JGKscRAH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/05/Final-Product.png%3Ffit%3D1024%252C444%26ssl%3D1" alt="" class="wp-image-847"&gt;&lt;/a&gt;Final product doesn't look too bad for a back-end engineer!&lt;/p&gt;

&lt;p&gt;If you enjoyed this content, follow me on Twitter to see more stuff like this!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>git</category>
      <category>s3</category>
    </item>
    <item>
      <title>How to manage multiple RaspberryPi's easily with Ansible</title>
      <dc:creator>Sean Ziegler</dc:creator>
      <pubDate>Thu, 30 Apr 2020 20:43:54 +0000</pubDate>
      <link>https://dev.to/sean_ziegler/how-to-manage-multiple-raspberrypi-s-easily-with-ansible-4pa8</link>
      <guid>https://dev.to/sean_ziegler/how-to-manage-multiple-raspberrypi-s-easily-with-ansible-4pa8</guid>
      <description>&lt;p&gt;I plan to run a bunch of services on my home network. Right now, my plan is to host most of the services on a small RaspberryPi cluster in a C4 Labs &lt;a href="https://www.c4labs.com/product/8-slot-stackable-cluster-case-raspberry-pi-3b-and-other-single-board-computers-color-options/"&gt;Cloudlet Case&lt;/a&gt;. All of these Pi's run Raspbian and each one will run a few services that I like having hosted on my home network. &lt;/p&gt;

&lt;p&gt;Although 3 RPis isn't exactly impossible to configure manually; why would I want to do that? Plus, the Cloudlet Case accepts up to 8 RPis which would be a lot to manage manually.&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;The Plan&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;For now, I'm going to configure all the following things with &lt;a href="https://www.ansible.com/"&gt;Ansible&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.bashrc&lt;/code&gt; - This enables me to use the same bash aliases across all nodes&lt;/li&gt;
&lt;li&gt;Changing the default password of every pi&lt;/li&gt;
&lt;li&gt;Installing &lt;a href="https://www.vim.org/"&gt;Vim&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.vimrc&lt;/code&gt; - Configures Vim settings like the color scheme and line numbers across all nodes&lt;/li&gt;
&lt;li&gt;MOTD - Just for fun, I'm going to install the &lt;code&gt;fortune | cowsay&lt;/code&gt; packages and broadcast funny cow sayings on log in&lt;/li&gt;
&lt;li&gt;Prometheus Exporters -  Eventually we will deploy some Prometheus exporters to remotely view each node's status&lt;/li&gt;
&lt;li&gt;Mounting a network share on boot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the future I'll also be deploying some Docker containers via Ansible but first we need to configure Ansible itself.&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;Installing Ansible on the Master Node&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;Since &lt;a href="https://www.raspbian.org/"&gt;Raspbian&lt;/a&gt; is a Debian derivative, we will need to add the Ansible PPA to the &lt;code&gt;/etc/apt/sources&lt;/code&gt; file.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /etc/apt
&lt;span class="nb"&gt;sudo &lt;/span&gt;vim sources
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The Ubuntu PPA works fine for Raspbian, at the top of the file add:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;deb http://ppa.launchpad.net/ansible/ansible/ubuntu trusty main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Update apt and then install with:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update 
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;ansible
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Alright, let's define the hosts on the network. Right now, there are three. One will function as a master node that runs Ansible and the others will be slaves that Ansible controls via SSH.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;master]

pi@192.168.0.101

&amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;slave]

pi@192.168.0.102
pi@192.168.0.103
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I could have used Ansible's built-in expansion syntax and written the slaves as 192.168.0.[102:103] but I like the readability of listing them explicitly. &lt;/p&gt;

&lt;p&gt;You need SSH keys configured for Ansible to work without password prompts. I already have SSH setup on all these nodes but I'll be writing a post on setting up headless ssh on a RPi in the future.&lt;/p&gt;

&lt;p&gt;Let's check if Ansible can talk to our nodes:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;ansible all &lt;span class="nt"&gt;-m&lt;/span&gt; ping

192.168.0.101 | SUCCESS &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"changed"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
    &lt;span class="s2"&gt;"ping"&lt;/span&gt;: &lt;span class="s2"&gt;"pong"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
192.168.0.103 | SUCCESS &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"changed"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
    &lt;span class="s2"&gt;"ping"&lt;/span&gt;: &lt;span class="s2"&gt;"pong"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
192.168.0.102 | SUCCESS &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"changed"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
    &lt;span class="s2"&gt;"ping"&lt;/span&gt;: &lt;span class="s2"&gt;"pong"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Great! We can talk to everything on to writing playbooks.&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;Writing a playbook&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;Okay, first let's add a very basic Ansible playbook to install Vim to all three nodes. First, move to the Ansible directory and create a folder for playbooks and the playbook itself:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /etc/ansible
&lt;span class="nb"&gt;mkdir &lt;/span&gt;playbooks
&lt;span class="nb"&gt;touch &lt;/span&gt;install_vim.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Inside the playbook, define a task that installs the latest version of Vim on all the hosts. I'll also add configuration to use sudo to install Vim.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;
    &lt;span class="s"&gt;remote_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pi&lt;/span&gt;
    &lt;span class="s"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&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="s"&gt;Install Vim&lt;/span&gt;
        &lt;span class="na"&gt;become&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;become_method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sudo&lt;/span&gt;
        &lt;span class="na"&gt;apt&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="s"&gt;vim&lt;/span&gt;
          &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&lt;/span&gt;
          &lt;span class="na"&gt;install_recommends&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;Save the file and run the following command:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;ansible-playbook install_vim.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Your output should be all ok.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;PLAY &lt;span class="o"&gt;[&lt;/span&gt;all] &lt;span class="k"&gt;**************************************************************************&lt;/span&gt;

TASK &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;Gathering Facts] &lt;span class="k"&gt;**************************************************************&lt;/span&gt;
ok: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.101]
ok: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.103]
ok: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.102]

TASK &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;Install Vim] &lt;span class="k"&gt;******************************************************************&lt;/span&gt;
ok: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.101]
ok: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.103]
ok: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.102]

PLAY RECAP &lt;span class="k"&gt;**************************************************************************&lt;/span&gt;
pi@192.168.0.101           : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2    &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
pi@192.168.0.102           : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2    &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
pi@192.168.0.103           : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2    &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Great, now that Vim is installed let's advertise some Vim settings (I like the desert color scheme and line numbers) to all 3 machines.&lt;/p&gt;

&lt;p&gt;Let's make a new folder to hold files we want to advertise to other nodes and then create the &lt;code&gt;.vimrc&lt;/code&gt; file:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;span class="nb"&gt;mkdir &lt;/span&gt;repo
&lt;span class="nb"&gt;cd &lt;/span&gt;repo
&lt;span class="nb"&gt;touch&lt;/span&gt; .vimrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Inside the &lt;code&gt;.vimrc&lt;/code&gt; file add the following lines to enable a desert color scheme and line numbers:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;color desert
&lt;span class="nb"&gt;set &lt;/span&gt;number
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now let's define a new task in the Ansible recipe:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&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="s"&gt;Advertise .vimrc&lt;/span&gt;
   &lt;span class="s"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
   &lt;span class="s"&gt;become_method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sudo&lt;/span&gt;
   &lt;span class="s"&gt;copy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../repo/.vimrc&lt;/span&gt;
    &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/vim/vimrc.local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Alright, re-run the &lt;code&gt;ansible-playbook install_vim.yml&lt;/code&gt; command and you should see all the same output plus a few new lines:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;Advertise .vimrc] &lt;span class="k"&gt;*************************************************************&lt;/span&gt;
changed: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.101]
changed: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.103]
changed: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.102]

PLAY RECAP &lt;span class="k"&gt;**************************************************************************&lt;/span&gt;
pi@192.168.0.101           : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3    &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1    &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
pi@192.168.0.102           : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3    &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1    &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
pi@192.168.0.103           : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3    &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1    &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Vim is now installed on every node and my personal &lt;code&gt;.vimrc&lt;/code&gt; file is also being used. The beauty of this system is adding new nodes is as simple as adding it to the Ansible inventory file and then will have all these new settings pushed to them immediately. &lt;/p&gt;

&lt;h4&gt;/etc/profile&lt;/h4&gt;

&lt;p&gt;What better way to use our new Ansible system than syncing some bash aliases to all three nodes. I really like using bash aliases but if they aren't perfectly synced across every system they can quickly become a pain. Let's make a new Ansible playbook for this task.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /etc/ansible/playbooks
&lt;span class="nb"&gt;touch &lt;/span&gt;etc_profile.yml
vim etc_profile.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now let's define two tasks. One that adds the aliases to the &lt;code&gt;/etc/profile&lt;/code&gt; file and one that sources the file so the aliases become available to us in the bash shell.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;
 &lt;span class="na"&gt;remote_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pi&lt;/span&gt;
  &lt;span class="s"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&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="s"&gt;Add aliases to global profile&lt;/span&gt;
    &lt;span class="na"&gt;become&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;become_method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sudo&lt;/span&gt;
    &lt;span class="na"&gt;blockinfile&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;/etc/profile&lt;/span&gt;
     &lt;span class="na"&gt;insertafter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EOF&lt;/span&gt;
     &lt;span class="na"&gt;block&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
       &lt;span class="s"&gt;alias 'll=ls -al'&lt;/span&gt;
       &lt;span class="s"&gt;alias '..=cd ..'&lt;/span&gt;
       &lt;span class="s"&gt;alias '...=cd .. &amp;amp;amp;&amp;amp;amp; cd..'&lt;/span&gt;
       &lt;span class="s"&gt;alias 'mvansible=cd /etc/ansible'&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="s"&gt;Source profile&lt;/span&gt;
    &lt;span class="na"&gt;become&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;become_method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sudo&lt;/span&gt;
    &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;. /etc/profile&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/bin/bash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This playbook will allow us to add bash aliases via the master node and sync them to all other nodes in the network with a single Ansible command! &lt;/p&gt;

&lt;p&gt;Let's try it: &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;ansible-playbook etc_profile.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;PLAY &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;all] &lt;span class="k"&gt;*********************************************************&lt;/span&gt;                                                                     &lt;span class="k"&gt;************&lt;/span&gt;

TASK &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;Gathering Facts] &lt;span class="k"&gt;*********************************************&lt;/span&gt;                                                                     &lt;span class="k"&gt;************&lt;/span&gt;
ok: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.101]
ok: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.103]
ok: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.102]

TASK &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;Add aliases to global profile] &lt;span class="k"&gt;*******************************&lt;/span&gt;                                                                     &lt;span class="k"&gt;************&lt;/span&gt;
ok: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.101]
ok: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.103]
ok: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.102]

TASK &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;Source profile] &lt;span class="k"&gt;**********************************************&lt;/span&gt;                                                                     &lt;span class="k"&gt;************&lt;/span&gt;
changed: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.101]
changed: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.103]
changed: &amp;amp;#91&lt;span class="p"&gt;;&lt;/span&gt;pi@192.168.0.102]

PLAY RECAP &lt;span class="k"&gt;*********************************************************&lt;/span&gt;                                                                     &lt;span class="k"&gt;************&lt;/span&gt;
pi@192.168.0.101           : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3    &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1    &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    f                                                                     &lt;span class="nv"&gt;ailed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
pi@192.168.0.102           : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3    &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1    &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    f                                                                     &lt;span class="nv"&gt;ailed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
pi@192.168.0.103           : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3    &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1    &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    f                                                                     &lt;span class="nv"&gt;ailed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Awesome! It looks like everything worked. Just for fun lets try it on a slave node:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;pi@raspberrypi3BP-1:~ &lt;span class="nv"&gt;$ &lt;/span&gt;ll

total 56K
drwxr-xr-x 7 pi   4.0K Oct 12 00:21 &lt;span class="nb"&gt;.&lt;/span&gt;
drwxr-xr-x 3 root 4.0K Sep 15 23:54 ..
drwx------ 3 pi   4.0K Oct 11 21:38 .ansible
&lt;span class="nt"&gt;-rw-------&lt;/span&gt; 1 pi   6.5K Oct 11 23:10 .bash_history
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 pi    220 Jul 10 01:07 .bash_logout
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 pi   3.5K Sep 15 23:27 .bashrc
drwx------ 3 pi   4.0K Sep  7 19:12 .config
drwx------ 3 pi   4.0K Jul 10 01:30 .gnupg
drwxr-xr-x 3 pi   4.0K Sep  7 18:24 .local
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 pi    807 Jul 10 01:07 .profile
drwxr-xr-x 2 pi   4.0K Sep  7 20:02 .ssh
&lt;span class="nt"&gt;-rw-------&lt;/span&gt; 1 pi   1.6K Oct 12 00:21 .viminfo
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 pi    165 Sep  7 18:53 .wget-hsts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Looks like our aliases were correctly synced. &lt;/p&gt;

&lt;p&gt;Ansible is now configured. We have a huge amount of potential for installing other applications and advertising configurations. Expect to see some more Ansible posts in the future!&lt;/p&gt;





</description>
      <category>ansible</category>
      <category>raspberrypi</category>
      <category>ssh</category>
    </item>
    <item>
      <title>Deploying code from GitHub to AWS EC2 with CodePipeline</title>
      <dc:creator>Sean Ziegler</dc:creator>
      <pubDate>Thu, 30 Apr 2020 11:32:41 +0000</pubDate>
      <link>https://dev.to/sean_ziegler/deploying-code-from-github-to-aws-ec2-with-codepipeline-25m7</link>
      <guid>https://dev.to/sean_ziegler/deploying-code-from-github-to-aws-ec2-with-codepipeline-25m7</guid>
      <description>&lt;p&gt;I’m not that old, but when I built my first website I manually copied code to an Apache server with FTP. That server was also running in my closet. As you can imagine, this deployment process was not exactly fullproof and I experienced frequent outages on my website. Deployments have come a long way in the 10 years since my first website and the general goal today is to automate code deployments as much as possible. Let’s explore how we can deploy code from GitHub to EC2 using CodePipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why automate?
&lt;/h3&gt;

&lt;p&gt;Put simply, the more repeatable your deployments are, the less downtime you will have. Automated deployments are easier to test, easier to troubleshoot, lend themselves to scalability, can perform rollbacks on failure, support blue/green and canary deployments. The list goes on.&lt;/p&gt;

&lt;p&gt;Ideally, your resources should be treated like cattle, not like pets. If it gets sick, you shoot it and replace it with another one. Automated deployments make that easy.&lt;/p&gt;

&lt;h3&gt;
  
  
  First, a Git repo
&lt;/h3&gt;

&lt;p&gt;Before we do anything else, we will need a Git repository to house the code. I’ll clone down a empty repo and create a demo file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;seanziegler&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;AWSDeployDemo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;
&lt;span class="n"&gt;touch&lt;/span&gt; &lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;
&lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="s"&gt;"This is prod"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;
&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; 
&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="s"&gt;"Init commit"&lt;/span&gt;
&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt; &lt;span class="n"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I’m going to create a seperate branch so I can push seperately to test and master.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;branch&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;
&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;checkout&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;
&lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="s"&gt;"This is test"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt; 
&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="s"&gt;"Create test branch"&lt;/span&gt;
&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Obviously, you’d normally be deploying an application, not just a text file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating deployment targets
&lt;/h3&gt;

&lt;p&gt;Now that we have repositories set up, some instances are needed. I’m going to use the management interface since this is just a demo but you can also use the awscli or Terraform/Cloudformation.&lt;/p&gt;

&lt;p&gt;It’s good practice to create a new subnet inside your VPC for each application you deploy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8nG37vks--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-25-at-1.02.04-PM.png%3Fresize%3D2048%252C1079%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8nG37vks--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-25-at-1.02.04-PM.png%3Fresize%3D2048%252C1079%26ssl%3D1" alt="Create Subnet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, next up are the EC2 instances themselves. I’m going to make two: one for test and one for production. Obviously this is just a dummy deployment but CodePipeline is versatile enough to allow deployments across hundreds of resources if needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xv-zKoy8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-25-at-1.12.21-PM-1.png%3Fw%3D2040%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xv-zKoy8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-25-at-1.12.21-PM-1.png%3Fw%3D2040%26ssl%3D1" alt="Create Instances"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ll also add some tags to identify the production vs test instance. I’ll be using these later to tell CodePipeline which one is which.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WQh77l51--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-25-at-1.12.54-PM-1.png%3Fw%3D1587%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WQh77l51--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-25-at-1.12.54-PM-1.png%3Fw%3D1587%26ssl%3D1" alt="Add Tags"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, we have what we need for instances.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--25ErYwo2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-25-at-1.23.27-PM.png%3Fw%3D1590%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--25ErYwo2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-25-at-1.23.27-PM.png%3Fw%3D1590%26ssl%3D1" alt="New instances"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing the CodeDeploy agent
&lt;/h3&gt;

&lt;p&gt;Before we can build a pipeline, we need to configure CodeDeploy and it’s agent. CodeDeploy requires a small agent daemon installed on every machine that is a deployment target.&lt;/p&gt;

&lt;p&gt;You can check if you have the CodeDepoy agent installed by connecting to your instance and running (on Amazon Linux or RHEL):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;service codedeploy-agent status
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You’ll either get an error or a message that the service is stopped. If the service is stopped, simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;service codedeploy-agent start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you get an error, the codedeploy-agent isn’t installed. So it becomes a bit more involved. Here’s the docs page on how to install the CodeDeploy agent. Essentially it boils down to the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;yum update &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;yum &lt;span class="nb"&gt;install &lt;/span&gt;ruby wget &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /home/ec2-user
wget https://bucket-name.s3.region-identifier.amazonaws.com/latest/install
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x ./install
&lt;span class="nb"&gt;sudo&lt;/span&gt; ./install auto
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the wget command above, you’ll need to replace both bucket-name and region-identifier with the values that corresponds to your region.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Region Name&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;bucket-name&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;region-identifier&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;US East (Ohio)&lt;/td&gt;
&lt;td&gt;aws-codedeploy-us-east-2&lt;/td&gt;
&lt;td&gt;us-east-2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;US East (N. Virginia)&lt;/td&gt;
&lt;td&gt;aws-codedeploy-us-east-1&lt;/td&gt;
&lt;td&gt;us-east-1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;US West (N. California)&lt;/td&gt;
&lt;td&gt;aws-codedeploy-us-west-1&lt;/td&gt;
&lt;td&gt;us-west-1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;US West (Oregon)&lt;/td&gt;
&lt;td&gt;aws-codedeploy-us-west-2&lt;/td&gt;
&lt;td&gt;us-west-2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canada (Central)&lt;/td&gt;
&lt;td&gt;aws-codedeploy-ca-central-1&lt;/td&gt;
&lt;td&gt;ca-central-1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Europe (Ireland)&lt;/td&gt;
&lt;td&gt;aws-codedeploy-eu-west-1&lt;/td&gt;
&lt;td&gt;eu-west-1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Europe (London)&lt;/td&gt;
&lt;td&gt;aws-codedeploy-eu-west-2&lt;/td&gt;
&lt;td&gt;eu-west-2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Europe (Paris)&lt;/td&gt;
&lt;td&gt;aws-codedeploy-eu-west-3&lt;/td&gt;
&lt;td&gt;eu-west-3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Once installed, check one last time to make sure the agent is running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;service codedeploy-agent status
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  CodeDeploy Role
&lt;/h3&gt;

&lt;p&gt;In order for CodeDeploy to work, we need to assign it a service role with the correct permissions. Let’s create a role with the AWSCodeDeployRole policy attached to it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--thMSOXdY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-7.10.22-AM.png%3Fw%3D1988%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--thMSOXdY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-7.10.22-AM.png%3Fw%3D1988%26ssl%3D1" alt="Create Role"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0RiQXeOo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-7.17.47-AM.png%3Fresize%3D2048%252C527%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0RiQXeOo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-7.17.47-AM.png%3Fresize%3D2048%252C527%26ssl%3D1" alt="Attach Role"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that the instance roles are setup, it’s time to turn to CodeDeploy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating an Application and Deployment Group
&lt;/h3&gt;

&lt;p&gt;Creating an application in CodeDeploy is straightforward. Just give it a name and tell it that you plan on deploying code to EC2 instances.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MWlBNlb6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-7.29.33-AM.png%3Fw%3D1714%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MWlBNlb6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-7.29.33-AM.png%3Fw%3D1714%26ssl%3D1" alt="Create Application"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creating a deployment group is a bit more complicated but not difficult. Give it a name and assign the CodeDeploy service role you created previously. This will allow CodeDeploy to access the resources specified in this deployment group.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iQa0KyZj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-7.42.46-AM.png%3Fw%3D1654%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iQa0KyZj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-7.42.46-AM.png%3Fw%3D1654%26ssl%3D1" alt="Create Deployment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, choose EC2 instances for deployment. You can also deploy to autoscaling groups but for now I’ll deploy to a single instance. Don’t forget to add the env:test tag. You should see one matched instance that corresponds to the test instance created earlier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1-6ffjA1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-7.44.44-AM.png%3Fw%3D1636%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1-6ffjA1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-7.44.44-AM.png%3Fw%3D1636%26ssl%3D1" alt="Environment Config"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We don’t need a special deployment setting so just leave the default AllAtOnce setting in place. Uncheck Enable load balancing since we haven’t set that up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uwpU7v6S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-7.44.56-AM.png%3Fw%3D1650%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uwpU7v6S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-7.44.56-AM.png%3Fw%3D1650%26ssl%3D1" alt="Deployment Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repeat this process again but target the instances with the env:prod tag.&lt;/p&gt;

&lt;h3&gt;
  
  
  appspec.yml
&lt;/h3&gt;

&lt;p&gt;CodePipeline needs to know what to do with the files in your Git repository when you deploy. A file called appspec.yml is CodePipeline’s way of defining the tasks you want to run when deploying code. There’s too much to cover here, but AWS has examples of how to build out an appspec.yml file.&lt;/p&gt;

&lt;p&gt;For this project, I’m just going to copy in some text files from the Git repo to test that the pipeline is working. You’ll need to do your own research on how to build an appspec file to suit your deployment. If you want to follow along with my dummy deployment, put this in a file at the root of your git repo. Don’t forget to name it appspec.yml!&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.0&lt;/span&gt;
&lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linux&lt;/span&gt;
&lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./demo.txt&lt;/span&gt;
    &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Building a pipeline
&lt;/h3&gt;

&lt;p&gt;We need to build two pipelines for this to work. One pipeline that deploys the test branch to test instances and one pipeline that deploys the master branch to production instances.&lt;/p&gt;

&lt;p&gt;Creating a pipeline is a straightforward process. I suggest letting CodePipeline create your servie role for you. It’s just easier that way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e_suU4Rt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-8.10.06-AM.png%3Fw%3D1582%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e_suU4Rt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-8.10.06-AM.png%3Fw%3D1582%26ssl%3D1" alt="Pipeline Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a stage that uses your Github repository and the test branch as the source.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MXJL_Hbt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-8.11.39-AM.png%3Fw%3D1618%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MXJL_Hbt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-8.11.39-AM.png%3Fw%3D1618%26ssl%3D1" alt="Source Stage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Skip the build stage for now. If you want, you can come back later and setup CodeBuild to do integration tests or build binaries if you need that sort of thing.&lt;/p&gt;

&lt;p&gt;Select the CodeDeploy provider and choose the application and deployment group for your test instances.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lM5GecW_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-8.12.32-AM.png%3Fw%3D1584%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lM5GecW_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-8.12.32-AM.png%3Fw%3D1584%26ssl%3D1" alt="Deploy Stage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click next and deploy the pipeline. You’ll see it try to download your source and deploy it to your test instances.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r8xuI-Bi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-12.18.18-PM.png%3Fresize%3D768%252C925%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r8xuI-Bi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-12.18.18-PM.png%3Fresize%3D768%252C925%26ssl%3D1" alt="Deploy Stage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great, we deployed to our test instances. But what about production? Click “Edit” at the top of the pipeline page. And then click “Edit” on each stage of the pipeline. From here, you can add another source and deploy action for the master branch and production deployment group.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cBSVYnVV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-11.56.27-AM.png%3Fresize%3D2048%252C1149%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cBSVYnVV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-11.56.27-AM.png%3Fresize%3D2048%252C1149%26ssl%3D1" alt="Deploy Edit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you click save, your pipeline will deploy the test branch to the test deployment group and the master branch to the production deployment group.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iupAMNd4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-12.08.32-PM.png%3Fresize%3D2048%252C1198%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iupAMNd4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/seanjziegler.com/wp-content/uploads/2020/04/Screen-Shot-2020-04-26-at-12.08.32-PM.png%3Fresize%3D2048%252C1198%26ssl%3D1" alt="Deploy Success"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s just check and see if the deployments worked. First, let’s check the test instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh ec2-user@test-instance

Last login: Sun Apr 26 16:00:02 2020 from &amp;lt;IP&amp;gt;

       __|  __|_  &lt;span class="o"&gt;)&lt;/span&gt;
       _|  &lt;span class="o"&gt;(&lt;/span&gt;     /   Amazon Linux 2 AMI
      ___|&lt;span class="se"&gt;\_&lt;/span&gt;__|___|

https://aws.amazon.com/amazon-linux-2/

&lt;span class="o"&gt;[&lt;/span&gt;ec2-user@test-instance ~]&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /demo.txt
This is &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, check the production instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh ec2-user@prod-instance

Last login: Sun Apr 26 16:00:02 2020 from &amp;lt;IP&amp;gt;

       __|  __|_  &lt;span class="o"&gt;)&lt;/span&gt;
       _|  &lt;span class="o"&gt;(&lt;/span&gt;     /   Amazon Linux 2 AMI
      ___|&lt;span class="se"&gt;\_&lt;/span&gt;__|___|

https://aws.amazon.com/amazon-linux-2/

&lt;span class="o"&gt;[&lt;/span&gt;ec2-user@prod-instance ~]&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /demo.txt
This is prod
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Awesome! Just what was expected. Your pipeline is setup and ready to go.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customising the deployment.
&lt;/h3&gt;

&lt;p&gt;There are several ways you can customize your pipeline.&lt;/p&gt;

&lt;h4&gt;
  
  
  appspec.yml
&lt;/h4&gt;

&lt;p&gt;For one thing, you’ll want to start with building out an appspec.yml file that reflects the structure of your application. Copy over all the files you need, run scripts to setup dependencies, etc.&lt;/p&gt;

&lt;h4&gt;
  
  
  AMI
&lt;/h4&gt;

&lt;p&gt;Make a custom AMI for the instances in each of your group. Include any dependencies your code needs to run (and the codedeploy-agent) in the AMI rather than installing it every deployment. This will increase the relability and speed of your deployments.&lt;/p&gt;

&lt;h4&gt;
  
  
  Autoscaling groups
&lt;/h4&gt;

&lt;p&gt;Instead of creating deployment groups with specific EC2 instances identified, consider deploying to autoscaling groups instead so you can apply scale-in and scale-out rules.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>git</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
