<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Counting Clouds</title>
    <description>An ICTer&apos;s blog about programming and cloud computing.</description>
    <link>https://vasko.io/</link>
    <atom:link href="https://vasko.io/feed.xml" rel="self" type="application/rss+xml" />
    
      <item>
        <title>Let&apos;s Talk Immutable</title>
        <description>&lt;p&gt;Immutable OSs&lt;/p&gt;

&lt;p&gt;Matthew Waanders recently brought to my attention a new desktop OS by Fedora: &lt;a href=&quot;https://kinoite.fedoraproject.org&quot;&gt;Kinoite&lt;/a&gt;. It is based on &lt;a href=&quot;https://silverblue.fedoraproject.org&quot;&gt;Fedora Silverblue&lt;/a&gt;, but with a KDE desktop environment. What is really fascinating about it is the idea behind both OSs. They’re both immutable desktop operating systems built around &lt;a href=&quot;https://coreos.github.io/rpm-ostree/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rpm-ostree&lt;/code&gt;&lt;/a&gt; and that is exactly what I’d like to focus on in this post.&lt;/p&gt;

&lt;p&gt;Usually operating systems use package installers like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnf&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yum&lt;/code&gt; on Linux and even &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;homebrew&lt;/code&gt; on macOS. These focus essentially on downloading packages and installing them in a local directory where they can be accessed by the user or other apps. This approach, although fast and quite flexible does have a drawback: its live updating of packages without easy stateful rollback. Sometimes packages can use different libraries across OSs and maybe for your specific one that you are installing them on, they’re quite simply not tested enough. So what can be done to improve this?&lt;/p&gt;

&lt;h2 id=&quot;enter-images&quot;&gt;Enter images&lt;/h2&gt;

&lt;p&gt;We know images from the container world. We package an application and all of its dependencies in an image which can then be replicated exactly on other machines. What if we take this concept and apply it to OSs? What if we make a repo for images of apps ready to use with the correct state and have users pull them to their local OSs from there?&lt;/p&gt;

&lt;p&gt;This is exactly what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rpm-ostree&lt;/code&gt; is doing. The packages to be installed are all on a remote server that OSs can synchronise from. If a package exists on the remote server, then it should be synced to the OSs as well. As the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rpm-ostree&lt;/code&gt; project &lt;a href=&quot;https://coreos.github.io/rpm-ostree/background/#how-rpm-ostree-provides-a-middle-ground&quot;&gt;self describes&lt;/a&gt; it is almost like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; where people push to and pull from remote.&lt;/p&gt;

&lt;p&gt;The main benefits of this are consistency and scalability. If you have a big fleet of EC2 instances to manage for example, you want to make sure that your package management system can handle that scale and do it consistently. We want the guarantee that once deployed a package will run the exact same way on one instance and every other around it. Of course, I’m an advocate for fully immutable infrastructures where instead of updating running EC2 instances you should just replace them with a newer AMI with all required updates, but that is a topic for a different post.&lt;/p&gt;

&lt;p&gt;Let’s go a bit further in the architecture of such an OS. Let’s take the following filesystem for example. These are the default mount points as show in the &lt;a href=&quot;https://docs.fedoraproject.org/en-US/fedora-coreos/storage/#_mounted_filesystems&quot;&gt;Fedora CoreOS docs&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;TARGET        SOURCE                                                   FSTYPE  OPTIONS
/             /dev/vda4[/ostree/deploy/fedora-coreos/deploy/$hash]     xfs     rw
|-/sysroot    /dev/vda4                                                xfs     ro
|-/etc        /dev/vda4[/ostree/deploy/fedora-coreos/deploy/$hash/etc] xfs     rw
|-/usr        /dev/vda4[/ostree/deploy/fedora-coreos/deploy/$hash/usr] xfs     ro
|-/var        /dev/vda4[/ostree/deploy/fedora-coreos/deploy/var]       xfs     rw
`-/boot       /dev/vda3                                                ext4    ro  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Every other mount point here, with the exception of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var&lt;/code&gt;, are immutable. Only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rpm-ostree&lt;/code&gt;, and in the case of Fedora CoreOS &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootupd&lt;/code&gt;, can make changes to the rest of the filesystem.&lt;/p&gt;

&lt;p&gt;This way of managing filesystems is secure and efficient for servers, but now projects like Kinoite and Silverblue have brought it to the desktop as well. I am definitely excited to see those in action and play around with them and I encourage you to do the same.&lt;/p&gt;
</description>
        <pubDate>Fri, 15 Oct 2021 09:12:00 +0200</pubDate>
        <link>https://vasko.io/linux/2021/10/15/lets-talk-immutable.html</link>
        <guid isPermaLink="true">https://vasko.io/linux/2021/10/15/lets-talk-immutable.html</guid>
      </item>
    
      <item>
        <title>The Complexity of Kube</title>
        <description>&lt;p&gt;Kubernetes and its features&lt;/p&gt;

&lt;p&gt;I recently read an article in the &lt;a href=&quot;https://www.eoswetenschap.eu/psyche-brein&quot;&gt;Dutch Eos Psyche &amp;amp; Brein&lt;/a&gt; magazine titled “Waarom je de makkelijke oplossing over het hoofd ziet”. It goes about explaining why is it that when faced with a challenge people tend to pick an additive solution in contrast to a subtractive one. The author cites the article “&lt;a href=&quot;https://www.nature.com/articles/s41586-021-03380-y&quot;&gt;People systematically overlook subtractive changes&lt;/a&gt;” from Nature where the authors describe the results of their research about why people tend to chose solutions that add stuff to solve a problem instead of the, in a lot of cases, simpler way of removing stuff instead.&lt;/p&gt;

&lt;p&gt;This got me thinking about the current state of the container orchestration platforms and the way that they are designed and built. Bear with me for a moment.&lt;/p&gt;

&lt;p&gt;From the inception of Borg (“&lt;a href=&quot;https://research.google/pubs/pub43438/&quot;&gt;Large-scale cluster management at Google with Borg&lt;/a&gt;”) the architecture of container management systems has been, just like the applications they were made to run, highly distributed, and that makes sense. Why would we make one single application that has to manage critical workloads across thousands of machines? That would be the biggest weakest link in the chain if there ever was one. In no way do I want to suggest that distributed, decoupled admin planes are a bad idea, on the contrary. However, one of the doors that such a design approach opens is the possibility of adding new functionality.&lt;/p&gt;

&lt;p&gt;Let’s look at the Kubernetes API for example. Over the years new APIs and resources have been added that can manage practically anything in your application’s lifecycle: Ingresses, Jobs, Persistent Volumes. Kube has become a one-stop-shop for everything needed to run distributed applications at scale. But then you start to wonder: does it need that? Do we want to have everything being managed and stored by one singular system on a comparatively small amount of storage (etcd)? At wat point is Kube just another layer of AWS-like functionality on top of AWS?&lt;/p&gt;

&lt;p&gt;If we zoom in to one specific resource, the ConfigMap, we can already see one of those extra functionalities that you wonder if we really need. Applications use a lot of environment variables for configuration on runtime. Kube provides us with a handy way of storing and giving the applications those environment variables, or even mounting whole files to them, whenever needed. All of that data get stored in the central control plane in etcd. If you use a managed Kubernetes solution you could say that that data is safe, however if you are managing it yourself, you have a lot of weight on your shoulders. Why not use something already existing with a much higher uptime and reliability guarantees? Something like the AWS SSM Parameter Store for example. Applications can get everything they need from the Parameter Store in a safe way without ever having to rely on plain-text environment variables in their runtimes.&lt;/p&gt;

&lt;p&gt;I can give more examples: why rely on volumes or EFS to write files to if you can just write them to S3?&lt;/p&gt;

&lt;p&gt;In any case, this is what I am trying to say: do we really need to add more complexity to what a container orchestrator or can we simplify it and make it easier for people not only to manage it, but to contribute to it?&lt;/p&gt;
</description>
        <pubDate>Thu, 29 Jul 2021 17:40:00 +0200</pubDate>
        <link>https://vasko.io/kubernetes/2021/07/29/the-complexity-of-kube.html</link>
        <guid isPermaLink="true">https://vasko.io/kubernetes/2021/07/29/the-complexity-of-kube.html</guid>
      </item>
    
      <item>
        <title>Terraform 0.12&apos;s Template Syntax</title>
        <description>&lt;h1 id=&quot;terraform-is-not-a-programming-language&quot;&gt;Terraform is &lt;em&gt;not&lt;/em&gt; a programming language&lt;/h1&gt;
&lt;p&gt;And this is exactly why in some cases you end up coming up with maybe weird and unnecessarily complex code to achieve something that you can easily fix if you had the conveniences of a programming language (like if else statements, for loops, etc.). There have been plenty of cases where you would want to generate something in your cloud init on the fly or just add something to some other configuration file, but you couldn’t extract the exact data you need because you want to loop over something or only add stuff that meets a certain condition.&lt;/p&gt;

&lt;h1 id=&quot;template-syntax-in-terraform-012&quot;&gt;Template Syntax in Terraform 0.12&lt;/h1&gt;
&lt;p&gt;Among a lot of other absolutely great features, which I’ll talk about in other blogposts, we finally get to play with if else statements and for loops. HashiCorp have a &lt;a href=&quot;https://www.hashicorp.com/blog/terraform-0-12-template-syntax&quot;&gt;blogpost&lt;/a&gt; about it and some of the things you’d be able to do in the latest release. I’m super excited to get my hands on this and play with it when it releases. I’m sure a lot of you would find it absolutely amazing as well.&lt;/p&gt;

&lt;p&gt;Have fun Terraforming. 😃&lt;/p&gt;
</description>
        <pubDate>Fri, 24 Aug 2018 18:38:00 +0200</pubDate>
        <link>https://vasko.io/terraform/2018/08/24/terraform-0-12s-template-syntax.html</link>
        <guid isPermaLink="true">https://vasko.io/terraform/2018/08/24/terraform-0-12s-template-syntax.html</guid>
      </item>
    
      <item>
        <title>CoreOS and RedHat</title>
        <description>&lt;h1 id=&quot;coreos-joins-redhat&quot;&gt;CoreOS joins RedHat&lt;/h1&gt;
&lt;p&gt;As you may have heard in recent &lt;a href=&quot;https://coreos.com/blog/coreos-tech-to-combine-with-red-hat-openshift&quot;&gt;blogposts&lt;/a&gt; from CoreOS and RedHat - CoreOS and all of their projects are joining RedHat. This is extremely interesting, especially for me since I really like Container Linux as an OS. There are, of course, going to be changes to the rest of the CoreOS projects, like:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Tectonic is going to be integrated into OpenShift&lt;/li&gt;
  &lt;li&gt;The Quay registry is going to become RedHat Quay&lt;/li&gt;
  &lt;li&gt;Projects such as etcd, Ignition, Clair, etc. will be moved to RedHat as well&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, in this post, I’d like to talk about two things:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Container Linux and the way it is going to be integrated in the RedHat product lineup&lt;/li&gt;
  &lt;li&gt;The Operator framework&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;fedora-coreos&quot;&gt;Fedora CoreOS&lt;/h1&gt;
&lt;p&gt;So, Container Linux is becoming an official Fedora project under the name Fedora CoreOS. The &lt;a href=&quot;https://fedoramagazine.org/announcing-fedora-coreos/&quot;&gt;official post&lt;/a&gt; on the Fedora blog touched the subject of how this is going to look like.&lt;/p&gt;

&lt;p&gt;From what we can see the new CoreOS is going to be build from the ground up based on Fedora technologies. This means that the old Container Linux is something that we’re not going to see in its original state. It is known that some technologies, such as Ignition, will be kept in the new OS, however the old update engine will probably be updated to something else.&lt;/p&gt;

&lt;p&gt;We also know that technologies from the current Fedora Atomic Host, like SELinux hardening, will be added to Fedora CoreOS as well.&lt;/p&gt;

&lt;p&gt;I’m still not exactly sure what I think of that, but I remain positive and hope to be able to play with the new Fedora CoreOS soon to see what it can do. Its definitely going to be exciting. 😃&lt;/p&gt;

&lt;h1 id=&quot;the-operator-framework&quot;&gt;The Operator Framework&lt;/h1&gt;
&lt;p&gt;CoreOS’ operators are amazing tools which I have been using more and more as of late. What exactly they are how they work is a topic for another blogpost. 😊&lt;/p&gt;

&lt;p&gt;What RedHat has already announced is that they’re planning on developing a way of testing and delivering Operators on OpenShift. How that exactly is going to be implemented - we’ll just have to wait and see.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;As a whole I find this topic extremely interesting, mainly because of my interest in the CoreOS technologies. I think that RedHat is definitely going to bring innovation and support for these and I’m really excited to see what they’re going to do. In any case I think the current community will be happy with the new technologies we’ll get to play with. 😃&lt;/p&gt;
</description>
        <pubDate>Sat, 21 Jul 2018 20:28:00 +0200</pubDate>
        <link>https://vasko.io/linux/2018/07/21/coreos-and-redhat.html</link>
        <guid isPermaLink="true">https://vasko.io/linux/2018/07/21/coreos-and-redhat.html</guid>
      </item>
    
      <item>
        <title>Buildkite Agent V3</title>
        <description>&lt;h1 id=&quot;hello-buildkite&quot;&gt;Hello Buildkite&lt;/h1&gt;
&lt;p&gt;I’ve written before about &lt;a href=&quot;https://vasko.io/devops/aws/2017/09/14/why-i-like-buildkite.html&quot;&gt;Buildkite&lt;/a&gt; and how awesome it is, but recently they have made it even more awesome than it was before. They have release v3 of their agent, which adds some really sweet functionality. Make sure to check &lt;a href=&quot;https://building.buildkite.com/announcing-buildkite-agent-v3-0-4781a0e2d4db&quot;&gt;their post&lt;/a&gt; about it as well. 😃&lt;/p&gt;

&lt;h1 id=&quot;welcome-v3&quot;&gt;Welcome v3&lt;/h1&gt;
&lt;p&gt;You can read about all new features, such as agent annotation and environment variable substitution in the post I mentioned above, but what I really want to talk about are the plugins.&lt;/p&gt;

&lt;p&gt;Plugins are essentially an extension to the native functionality of the agent itself. We currently run a lot in docker containers in which we install extra software that we need or we add extra steps with scripts that provide some extra functionality, logging in to AWS ECR for example.&lt;/p&gt;

&lt;p&gt;Well, now we can just simply use a plugin. There is already a &lt;a href=&quot;https://github.com/buildkite-plugins&quot;&gt;library with open-source plugins&lt;/a&gt; which you can directly use, or you can write a plugin yourself.&lt;/p&gt;

&lt;p&gt;Let’s take the &lt;a href=&quot;https://github.com/buildkite-plugins/ecr-buildkite-plugin&quot;&gt;ecr-buildkite-plugin&lt;/a&gt; for example. You can use it to automatically log in to ECR without having to add an extra step with a custom script.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ruby build.rb&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;s&quot;&gt;ecr#v1.1.3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Awesome, right? 😃 There are much more plugins which I encourage you to go and play around with.&lt;/p&gt;

&lt;h1 id=&quot;go-an-try-it-out-yourself&quot;&gt;Go an try it out yourself&lt;/h1&gt;
&lt;p&gt;The Buildkite documentation offers extensive information on &lt;a href=&quot;https://buildkite.com/docs/agent/v3/plugins&quot;&gt;using the plugins&lt;/a&gt; and the rest of the new features, so definitely check it out together with the rest of the awesome new additions to the agent as well.&lt;/p&gt;
</description>
        <pubDate>Wed, 11 Apr 2018 13:21:00 +0200</pubDate>
        <link>https://vasko.io/devops/aws/2018/04/11/buildkite-agent-v3.html</link>
        <guid isPermaLink="true">https://vasko.io/devops/aws/2018/04/11/buildkite-agent-v3.html</guid>
      </item>
    
      <item>
        <title>Quickstart - Building Alexa Bots</title>
        <description>&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Some time ago I got a Echo Dot to experiment with building bots and serverless computing. I have to say, the Echo Dot is the perfect device for starting with that since the development for it is pretty intuitive, well documented and, best of all, you can easily run your app on AWS.&lt;/p&gt;

&lt;p&gt;Needless to say, make sure you have an Amazon account with which you can register for Amazon Developers and AWS.&lt;/p&gt;

&lt;p&gt;So, let’s have a look how to get started with building bots quickly.&lt;/p&gt;

&lt;h1 id=&quot;skill-types-user-interaction-and-components&quot;&gt;Skill Types, User Interaction and Components&lt;/h1&gt;

&lt;h2 id=&quot;choosing-the-proper-skill-type&quot;&gt;Choosing the Proper Skill Type&lt;/h2&gt;

&lt;p&gt;Before starting to code anything you should have a clear idea what your skill is going to do and how your user is going to interact with it. Since this is a simple introduction you don’t have to make anything super complicated. Make a simple trivia game or a weather bot for example.&lt;/p&gt;

&lt;p&gt;There are multiple skill types you can choose from:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Custom Skill&lt;/li&gt;
  &lt;li&gt;Smart Home Skill&lt;/li&gt;
  &lt;li&gt;Video Skill&lt;/li&gt;
  &lt;li&gt;Flash Briefing Skill&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a more in-depth look of the different types of skills you can check the &lt;a href=&quot;https://developer.amazon.com/docs/ask-overviews/understanding-the-different-types-of-skills.html&quot;&gt;Alexa Skills Kit documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For these kind of bots you’d have to go for a “custom skill”, since what we’re trying to do is not related to any of the other supported uses.&lt;/p&gt;

&lt;h2 id=&quot;user-interaction-and-components&quot;&gt;User Interaction and Components&lt;/h2&gt;

&lt;p&gt;When going for a custom skill you have to define the way the user interacts completely by yourself. This means taking care of things like:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Intents&lt;/li&gt;
  &lt;li&gt;Slots&lt;/li&gt;
  &lt;li&gt;Sample utterances&lt;/li&gt;
  &lt;li&gt;Interaction model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, what’s what?&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Component&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Function&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Intents&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;What a user can do with a skill. For example - get weather for a specific city, set default city, etc. You would usually name them the same way in your code - “GetWeatherForCity” or “SetDefaultCity”, etc.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Slots&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Essentially the variable in your intent. For example the “GetWeatherForCity” and “SetDefaultCity” intents will require a city to be defined. In this case we will have a “City” slot.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Sample utterances&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;A list of phrases a user might use when communicating with the skill. For example a sample utterance might be “weather in Amsterdam”.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Interaction model&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;The mapping of intents and sample utterances. For example the utterance “weather in my city” will be mapped to the “GetWeatherForCity” intent.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Before you start building any code think about how the user is going to interact with your bot. Start by:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Making intents based on the different actions users can take.&lt;/li&gt;
  &lt;li&gt;Defining the variables in the intents and making slots for them.&lt;/li&gt;
  &lt;li&gt;Thinking of sample utterances.&lt;/li&gt;
  &lt;li&gt;Mapping your intents to the sample utterances.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;the-alexa-skills-console&quot;&gt;The Alexa Skills Console&lt;/h2&gt;

&lt;p&gt;This is where we’re going to do all of the necessary configurations of the skill and build our interaction model. You can access it through the &lt;a href=&quot;https://developer.amazon.com/alexa&quot;&gt;Amazon Developers portal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The process is pretty simple and straightforward:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Create a new skill by clicking on the “Create Skill” button.&lt;/li&gt;
  &lt;li&gt;Give it a name and a locale.&lt;/li&gt;
  &lt;li&gt;Choose a model - on our case “custom”.&lt;/li&gt;
  &lt;li&gt;Click on “Create Skill”.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After the skill has been created you will be presented with a console where you can build, test and publish your skill. In the beginning page there is a handy checklist which I recommend you to follow to get started easily. It will guide you through:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Configuring an invocation name.&lt;/li&gt;
  &lt;li&gt;Configuring your intents, sample utterances and slots.&lt;/li&gt;
  &lt;li&gt;Building the interaction model.&lt;/li&gt;
  &lt;li&gt;Configuring the endpoint for your code.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;the-code&quot;&gt;The code&lt;/h1&gt;

&lt;p&gt;When you’re ready with designing the next step is to put everything in our code.&lt;/p&gt;

&lt;p&gt;I recommend having a look at some of the sample code which is available on &lt;a href=&quot;https://github.com/alexa&quot;&gt;the Alexa organisation in GitHub&lt;/a&gt;. Depending on your preferences have a look at:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/alexa/skill-sample-nodejs-fact&quot;&gt;Alexa Fact Skill in NodeJS&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/alexa/skill-sample-python-fact&quot;&gt;Alexa Fact Skill in Python&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I personally work mainly with Ruby and Python, and since Ruby is not an option for AWS Lambda I’m going to be using Python.&lt;/p&gt;

&lt;p&gt;What I usually do is split the helpers, intents and main functions in separate files. This makes it more readable in my personal opinion.&lt;/p&gt;

&lt;p&gt;Have a look through the sample code and tinker around with it. You can familiarise yourself with the request and response JSON interface on the &lt;a href=&quot;https://developer.amazon.com/docs/custom-skills/request-and-response-json-reference.html&quot;&gt;Alexa developers documentation&lt;/a&gt;. The documentation details the request format (what is going to be sent to your code) and the response format (what is going to be sent back to your Alexa bot), and that is, at the end of the day, what is the most important part. The rest of the code is up to your preferences.&lt;/p&gt;

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

&lt;p&gt;You can run your code on AWS Lambda which makes it extremely simple. You can connect it easily to your Alexa bot - just provide the ARN of your Lambda function and tada, you’re done. 🎉&lt;/p&gt;

&lt;p&gt;Make sure to package your code and any extra modules you may have used to a zip file and upload it directly to Lambda or S3. You can automate it pretty easily with a Makefile or something of the sorts. The AWS documentation has a page about creating &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html&quot;&gt;NodeJS&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html&quot;&gt;Python&lt;/a&gt; deployment packages for AWS Lambda which are pretty useful.&lt;/p&gt;

&lt;h1 id=&quot;testing&quot;&gt;Testing&lt;/h1&gt;

&lt;p&gt;Its pretty easy to test your bot. Use the Alexa developers console to test your both using voice, text or JSON input. You can also connect it to an Echo device you own and test it there as well.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;So, this is how to get started building Alexa bot in a nutshell. Have fun creating awesome bots and coming up with new ideas. 😃&lt;/p&gt;
</description>
        <pubDate>Mon, 12 Mar 2018 12:01:00 +0100</pubDate>
        <link>https://vasko.io/lambda/aws/python/serverless/2018/03/12/quickstart-building-alexa-bots.html</link>
        <guid isPermaLink="true">https://vasko.io/lambda/aws/python/serverless/2018/03/12/quickstart-building-alexa-bots.html</guid>
      </item>
    
      <item>
        <title>Why I like Buildkite</title>
        <description>&lt;p&gt;&lt;img src=&quot;https://vasko.io/images/buildkite/logo.png&quot; alt=&quot;Buildkite Logo&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;buildkite-an-extremely-quick-overview&quot;&gt;Buildkite, an extremely quick overview&lt;/h1&gt;

&lt;p&gt;According to the guys @ Buildkite&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;Buildkite is a CI and build automation tool that combines the power of your own build infrastructure with the convenience of a managed, centralised web UI. The open source agent is installable on any machine or network and provides a simple, repeatable process for running builds using the same tools you use for development and production. Buildkite’s centralised web service handles job distribution, agent monitoring, integration with GitHub and Slack, and provides everyone on your team with an elegant interface for monitoring builds, tailing logs and downloading artefacts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can imagine it like a tool which allows you to do CI, automate deployments and updates by utilising your own scripts and build steps on your own infrastructure.&lt;/p&gt;

&lt;p&gt;So, with that really quick intro out of the way, let me explain why I like Buildkite.&lt;/p&gt;

&lt;h1 id=&quot;script-and-automate-all-the-things&quot;&gt;Script and Automate All the Things&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://vasko.io/images/memes/allthethings.jpg&quot; alt=&quot;Script and Automate All the Things&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Build steps are usually defined in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildkite.yml&lt;/code&gt; file in the repository for which a pipeline was created. Usually the very first step is configured directly using the Buildkite web-UI - that would be the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildkite-agent pipeline upload&lt;/code&gt; step which uploads the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildkite.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;That would look something like this:&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;stuff&apos;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;docker&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-t&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;my_app:$BUILDKITE_COMMIT&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;.&apos;&lt;/span&gt;

  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;wait&lt;/span&gt;

  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;label &apos;Run CI stuff&apos;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;docker&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;my_app:$BUILDKITE_COMMIT&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;random_test_script.sh&apos;&lt;/span&gt;

  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;label &apos;Run even more CI stuff&apos;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;docker&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;my_app:$BUILDKITE_COMMIT&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;random_test_script2.sh&apos;&lt;/span&gt;

  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;wait&lt;/span&gt;

  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;label &apos;Push&apos;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;docker&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;my_app:$BUILDKITE_COMMIT&apos;&lt;/span&gt;

  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Deploy&quot;&lt;/span&gt;

  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Deploy&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;docker&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--rm=true&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;my_app:$BUILDKITE_COMMIT&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;random_deploy_script.sh&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this example we assume that we’re building a Docker container for our app, then we run our test scripts, we push it and we run or deploy scripts. Now, the thing is, this is pretty static. And yes, we have already automated a lot - testing, deploying, etc, however maybe we don’t want to run the same scripts in every scenario. We may want to run some extra CI stuff or even change our deploy script.&lt;/p&gt;

&lt;p&gt;What we’re already doing is already really useful, but we can optimise it even more.&lt;/p&gt;

&lt;p&gt;For example, we can dynamically generate our build steps every time we run a build. Instead of our first step being &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildkite-agent pipeline upload&lt;/code&gt; we can make a script that generates our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildkite.yml&lt;/code&gt; and then have our first step be something like this: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ruby generate_script.rb | buildkite-agent pipeline upload&lt;/code&gt;. Buildkite already provides us with a lot of useful ENV variables, such as the commit SHA, build ID, etc, so we can make our build script compare between commits, see if there is something extra we need to do this time (for example a database migration before a deploy) and automatically generate our build steps accordingly. Imagine integrating such a system with a Slack bot - you could deploy with a simple command from your #devops channel. :smiley:&lt;/p&gt;

&lt;h1 id=&quot;nodes-for-buildkite&quot;&gt;Nodes for Buildkite&lt;/h1&gt;
&lt;p&gt;Buildkite agents run on your own infrastructure, this means that you can easily automate it’s scaling in the cloud. For example if you use bigger nodes and your run the Buildkite agent in Docker you can automatically start more Docker containers with the Buildkite agent, which will allow you to run more builds at the same time. In AWS you can configure an autoscaling group which can scale in and out when required. This means that you don’t need to run any Buildkite agents if you don’t have anything to build. Furthermore, if you provision your infrastructure with Terraform you can easily update anything (for example the Buildkite agent) by adjusting the launch configuration of your autoscaling group.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;As a whole you can see what you can do with Buildkite. I use it both for personal projects, such as this blog, and at work. It integrates really well with your workflows and is highly customisable. It is definitely for anyone who wants a good CI tool with some cool functionality.&lt;/p&gt;
</description>
        <pubDate>Thu, 14 Sep 2017 17:41:00 +0200</pubDate>
        <link>https://vasko.io/devops/aws/2017/09/14/why-i-like-buildkite.html</link>
        <guid isPermaLink="true">https://vasko.io/devops/aws/2017/09/14/why-i-like-buildkite.html</guid>
      </item>
    
      <item>
        <title>Orchestrating the Orchestration</title>
        <description>&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Docker with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-compose&lt;/code&gt; is an amazing combination for local development and testing, but it’s not something you would simple use on it’s own when running containers in production, and especially in distributed environments. We want to automate as much as possible so that everything can be done with one simple command in Slack. (And yes, chatops is quite the efficient way of working with your environments.) When we’re working with (really) big environments it’s no longer enough to have deployment scripts that SSH to each node, or tools like “capistrano”.&lt;/p&gt;

&lt;p&gt;So, what can we do about inefficient deployments, and as a whole, production environments?&lt;/p&gt;

&lt;h1 id=&quot;enter-kubernetes&quot;&gt;Enter Kubernetes&lt;/h1&gt;
&lt;p&gt;After poking around a couple of other solutions, such as smarm mode in Docker, Kubernetes felt like the more &lt;em&gt;mature&lt;/em&gt;, optimisable and scalable option. And although it has it’s upsides, it comes with a lot of quirks.&lt;/p&gt;

&lt;p&gt;In order to get Kubernetes to qualify for production you need to do a couple of things yourself.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Plan it’s deployment (Terraform, scripts, etc.)&lt;/li&gt;
  &lt;li&gt;Configure monitoring tools (Heapster, InfluxDB, Grafana)&lt;/li&gt;
  &lt;li&gt;Configure logging tools (Fluentd, Elasticsearch, Kibana)&lt;/li&gt;
  &lt;li&gt;Configure RBAC access control&lt;/li&gt;
  &lt;li&gt;Set up autoscaling&lt;/li&gt;
  &lt;li&gt;Figure out updating&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you only deploy Kubernetes by itself you basically get a really fancy environment which can do a lot for you, but it will be insecure, prone to failure and tedious to manage.&lt;/p&gt;

&lt;p&gt;Now, the question is - weren’t orchestration tools supposed to make it easy for us to work with distributed production environments? To be honest, that’s pretty idealistic. In the current state Kubernetes requires manual maintenance and although it does not necessarily mean that it is complicated, but why can’t we automate it?&lt;/p&gt;

&lt;h1 id=&quot;personal-experience&quot;&gt;Personal experience&lt;/h1&gt;
&lt;p&gt;In the company I currently work for we ended up crating a step-by-step plan for upgrading Kuberentes. It basically consists of&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;SSH-ing to every node and updating the running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubelet&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Updating the cloud-config of the worker autoscaling group in AWS and replacing the master nodes one by one with the new cloud-config&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you can see this can be a tedious process. It requires SSH-ing to nodes which work production loads and updating a lot of configurations. This is already quite the risk. The last thing we want to do is SSH to nodes and manually update them.&lt;/p&gt;

&lt;h1 id=&quot;tectonic-by-coreos&quot;&gt;Tectonic by CoreOS&lt;/h1&gt;
&lt;p&gt;Tectonic is actually a pretty nifty solution for managing Kubernetes. You can use it to deploy a Kubernetes cluster with Terraform (yes, Tectonic uses Terraform), update it, manage the nodes and also work with Kubernetes itself - manage deployments, services, etc.&lt;/p&gt;

&lt;p&gt;The software comes with a CLI and GUI installers for deploying Kubernetes and a handy dashboard for further management of the working cluster.&lt;/p&gt;

&lt;p&gt;What I personally think is really nice is the built-in Prometheus monitoring for your cluster, so you don’t have to worry with the whole Heapster and InfluxDB setup. If anyone has had to deal with setting up RBAC authorisation in Kubernetes, you’de be happy to hear that you can manage that via Tectonic too.&lt;/p&gt;

&lt;h1 id=&quot;orchestrating-the-orchestration&quot;&gt;Orchestrating the orchestration&lt;/h1&gt;
&lt;p&gt;Now, my question is - why isn’t Kubernetes shipped with Tectonic by default? A whole extra layer of orchestration has been added for the purpose of orchestrating our orchestration tool. It is kinda funny for me to see that so many systems exist on top of each other when it can all be boiled down to one. I think it would be amazing if Kubernetes just shipped with Tectonic by default and we would not have to worry about all of the management.&lt;/p&gt;

&lt;p&gt;For anyone that would like to start using Kubernetes in production - take a look at Tectonic. 😃&lt;/p&gt;
</description>
        <pubDate>Fri, 25 Aug 2017 21:37:00 +0200</pubDate>
        <link>https://vasko.io/aws/docker/kubernetes/2017/08/25/orchestrating-the-orchestration.html</link>
        <guid isPermaLink="true">https://vasko.io/aws/docker/kubernetes/2017/08/25/orchestrating-the-orchestration.html</guid>
      </item>
    
      <item>
        <title>Terraform and IAM</title>
        <description>&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;In my previous post I talked about deploying a Jekyll blog on AWS and I mentioned the possibility to manage the IAM configuration (which I then explained how it can be done via the AWS console) with Terraform. So, let’s have a look.&lt;/p&gt;

&lt;p&gt;There is a solid reason why people use the infrastructure-as-code approach. Not only can we keep everything documented and version-controlled, but we can also do all of our management from the comfort of the CLI.&lt;/p&gt;

&lt;p&gt;Of course, there are other infrastructure-as-code implementations, such as &lt;a href=&quot;https://puppet.com&quot;&gt;Puppet&lt;/a&gt;, but I personally use &lt;a href=&quot;https://www.terraform.io&quot;&gt;Terraform&lt;/a&gt;, mainly because of it’s simplicity and capabilities.&lt;/p&gt;

&lt;p&gt;If you are new to Terraform I advise you the check it’s documentation and play around with it. It’s definitely worth it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: In this post I will not be talking about setting up and configuring Terraform.&lt;/em&gt;&lt;/p&gt;

&lt;h1 id=&quot;making-the-iam-policy&quot;&gt;Making the IAM policy&lt;/h1&gt;
&lt;p&gt;If you want to easily generate an IAM policy you can use the Policy Generator, located in the “Create Policy” section of your IAM dashboard.&lt;/p&gt;

&lt;p&gt;We want our deployer to have the following permissions:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Create and manage CloudFront distributions&lt;/li&gt;
  &lt;li&gt;Create and manage S3 buckets&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These options are quite permissive, but if we want to limit them we have to do some parts of the deployment process manually, like:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Creating an S3 bucket&lt;/li&gt;
  &lt;li&gt;Creating a CloudFront distribution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m fine with the deployer having the permissions to create CloudFront distributions and S3 buckets, so for now I’ll allow it to have all permissions for S3 and CloudFront.&lt;/p&gt;

&lt;p&gt;You can play around with the policy generator and when you’re ready review your policy. Mine looks like this:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2012-10-17&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Statement&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Sid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;GENERATED_SID&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cloudfront:*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Sid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;GENERATED_SID&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;s3:CreateBucket&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;refining-the-policy-for-terraform-usage&quot;&gt;Refining the policy for Terraform usage&lt;/h2&gt;
&lt;p&gt;Terraform will take care for generating IDs, etc. so we can remove the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sid&lt;/code&gt; fields from our JSON.&lt;/p&gt;

&lt;p&gt;You’ll end up having something like this:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2012-10-17&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Statement&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cloudfront:*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;s3:CreateBucket&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;the-terraform-part-of-everything&quot;&gt;The Terraform part of everything&lt;/h1&gt;
&lt;p&gt;Now we can make our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.tf&lt;/code&gt; files, which will define what Terraform should do.&lt;/p&gt;

&lt;p&gt;What we’re going to need is:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;An account&lt;/li&gt;
  &lt;li&gt;A user policy&lt;/li&gt;
  &lt;li&gt;An IAM access key&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;user&quot;&gt;User&lt;/h2&gt;
&lt;p&gt;That’s pretty simple, I have the following configuration:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;resource&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;aws_iam_user&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;blog_deployer&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;blog_deployer&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;iam-access-key&quot;&gt;IAM Access Key&lt;/h2&gt;
&lt;p&gt;This would look something like this:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;resource&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;aws_iam_access_key&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;blog_deployer_access_key&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;${aws_iam_user.blog_deployer.name}&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;pgp_key&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;base&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-64&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;encoded&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;PGP&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;key&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By adding your PGP public key you can then get the IAM user’s secret key from Terraform.&lt;/p&gt;

&lt;h2 id=&quot;iam-user-policy&quot;&gt;IAM User Policy&lt;/h2&gt;
&lt;p&gt;This is what your user policy should look like in Terraform:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;resource&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;aws_iam_user_policy&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;blog_deployer_user_policy&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;blog_deployer_user_policy&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;${aws_iam_user.blog_deployer.name}&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;policy&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;&amp;lt;EOF&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2012-10-17&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Statement&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cloudfront:*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;s3:CreateBucket&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;output&quot;&gt;Output&lt;/h2&gt;
&lt;p&gt;There are a couple of ways to get the IAM user’s access ID and secret key, the easiest of all being to just output it to the console, which I would not recommend since it’s totally not secure.&lt;/p&gt;

&lt;p&gt;You can output the user’s ID by including this in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.tf&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;${aws_iam_access_key.blog_deployer_access_key.id}&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For outputting your secret key add the following:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;secret&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;${aws_iam_access_key.blog_deployer_access_key.encrypted_secret}&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To get the secret key in a secure way run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;terraform output secret&lt;/code&gt; and then you can decrypt it.&lt;/p&gt;

&lt;h2 id=&quot;applying-the-terraform-configuration&quot;&gt;Applying the Terraform configuration&lt;/h2&gt;
&lt;p&gt;If you’re working in a new directory remember to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;terraform init&lt;/code&gt; to download the Terraform AWS plugin.&lt;/p&gt;

&lt;p&gt;When you’re ready you can run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;terraform plan&lt;/code&gt; and you should see something like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Refreshing Terraform state in-memory prior to plan...

Plan: 3 to add, 0 to change, 0 to destroy.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Check to make sure that we’re deploying the correct configuration and then run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;terraform apply&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You’ll see the following when Terraform has applied everything:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Outputs:

access key = &amp;lt;ACCESS_KEY&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;That’s how you can deploy an IAM user with an attached user policy with Terraform. You can use the provisioned user with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s3_website&lt;/code&gt; to deploy to S3 and CloudFront.&lt;/p&gt;
</description>
        <pubDate>Sat, 05 Aug 2017 17:53:00 +0200</pubDate>
        <link>https://vasko.io/aws/terraform/2017/08/05/terraform-and-iam.html</link>
        <guid isPermaLink="true">https://vasko.io/aws/terraform/2017/08/05/terraform-and-iam.html</guid>
      </item>
    
      <item>
        <title>Jekyll, S3 &amp; CloudFront</title>
        <description>&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;I’ve been poking around with Jekyll in my free time and I have to say I really enjoy working with it. It, unlike other platforms, such as Ghost, can not only be deployed easily, but you can version control it with Git and automate a lot of the work.&lt;/p&gt;

&lt;p&gt;I am planning, in future posts, to have a look at automating Jekyll deployment. A script triggered after a new push is something that I find really cool.&lt;/p&gt;

&lt;p&gt;From what I’ve noticed a decent chunk of people host their blogs on GitHub Pages, which, although a decent service, still lacks SSL on own domains. I, myself, have the urge to always SSL web traffic, so I decided to have a look for a different hosting method.&lt;/p&gt;

&lt;h1 id=&quot;enter-aws&quot;&gt;Enter AWS&lt;/h1&gt;
&lt;p&gt;I work with AWS quite a lot, both for my work and school, and it is the platform I am most familiar with. Keeping in mind how cheap and scalable S3 is, especially for hosting static websites, I think it’s a pretty decent option for hosting a Jekyll blog.&lt;/p&gt;

&lt;p&gt;So, this is basically how I deployed my blog:&lt;/p&gt;

&lt;h1 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h1&gt;
&lt;ol&gt;
  &lt;li&gt;Have a jekyll blog&lt;/li&gt;
  &lt;li&gt;Have an AWS account&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;provision-a-deployer-account-in-iam&quot;&gt;Provision a deployer account in IAM&lt;/h1&gt;
&lt;p&gt;It is a good idea to make an IAM account for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s3_website&lt;/code&gt; with only the needed permissions. I would personally not like it if it had full permissions to my AWS account.&lt;/p&gt;

&lt;p&gt;I will be talking about managing AWS with Terraform in future posts, so for now we’ll just use the AWS console.&lt;/p&gt;

&lt;h2 id=&quot;creating-an-iam-policy&quot;&gt;Creating an IAM policy&lt;/h2&gt;
&lt;p&gt;So, let’s go ahead and create an IAM policy for our deployer.&lt;/p&gt;

&lt;p&gt;In your AWS console hit the “Create Policy” button in IAM -&amp;gt; Policies and select the Policy Generator option. The Policy Generator is a super easy tool for making IAM policies by just selection the resources and actions that should be allowed to be used.&lt;/p&gt;

&lt;p&gt;I did not refine the policies that much, and yes, I really should, but just for starters I came up with the following policy:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: [
        {
            &quot;Sid&quot;: &quot;&amp;lt;GENERATED_SID&amp;gt;&quot;,
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;s3:*&quot;
            ],
            &quot;Resource&quot;: [
                &quot;arn:aws:s3:::vasko.io&quot;
            ]
        },
        {
            &quot;Sid&quot;: &quot;&amp;lt;GENERATED_SID&amp;gt;&quot;,
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;cloudfront:*&quot;
            ],
            &quot;Resource&quot;: [
                &quot;*&quot;
            ]
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, when you’re done, review your policy, test it out, give it a name and hit “Create Policy”.&lt;/p&gt;

&lt;h2 id=&quot;creating-an-iam-account&quot;&gt;Creating an IAM account&lt;/h2&gt;
&lt;p&gt;So, after we’re done with the policy we can proceed with creating the account. In IAM go to “Users” and hit “Add User”. Give it a recognisable name, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s3_website_deployer&lt;/code&gt; or something of the sorts.&lt;/p&gt;

&lt;p&gt;Please make sure to tick the “Programmatic access” checkbox at “Access type”.&lt;/p&gt;

&lt;p&gt;Next give it your permission by selecting “Attach existing polices directly” and searching for your policy.&lt;/p&gt;

&lt;p&gt;Now you can review and create your account. In the final screen you will be presented with the ID and secret key, which you need to copy to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s3_website.yml&lt;/code&gt; config file.&lt;/p&gt;

&lt;h2 id=&quot;creating-a-certificate-in-certificate-manager&quot;&gt;Creating a certificate in “Certificate Manager”&lt;/h2&gt;
&lt;p&gt;NOTE: Make sure you’re in the N. Virginia region for this.&lt;/p&gt;

&lt;p&gt;We can provision a certificate for your CloudFront distribution for free from the AWS Certificate Manager.&lt;/p&gt;

&lt;p&gt;Go to Certificate Manager from your dashboard and hit “Request a certificate”, type in your domain, review and request. AWS will send you a mail for approval.&lt;/p&gt;

&lt;p&gt;After you’ve approved it you can go back to your preferred region.&lt;/p&gt;

&lt;h1 id=&quot;configuring-s3_website&quot;&gt;Configuring &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s3_website&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;First have a look at the &lt;a href=&quot;https://github.com/laurilehmijoki/s3_website&quot;&gt;official repo on GitHub&lt;/a&gt;. You can find most of the information you need there, but just to sum up the deployment process, here is what you need to do.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Install the gem by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem install s3_website&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd&lt;/code&gt; to the directory where your blog is&lt;/li&gt;
  &lt;li&gt;Run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s3_website cfg create&lt;/code&gt; to generate the configuration file&lt;/li&gt;
  &lt;li&gt;Put your AWS credentials by either:
    &lt;ul&gt;
      &lt;li&gt;Copy-pasting your access credentials&lt;/li&gt;
      &lt;li&gt;Using ENV variables&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Put your S3 bucket name&lt;/li&gt;
  &lt;li&gt;Configure which files should be excluded from download by listing them under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exclude_from_upload&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Configure CloudFront&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;configuring-credentials&quot;&gt;Configuring Credentials&lt;/h2&gt;
&lt;p&gt;I ended up with the following as my configuration:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;ss&quot;&gt;s3_id: &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%= ENV[&apos;AWS_ID&apos;] %&amp;gt;
s3_secret: &amp;lt;%=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;AWS_SECRET&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configuring-s3&quot;&gt;Configuring S3&lt;/h2&gt;
&lt;p&gt;For S3 make sure to put your&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;S3 bucket name (if it does not exist yet it will make it for out)&lt;/li&gt;
  &lt;li&gt;S3 endpoint(if you wish to use something else than the default one)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should end up having something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;ss&quot;&gt;s3_bucket: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;s3_endpoint: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;west&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configuring-files-to-be-excluded-from-upload&quot;&gt;Configuring files to be excluded from upload&lt;/h2&gt;
&lt;p&gt;You probably don’t want anything extra to be uploaded than just your blog, so we can just remove some files from the upload list. For example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;ss&quot;&gt;exclude_from_upload:
  &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rakefile&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configuring-cloudfront&quot;&gt;Configuring CloudFront&lt;/h2&gt;
&lt;p&gt;You do not have to add a CloudFront distribution ID yet, since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s3_website&lt;/code&gt; will make a new one for you. You should, however, configure the CloudFront default cache behaviour, aliases and invalidations. I have the following configuration:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;ss&quot;&gt;cloudfront_distribution_config:
  default_cache_behavior:
    min_ttl: &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%= 60 * 60 * 24 %&amp;gt;
  aliases:
    quantity: 1
    items:
      - vasko.io

cloudfront_invalidate_root: true
cloudfront_wildcard_invalidation: true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After applying the configuration, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s3_website&lt;/code&gt; will present you with a prompt asking whether you want to use CloudFront or not. You can type in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Y&lt;/code&gt; and you will be given your CloudFront distribution ID. Then you can add it to the config file.&lt;/p&gt;

&lt;h3 id=&quot;cloudfront-ssl&quot;&gt;CloudFront SSL&lt;/h3&gt;
&lt;p&gt;When all of that is done go to CloudFront in your AWS dashboard and locate your distribution. From there you can hit the “Edit” button and configure SSL by selecting “Custom SSL Certificate” and then picking the correct certificate for your domain.&lt;/p&gt;

&lt;h3 id=&quot;restrict-s3-access&quot;&gt;Restrict S3 access&lt;/h3&gt;
&lt;p&gt;Also, you can block access to the S3 bucket from the outside, so that people can only access your blog via CloudFront. You can do that by going to your CloudFront distribution in your AWS console -&amp;gt; “Origins”. Select the default origin and edit it. You will see that you get the option to “Restrict Bucket Access”, so go ahead and choose “yes”. Then create a new identity and choose “Yes, Update Bucket Policy”. CloudFront will automatically update the S3 bucket’s policy.&lt;/p&gt;

&lt;p&gt;If the option to restrict bucket access is not available click on “Origin Domain Name” and re-select the S3 bucket that you’re using to host the blog.&lt;/p&gt;

&lt;p&gt;Now, after CloudFront has updated the S3 policy, you will find out that you can still browse to it. That’s because CloudFront added the restricting policy, but it never removed the allowing policy. To fix that go to your S3 bucket in the AWS dashboard -&amp;gt; Permissions -&amp;gt; Bucket Policy. Remove the block that allows public access and leave only the CloudFront Origin Access Identity and save it.&lt;/p&gt;

&lt;p&gt;Your end file should look something like this:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
    &quot;Version&quot;: &quot;2008-10-17&quot;,
    &quot;Statement&quot;: [
        {
            &quot;Sid&quot;: &quot;2&quot;,
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Principal&quot;: {
                &quot;AWS&quot;: &quot;arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity &amp;lt;CLOUDFRONT_ID&amp;gt;&quot;
            },
            &quot;Action&quot;: &quot;s3:GetObject&quot;,
            &quot;Resource&quot;: &quot;arn:aws:s3:::&amp;lt;BUCKET&amp;gt;/*&quot;
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;deploying-your-blog&quot;&gt;Deploying your blog&lt;/h1&gt;
&lt;p&gt;Now, after all of the configuring is done we can go ahead and deploy our blog.&lt;/p&gt;

&lt;p&gt;We need to do the following:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Generate our blog by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll build&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle exec jekyll build&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Push the website to S3 by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s3_website push&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Give CloudFront some time to run the invalidation and then browse to your blog. 🎉&lt;/p&gt;

&lt;h1 id=&quot;so-is-it-ready-yet&quot;&gt;So, is it ready yet?&lt;/h1&gt;
&lt;p&gt;Yes, yes it is. 😃 Your blog should now be accessible via your own domain. Any time you add more content just follow the deployment steps from above and your blog will be updated.&lt;/p&gt;

&lt;p&gt;In future posts I will also look into automating the process with deployment scripts and Terraform.&lt;/p&gt;

&lt;p&gt;So, how do you deploy your blog?&lt;/p&gt;
</description>
        <pubDate>Thu, 03 Aug 2017 19:30:00 +0200</pubDate>
        <link>https://vasko.io/jekyll/aws/2017/08/03/jekyll-s3-cloudfront.html</link>
        <guid isPermaLink="true">https://vasko.io/jekyll/aws/2017/08/03/jekyll-s3-cloudfront.html</guid>
      </item>
    
  </channel>
</rss>
