<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>AWS on Mark Wolfe&#39;s Blog</title>
    <link>https://www.wolfe.id.au/tags/aws/</link>
    <description>Recent content in AWS on Mark Wolfe&#39;s Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Thu, 11 Apr 2024 22:07:22 +1000</lastBuildDate><atom:link href="https://www.wolfe.id.au/tags/aws/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>What you should consider when storing datasets in s3</title>
      <link>https://www.wolfe.id.au/2024/04/11/what-you-should-consider-when-storing-datasets-in-s3/</link>
      <pubDate>Thu, 11 Apr 2024 22:07:22 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2024/04/11/what-you-should-consider-when-storing-datasets-in-s3/</guid>
      <description>&lt;p&gt;As an &lt;a href=&#34;https://aws.amazon.com&#34;&gt;Amazon Web Services (AWS)&lt;/a&gt; developer, I am often asked what is the best way to organise datasets in &lt;a href=&#34;https://aws.amazon.com/s3/&#34;&gt;S3&lt;/a&gt;. A dataset could comprise data exported by business systems, or data emitted by AWS services, such as &lt;a href=&#34;https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/AccessLogs.html&#34;&gt;CloudFront logs&lt;/a&gt;, or &lt;a href=&#34;https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-working-with-log-files.html&#34;&gt;CloudTrail logs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Far too often I have seen datasets just dumped into one massive S3 bucket, and left for someone else to tidy up later, however with a little consideration, and empathy for those dealing with this in the future, we can do better than this.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>As an <a href="https://aws.amazon.com">Amazon Web Services (AWS)</a> developer, I am often asked what is the best way to organise datasets in <a href="https://aws.amazon.com/s3/">S3</a>. A dataset could comprise data exported by business systems, or data emitted by AWS services, such as <a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/AccessLogs.html">CloudFront logs</a>, or <a href="https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-working-with-log-files.html">CloudTrail logs</a>.</p>
<p>Far too often I have seen datasets just dumped into one massive S3 bucket, and left for someone else to tidy up later, however with a little consideration, and empathy for those dealing with this in the future, we can do better than this.</p>
<h1 id="start-by-asking-a-few-questions">Start By Asking a few questions</h1>
<p>When I am planning to store a dataset in s3 I typically ask a few questions, one thing to note is I am focused on the semantics of the data, and the business, not just the bucket(s) technical configuration at this stage.</p>
<h2 id="what-will-consume-this-information">What will consume this information?</h2>
<p>What I am trying to understand here is whether this dataset has any known consumers, with the AWS logs example, this may be an ingestion tool like <a href="https://www.splunk.com/">Splunk</a>, which is easier to integrate with if there are a few aggregate buckets.</p>
<p>For datasets which are exported from other systems, or transformed for use in an application, or with an integration it may be easier to combine them into one bucket, especially if other factors I cover in the next few questions aren&rsquo;t a concern.</p>
<p>As you will see in my following questions, this is a trade off, and I would also review other points below to determine which is the best approach in the long run.</p>
<h2 id="what-is-the-classification-for-the-data">What is the classification for the data?</h2>
<p>My goal here is to consider the sensitivity of the data, and how it could affect who is granted access.</p>
<p>Keeping sensitive datasets isolated in their own bucket makes it easier to add controls, and simplifies auditing as there is only one top level identifier, i.e., the bucket name.</p>
<p>One thing to avoid is mixing different data classifications in one bucket, as you then need to tag all data in that bucket at the highest classification, which could complicate granting access to the data.</p>
<p>For an example of data classifications, this is a five-tiered commercial data classification approach provided in this book <a href="https://www.pearsonitcertification.com/articles/article.aspx?p=30287&amp;seqNum=9">CISSP Security Management and Practices</a>:</p>
<ul>
<li>Sensitive</li>
<li>Confidential</li>
<li>Private</li>
<li>Proprietary</li>
<li>Public</li>
</ul>
<p>These classifications would be assigned to a tag, such named <code>Classification</code> on your bucket, for more on this see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-tagging.html">Categorizing your storage using tags</a>.</p>
<p>In general I recommend keeping different classifications of data separated, for example having raw data and anonymised, or cleaned data in the same bucket is <strong>not</strong> a good idea.</p>
<h2 id="what-are-the-cost-implications-for-keeping-this-dataset">What are the cost implications for keeping this dataset?</h2>
<p>The aim with this question is to understand how cost will be managed for a dataset, there are a couple of factors here, the size of the data, and how much churn will occur for the dataset, either in the form of reads or updates to the data.</p>
<p>For datasets which grow quickly, it may be easier to isolate them in their own bucket, as reporting cost for this dataset is easier, and cost control mechanisms such as lifecycle policies, or disabling/enabling versioning simpler to apply.</p>
<p>For more information on optimising storage costs, see <a href="https://aws.amazon.com/s3/cost-optimization/">Optimizing costs for Amazon S3</a>.</p>
<h2 id="what-is-the-likely-growth-of-this-dataset-in-6-to-12-months">What is the likely growth of this dataset in 6 to 12 months?</h2>
<p>This question is related to the previous cost question, but I am trying to understand how challenging the dataset will be to handle over time. External factors such as traffic spikes for log datasets, which are often outside your control, should be taken into consideration as well.</p>
<p>There are two dimensions to this, the size of the data, and the number of objects in the dataset, both can have an impact on how difficult to wrangle the dataset will be in the future, and how much it will cost to move, or backup.</p>
<p>For more information on how to monitor and manage dataset growth in Amazon S3 I recommend digging into <a href="https://aws.amazon.com/s3/storage-lens/">Amazon S3 Storage Lens</a>.</p>
<h1 id="summary">Summary</h1>
<p>As a general rule, I would recommend keeping datasets in separate buckets, with each bucket containing data of a single classification, and ideally a single purpose. This will help to simplify cost control, and make it easier to manage the data in the future.</p>
<p>Getting things right from the start will enable you to make the most of your datasets, which is a potential differentiator for your business in this new era of cloud computing, data engineering and AI.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Avoid accidental exposure of authenticated Amazon API Gateway resources</title>
      <link>https://www.wolfe.id.au/2023/11/12/avoid-accidental-exposure-of-authenticated-amazon-api-gateway-resources/</link>
      <pubDate>Sun, 12 Nov 2023 08:55:22 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2023/11/12/avoid-accidental-exposure-of-authenticated-amazon-api-gateway-resources/</guid>
      <description>&lt;p&gt;I have been working with &lt;a href=&#34;https://aws.amazon.com/api-gateway/&#34;&gt;Amazon API Gateway&lt;/a&gt; for a while and one thing I noticed is there are a few options for authentication, which can be confusing to developers, and lead to security issues. This post will cover one of the common security pitfalls with API Gateway and how to mitigate it.&lt;/p&gt;
&lt;p&gt;If your using &lt;code&gt;AWS_IAM&lt;/code&gt; authentication on an API Gateway, then make sure you set the default authorizer for all API resources. This will avoid accidental exposing an API if you mis-configure, or omit an authentication method for an API resource as the default is &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I have been working with <a href="https://aws.amazon.com/api-gateway/">Amazon API Gateway</a> for a while and one thing I noticed is there are a few options for authentication, which can be confusing to developers, and lead to security issues. This post will cover one of the common security pitfalls with API Gateway and how to mitigate it.</p>
<p>If your using <code>AWS_IAM</code> authentication on an API Gateway, then make sure you set the default authorizer for all API resources. This will avoid accidental exposing an API if you mis-configure, or omit an authentication method for an API resource as the default is <code>None</code>.</p>
<p>In addition to this there is a way to apply a resource policy to an API Gateway, which will enforce a specific iam access check on all API requests. Combining the override to default authorizer, and the resource policy allows us to apply multiply layers of protection to our API, allowing us to follow the principle of defense in depth.</p>
<p>So to summarise, to protect your API with IAM authentication is as follows:</p>
<ol>
<li>Enable a default authorizer method on the API Gateway resource.</li>
<li>Enable an authentication method on the API.</li>
<li>Assign an API resource policy which requires IAM authentication to access the API.</li>
</ol>
<p>Doing this with <a href="https://aws.amazon.com/serverless/sam/">AWS SAM</a> is fairly straight forward, to read more about it see the <a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-apiauth.html">SAM ApiAuth documentation</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">  </span><span class="nt">AthenaWorkflowApi</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="l">AWS::Serverless::Api</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="l">...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">Auth</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c"># Specify a default authorizer for the API Gateway API to protect against missing configuration</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">DefaultAuthorizer</span><span class="p">:</span><span class="w"> </span><span class="l">AWS_IAM</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="c"># Configure Resource Policy for all methods and paths on an API as an extra layer of protection</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">ResourcePolicy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="c"># The AWS accounts to allow</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">AwsAccountWhitelist</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">           </span>- !<span class="l">Ref AWS::AccountId</span><span class="w">
</span></span></span></code></pre></div><p>Through the magic of AWS SAM this results in a resource policy which looks like the following, this results in all the API methods being protected and only accessible by users authenticated to this account, and only where they are granted access via an IAM policy.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;Version&#34;</span><span class="p">:</span> <span class="s2">&#34;2012-10-17&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;Statement&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;Effect&#34;</span><span class="p">:</span> <span class="s2">&#34;Allow&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;Principal&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;AWS&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:iam::123456789012:root&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;Action&#34;</span><span class="p">:</span> <span class="s2">&#34;execute-api:Invoke&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;Resource&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:execute-api:us-west-2:123456789012:abc123abc1/Prod/POST/athena/run_s3_query_template&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;Effect&#34;</span><span class="p">:</span> <span class="s2">&#34;Allow&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;Principal&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;AWS&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:iam::123456789012:root&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;Action&#34;</span><span class="p">:</span> <span class="s2">&#34;execute-api:Invoke&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;Resource&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:execute-api:us-west-2:123456789012:abc123abc1/Prod/POST/athena/run_query_template&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>I typically use an openapi spec to define the API, using the extensions provided by AWS such as <code>x-amazon-apigateway-auth</code> to define the authorisation.</p>
<p>With the default authentication set to <code>AWS_IAM</code> hitting an API which is missing <code>x-amazon-apigateway-auth</code> using curl returns the following error.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span><span class="nt">&#34;message&#34;</span><span class="p">:</span><span class="s2">&#34;Missing Authentication Token&#34;</span><span class="p">}</span>
</span></span></code></pre></div><p>With default authentication disabled, and the resource policy enabled the API returns the following error, which illustrates the principle of defense in depth.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span><span class="nt">&#34;Message&#34;</span><span class="p">:</span><span class="s2">&#34;User: anonymous is not authorized to perform: execute-api:Invoke on resource: arn:aws:execute-api:us-east-1:********9012:abc123abc1/Prod/POST/athena/run_query_template&#34;</span><span class="p">}</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    
    <item>
      <title>RIP AWS Go Lambda Runtime</title>
      <link>https://www.wolfe.id.au/2023/08/09/rip-aws-go-lambda-runtime/</link>
      <pubDate>Wed, 09 Aug 2023 08:55:22 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2023/08/09/rip-aws-go-lambda-runtime/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://aws.amazon.com/&#34;&gt;Amazon Web Services (AWS)&lt;/a&gt; is &lt;a href=&#34;https://aws.amazon.com/blogs/compute/migrating-aws-lambda-functions-from-the-go1-x-runtime-to-the-custom-runtime-on-amazon-linux-2/&#34;&gt;deprecating the &lt;code&gt;go1.x&lt;/code&gt; runtime on Lambda&lt;/a&gt;, this is currently scheduled for December 31, 2023. Customers need to migrate their Go based lambda functions to the &lt;code&gt;al2.provided&lt;/code&gt; runtime, which uses &lt;a href=&#34;https://aws.amazon.com/amazon-linux-2/&#34;&gt;Amazon Linux 2&lt;/a&gt; as the execution environment. I think this is a bad thing for a couple of reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There is no automated migration path from existing &lt;a href=&#34;https://go.dev&#34;&gt;Go&lt;/a&gt; Lambda functions to the new custom runtime. Customers will need to manually refactor and migrate each function to this new runtime, which this is time-consuming and error-prone.&lt;/li&gt;
&lt;li&gt;This will remove &lt;code&gt;Go1.x&lt;/code&gt; name from the lambda console, Go will now just be another &amp;ldquo;custom&amp;rdquo; runtime instead of a first class supported language. This makes Go development on Lambda seem less official/supported compared to other languages like Node, Python, Java etc.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Case in point, try searching for &amp;ldquo;al2.provided lambda&amp;rdquo; on Google and see how little documentation comes up compared to &amp;ldquo;go1.x lambda&amp;rdquo;. The migration essentially removes the branding and discoverability of Go as a Lambda language, I am sure this will improve over time, but it is still ambiguous.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://aws.amazon.com/">Amazon Web Services (AWS)</a> is <a href="https://aws.amazon.com/blogs/compute/migrating-aws-lambda-functions-from-the-go1-x-runtime-to-the-custom-runtime-on-amazon-linux-2/">deprecating the <code>go1.x</code> runtime on Lambda</a>, this is currently scheduled for December 31, 2023. Customers need to migrate their Go based lambda functions to the <code>al2.provided</code> runtime, which uses <a href="https://aws.amazon.com/amazon-linux-2/">Amazon Linux 2</a> as the execution environment. I think this is a bad thing for a couple of reasons:</p>
<ol>
<li>There is no automated migration path from existing <a href="https://go.dev">Go</a> Lambda functions to the new custom runtime. Customers will need to manually refactor and migrate each function to this new runtime, which this is time-consuming and error-prone.</li>
<li>This will remove <code>Go1.x</code> name from the lambda console, Go will now just be another &ldquo;custom&rdquo; runtime instead of a first class supported language. This makes Go development on Lambda seem less official/supported compared to other languages like Node, Python, Java etc.</li>
</ol>
<p>Case in point, try searching for &ldquo;al2.provided lambda&rdquo; on Google and see how little documentation comes up compared to &ldquo;go1.x lambda&rdquo;. The migration essentially removes the branding and discoverability of Go as a Lambda language, I am sure this will improve over time, but it is still ambiguous.</p>
<p>There are articles on the advantages of the <code>al2.provided</code> runtime, including how to migrate functions over to it, such as <a href="https://www.capitalone.com/tech/cloud/custom-runtimes-for-go-based-lambda-functions/">https://www.capitalone.com/tech/cloud/custom-runtimes-for-go-based-lambda-functions/</a>.</p>
<h1 id="why-is-this-hard">Why is this hard?</h1>
<p>The main reason migrating Go Lambda functions to the new runtime is difficult is because:</p>
<ol>
<li>Unlike the runtime provided for other languages, the custom runtime doesn&rsquo;t use the <code>Handler</code> parameter to determine the function entry point, this value is ignored, but still required. This is a subtle difference can cause issues if developers are unaware or don&rsquo;t read the documentation closely.</li>
<li>The lambda service doesn&rsquo;t check if the bootstrap entry point exists in the archive, so customers may deploy broken functions if they don&rsquo;t validate this. Sadly, this is NOT very intuitive, and often leads to confusion and errors.</li>
</ol>
<p><strong>Note:</strong> As pointed out by <a href="https://twitter.com/__steele">@Aidan W Steele</a> some deployment tools upload empty archives, then later replace them with an updated archive containing the deployed code, so this could be problematic.</p>
<p>For those interested in what the error looks like if you&rsquo;re missing the bootstrap file, it will return:</p>
<pre tabindex="0"><code>{&#34;errorType&#34;:&#34;Runtime.InvalidEntrypoint&#34;,&#34;errorMessage&#34;:&#34;RequestId: d604d105-51be-49ce-8457-eee1641398eb Error: Couldn&#39;t find valid bootstrap(s): [/var/task/bootstrap /opt/bootstrap]&#34;}
</code></pre><p>If you see this, you need to validate your deployment package contains the required <code>bootstrap</code> file in the root of the zip archive.</p>
<h1 id="why-is-removing-go-1x-a-bad-idea">Why is removing Go 1.x a bad idea?</h1>
<p>There will be no <code>Go</code> Lambda runtime available after this date, this will be more of an issue for developers who have never used AWS and expect lambda to have a Go runtime available out of the box. This is a change that will require some education and guidance for new developers.</p>
<p>Some of the drawbacks of this are:</p>
<ol>
<li>You won&rsquo;t be able to see Go functions directly in the Lambda console anymore. Go will just be another &ldquo;custom&rdquo; runtime instead of a first class supported language like Node, Python, Java etc. This makes Go development on Lambda seem less official/supported.</li>
<li>Developers will find samples or projects using the old Go 1.x runtime that no longer work out of the box. This will lead to confusion as they try to migrate those functions over to the new runtime.</li>
<li>Listing lambda functions by runtime used will no longer show &ldquo;Go1.x&rdquo; making it less clear if a function was written for Go or another language like Rust or Nim that also use the custom runtime.</li>
<li>Finding code samples for Go lambda functions on GitHub or tutorials will need to specify if they are using the old or new runtime. A lot of existing content will be outdated immediately.</li>
</ol>
<h1 id="what-can-aws-do-better">What can AWS do better?</h1>
<p>So what could AWS do to mitigate some of these issues? Here are a few suggestions:</p>
<ol>
<li>Provide an updated <code>go1.al2</code>, which would match the pattern of Java <a href="https://aws.amazon.com/blogs/compute/migrating-aws-lambda-functions-to-al2/">update <code>java8.al2</code> runtime announced a few years ago</a>. This updated runtime would use the same entry point convention as the other languages like Node, Python etc and retain the existing user experience, avoiding the hard coded <code>bootstrap</code> file which is not very intuitive.</li>
<li>Add validation to the deployment process to check for the required bootstrap file, and prevent deployment of invalid archives. This would avoid broken functions being deployed.</li>
</ol>
<p>I am disappointed that AWS did not invest a bit more time in listening to customers around the usability of the <code>al2.provided</code> runtime. Customers are used to compiling applications to a binary with a descriptive name, then deploying that binary to AWS, having to output a specific file called <code>bootstrap</code> is not very intuitive or discoverable.</p>
<h1 id="examples">Examples</h1>
<p>To illustrate the differences I have included some examples, hopefully this helps those not familiar with lambda see the challenges.</p>
<h2 id="building">Building</h2>
<p>This is an example compile command for go based function prior to migration, this will build all commands using the name of the directory as their binary name, then zip up all the binaries with a name ending in <code>-lambda</code>.</p>
<pre tabindex="0"><code>build:
  CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags=&#34;-s -w&#34; -trimpath -o dist ./cmd/...

archive:
  cd dist &amp;&amp; zip -X -9 ./deploy.zip *-lambda
</code></pre><p>With this migration, developers will need to package each of their functions to include a bootstrap file, and upload each archive to s3 individually rather than zipping multiple binaries together.</p>
<h2 id="deployment-configuration-examples">Deployment Configuration Examples</h2>
<p>This is an example sam template for a go based function prior to migration:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">  </span><span class="nt">ExampleFunction</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="l">AWS::Serverless::Function</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">Runtime</span><span class="p">:</span><span class="w"> </span><span class="l">go1.x</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c"># this is a example archive containing one or more go binary files</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">CodeUri</span><span class="p">:</span><span class="w"> </span><span class="l">../../dist/deploy.zip  </span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c"># note example is the name of the compiled go binary file</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">Handler</span><span class="p">:</span><span class="w"> </span><span class="l">example-lambda</span><span class="w">
</span></span></span></code></pre></div><p>This is an example sam template for a go based function after migration:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">  </span><span class="nt">ExampleFunction</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="l">AWS::Serverless::Function</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">Runtime</span><span class="p">:</span><span class="w"> </span><span class="l">provided.al2</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c"># example archive which must contain a file named bootstrap, </span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c"># which is not referenced or checked during deploy.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">CodeUri</span><span class="p">:</span><span class="w"> </span><span class="l">../../dist/example_Linux_arm64.zip</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c"># unused by this runtime but still required and can </span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c"># cause some confusion with developers if not aware</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">Handler</span><span class="p">:</span><span class="w"> </span><span class="l">nope </span><span class="w">
</span></span></span></code></pre></div><h1 id="closing-thoughts">Closing Thoughts</h1>
<p>While the custom runtime provides better performance, and an updated operating system, the change will require effort for many Go developers on AWS Lambda. Some automated assistance and validation from AWS could help reduce friction and issues from this change.</p>
<p>Personally I am sad to see AWS lambda remove Go as a first class language, as an early adopter of serverless it felt great to have Go supported out of the box. I will miss seeing the gopher logo when browsing functions! 😞🪦</p>
<p>Overall, I think this will negatively the adoption of Go in AWS lambda, at least in the short term, as a lot of developers will find the custom runtime requirements unfamiliar and confusing compared to other runtimes.</p>
<p>As is often the case, new developers will likely struggle most with the <code>provided.al2</code>, then most likely give up and use another language instead of taking the time to understand the custom runtime complexities.</p>
<p>What are your thoughts on the migration and how AWS could improve the experience?</p>
<h1 id="updates">Updates</h1>
<p>Thanks to <a href="https://twitter.com/__steele">@Aidan W Steele</a> for the feedback on my <code>go2.x</code> suggestion with a much better one of <code>go1.al2</code> which would match the pattern of <code>java8.al2</code>, and reminder of the various empty zip file shenanigans used in some deployment tools.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Stop using IAM User Credentials with Terraform Cloud</title>
      <link>https://www.wolfe.id.au/2023/07/17/stop-using-iam-user-credentials-with-terraform-cloud/</link>
      <pubDate>Mon, 17 Jul 2023 07:55:22 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2023/07/17/stop-using-iam-user-credentials-with-terraform-cloud/</guid>
      <description>&lt;p&gt;I recently started using &lt;a href=&#34;https://www.terraform.io/&#34;&gt;Terraform Cloud&lt;/a&gt; but discovered that the &lt;a href=&#34;https://developer.hashicorp.com/terraform/tutorials/cloud-get-started/cloud-create-variable-set#create-a-variable-set&#34;&gt;getting started tutorial&lt;/a&gt; which describes how to integrate it with &lt;a href=&#34;https://aws.amazon.com/&#34;&gt;Amazon Web Services (AWS)&lt;/a&gt; suggested using &lt;a href=&#34;https://aws.amazon.com/iam/features/managing-user-credentials/&#34;&gt;IAM user credentials&lt;/a&gt;. This is not ideal as these credentials are long-lived and can lead to security issues.&lt;/p&gt;
&lt;h2 id=&#34;what-is-the-problem-with-iam-user-credentials&#34;&gt;What is the problem with IAM User Credentials?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;IAM User Credentials are long lived, meaning once compromised they allow access for a long time&lt;/li&gt;
&lt;li&gt;They are static, so if leaked it is difficult to revoke access immediately&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But there are better alternatives, the one I recommend is &lt;a href=&#34;https://openid.net/developers/how-connect-works/&#34;&gt;OpenID Connect (OIDC)&lt;/a&gt;, which if you dig deep into the Terraform Cloud docs is a supported approach. This has a few benefits:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I recently started using <a href="https://www.terraform.io/">Terraform Cloud</a> but discovered that the <a href="https://developer.hashicorp.com/terraform/tutorials/cloud-get-started/cloud-create-variable-set#create-a-variable-set">getting started tutorial</a> which describes how to integrate it with <a href="https://aws.amazon.com/">Amazon Web Services (AWS)</a> suggested using <a href="https://aws.amazon.com/iam/features/managing-user-credentials/">IAM user credentials</a>. This is not ideal as these credentials are long-lived and can lead to security issues.</p>
<h2 id="what-is-the-problem-with-iam-user-credentials">What is the problem with IAM User Credentials?</h2>
<ul>
<li>IAM User Credentials are long lived, meaning once compromised they allow access for a long time</li>
<li>They are static, so if leaked it is difficult to revoke access immediately</li>
</ul>
<p>But there are better alternatives, the one I recommend is <a href="https://openid.net/developers/how-connect-works/">OpenID Connect (OIDC)</a>, which if you dig deep into the Terraform Cloud docs is a supported approach. This has a few benefits:</p>
<ol>
<li>Credentials are dynamically created for each run, so if one set is compromised it does not affect other runs.</li>
<li>When Terraform Cloud authenticates with AWS using OIDC it will pass information about the project and run, so you can enforce IAM policies based on this context.</li>
<li>Credentials are short lived, expiring after the Terraform run completes.</li>
<li>You can immediately revoke access by removing the OIDC provider from AWS.</li>
<li>You don’t need to export credentials from AWS and manage their rotation.</li>
</ol>
<p>Overall this allows for a more secure and scalable approach to integrating Terraform Cloud with AWS. If you are just starting out, I would recommend setting up OpenID Connect integration instead of using IAM credentials.</p>
<h2 id="aws-deployment">AWS Deployment</h2>
<p>To setup the resources on the AWS side required to link AWS to Terraform Cloud we need to deploy some resources, in my case I am using a Cloudformation Template which deploy manually. You can find the source code to this template in my <a href="https://github.com/wolfeidau/terraform-cloud-aws-blog">GitHub Repo</a> along with a Terraform example to deploy the resources.</p>
<p>Using the Cloudformation template as the example for this post, it creates:</p>
<ol>
<li>IAM Role, which assumed by Terraform Cloud when deploying</li>
<li>Open ID Connect Provider, which is used to connect Terraform Cloud to AWS</li>
</ol>
<p>The Terraform Deployment role is as follows:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">  </span><span class="nt">TerraformDeploymentRole</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="l">AWS::IAM::Role</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">AssumeRolePolicyDocument</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">Statement</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- <span class="nt">Effect</span><span class="p">:</span><span class="w"> </span><span class="l">Allow</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">Action</span><span class="p">:</span><span class="w"> </span><span class="l">sts:AssumeRoleWithWebIdentity</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">Principal</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span><span class="nt">Federated</span><span class="p">:</span><span class="w"> </span>!<span class="l">Ref TerraformOIDCProvider</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">Condition</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span><span class="nt">StringEquals</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">app.terraform.io:aud</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;aws.workload.identity&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span><span class="nt">StringLike</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">app.terraform.io:sub</span><span class="p">:</span><span class="w"> </span>!<span class="l">Sub organization:${OrganizationName}:project:${ProjectName}:workspace:${WorkspaceName}:run_phase:*</span><span class="w">
</span></span></span></code></pre></div><p><strong>Note:</strong></p>
<ul>
<li>The IAM role allows Terraform Cloud to assume the role using the OIDC provider, and limits it to the given organization, project and workspace names.</li>
<li>The policy attached to this role, in my example, only allows Terraform to list s3 buckets; you should customise this based on your needs.</li>
</ul>
<p>The Open ID Connect Provider is created as follows:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">  </span><span class="nt">TerraformOIDCProvider</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="l">AWS::IAM::OIDCProvider</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">Url</span><span class="p">:</span><span class="w"> </span><span class="l">https://app.terraform.io</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">ClientIdList</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="l">aws.workload.identity</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">ThumbprintList</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="l">9e99a48a9960b14926bb7f3b02e22da2b0ab7280</span><span class="w">
</span></span></span></code></pre></div><p>Once deployed this template will provide two outputs:</p>
<ol>
<li>The role ARN for the Terraform Deployment role.</li>
<li>An Optional Audience value, this is only needed if you want to customise this value.</li>
</ol>
<h2 id="terraform-cloud-configuration">Terraform Cloud Configuration</h2>
<p>You’ll need to set a couple of environment variables in your Terraform Cloud workspace in order to authenticate with AWS using OIDC. You can set these as workspace variables, or if you’d like to share one AWS role across multiple workspaces, you can use a variable set.</p>
<table>
  <thead>
      <tr>
          <th>Variable</th>
          <th>Value</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>TFC_AWS_PROVIDER_AUTH</td>
          <td><code>true</code></td>
      </tr>
      <tr>
          <td>TFC_AWS_RUN_ROLE_ARN</td>
          <td>The role ARN from the cloudformation stack outputs</td>
      </tr>
      <tr>
          <td>TFC_AWS_WORKLOAD_IDENTITY_AUDIENCE</td>
          <td>The optional audience value from the stack outputs. Defaults to <code>aws.workload.identity</code>.</td>
      </tr>
  </tbody>
</table>
<p>Note for more advanced configuration options please refer to <a href="https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/aws-configuration">Terraform Cloud - Dynamic Credentials with the AWS Provider</a>.</p>
<p>That is it, your now ready to run plans in your Terraform Cloud workspace!</p>
<h2 id="auditing">Auditing</h2>
<p>Once you have setup both side of this solution you should be able to see events in <a href="https://aws.amazon.com/cloudtrail/">AWS CloudTrail</a>, filter by service <code>sts.amazonaws.com</code> and look at the <code>AssumeRoleWithWebIdentity</code> events. Each event will contain a record of the Terraform Cloud run, and the name of the project and workspace.</p>
<p>This is a cut down cloudtrail event showing the key information:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;userIdentity&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;WebIdentityUser&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;principalId&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:iam::12121212121212:oidc-provider/app.terraform.io:aws.workload.identity:organization:test-organization:project:Default Project:workspace:test-terraform-cloud:run_phase:plan&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;userName&#34;</span><span class="p">:</span> <span class="s2">&#34;organization:test-organization:project:Default Project:workspace:test-terraform-cloud:run_phase:plan&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;identityProvider&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:iam::12121212121212:oidc-provider/app.terraform.io&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;eventTime&#34;</span><span class="p">:</span> <span class="s2">&#34;2023-07-18T00:08:34Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;eventSource&#34;</span><span class="p">:</span> <span class="s2">&#34;sts.amazonaws.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;eventName&#34;</span><span class="p">:</span> <span class="s2">&#34;AssumeRoleWithWebIdentity&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;awsRegion&#34;</span><span class="p">:</span> <span class="s2">&#34;ap-southeast-2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;sourceIPAddress&#34;</span><span class="p">:</span> <span class="s2">&#34;x.x.x.x&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;userAgent&#34;</span><span class="p">:</span> <span class="s2">&#34;APN/1.0 HashiCorp/1.0 Terraform/1.5.2 (+https://www.terraform.io) terraform-provider-aws/5.7.0 (+https://registry.terraform.io/providers/hashicorp/aws) aws-sdk-go-v2/1.18.1 os/linux lang/go/1.20.5 md/GOOS/linux md/GOARCH/amd64 api/sts/1.19.2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;requestParameters&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;roleArn&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:iam::12121212121212:role/terraform-cloud-oidc-acces-TerraformDeploymentRole-NOPE&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;roleSessionName&#34;</span><span class="p">:</span> <span class="s2">&#34;terraform-run-abc123&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;responseElements&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;subjectFromWebIdentityToken&#34;</span><span class="p">:</span> <span class="s2">&#34;organization:test-organization:project:Default Project:workspace:test-terraform-cloud:run_phase:plan&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;assumedRoleUser&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;assumedRoleId&#34;</span><span class="p">:</span> <span class="s2">&#34;CDE456:terraform-run-abc123&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;arn&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:sts::12121212121212:assumed-role/terraform-cloud-oidc-acces-TerraformDeploymentRole-NOPE/terraform-run-abc123&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;provider&#34;</span><span class="p">:</span> <span class="s2">&#34;arn:aws:iam::12121212121212:oidc-provider/app.terraform.io&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;audience&#34;</span><span class="p">:</span> <span class="s2">&#34;aws.workload.identity&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;readOnly&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;eventType&#34;</span><span class="p">:</span> <span class="s2">&#34;AwsApiCall&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;recipientAccountId&#34;</span><span class="p">:</span> <span class="s2">&#34;12121212121212&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="links">Links</h2>
<ul>
<li><a href="https://www.wiz.io/blog/how-to-get-rid-of-aws-access-keys-part-1-the-easy-wins">How to get rid of AWS access keys - Part 1: The easy wins</a></li>
<li><a href="https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/aws-configuration">Terraform Cloud - Dynamic Credentials with the AWS Provider</a></li>
<li><a href="https://aws.amazon.com/blogs/apn/simplify-and-secure-terraform-workflows-on-aws-with-dynamic-provider-credentials/">AWS Partner Network (APN) Blog - Simplify and Secure Terraform Workflows on AWS with Dynamic Provider Credentials</a></li>
</ul>
<p>So instead of using IAM User credentials, this approach uses IAM Roles and OpenID Connect to dynamically assign credentials to Terraform Cloud runs which is a big win from a security perspective!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Automated Cloud Security Remediation</title>
      <link>https://www.wolfe.id.au/2023/02/19/automated-cloud-security-remediation/</link>
      <pubDate>Sun, 19 Feb 2023 11:00:00 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2023/02/19/automated-cloud-security-remediation/</guid>
      <description>&lt;p&gt;Recently I have been looking into automated security remediation to understand its impacts, positive and negative. As I am a user of AWS, as well other cloud services, I was particularly interested in how it helped maintain security in these environments. As with anything, it is good to understand what problem it is trying to solve and why it exists in the first place.&lt;/p&gt;
&lt;h2 id=&#34;so-firstly-what-does-automated-security-remediation-for-a-cloud-service-do&#34;&gt;So firstly what does automated security remediation for a cloud service do?&lt;/h2&gt;
&lt;p&gt;This is software which detects threats, more specifically misconfigurations of services, and automatically remediates problems.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Recently I have been looking into automated security remediation to understand its impacts, positive and negative. As I am a user of AWS, as well other cloud services, I was particularly interested in how it helped maintain security in these environments. As with anything, it is good to understand what problem it is trying to solve and why it exists in the first place.</p>
<h2 id="so-firstly-what-does-automated-security-remediation-for-a-cloud-service-do">So firstly what does automated security remediation for a cloud service do?</h2>
<p>This is software which detects threats, more specifically misconfigurations of services, and automatically remediates problems.</p>
<h2 id="how-does-automated-security-remediation-work">How does automated security remediation work?</h2>
<p>Typically, security remediation tools take a feed of events from a service such as <a href="https://aws.amazon.com/cloudtrail/">AWS CloudTrail</a> (audit logging service) and checks the configuration of the resources being modified. This is typically paired with regular scheduled scans to ensure nothing is missed in the case of dropped or missing events.</p>
<h2 id="can-you-use-iam-to-avoid-security-misconfigurations-in-the-first-place">Can you use IAM to avoid security misconfigurations in the first place?</h2>
<p>Cloud services, such as AWS, have fairly complex <a href="https://aws.amazon.com/iam/">AWS Identity and Access Management (IAM)</a> services which provide course grained security policy language called IAM policies. These policies are hard to fine tune for the myriad of security misconfigurations deployed by the people working on in these cloud services.</p>
<p>Everyone has seen something like the following administrator policy allowing all permissions for administrators of an AWS environments, this is fine for a &ldquo;sandbox&rdquo; learning account, but is far too permissive for production accounts.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">Version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;2012-10-17&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">Statement</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">Sid</span><span class="p">:</span><span class="w"> </span><span class="l">AdminAccess</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Effect</span><span class="p">:</span><span class="w"> </span><span class="l">Allow</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Action</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;*&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Resource</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;*&#39;</span><span class="w">
</span></span></span></code></pre></div><p>That said, authoring IAM policies following the least privilege to cover current requirements, new services coming online and keeping up with emerging threats can be a significant cost in time and resources, and like at some point provide diminishing returns.</p>
<h2 id="can-you-use-aws-service-control-polices-scp-to-avoid-security-misconfigurations">Can you use AWS service control polices (SCP) to avoid security misconfigurations?</h2>
<p>In AWS there is another way to deny specific operations, this comes in the for of service control policies (SCP). These policies are a part of AWS Organizations and provide another layer of control above an account&rsquo;s IAM policies, allowing administrators to target specific operations and protect common resources. Again, these are also very complex to configure and maintain, as they use the same course grained security layer.</p>
<p>Below is an example SCP which prevents any VPC that doesn&rsquo;t already have internet access from getting it.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">Version</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;2012-10-17&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">Statement</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">Effect</span><span class="p">:</span><span class="w"> </span><span class="l">Deny</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">Action</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">ec2:AttachInternetGateway</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">ec2:CreateInternetGateway</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">ec2:CreateEgressOnlyInternetGateway</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">ec2:CreateVpcPeeringConnection</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">ec2:AcceptVpcPeeringConnection</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">globalaccelerator:Create*</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">globalaccelerator:Update*</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">Resource</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;*&#34;</span><span class="w">
</span></span></span></code></pre></div><p>Investment in SCPs is important for higher level controls, such as disabling the modification of security services such as <a href="https://aws.amazon.com/guardduty/">Amazon GuardDuty</a>, <a href="https://aws.amazon.com/config/">AWS Config</a> and <a href="https://aws.amazon.com/cloudtrail/">AWS CloudTrail</a> as changes to these services may result in data loss. That said, SCPs are still dependent on IAMs course grained policy language, which in turn is limited by the service&rsquo;s integration with IAM.</p>
<p>A note about SCPs, often you will see exclusions for roles which enable administrators, or continuous integration and delivery (CI\CD) systems to bypass these policies. These should be used for exceptional situations, for example bootstrapping of services, or incidents. So, using these roles should be gated via some sort incident response process.</p>
<h3 id="so-why-does-automated-security-remediation-exist">So why does automated security remediation exist?</h3>
<p>Given the complexity of managing fine-grained security policies, organizations implement a more reactive solution, which is often in the form of automated security remediation services.</p>
<h3 id="what-are-some-of-disadvantages-of-these-automated-security-remediation-tools">What are some of disadvantages of these automated security remediation tools?</h3>
<ul>
<li>False positives and false negatives: They may generate false positives, where legitimate actions are flagged as security threats, or false negatives, where actual security issues are missed.</li>
<li>Over-reliance on automation: Organizations may become over-reliant on tools, potentially leading to complacency or a lack of human oversight, which can create new risks and vulnerabilities.</li>
<li>Limited scope: They may not be able to detect or remediate all types of security issues or vulnerabilities, especially those that are highly complex or require a more nuanced approach.</li>
<li>Compliance and regulatory issues: Some compliance and regulatory frameworks may require manual security review or approval for certain types of security incidents, which can be challenging to reconcile with automated processes.</li>
<li>Cultural resistance: Some organizations may experience cultural resistance to automated remediation, as it may be perceived as a threat to job security or the role of security professionals.</li>
<li>Delayed or dropped trigger events: Automated remediation typically primarily depend on triggers from audit events provided, these events can be delayed in large AWS environments, or by a flood of activity.</li>
</ul>
<h2 id="what-are-some-of-the-positive-impacts-automated-remediation-tools">What are some of the positive impacts automated remediation tools?</h2>
<ul>
<li>Increased efficiency: Can reduce the time and resources required to respond to security incidents, allowing security teams to focus on higher-value tasks.</li>
<li>Improved collaboration: Can help break down silos between different teams, as it often requires cross-functional collaboration between security, operations, and development teams.</li>
<li>Reduced burnout: By automating repetitive and time-consuming tasks, automated remediation can help reduce burnout among security people, who may otherwise be overwhelmed by the volume of security incidents they need to respond to manually.</li>
<li>Skills development: As organizations adopt these tools and processes, security teams may need to develop new skills and competencies in areas such as automation, scripting, and orchestration, which can have positive impacts on employee development and job satisfaction.</li>
<li>Cultural shift towards proactive security: They can help shift the culture of security within an organization from reactive to proactive, by enabling security teams to identify and remediate potential security risks before they become actual security incidents.</li>
</ul>
<h1 id="summary">Summary</h1>
<p>Overall, while automated security remediation can have some cultural and productivity impacts that need to be managed, it can also bring significant benefits to organizations by enabling more efficient, collaborative, and proactive security practices.</p>
<p>That said, automated security remediation really needs to be part of a three-pronged approach:</p>
<ol>
<li>Ensure people are working in cloud environments with only the privileges they require to do their work. There are of course exceptions to this, but they should be covered with a process which allows users to request more access when required.</li>
<li>SCPs should be used to protect security and governance services, and implement core restrictions within a collection of AWS accounts, depending on your business.</li>
<li>Automated security remediation should be used to cover all the edge cases, again this should be used only where necessary, and with the understanding it may take a period of time to fix.</li>
</ol>
<p>One thing to note is we are working in an environment with a lot of smart and resourceful people, so organizations need to watch for situations complex workarounds evolve to mitigate ineffective or complex controls otherwise they may impact morale, onboarding of staff and overall success of a business.</p>
<p>Security works best when it balances threats and usability!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>My Development Environment</title>
      <link>https://www.wolfe.id.au/2022/07/23/my-development-environment/</link>
      <pubDate>Sat, 23 Jul 2022 22:00:00 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2022/07/23/my-development-environment/</guid>
      <description>&lt;p&gt;I was inspired by others to document the tools I use working as a software developer professionally, and hacking on side projects out side of work.&lt;/p&gt;
&lt;p&gt;One thing to note is in my day job I work on an Apple Mac, but my personal machine is a Linux laptop running &lt;a href=&#34;https://pop.system76.com/&#34;&gt;PopOS&lt;/a&gt;. I find using Linux as a desktop works as most software I use is web based or supported on linux. I also use it for IoT development as pretty much all the tool chains I use supports it.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I was inspired by others to document the tools I use working as a software developer professionally, and hacking on side projects out side of work.</p>
<p>One thing to note is in my day job I work on an Apple Mac, but my personal machine is a Linux laptop running <a href="https://pop.system76.com/">PopOS</a>. I find using Linux as a desktop works as most software I use is web based or supported on linux. I also use it for IoT development as pretty much all the tool chains I use supports it.</p>
<p>On a whole over the years I have moved to a more minimal setup, primarily to keep things simple, <strong>less</strong> is easier to maintain, easier to share, and more likely to be adopted by others.</p>
<p>The stack I work with professionally is pretty varied, but can be summarized as:</p>
<ul>
<li><a href="https://aws.amazon.com/">Amazon Web Services (AWS)</a>, I work primarily this cloud platform in my day job</li>
<li><a href="https://aws.amazon.com/cloudformation/">Cloudformation</a>, native AWS infrastructure deployment</li>
<li><a href="https://go.dev">Go</a>, great language for building tools, apis, and backend services</li>
<li><a href="https://www.python.org/">Python</a>, used for cloud orchestration, scripting and machine learning</li>
<li><a href="https://nodejs.org/en/">NodeJS</a> often using <a href="https://www.typescriptlang.org/">Typescript</a>, for frontend development</li>
<li><a href="https://git-scm.com/">Git</a>, used for all things source code</li>
</ul>
<h2 id="cli-tools">CLI Tools</h2>
<p>I primarily use zsh as my shell, sticking to a pretty minimal setup tools wise.</p>
<ul>
<li><a href="https://www.docker.com/">Docker</a> for containers, which I mainly use for testing.</li>
<li><a href="https://direnv.net/">direnv</a> which is used to change environment settings in projects.</li>
<li><a href="https://github.com/ggreer/the_silver_searcher">The Silver Searcher</a> a faster search tool for the cli, <code>ag</code> is my goto for locating stuff in files when developing.</li>
<li><a href="https://github.com/cli/cli">Git Hub CLI</a>, makes working with GitHub from the CLI a dream.</li>
<li><a href="https://awscli.amazonaws.com/v2/documentation/api/latest/index.html">AWS CLI</a> is used to write scripts and diagnosing what is up with my cloud.</li>
<li><a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html">AWS SAM CLI</a> for deploying cloudformation in a semi sane way.</li>
<li><a href="https://github.com/nvm-sh/nvm">nvm</a>, nodejs changes a lot so I often need a couple of versions installed to support both new and old software.</li>
<li><a href="https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh">Git Prompt</a> for a dash more information in my shell about the current trees Git status.</li>
<li><a href="https://gnupg.org/">gnupg</a>, which I mostly use for Signing of Git commits and software, and a bit of data encryption.</li>
</ul>
<p>Most of my builds done using the good old <code>Makefile</code> so I always have <a href="https://www.gnu.org/software/make/">make</a> installed.</p>
<h2 id="editor">Editor</h2>
<p>Currently I use <a href="https://code.visualstudio.com/">vscode</a> when developing, it is one of the first things I open each day. I was a vim user but moved to vscode as I prefer to use a more approachable editor, especially as I work with developers and &ldquo;non tech&rdquo; people and they find it less daunting to learn.</p>
<p>I am trying to help <strong>everyone</strong> code, so using an approachable editor is <strong>really</strong> helpful!</p>
<p>To support the stack I use the following plugins:</p>
<ul>
<li><a href="https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker">Code Spell Checker</a>, I really hate misspelling words in my code.</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig">EditorConfig for VS Code</a>, handy way to keep things consistently formatted across editors when working in a team.</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens">GitLens — Git supercharged</a>, helps me figure out what changed and who changed it without leaving my editor.</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=golang.Go">Go</a>, primary language I develop in.</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow">indent-rainbow</a>, this addon keeps me sane when editing whitespace sensitive languages such as python and YAML!</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=ms-python.python">Python</a>, tons of stuff uses this language so I always end up using it.</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=kddejong.vscode-cfn-lint">vscode-cfn-lint</a>, avoiding obvious errors and typos in my cloudformation templates saves a ton of time and frustration.</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=wayou.vscode-todo-highlight">TODO Highlight</a>, I always try and add information and notes to my code, this helps highlight the important stuff.</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml">YAML</a>, most of the tools I deploy with use it for configuration so I need a good linter.</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=GitHub.github-vscode-theme">GitHub Theme</a>, I use the dimmed dark mode which is really nice comfortable coding theme.</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Diving into AWS Billing Data</title>
      <link>https://www.wolfe.id.au/2022/07/05/diving-into-aws-billing-data/</link>
      <pubDate>Tue, 05 Jul 2022 22:47:59 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2022/07/05/diving-into-aws-billing-data/</guid>
      <description>&lt;p&gt;Billing is an integral part of day to day &lt;a href=&#34;https://aws.amazon.com/&#34;&gt;AWS&lt;/a&gt; account operation, and to most it seems like a chore, however there is a lot to be learnt interacting with &lt;a href=&#34;https://aws.amazon.com/aws-cost-management/aws-billing/&#34;&gt;AWS Billing&lt;/a&gt; data.&lt;/p&gt;
&lt;p&gt;So why would you ever want to dive into AWS Billing data in the first place?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It is pretty easy for both novices, and experience developers to rack up a sizable bill in AWS, part of the learning experience is figuring out how this happened.&lt;/li&gt;
&lt;li&gt;The billing data itself is available in &lt;a href=&#34;https://parquet.apache.org/&#34;&gt;parquet format&lt;/a&gt;, which is a great format to query and dig into with services such as Athena.&lt;/li&gt;
&lt;li&gt;This billing data is the only way of figuring out how much a specific AWS resource costs, this again is helpful for the learning experience.&lt;/li&gt;
&lt;li&gt;The Cost Explorer in AWS is great if you just want an overview, but having SQL access to the data is better for developers looking to dive a bit deeper.&lt;/li&gt;
&lt;li&gt;The billing service has a feature which records &lt;code&gt;created_by&lt;/code&gt; for resources, this is only available in the CUR data. If you have already you can enable it via &lt;a href=&#34;https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html&#34;&gt;Cost Allocation Tags&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These points paired with the fact that a basic understanding of data wrangling in AWS is an invaluable skill to have in your repertoire.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Billing is an integral part of day to day <a href="https://aws.amazon.com/">AWS</a> account operation, and to most it seems like a chore, however there is a lot to be learnt interacting with <a href="https://aws.amazon.com/aws-cost-management/aws-billing/">AWS Billing</a> data.</p>
<p>So why would you ever want to dive into AWS Billing data in the first place?</p>
<ol>
<li>It is pretty easy for both novices, and experience developers to rack up a sizable bill in AWS, part of the learning experience is figuring out how this happened.</li>
<li>The billing data itself is available in <a href="https://parquet.apache.org/">parquet format</a>, which is a great format to query and dig into with services such as Athena.</li>
<li>This billing data is the only way of figuring out how much a specific AWS resource costs, this again is helpful for the learning experience.</li>
<li>The Cost Explorer in AWS is great if you just want an overview, but having SQL access to the data is better for developers looking to dive a bit deeper.</li>
<li>The billing service has a feature which records <code>created_by</code> for resources, this is only available in the CUR data. If you have already you can enable it via <a href="https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html">Cost Allocation Tags</a>.</li>
</ol>
<p>These points paired with the fact that a basic understanding of data wrangling in AWS is an invaluable skill to have in your repertoire.</p>
<h2 id="suggested-cur-solution">Suggested CUR Solution</h2>
<p>I have put together an automated solution which uses <a href="https://aws.amazon.com/cloudformation/">AWS CloudFormation</a> to create a <a href="https://docs.aws.amazon.com/cur/latest/userguide/what-is-cur.html">Cost and Usage Reports</a> (CUR) in your billing account with a <a href="https://aws.amazon.com/glue/">Glue</a> Table enabling querying of the latest data for each month in <a href="https://aws.amazon.com/athena/">Amazon Athena</a>. This project is on github at <a href="https://github.com/wolfeidau/aws-billing-store">https://github.com/wolfeidau/aws-billing-store</a>, follow the <code>README.md</code> to get it setup.</p>
<p>In summary it deploys:</p>
<ol>
<li>Creates the CUR in the billing service and the bucket which receives the reports.</li>
<li>Configures a Glue Database and Table for use by Athena.</li>
<li>Deploys a Lambda function to manage the partitions using  <a href="https://aws.amazon.com/eventbridge/">Amazon EventBridge</a> <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/EventBridge.html">S3 events</a>.</li>
</ol>
<p>Once deployed all you need to do is wait till AWS pushes the first report to the solution, this can take up to 8 hours in my experience, then you should be able to log into Athena and start querying the data.</p>
<figure>
    <img loading="lazy" src="/images/2022-07-02_cur_managment_diagram.png"/> <figcaption>
            CUR Solution Diagram
        </figcaption>
</figure>

<p>One thing to note is designed to be a starting point, I have released it under <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 license</a> so your welcome to pull this solution apart and integrate it into your environment.</p>
<h2 id="next-steps">Next Steps</h2>
<p>To test the solution you can start with a query which shows you <code>AmazonS3</code> costs grouped by bucket name and aggregated using <code>sum</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">line_item_resource_id</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">bucket_name</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">round</span><span class="p">(</span><span class="k">sum</span><span class="p">(</span><span class="n">line_item_blended_cost</span><span class="p">),</span><span class="w"> </span><span class="mi">4</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">cost</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">month</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">from</span><span class="w"> </span><span class="s2">&#34;raw_cur_data&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span><span class="k">year</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;2022&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">and</span><span class="w"> </span><span class="k">month</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;7&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">AND</span><span class="w"> </span><span class="n">line_item_product_code</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;AmazonS3&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">line_item_resource_id</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">month</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">cost</span><span class="w"> </span><span class="k">DESC</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>There are some great resources with other more advanced queries which provide insights from your CUR data, one of the best is <a href="https://wellarchitectedlabs.com/cost/300_labs/300_cur_queries/">Level 300: AWS CUR Query Library</a> from the <a href="https://wellarchitectedlabs.com/">The Well-Architected Labs website</a>.</p>
<p>The standout queries for me are:</p>
<ol>
<li><a href="https://wellarchitectedlabs.com/cost/300_labs/300_cur_queries/queries/security_identity__compliance/#amazon-guardduty">Amazon GuardDuty</a> - This query provides daily unblended cost and usage information about Amazon GuardDuty Usage. The usage amount and cost will be summed.</li>
<li><a href="https://wellarchitectedlabs.com/cost/300_labs/300_cur_queries/queries/storage/#amazon-s3">Amazon S3</a> - This query provides daily unblended cost and usage information for Amazon S3. The output will include detailed information about the resource id (bucket name), operation, and usage type. The usage amount and cost will be summed, and rows will be sorted by day (ascending), then cost (descending).</li>
</ol>
<h2 id="cost-allocation-tags">Cost Allocation Tags</h2>
<p>The <a href="https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html">Cost Allocation Tags</a> in billing allows you to record data which is included in the CUR. This is a great resource for attributing cost to a user, role or service, or alternatively a cloudformation stack.</p>
<p>I enable the following AWS tags for collection and inclusion in the CUR.</p>
<ul>
<li><code>aws:cloudformation:stack-name</code></li>
<li><code>aws:createdBy</code></li>
</ul>
<p>I also enable some of my own custom tags for collection and inclusion in the CUR.</p>
<ul>
<li><code>application</code></li>
<li><code>component</code></li>
<li><code>branch</code></li>
<li><code>environment</code></li>
</ul>
<p>You can see how these are added in the <a href="https://github.com/wolfeidau/aws-billing-store">https://github.com/wolfeidau/aws-billing-store</a> project <code>Makefile</code> when the stacks are launched.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Why isn&#39;t my s3 bucket secure?</title>
      <link>https://www.wolfe.id.au/2020/10/08/why-isnt-my-s3-bucket-secure/</link>
      <pubDate>Thu, 08 Oct 2020 19:30:00 +1100</pubDate>
      
      <guid>https://www.wolfe.id.au/2020/10/08/why-isnt-my-s3-bucket-secure/</guid>
      <description>&lt;p&gt;We have all read horror stories of &lt;a href=&#34;https://aws.amazon.com/s3/&#34;&gt;Amazon Simple Storage Service&lt;/a&gt; (S3) buckets being “hacked” in the popular media, and we have seen lots of work by &lt;a href=&#34;https://aws.amazon.com&#34;&gt;Amazon Web Services&lt;/a&gt; (AWS) to tighten up controls and messaging around best practices. So how do the amazon tools help you avoid some of the pitfalls with S3?&lt;/p&gt;
&lt;p&gt;Case in point, the &lt;a href=&#34;https://aws.amazon.com/cli/&#34;&gt;AWS CLI&lt;/a&gt; which a large number of engineers and developers rely on every day, the following command will create a bucket.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>We have all read horror stories of <a href="https://aws.amazon.com/s3/">Amazon Simple Storage Service</a> (S3) buckets being “hacked” in the popular media, and we have seen lots of work by <a href="https://aws.amazon.com">Amazon Web Services</a> (AWS) to tighten up controls and messaging around best practices. So how do the amazon tools help you avoid some of the pitfalls with S3?</p>
<p>Case in point, the <a href="https://aws.amazon.com/cli/">AWS CLI</a> which a large number of engineers and developers rely on every day, the following command will create a bucket.</p>
<pre tabindex="0"><code>$ aws s3 mb s3://my-important-data
</code></pre><p>One would assume this commonly referenced example which is used in a lot of the resources provided by AWS would create a bucket following the best practices. But alas no…</p>
<p>The configuration which is considered <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/security-best-practices.html">best practice for security of an S3 bucket</a> missing is:</p>
<ul>
<li>Enable Default Encryption</li>
<li>Block Public access configuration</li>
<li>Enforce encryption of data in transit (HTTPS)</li>
</ul>
<h2 id="why-is-this-a-problem">Why is this a Problem?</h2>
<p>I personally have a lot of experience teaching developers how to get started in AWS, and time and time again it is lax defaults which let this cohort down. Of course this happens a lot while they are just getting started.</p>
<p>Sure there are <a href="https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-cis-controls.html">guard rails</a> implemented using services such as AWS Security Hub, pointing out issues left right and center, but these typically identity problems which wouldn&rsquo;t be there in the first place if the tools where providing better defaults.</p>
<p>Sure there is more advanced configuration but <strong>encryption</strong> and blocking <strong>public access</strong> by default seem like a good start, and would reduce the noise of these tools.</p>
<p>The key point here is it should be hard for new developers to avoid these recommended, and recognised best practices when creating an S3 bucket.</p>
<p>In addition to this, keeping up with the ever growing list of “best practice” configuration is really impacting both velocity and morale of both seasoned, and those new the platform. Providing some tools which help developers keep up, and provide some uplift when upgrading existing infrastructure would be a boon.</p>
<p>Now this is especially the case for developers building solutions using <em>serverless</em> as they tend to use more of the AWS native services, and in turn trigger more of these “guard rails”.</p>
<p>Lastly there are a lot of developers out there who just don&rsquo;t have time to &ldquo;harden&rdquo; their environments, teams who have no choice but to ignore &ldquo;best practices&rdquo; and may benefit a lot from some uplift in this area.</p>
<h2 id="what-about-cloudformation">What about Cloudformation?</h2>
<p>To further demonstrate this issue this is s3 bucket creation in <a href="https://aws.amazon.com/cloudformation/">cloudformation</a>, which is the baseline orchestration tool for building resources, provided free of charge by AWS. This is a very basic example, as seen in a lot of projects on GitHub, and the <a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#aws-properties-s3-bucket--examples">AWS cloudformation documentation</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MyDataBucket</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="l">AWS::S3::Bucket</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">BucketName</span><span class="p">:</span><span class="w"> </span><span class="l">MyDataBucket</span><span class="w">
</span></span></span></code></pre></div><p>Now you could argue that cloudformation is doing exactly what you tell it to do, it is just a primitive layer which translates YAML or JSON into API calls to AWS, but I think again this is really letting developers down.</p>
<p>Again this is missing default encryption, and public access safe guards. Now in addition to this a lot of quality tools also recommend the following:</p>
<ul>
<li>Explicit deny of Delete* operations, good practice for systems of record</li>
<li>Enable Versioning, optional but good practice for systems of record</li>
<li>Enable object access logging, which is omitted it to keep the example brief</li>
</ul>
<p>So this is a basic example with most of these options enabled, this is quite a lot to fill in for yourself.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">     </span><span class="nt">MyDataBucket</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="l">AWS::S3::Bucket</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">DeletionPolicy</span><span class="p">:</span><span class="w"> </span><span class="l">Retain</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">UpdateReplacePolicy</span><span class="p">:</span><span class="w"> </span><span class="l">Retain</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">BucketName</span><span class="p">:</span><span class="w"> </span>!<span class="l">Ref BucketName</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">BucketEncryption</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">ServerSideEncryptionConfiguration</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span>- <span class="nt">ServerSideEncryptionByDefault</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                  </span><span class="nt">SSEAlgorithm</span><span class="p">:</span><span class="w"> </span><span class="l">AES256</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">VersioningConfiguration</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">Status</span><span class="p">:</span><span class="w"> </span><span class="l">Enabled</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">PublicAccessBlockConfiguration</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">BlockPublicAcls</span><span class="p">:</span><span class="w"> </span><span class="kc">True</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">BlockPublicPolicy</span><span class="p">:</span><span class="w"> </span><span class="kc">True</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">IgnorePublicAcls</span><span class="p">:</span><span class="w"> </span><span class="kc">True</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">RestrictPublicBuckets</span><span class="p">:</span><span class="w"> </span><span class="kc">True</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MyDataBucketPolicy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">Type</span><span class="p">:</span><span class="w"> </span><span class="l">AWS::S3::BucketPolicy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">Properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">Bucket</span><span class="p">:</span><span class="w"> </span>!<span class="l">Ref MyDataBucket</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">PolicyDocument</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">Id</span><span class="p">:</span><span class="w"> </span><span class="l">AccessLogBucketPolicy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">Version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;2012-10-17&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">Statement</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span>- <span class="nt">Sid</span><span class="p">:</span><span class="w"> </span><span class="l">AllowSSLRequestsOnly</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">Action</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                  </span>- <span class="l">s3:*</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">Effect</span><span class="p">:</span><span class="w"> </span><span class="l">Deny</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">Resource</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                  </span>- !<span class="l">Sub &#34;arn:aws:s3:::${MyDataBucket}/*&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                  </span>- !<span class="l">Sub &#34;arn:aws:s3:::${MyDataBucket}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">Condition</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                  </span><span class="nt">Bool</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                    </span><span class="nt">&#34;aws:SecureTransport&#34;: </span><span class="s2">&#34;false&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">Principal</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;*&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span>- <span class="nt">Sid</span><span class="p">:</span><span class="w"> </span><span class="l">Restrict Delete* Actions</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">Action</span><span class="p">:</span><span class="w"> </span><span class="l">s3:Delete*</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">Effect</span><span class="p">:</span><span class="w"> </span><span class="l">Deny</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">Principal</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;*&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">Resource</span><span class="p">:</span><span class="w"> </span>!<span class="l">Sub &#34;arn:aws:s3:::${MyDataBucket}/*&#34;</span><span class="w">
</span></span></span></code></pre></div><p>To do this with the AWS CLI in one command would require quite a few flags, and options, rather than including that here I will leave that exercise up to the reader.</p>
<p>Now some may say this is a great opportunity for consulting companies to endlessly uplift customer infrastructure. But this again begs the questions:</p>
<ol>
<li>Why is this the case for customers using the recommended tools?</li>
<li>What about developers getting started on their first application?</li>
<li>Wouldn&rsquo;t be better to have these consultants building something new, rather than crafting reams of YAML?</li>
</ol>
<h2 id="why-provide-resources-which-are-secure-by-default">Why Provide Resources which are Secure by Default?</h2>
<p>So I have used S3 buckets as a very common example, but there is an ever growing list of services in the AWS that I think would benefit from better default configuration.</p>
<p>Just to summarise some of the points I have made above:</p>
<ol>
<li>It would make it harder for those new to the cloud to do the wrong thing when following examples.</li>
<li>The cost of building and maintaining infrastructure would be reduced over time as safer defaults would remove the need for pages of code to deploy “secure” s3 buckets.</li>
<li>For new and busy developers things would be mostly right from the beginning, and likewise update that baseline even just for new applications, leaving them more time to do the actual work they should be doing.</li>
</ol>
<p>So anyone who is old enough to remember <a href="https://en.wikipedia.org/wiki/Solaris_%28operating_system%29">Sun Solaris</a> will recall the “secure by default” effort launched with Solaris 10 around 2005, this also came with “self healing” (stretch goal for AWS?), so security issues around defaults is not a new problem, but has been addressed before!</p>
<h2 id="follow-up-qa">Follow Up Q&amp;A</h2>
<p>I have added some of the questions I received while reviewing this article, with some answers I put together.</p>
<h4 id="will-cdk-help-with-this-problem-of-defaults">Will CDK help with this problem of defaults?</h4>
<p>So as it stands now I don&rsquo;t believe the default s3 bucket construct has any special default settings, there is certainly room for someone to make &ldquo;secure&rdquo; versions of the constructs but developers would need to search for them and that kind of misses the point of helping wider AWS user community.</p>
<h4 id="why-dont-you-just-write-your-own-cli-to-create-buckets">Why don&rsquo;t you just write your own CLI to create buckets?</h4>
<p>This is a good suggestion, however I already have my fair share of side projects, if I was to do this it would need to be championed by a orginisation, and team that got value from the effort. But again, needing to tell every new engineer to ignore the default AWS CLI as it isn&rsquo;t &ldquo;secure&rdquo; seems to be less than ideal, I really want everyone to be &ldquo;secure&rdquo;.</p>
<h4 id="how-did-you-come-up-with-this-topic">How did you come up with this topic?</h4>
<p>Well I am currently working through &ldquo;retrofitting&rdquo; best practices (the latest ones) on a bunch of aws serverless stacks which I helped build a year or so ago, this is when I asked the question why am I searching then helping to document what is &ldquo;baseline&rdquo; configuration for s3 buckets?!</p>
<h4 id="wont-this-make-the-tools-more-complicated-adding-all-these-best-practices">Won&rsquo;t this make the tools more complicated adding all these best practices?</h4>
<p>I think any uplift at all would be a bonus at the moment, I don&rsquo;t think it would be wise to take on every best practice out there, but surely the 80/20 rule would apply here. Anything to reduce the amount of retro fitting we need to do would be a good thing in my view.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>AWS Events reading list</title>
      <link>https://www.wolfe.id.au/2020/03/31/aws-events-reading-list/</link>
      <pubDate>Tue, 31 Mar 2020 04:30:00 +1100</pubDate>
      
      <guid>https://www.wolfe.id.au/2020/03/31/aws-events-reading-list/</guid>
      <description>&lt;p&gt;For some time now I have been working on internal, and some product related services which use AWS events, some of this has been paired with &lt;a href=&#34;https://docs.aws.amazon.com/appsync/latest/devguide/real-time-data.html&#34;&gt;AppSync subscriptions&lt;/a&gt;, &lt;a href=&#34;https://slack.com/&#34;&gt;slack&lt;/a&gt; and &lt;a href=&#34;https://aws.amazon.com/sns/&#34;&gt;AWS SNS&lt;/a&gt;. To help everyone come up to speed with events, and async messaging in general in a world of REST and synchronous APIs I have been compiling a list of links, which I thought I would share in a post.&lt;/p&gt;
&lt;p&gt;To start out it is helpful to have an overview, this post and the associated talk &lt;a href=&#34;https://www.youtube.com/watch?v=h46IquqjF3E&#34;&gt;Moving to event-driven architectures (SVS308-R1)&lt;/a&gt; are a good place to start.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>For some time now I have been working on internal, and some product related services which use AWS events, some of this has been paired with <a href="https://docs.aws.amazon.com/appsync/latest/devguide/real-time-data.html">AppSync subscriptions</a>, <a href="https://slack.com/">slack</a> and <a href="https://aws.amazon.com/sns/">AWS SNS</a>. To help everyone come up to speed with events, and async messaging in general in a world of REST and synchronous APIs I have been compiling a list of links, which I thought I would share in a post.</p>
<p>To start out it is helpful to have an overview, this post and the associated talk <a href="https://www.youtube.com/watch?v=h46IquqjF3E">Moving to event-driven architectures (SVS308-R1)</a> are a good place to start.</p>
<ul>
<li><a href="https://www.tbray.org/ongoing/When/202x/2020/03/07/Eventing-Facets">Tim Bray - Eventing Facets</a></li>
</ul>
<p>Then for those that want to see some code, take a look at the analytics component in this project developed by the serverless team at AWS, there are tons of great infra examples in this project. Although the code is a bit complex there is a lot to garner even if your not a Java developer.</p>
<ul>
<li><a href="https://github.com/awslabs/realworld-serverless-application">awslabs/realworld-serverless-application</a></li>
</ul>
<p>This project uses a great reusable component which takes a <a href="https://aws.amazon.com/dynamodb">AWS DynamoDB</a> stream and publishes it onto <a href="https://aws.amazon.com/eventbridge">AWS Eventbridge</a>, again if Java isn&rsquo;t your language of choice there are still some gems in here, such as the logic used to <a href="https://github.com/awslabs/aws-dynamodb-stream-eventbridge-fanout/blob/master/src/main/java/com/amazonaws/dynamodb/stream/fanout/publisher/EventBridgeRetryClient.java">retry submission of events to Eventbridge</a>.</p>
<ul>
<li><a href="https://github.com/awslabs/aws-dynamodb-stream-eventbridge-fanout">awslabs/aws-dynamodb-stream-eventbridge-fanout</a></li>
</ul>
<p>From the AWS Samples comes this project which is worth digging into, it has a bunch of simple examples with diagrams which are always a plus.</p>
<ul>
<li><a href="https://github.com/aws-samples/aws-serverless-ecommerce-platform/tree/master/orders">aws-samples/aws-serverless-ecommerce-platform</a></li>
</ul>
<p>To enable some experimentation and development this CLI tool is pretty handy.</p>
<ul>
<li><a href="https://github.com/spezam/eventbridge-cli">spezam/eventbridge-cli</a></li>
</ul>
<p>As I go I will add links and happy to take suggestions.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Getting started with Cognito?</title>
      <link>https://www.wolfe.id.au/2019/12/16/getting-started-with-cognito/</link>
      <pubDate>Mon, 16 Dec 2019 10:46:00 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2019/12/16/getting-started-with-cognito/</guid>
      <description>&lt;p&gt;The AWS &lt;a href=&#34;https://aws.amazon.com/cognito/&#34;&gt;Cognito&lt;/a&gt; product enables developers to build web or API based applications without worrying about authentication and authorisation.&lt;/p&gt;
&lt;p&gt;When setting up an applications authentication I try to keep in mind a few goals:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Keep my users data as safe as possible.&lt;/li&gt;
&lt;li&gt;Try and find something which is standards based, or supports integrating with standard protocols such as &lt;a href=&#34;https://openid.net/&#34;&gt;openid&lt;/a&gt;, &lt;a href=&#34;https://oauth.net/2/&#34;&gt;oauth2&lt;/a&gt; and &lt;a href=&#34;https://en.wikipedia.org/wiki/Security_Assertion_Markup_Language&#34;&gt;SAML&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Evaluate the authentication flows I need and avoid increasing scope and risk.&lt;/li&gt;
&lt;li&gt;Try to use a service to start with, or secondarily, an opensource project with a good security process and a healthy community.&lt;/li&gt;
&lt;li&gt;Limit any custom development to extensions, rather than throwing out the baby with the bath water.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As you can probably tell, my primary goal is to keep authentication out of my applications, I really don&amp;rsquo;t have the time or inclination to manage a handcrafted authentication solution.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The AWS <a href="https://aws.amazon.com/cognito/">Cognito</a> product enables developers to build web or API based applications without worrying about authentication and authorisation.</p>
<p>When setting up an applications authentication I try to keep in mind a few goals:</p>
<ol>
<li>Keep my users data as safe as possible.</li>
<li>Try and find something which is standards based, or supports integrating with standard protocols such as <a href="https://openid.net/">openid</a>, <a href="https://oauth.net/2/">oauth2</a> and <a href="https://en.wikipedia.org/wiki/Security_Assertion_Markup_Language">SAML</a>.</li>
<li>Evaluate the authentication flows I need and avoid increasing scope and risk.</li>
<li>Try to use a service to start with, or secondarily, an opensource project with a good security process and a healthy community.</li>
<li>Limit any custom development to extensions, rather than throwing out the baby with the bath water.</li>
</ol>
<p>As you can probably tell, my primary goal is to keep authentication out of my applications, I really don&rsquo;t have the time or inclination to manage a handcrafted authentication solution.</p>
<h3 id="what-does-aws-cognito-provide-out-of-the-box">What does AWS Cognito provide out of the box?</h3>
<p>Lets look at what we get out of the box:</p>
<ul>
<li>Storing and protecting your users data with features such as <a href="https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol">Secure Remote Password Protocol (SRP)</a>.</li>
<li>Signing up for an account with email / sms verification</li>
<li>Signing in, optionally with Multi Factor Authentication (MFA)</li>
<li>Password change and recovery</li>
<li>A number of triggers which can be used to extend the product</li>
</ul>
<h3 id="what-is-great-about-cognito">What is great about Cognito?</h3>
<p>Where AWS Cognito really shines is:</p>
<ul>
<li>Out of the box <a href="https://aws.amazon.com/compliance/services-in-scope/">compliance to standards such as SOC and PCI</a></li>
<li>Integration with a range of <a href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-social-idp.html">platform identity providers</a>, such as Google, Apple and Amazon</li>
<li>Support for integration with identity providers (IdPs) using OpenID and SAML.</li>
<li>Really easy to integrate into your application using libraries such as <a href="https://github.com/aws-amplify/amplify-js">AmplifyJS</a>.</li>
<li>AWS is managing it for a minimal cost</li>
</ul>
<h3 id="what-is-not-so-great-about-cognito">What is not so great about Cognito?</h3>
<p>Where AWS Cognito can be a challenge for developers:</p>
<ul>
<li>Can be difficult to setup, and understand some of the settings which can only be updated during creation, changing these requires you to delete and recreate your pool.</li>
<li>Per account quotas on API calls</li>
<li>A lack of search</li>
<li>No inbuilt to backup and restore the user data in your pool</li>
</ul>
<p>So how do we address some of these challenges, while still getting the value provided and being able to capitalise on it&rsquo;s security and compliance features.</p>
<h3 id="what-is-the-best-way-to-setup-cognito">What is the best way to setup Cognito?</h3>
<p>To setup Cognito I typically use one of the many open source <a href="https://aws.amazon.com/cloudformation/">cloudformation</a> templates on <a href="https://github.com/">GitHub</a>. I crafted this template some time ago <a href="https://gist.github.com/wolfeidau/70531fc1a593c0bad7fb9ebc9ae82580">cognito.yml</a>, it supports login using <code>email</code> address, and domain white listing for sign ups.</p>
<p>As a follow on from this I built a serverless application <a href="https://github.com/wolfeidau/serverless-cognito-auth">serverless-cognito-auth</a> which encapsulates a lot of the standard functionality I use in applications.</p>
<p>You can also use <a href="https://docs.aws.amazon.com/aws-mobile/latest/developerguide/mobile-hub-features.html">AWS Mobile Hub</a> or <a href="https://aws.amazon.com/amplify/">AWS Amplify</a> to bootstrap a Cognito pool for you.</p>
<p>Overall recommendations are:</p>
<ol>
<li>If your new to Cognito and want things to just work then I recommend trying <a href="https://aws.amazon.com/amplify/">AWS Amplify</a>.</li>
<li>If you are an old hand and just want Cognito the way you like it, then use one of the many prebuilt templates.</li>
</ol>
<h3 id="how-do-i-avoid-quota-related-issues">How do I avoid quota related issues?</h3>
<p>Firstly I recommend familiarising yourself with the <a href="https://docs.aws.amazon.com/cognito/latest/developerguide/limits.html">AWS Cognito Limits Page</a>.</p>
<p>I haven&rsquo;t seen an application hit request rate this more than a couple of times, and both those were related to UI bugs which continuously polled the Cognito API.</p>
<p>The one limit I have seen hit is the sign up emails per day limit, this can be a pain on launch days for apps, or when there is a spike in sign ups. If your planning to use Cognito in a startup you will need to integrate with <a href="https://aws.amazon.com/ses/">SES</a>.</p>
<h3 id="how-do-i-work-around-searching-my-user-database">How do I work around searching my user database?</h3>
<p>Out of the box cognito will only allow you to list and filter users by a list of common attributes, this doesn&rsquo;t include custom attributes, so if you add an attribute like customerId you won&rsquo;t be able to find all users with a given value.</p>
<p>This limitation makes it difficult to replace an internal database driven authentication library just using the cognito service, so for this reason I recommend adding a DynamoDB table to your application and integrating this with cognito using <a href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html">lambda triggers</a> to build your own global user store.</p>
<p>To simplify interacting with Cognito I wrote a CLI which provides some helpful commands to scan, filter, export and perform some common admin functions, you can find it at <a href="https://github.com/wolfeidau/cognito-cli">https://github.com/wolfeidau/cognito-cli</a>.</p>
<h3 id="how-do-i-back-up-my-user-pool">How do I back up my user pool?</h3>
<p>Backing up user accounts in any system is something you need to consider carefully as this information typically includes credentials as well as other sensitive data such as mobile number which is often used as a second factor for other services.</p>
<p>Currently Cognito doesn&rsquo;t provide a simple way of exporting user data, the service does however have an import function which will import users in from a CSV file.</p>
<p><strong>Note:</strong> AWS cognito doesn&rsquo;t support export user passwords, these will need to be reset after restore.</p>
<p>For some examples of tooling see <a href="https://www.npmjs.com/package/cognito-backup-restore">cognito-backup-restore</a>.</p>
<h1 id="conclusion">Conclusion</h1>
<p>If you really care about security and compliance then cognito is a great solution, it has some limitations, and gaps but these can be worked around if you want to focus your effort somewhere else.</p>
<p>Personally I think it is really important that as a developer I pick solutions which ensure my customers data is locked away as securely as possible, and ideally using a managed service.</p>
<p>You could totally roll your own authentication solution, and manage all the patching and challenges which go with that but that makes very little sense when you should probably be solving the original problem you had.</p>
<p>Authentication is a <a href="https://americanexpress.io/yak-shaving/">yak I am willing to let someone else <del>shave</del></a>  manage, and so should you, if not for your own sanity, then that of your users.</p>
<p>Lastly if your building out a web application use <a href="https://aws-amplify.github.io/amplify-js/api/">amplify-js</a>, this library makes it so easy to add Cognito authentication to your web application. I used it on <a href="https://github.com/wolfeidau/cognito-vue-bootstrap">cognito-vue-bootstrap</a> which you can also check out.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Why CDK?</title>
      <link>https://www.wolfe.id.au/2019/08/01/why-cdk/</link>
      <pubDate>Thu, 01 Aug 2019 10:46:00 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2019/08/01/why-cdk/</guid>
      <description>&lt;p&gt;Early this year amazon web services released the &lt;a href=&#34;https://aws.amazon.com/cdk/&#34;&gt;Cloud Development Kit (CDK)&lt;/a&gt; which is best summed up by a quote from the GitHub project.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The AWS Cloud Development Kit (AWS CDK) is an open-source software development framework to define cloud infrastructure in code and provision it through AWS CloudFormation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Before I go recommending this new project to anyone I most certainly need to road test it myself. This post provides a bit of background on where I work, and why I am looking into CDK, and what I love to see in the future.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Early this year amazon web services released the <a href="https://aws.amazon.com/cdk/">Cloud Development Kit (CDK)</a> which is best summed up by a quote from the GitHub project.</p>
<blockquote>
<p>The AWS Cloud Development Kit (AWS CDK) is an open-source software development framework to define cloud infrastructure in code and provision it through AWS CloudFormation.</p>
</blockquote>
<p>Before I go recommending this new project to anyone I most certainly need to road test it myself. This post provides a bit of background on where I work, and why I am looking into CDK, and what I love to see in the future.</p>
<h1 id="background">Background</h1>
<p>I have been building applications in <a href="https://aws.amazon.com/">Amazon Web Services (AWS)</a> for a number of years using as many of the services as possible to keep things lean and online, that said it doesn’t come without some overhead and many lessons learned. While working in AWS I have always chosen to stick to native tools, such as <a href="https://aws.amazon.com/cloudformation/">Cloudformation</a>, augmented by a range of deployment tools, this has means I get all the power with the inherent complexity, which grows every <a href="https://reinvent.awsevents.com/">AWS reinvent</a> conference.</p>
<p>Hiring into an organization which works very closely with AWS comes with some challenges. New hires will typically find themselves learning a lot of new services, while also grappling with Cloudformation. This can really impact a new team members productivity, and more importantly their confidence, especially when the first few PR reviews call out security issues, and subtle pitfalls around resource naming the examples they build find on the internet.</p>
<p>For this reason I have been looking at ways to reduce risk of issues in production without falling into the trap of isolating infrastructure development to a small number of &ldquo;experts&rdquo;, this is why CDK popped up on my radar. It promises to allow developers to manage to assemble stacks using reusable patterns either developed by AWS, or internally using code not <a href="https://en.wikipedia.org/wiki/YAML">YAML</a>, which in my view is a big plus.</p>
<p>In short I care more about people than I care about technology, I want it to empower those who use it, not hold them back.</p>
<h1 id="road-testing">Road Testing</h1>
<p>As I was starting to road test CDK I was fortunate enough to catch up with some of my peers from <a href="https://aws.amazon.com/partners/ambassadors/">AWS Partner Community</a> and get some good tips and anecdotes on what to dig into. Based on this I have put together some points, these are grouped into the good, the bad and the ugly.</p>
<h1 id="the-good">The Good</h1>
<ul>
<li>CDK enables developers to describe their infrastructure in code using an object model, then lets them synthesize it into Cloudformation templates.
<ul>
<li>VPC resources can be “connected” to each other, this automatically creates the required security groups, and entries in them.</li>
<li>Accessing a secret value will also update <a href="https://aws.amazon.com/iam/">IAM</a> policies, updating roles with the required policy changes.</li>
</ul>
</li>
<li>CDK automatically creates policies that narrow access down to the least privileges required to operate based on your model. This is a boon as because it is one of the most complex and time consuming aspects of crafting a Cloudformation template.</li>
<li>The Cloudformation produced by CDK has sane defaults such as:
<ul>
<li>Enables deletion protection for <a href="https://aws.amazon.com/rds/">Relational Database Service (RDS)</a> instances to avoid accidental deletion during stack updates.</li>
<li>Enables orphaning of S3 buckets which leaves them behind when a stack update occurs, therefore avoiding deletion of all your data when messing with configuration of a resource in your stack.</li>
</ul>
</li>
<li>Includes patterns which incorporate a range of best practices, helpers and security enhancements.
<ul>
<li>An example of this is the <code>LoadBalancedFargateService</code> which can deploy a build and deploy a local service using a <code>Dockerfile</code> without ever having to delve into the finer points of Elastic Container Registry (ECR), Elastic Container Service (ECS) or Application Load balancers (ALB).</li>
</ul>
</li>
<li>Personally I feel a lot more productive with CDK, I am writing less code and producing more secure, consistent infrastructure.</li>
</ul>
<h1 id="the-bad">The Bad</h1>
<ul>
<li>Although amazing, the patterns feel like black boxes, there is no way to click through into the source code of an underlying pattern and dig into how it works.
<ul>
<li>Personally I think these should illustrate how amazing this model is, and act as a spring board into developing your own modules, currently it feels like a black box.</li>
<li>Yes I can clone and dig into repositories but the whole point of this is to be here for a good time, not a long time.</li>
</ul>
</li>
<li>It is really difficult to lock down the version of CDK in your NodeJS projects once a new release has come out. If there are changes I want to skip then I have to get a lock file from an older project, which breaks as soon as I add other CDK modules.
<ul>
<li>This is a less than ideal user experience for teams who aren’t moving as fast as the CDK development team.</li>
<li>Note work is happening to sort out semver usage in cdk packages <a href="https://github.com/aws/aws-cdk/issues/3711">issue #3711</a> which is great!</li>
</ul>
</li>
<li>The whole multi language, cross compiled thing seems very limited at the moment, especially around the lack of support for sharing modules developed in languages other than Typescript.
<ul>
<li>For more information on how CDK <em>deliver polyglot libraries</em> checkout the <a href="https://github.com/aws/jsii">aws/jsii project on GitHub</a></li>
<li>Some background on <a href="https://github.com/aws/aws-cdk/issues/972#issuecomment-502715577">Python</a> experience requiring NodeJS tooling.</li>
</ul>
</li>
</ul>
<h1 id="the-ugly">The Ugly</h1>
<ul>
<li>In the current CDK I am encouraged, if not required to synthesize my templates in every AWS account I use, this is a big red flag for me.
<ul>
<li>If team member updates a service deployed a couple of month after it’s initial release there is NO guarantee the same code Cloudformation will be generated. To cover this operators will need to “stash” or archive templates for every account, before every deploy.</li>
<li>The NPM locking issues around pinning upgrades really restricts your power to ensure managed changes to Cloudformation.</li>
</ul>
</li>
</ul>
<p>This lack of reusable, easily reproducible artifacts is a bit of a show stopper for me, given the number of times I have been let down by tools which generate Cloudformation, I am loath to leap back into it for a production environment.</p>
<h1 id="summary">Summary</h1>
<p>In short I will not be putting CDK between me and a production environment until some of the reproducible challenges are addressed. Like many of my peers, I have always advocated for solid, reproducible infrastructure tooling that is as simple as possible to recover and rollback.</p>
<p>That said I will most definitely be using CDK to quickly generate Cloudformation, especially generating IAM policies with least privileged, and harvesting some of the great ideas, and tricks from the patterns.</p>
<p>I would recommend using Typescript to develop CDK scripts, this will ensure you get the most reuse and enable harvesting directly from the CDK patterns!</p>
<h2 id="contributors">Contributors</h2>
<p>Thanks to <a href="https://twitter.com/hashishrajan">Ashish Rajan @hashishrajan</a> and <a href="https://twitter.com/elrowan">Rowan Udell @elrowan</a> for reviewing this post, <a href="https://twitter.com/iann0036">Ian Mckay @iann0036</a> for starting a impromptu CDK discussion in Seattle and <a href="https://twitter.com/aaronwalker">Aaron Walker @aaronwalker</a> for being a great sounding board and walking me through some of his experience with CDK.</p>
<h2 id="example-project">Example Project</h2>
<p>My current work with CDK is mainly focused on providing infrastructure to a container based application called exitus which is hosted on <a href="https://github.com/wolfeidau/exitus">GitHub</a> with the CDK infra code <a href="https://github.com/wolfeidau/exitus/blob/master/infra/exitus.ts">exitus.ts</a>.
Ian Mckay</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Serverless Background jobs part 2</title>
      <link>https://www.wolfe.id.au/2019/05/12/serverless-background-jobs-part-2/</link>
      <pubDate>Sun, 12 May 2019 12:00:47 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2019/05/12/serverless-background-jobs-part-2/</guid>
      <description>&lt;p&gt;Step Functions allow you to build pipelines involving one or more amazon, or external service. Some examples of this are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;complex customer on boarding processes jobs which provision resources then send a welcome email&lt;/li&gt;
&lt;li&gt;billing jobs where you may need wait for payment authorisation&lt;/li&gt;
&lt;li&gt;provisioning users and setup of any resources each user may need&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;pipeline&#34;&gt;pipeline&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;In software engineering, a pipeline consists of a chain of processing elements (processes, threads, coroutines, functions, etc.), arranged so that the output of each element is the input of the next; the name is by analogy to a physical pipeline.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Step Functions allow you to build pipelines involving one or more amazon, or external service. Some examples of this are:</p>
<ul>
<li>complex customer on boarding processes jobs which provision resources then send a welcome email</li>
<li>billing jobs where you may need wait for payment authorisation</li>
<li>provisioning users and setup of any resources each user may need</li>
</ul>
<h2 id="pipeline">pipeline</h2>
<blockquote>
<p>In software engineering, a pipeline consists of a chain of processing elements (processes, threads, coroutines, functions, etc.), arranged so that the output of each element is the input of the next; the name is by analogy to a physical pipeline.</p>
</blockquote>
<p>The term pipeline is used a lot in building of software, but can refer to any chain of tasks.</p>
<p>Over the last couple of years I have used Step Functions in a range of business applications, initially with mixed success due to service limitations and trying to fit complex &ldquo;new requirements&rdquo; into the model. Over time this changed as I better understand where step functions start and end.</p>
<p>I have put together a list of tips and recommendations for those using step functions.</p>
<h3 id="start-small">Start Small</h3>
<p>Practice with a few small workflows to get started, avoid building a <a href="https://en.wikipedia.org/wiki/Rube_Goldberg_machine">Rube Goldberg machine</a>. This means starting with something you already know and refactoring it to incorporate a step function, get used to tracing issues and make sure you have all the tools and experience to operate a serverless application.</p>
<h3 id="track-executions">Track Executions</h3>
<p>Include a correlation id in all flow execution payloads, this could be seeded from Amazon correlation id included with all API gateway calls. This correlation id may be used for reruns of the state machine so don&rsquo;t use it as the execution name.</p>
<h3 id="naming-things">Naming Things</h3>
<p>Execution name should include some hints to why the flow is running, with a unique id or timestamp appended.</p>
<p>Step names should clearly indicate what this step does as this will enable devs or operations identify where errors or mistakes are occurring.</p>
<h3 id="exception-handling">Exception Handling</h3>
<p>When using <a href="https://aws.amazon.com/lambda/">Lambda</a> functions make sure you use an exception tracker such as <a href="https://www.bugsnag.com/">bugsnag</a> or <a href="https://sentry.io/welcome/">sentry</a> to make fault finding easier. This allows you to track issues over time and avoids sifting through logs looking for errors.</p>
<p>Use the retry backoff built into each step to make your flows more robust.</p>
<h3 id="logging">Logging</h3>
<p>Emit structured logs with key start and end information and use <a href="https://aws.amazon.com/cloudwatch/">cloudwatch</a> to search capture metrics, and trigger alerts based on them.</p>
<h3 id="infrastructure-automation">Infrastructure Automation</h3>
<p>As an infrastructure engineer I use Step Functions to build and deploy a number of different applications, this is mainly where:</p>
<ol>
<li>The task happens often</li>
<li>Someone owns the infrastructure and integration is required to orchestrate with external systems</li>
<li>There are a lot of &ldquo;services&rdquo; of a similar shape which need to be deployed the same way</li>
</ol>
<p>When using cloudformation make sure you use change sets, this will allow you to:</p>
<ol>
<li>Print a nice list of what will change before performing a change or create.</li>
<li>Rollback in a nicer way</li>
</ol>
<p>When cloudformation changes fail try to collect the tail of the execution events to simplify fault finding.</p>
<p>When designing flows make sure they aren&rsquo;t too generic, their structure should reflect what your automating, similar to an <a href="https://www.ansible.com/">ansible</a> playbook.</p>
<p>Build up a task modules to interface with cloudformation, and whenever possible just use that with custom cloud formation tasks.</p>
<p>Build up a library of common tasks, which can be used by lambdas. Test these thoroughly using unit and integration tests.</p>
<p>Use common sense when managing common code, don&rsquo;t dump everything in there, keep to just the most important tasks. This just results in a teams or systems having a massive boat anchor holding back, and contributing to the fragility of the entire platform.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Serverless Background jobs part 1</title>
      <link>https://www.wolfe.id.au/2019/05/11/serverless-background-jobs-part-1/</link>
      <pubDate>Sat, 11 May 2019 12:00:47 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2019/05/11/serverless-background-jobs-part-1/</guid>
      <description>&lt;p&gt;Background jobs form the backbone of a lot of modern applications, they are used to perform a range of asynchronous tasks, from image processing through to order processing, fulfillment and shipping. Wherever there is a need to dispatch some sort of task, then monitor or wait for it&amp;rsquo;s result.&lt;/p&gt;
&lt;p&gt;In the serverless space AWS Step Functions play a similar role to projects such as &lt;a href=&#34;https://github.com/collectiveidea/delayed_job&#34;&gt;delayed job&lt;/a&gt; or &lt;a href=&#34;https://github.com/resque/resque&#34;&gt;resque&lt;/a&gt; in ruby, &lt;a href=&#34;http://www.celeryproject.org/&#34;&gt;celery&lt;/a&gt; in python, but with the following differences:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Background jobs form the backbone of a lot of modern applications, they are used to perform a range of asynchronous tasks, from image processing through to order processing, fulfillment and shipping. Wherever there is a need to dispatch some sort of task, then monitor or wait for it&rsquo;s result.</p>
<p>In the serverless space AWS Step Functions play a similar role to projects such as <a href="https://github.com/collectiveidea/delayed_job">delayed job</a> or <a href="https://github.com/resque/resque">resque</a> in ruby, <a href="http://www.celeryproject.org/">celery</a> in python, but with the following differences:</p>
<ul>
<li>Built on a flexible flow definition language called <a href="https://states-language.net/spec.html">Amazon States Language</a> which is written in JSON</li>
<li>Powered by lambda, with native integration to SNS, SQS, Kinesis and API Gateway</li>
<li>Fully Managed by AWS</li>
</ul>
<h1 id="step-functions">Step Functions?</h1>
<p>AWS Step Functions provides a way of executing flows you have defined, and provides a visual representation, like a CI pipeline, showing the current state of the execution.</p>
<p>A simple task management example which polls the status of a task, and reports completion status can be seen as follows:</p>
<figure>
    <img loading="lazy" src="/images/2019-05-11_stepfunction.png"/> <figcaption>
            Step Function Example
        </figcaption>
</figure>

<h1 id="why-step-functions">Why Step Functions?</h1>
<p>So this is great but why should we decompose our workflows into functions and glue them together using a managed service?</p>
<p>There are a number of things to be gained by moving to Step Functions:</p>
<ol>
<li>Testing, you will be able to test each element in the chain and make sure it performs it&rsquo;s discreet task.</li>
<li>Decoupling, you will have broken things down into pieces of code which can be refactored, or replaced independent of each other.</li>
<li>Monitoring, given the visual nature of these pipelines you will be able to zero in on failures faster.</li>
</ol>
<p>Step Functions aren&rsquo;t the answer to every problem, but for multi step, long running jobs they are a great solution, if your fluent in the AWS ecosystem.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Using AWS DeepRacer for ROS development</title>
      <link>https://www.wolfe.id.au/2018/12/22/using-aws-deepracer-for-ros-development/</link>
      <pubDate>Sat, 22 Dec 2018 16:33:47 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2018/12/22/using-aws-deepracer-for-ros-development/</guid>
      <description>&lt;p&gt;So the &lt;a href=&#34;https://aws.amazon.com/deepracer/&#34;&gt;DeepRacer&lt;/a&gt; was released with much fanfare by &lt;a href=&#34;https://aws.amazon.com&#34;&gt;Amazon Web Services&lt;/a&gt; (AWS) at this years Reinvent conference in Las Vegas. This combines an off the shelf radio control (RC) car chassis, with an intel based compute module which has been configured to control the throttle, steering of the car. DeepRacer is powered by &lt;a href=&#34;http://wiki.ros.org/ROS/Introduction&#34;&gt;Robot Operating System&lt;/a&gt; (ROS) as a framework which is used for the internal control systems making it a very interesting device for anyone getting started in robotics.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>So the <a href="https://aws.amazon.com/deepracer/">DeepRacer</a> was released with much fanfare by <a href="https://aws.amazon.com">Amazon Web Services</a> (AWS) at this years Reinvent conference in Las Vegas. This combines an off the shelf radio control (RC) car chassis, with an intel based compute module which has been configured to control the throttle, steering of the car. DeepRacer is powered by <a href="http://wiki.ros.org/ROS/Introduction">Robot Operating System</a> (ROS) as a framework which is used for the internal control systems making it a very interesting device for anyone getting started in robotics.</p>
<p>In this post I will show how to use the DeepRacer for ROS development.</p>
<p>So why would I use DeepRacer for ROS development?</p>
<ol>
<li>Intel based so very easy to build and upload binaries / projects.</li>
<li>It works out of the box and is very well designed.</li>
<li>It will retail for 249 USD in march, given it&rsquo;s high quality components it will be very useful.</li>
<li>It is based on <a href="https://www.ubuntu.com/">Ubuntu</a> 16.04.3, and <a href="http://wiki.ros.org/kinetic">ROS Kinetic</a> which is a good solid starting point for ROS Development.</li>
</ol>
<p>Below is a picture the RC car chassis which is a really nice size.</p>
<figure>
    <img loading="lazy" src="/images/deepracer_rc_car.png"/> <figcaption>
            Base RC Car
        </figcaption>
</figure>

<h2 id="logging-into-your-deepracer">Logging into your DeepRacer</h2>
<p>Logging into the DeepRacer for the first time is very similar to the DeepLens product, plug the compute module into a monitor using a HDMI cable and a USB Keyboard and mouse, then reset the users password to some value which satisfies the complexity requirements. I believe it is at least 8 characters, one upper, lower, number and a symbol.</p>
<p><strong>Note:</strong> The username is <code>deepracer</code>.</p>
<h2 id="preparing-your-deepracer">Preparing your DeepRacer</h2>
<p>In my case I also disabled x11, and enabled SSH.</p>
<p>To permit ssh through the firewall configured on the device I ran, the server was already installed and started.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo ufw allow ssh
</span></span></code></pre></div><p>To disable the desktop environment on the next restart run the following.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo systemctl disable lightdm.service
</span></span></code></pre></div><p><strong>Note:</strong> I did this while the screen and keyboard where plugged in, then tested I could ssh to the DeepRacer from my laptop before restarting.</p>
<p>Now that you have ssh&rsquo;d into the DeepRacer using your login details, and the <code>TAG_HOSTNAME</code> is on a tag on the bottom of the car.</p>
<pre tabindex="0"><code>ssh deepracer@TAG_HOSTNAME
</code></pre><p>Before you starting to mess around on the host you probably want to disable ufw to enable access to all the services from your laptop/desktop.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo ufw disable
</span></span></code></pre></div><p>Once you have disabled the firewall your should be able to access the video stream from ROS <code>web_video_server</code> using <a href="http://TAG_HOSTNAME.local:8080/stream_viewer?topic=/video_mjpeg">http://TAG_HOSTNAME.local:8080/stream_viewer?topic=/video_mjpeg</a> where the <code>TAG_HOSTNAME</code> is on a tag on the bottom of the car. For more information on this service see <a href="http://wiki.ros.org/web_video_server">http://wiki.ros.org/web_video_server</a>.</p>
<h2 id="disable-ros-services">Disable ROS Services</h2>
<p>We are going to disable services which relate to the DeepRacer service, including the updates service so we can just use the control and media systems.</p>
<p>This is as simple as replacing <code>/opt/aws/deepracer/share/deepracer_launcher/launch/deepracer.launch</code> with content as follows, this simply comments out some of the AWS supplied services.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="cp">&lt;?xml version=&#34;1.0&#34;?&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;launch&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;node</span> <span class="na">pkg=</span><span class="s">&#34;web_video_server&#34;</span> <span class="na">type=</span><span class="s">&#34;web_video_server&#34;</span> <span class="na">name=</span><span class="s">&#34;web_video_server&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">&#34;ros_threads&#34;</span> <span class="na">value=</span><span class="s">&#34;1&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/node&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;node</span> <span class="na">name=</span><span class="s">&#34;servo_node&#34;</span> <span class="na">pkg=</span><span class="s">&#34;servo_pkg&#34;</span> <span class="na">type=</span><span class="s">&#34;servo_node&#34;</span> <span class="na">respawn=</span><span class="s">&#34;true&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;node</span> <span class="na">name=</span><span class="s">&#34;media_engine&#34;</span> <span class="na">pkg=</span><span class="s">&#34;media_pkg&#34;</span> <span class="na">type=</span><span class="s">&#34;media_node&#34;</span> <span class="na">respawn=</span><span class="s">&#34;true&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- &lt;node name=&#34;inference_engine&#34; pkg=&#34;inference_pkg&#34; type=&#34;inference_node&#34; respawn=&#34;true&#34; output=&#34;screen&#34;/&gt; --&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- &lt;node name=&#34;inference_probability&#34; pkg=&#34;inference_pkg&#34; type=&#34;inference_probability.py&#34; respawn=&#34;true&#34;/&gt; --&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- &lt;node name=&#34;model_optimizer&#34; pkg=&#34;inference_pkg&#34; type=&#34;model_optimizer_node.py&#34; respawn=&#34;true&#34; /&gt; --&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;node</span> <span class="na">name=</span><span class="s">&#34;control_node&#34;</span> <span class="na">pkg=</span><span class="s">&#34;ctrl_pkg&#34;</span> <span class="na">type=</span><span class="s">&#34;ctrl_node&#34;</span> <span class="na">respawn=</span><span class="s">&#34;true&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- &lt;node name=&#34;navigation_node&#34; pkg=&#34;ctrl_pkg&#34; type=&#34;navigation_node.py&#34; respawn=&#34;true&#34; /&gt; --&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- &lt;node name=&#34;software_update&#34; pkg=&#34;software_update_pkg&#34; type=&#34;software_update_process.py&#34; respawn=&#34;true&#34; /&gt; --&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- &lt;node name=&#34;webserver&#34; pkg=&#34;webserver_pkg&#34; type=&#34;webserver.py&#34; respawn=&#34;true&#34; /&gt; --&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/launch&gt;</span>
</span></span></code></pre></div><p>Now restart the DeepRacer service.</p>
<pre tabindex="0"><code>$ sudo systemctl restart deepracer-core.service
</code></pre><h2 id="is-this-thing-on">Is this thing on?</h2>
<p>To test whether or not we can still drive the DeepRacer around, we will explore then interface with the control node provided.</p>
<p>Now we load the ROS environment, using the AWS <code>setup.bash</code>, this will populate variables holding names and paths for services, if you have never used ROS before you may want to run through some of the <a href="http://wiki.ros.org/ROS/Tutorials">Tutorials</a>.</p>
<pre tabindex="0"><code>$ source /opt/aws/deepracer/setup.bash
</code></pre><p>Now we should just have the services we need to start working with ROS.</p>
<pre tabindex="0"><code>$ rosnode list
/control_node
/media_engine
/rosout
/servo_node
/web_video_server
</code></pre><p>Lets look at the topics which are now accepting messages.</p>
<pre tabindex="0"><code>$ rostopic list
/auto_drive
/calibration_drive
/manual_drive
/rosout
/rosout_agg
/video_mjpeg
</code></pre><p>Now we are interested in <code>/manual_drive</code> to test out the throttle and steering.</p>
<pre tabindex="0"><code>$ rostopic info /manual_drive
Type: ctrl_pkg/ServoCtrlMsg

Publishers: None

Subscribers: 
 * /control_node (http://amss-n4lp:37837/)
</code></pre><p>So we need to post a message to this topic, but we need to know the format so lets print it&rsquo;s structure.</p>
<pre tabindex="0"><code>$ rosmsg info ctrl_pkg/ServoCtrlMsg
float32 angle
float32 throttle
</code></pre><p>Now while the DeepRacer is off my desk, to stop it racing off, I run the following command which should trigger a throttle change. Note that the limit for this value is <code>0.7</code> by default, and <code>0</code> will stop it.</p>
<pre tabindex="0"><code>rostopic pub -1 /manual_drive ctrl_pkg/ServoCtrlMsg -- 0 0.3
</code></pre><p>Now we can stop the throttle by running.</p>
<pre tabindex="0"><code>rostopic pub -1 /manual_drive ctrl_pkg/ServoCtrlMsg -- 0 0
</code></pre><p>Likewise we can turn the DeepRacer to the left using the first value.</p>
<pre tabindex="0"><code>rostopic pub -1 /manual_drive ctrl_pkg/ServoCtrlMsg -- 0.9 0
</code></pre><p>And to the right.</p>
<pre tabindex="0"><code>rostopic pub -1 /manual_drive ctrl_pkg/ServoCtrlMsg -- -0.9 0
</code></pre><p>Then back to the center.</p>
<pre tabindex="0"><code>rostopic pub -1 /manual_drive ctrl_pkg/ServoCtrlMsg -- 0 0
</code></pre><p>I am really impressed with the DeepRacer so far, it is a great platform to start working with ROS at a great price, hopefully it spurs a whole raft of great robotics projects in the future. I would also love to see more detail, and hopefully source code for the services in this product as they seem to be really well thought out and could most certainly provide a spring board for future innovation.</p>
<p>In my next post we will write a ROS node which will use these services to drive the DeepRacer.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>AWS User Federation with Keycloak</title>
      <link>https://www.wolfe.id.au/2017/11/05/aws-user-federation-with-keycloak/</link>
      <pubDate>Sun, 05 Nov 2017 10:22:47 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2017/11/05/aws-user-federation-with-keycloak/</guid>
      <description>&lt;p&gt;As a user of Amazon Web Services (AWS) in large organisations I am always mindful of providing a mechanism to enable single sign on (SSO) to simplify the login process for users, enable strict controls for the organisation, and simplify on/off boarding for operations staff. As an advocate for open source I was happy find &lt;a href=&#34;http://www.keycloak.org/index.html&#34;&gt;Keycloak&lt;/a&gt;, which is developed by &lt;a href=&#34;https://www.redhat.com/en&#34;&gt;Redhat&lt;/a&gt; and is now an option for organisations looking for an open solution to identity federation with AWS.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>As a user of Amazon Web Services (AWS) in large organisations I am always mindful of providing a mechanism to enable single sign on (SSO) to simplify the login process for users, enable strict controls for the organisation, and simplify on/off boarding for operations staff. As an advocate for open source I was happy find <a href="http://www.keycloak.org/index.html">Keycloak</a>, which is developed by <a href="https://www.redhat.com/en">Redhat</a> and is now an option for organisations looking for an open solution to identity federation with AWS.</p>
<p>This post will detail how I configured Keycloak with AWS SAML federation.</p>
<p>To demonstrate Keycloak I have setup a docker-compose project which can be cloned from <a href="https://github.com/wolfeidau/keycloak-docker-compose">https://github.com/wolfeidau/keycloak-docker-compose</a>.</p>
<p>Assuming you have <a href="https://www.docker.com/docker-mac">docker for mac</a> installed you should be able to navigate to the project then run.</p>
<pre tabindex="0"><code>docker-compose up -d
</code></pre><p>Then to ensure it is all working you should be able to navigate to http://0.0.0.0:18080/auth/admin/master/console/#/realms/master.</p>
<h3 id="setup-of-the-aws-saml-client">Setup of the AWS SAML Client</h3>
<p>To simplify the automated setup we can export a client configuration file containing the AWS SAML configuration, in my case I did this in the master realm then exported it.</p>
<p>First thing you need to do is download <a href="https://signin.aws.amazon.com/static/saml-metadata.xml">https://signin.aws.amazon.com/static/saml-metadata.xml</a>, just put it in your Downloads folder.</p>
<p>Once you login navigate to clients http://0.0.0.0:18080/auth/admin/master/console/#/realms/master/clients then hit the create button and import the <code>saml-metadata.xml</code> file, then hit save.</p>
<figure>
    <img loading="lazy" src="/images/2017-11-05_keycloak-create-aws-client.png"/> <figcaption>
            Keycloak AWS Client Creation
        </figcaption>
</figure>

<p>Now configure:</p>
<ul>
<li><strong>IDP Initiated SSO URL Name</strong> to <code>amazon-aws</code></li>
<li><strong>Base URL</strong> to <code>/auth/realms/wolfeidau/protocol/saml/clients/amazon-aws</code></li>
</ul>
<figure>
    <img loading="lazy" src="/images/2017-11-05_keycloak-configure-aws-client.png"/> <figcaption>
            Keycloak AWS Client Configuration
        </figcaption>
</figure>

<p>Lastly under the Scope tab disable Full Scope Allowed, this will ensure we only pass through the roles configured in our client to AWS.</p>
<figure>
    <img loading="lazy" src="/images/2017-11-05_keycloak-configure-aws-client-scopes.png"/> <figcaption>
            Keycloak AWS Client Scope Configuration
        </figcaption>
</figure>

<p>Now you can navigate back to http://0.0.0.0:18080/auth/admin/master/console/#/realms/master/clients and hit the export button next to the aws client.</p>
<h3 id="keycloak-setup-using-admin-cli">Keycloak Setup Using Admin CLI</h3>
<p>As a big proponent of automation I really wanted to illustrate, and indeed learn how to automate setup of keycloak, hence the CLI approach.</p>
<p>To get the tools we need for this guide download keycloak from <a href="http://www.keycloak.org/downloads.html">Keycloak Downloads</a> and extract this to say <code>$HOME/Development/keycloak</code> then add <code>$HOME/Development/keycloak/bin</code> to your <code>$PATH</code> as per <a href="http://www.keycloak.org/docs/latest/server_admin/topics/admin-cli.html">Keycloak administration CLI docs</a>.</p>
<pre tabindex="0"><code>export PATH=$PATH:$HOME/Development/keycloak/bin
</code></pre><p><strong>Note:</strong> Commands which create new objects generate a unique GUID which looks like <code>6c684579-51a1-4bdf-a694-d641199874d8</code>, you will need to adjust those values in the subsequent commands.</p>
<p>Now we can use the administration CLI program to configure our keycloak service.</p>
<p>To test it out and configure your account locally.</p>
<pre tabindex="0"><code>kcadm.sh config credentials --server http://0.0.0.0:18080/auth --realm master --user admin
</code></pre><p>Create a realm, in my case I am naming this <code>wolfeidau</code>.</p>
<pre tabindex="0"><code>$ kcadm.sh create realms -s realm=wolfeidau -s enabled=true
</code></pre><p>Import the keycloak client for AWS and add it to the <code>wolfeidau</code> realm we created, the JSON file is in the <code>keycloak-docker-compose</code> project.</p>
<pre tabindex="0"><code>$ kcadm.sh create clients -r wolfeidau -s clientId=&#34;urn:amazon:webservices&#34; -s enabled=true -f urn-amazon-webservices.json
Created new client with id &#39;6c684579-51a1-4bdf-a694-d641199874d8&#39;
</code></pre><p>Create our AWS role under the AWS client, note this is an example name you will need to replace 123456789012 with your account id.</p>
<pre tabindex="0"><code>kcadm.sh create clients/6c684579-51a1-4bdf-a694-d641199874d8/roles -r wolfeidau -s &#39;name=arn:aws:iam::123456789012:role/wolfeidau-admin,arn:aws:iam::123456789012:saml-provider/docker-keycloak&#39; -s &#39;description=AWS Administration Access&#39;
Created new role with id &#39;docker-keycloak&#39;
</code></pre><p>Create a group to grant AWS administration access.</p>
<pre tabindex="0"><code>$ kcadm.sh create groups -r wolfeidau -s name=aws-admins
Created new group with id &#39;dd02ed86-dd49-47c6-bd8a-5f74844b56d0&#39;
</code></pre><p>Add a role to the group, note this is an example name you will need to replace 123456789012 with your account id.</p>
<pre tabindex="0"><code>$ kcadm.sh add-roles -r wolfeidau --gname &#39;aws-admins&#39; --cclientid &#39;urn:amazon:webservices&#39;  --rolename &#39;arn:aws:iam::123456789012:role/wolfeidau-admin,arn:aws:iam::123456789012:saml-provider/docker-keycloak&#39;
</code></pre><p>Create a user for testing.</p>
<pre tabindex="0"><code>$ kcadm.sh create users -r wolfeidau -s username=wolfeidau -s email=mark@wolfe.id.au -s enabled=true
Created new user with id &#39;eb02cbfd-fa9c-4094-a437-3a218be53fe9&#39;
</code></pre><p>Reset the users password and require update on login.</p>
<pre tabindex="0"><code>$ kcadm.sh update users/eb02cbfd-fa9c-4094-a437-3a218be53fe9/reset-password -r wolfeidau -s type=password -s value=NEWPASSWORD -s temporary=true -n
</code></pre><p>Add the user to our AWS administration group.</p>
<pre tabindex="0"><code>$ kcadm.sh update users/eb02cbfd-fa9c-4094-a437-3a218be53fe9/groups/dd02ed86-dd49-47c6-bd8a-5f74844b56d0 -r wolfeidau -s realm=wolfeidau -s userId=eb02cbfd-fa9c-4094-a437-3a218be53fe9 -s groupId=dd02ed86-dd49-47c6-bd8a-5f74844b56d0 -n
</code></pre><p>Export the metadata file required by AWS to setup the SAML provider.</p>
<pre tabindex="0"><code>$ kcadm.sh get -r wolfeidau clients/6c684579-51a1-4bdf-a694-d641199874d8/installation/providers/saml-idp-descriptor &gt; client-tailored-saml-idp-metadata.xml
</code></pre><h3 id="aws-setup">AWS Setup</h3>
<p>Create the AWS SAML Provider in your account using the metadata file exported from keycloak.</p>
<pre tabindex="0"><code>aws iam create-saml-provider --saml-metadata-document file://client-tailored-saml-idp-metadata.xml --name docker-keycloak
</code></pre><p>Deploy the cloudformation template supplied in the <code>keycloak-docker-compose</code> project, this contains the SAML SSO IAM roles and saves clicking around in the UI.</p>
<pre tabindex="0"><code>aws cloudformation create-stack --capabilities CAPABILITY_IAM --stack-name sso-roles --template-body file://sso-roles-cfn.yaml
</code></pre><p><strong>Note:</strong> You can just create the saml provider and launch the cloudformation from the AWS console.</p>
<h3 id="logging-into-aws">Logging Into AWS</h3>
<p>Now you should be ready to log into AWS using keycloak using the link http://0.0.0.0:18080/auth/realms/wolfeidau/protocol/saml/clients/amazon-aws.</p>
<h3 id="command-line-saml-authentication">Command Line SAML Authentication</h3>
<p>To enable the use of SAML by command line tools such as ansible and the AWS CLI my colleagues and I developed <a href="https://github.com/Versent/saml2aws">saml2aws</a>.</p>
<h3 id="references">References</h3>
<ul>
<li><a href="http://www.keycloak.org/docs/latest/server_admin/topics/admin-cli.html">Keycloak Admin CLI Docs</a></li>
<li><a href="http://docs.aws.amazon.com/IAM/latest/UserGuide/troubleshoot_saml.html">Troubleshooting SAML 2.0 Federation with AWS</a></li>
<li><a href="https://stories.scandiweb.com/sign-in-to-amazon-aws-using-saml-protocol-and-keycloak-as-identity-provider-e3798387de99">Sign in to Amazon AWS using SAML protocol and Keycloak as Identity Provider</a></li>
</ul>
<!-- 
Import the file into the AWS console by navigating to [IAM Identity Providers](https://console.aws.amazon.com/iam/home?region=us-west-2#/providers), click on your provider which in my case named `docker-keycloak` and click on the Upload Metadata.

![IAM Identity Providers](/images/2017-11-05_keycloak-screen-iam-identity-providers.png) -->]]></content:encoded>
    </item>
    
    <item>
      <title>So you want to use DynamoDB?</title>
      <link>https://www.wolfe.id.au/2017/05/25/so-you-want-to-use-dynamodb/</link>
      <pubDate>Thu, 25 May 2017 22:22:47 +1000</pubDate>
      
      <guid>https://www.wolfe.id.au/2017/05/25/so-you-want-to-use-dynamodb/</guid>
      <description>&lt;p&gt;Over the last few months I have been working on a project which uses &lt;a href=&#34;https://aws.amazon.com/dynamodb/&#34;&gt;DynamoDB&lt;/a&gt; almost exclusively for persistence, this has been a big challenge for everyone on the team. As a developer, most of us are comfortable using a Relational database management system (RDBMS) systems, so the move to a primitive key value store has been fun, but we have learnt a lot. To try and capture some of these learnings I have written this article, hopefully it will help those who embark on a similar journey.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Over the last few months I have been working on a project which uses <a href="https://aws.amazon.com/dynamodb/">DynamoDB</a> almost exclusively for persistence, this has been a big challenge for everyone on the team. As a developer, most of us are comfortable using a Relational database management system (RDBMS) systems, so the move to a primitive key value store has been fun, but we have learnt a lot. To try and capture some of these learnings I have written this article, hopefully it will help those who embark on a similar journey.</p>
<h2 id="why-dynamodb">Why DynamoDB?</h2>
<p>Some of the advantages DynamoDB offers:</p>
<ul>
<li>A Key/Value model where the values are any number of fields</li>
<li>Simplified data access</li>
<li>Low operational overhead</li>
<li>Cost, a well tuned DynamoDB costs a few dollars a month to operate</li>
</ul>
<p>As a developer getting starting with DynamoDB you need to know about:</p>
<ol>
<li>Eventual consistency, this is integral to how DynamoDB achieves it&rsquo;s cost, resilience and scalability. Simple things such as writing a record, then retrieving it straight afterwards require some logic to cope with records which aren&rsquo;t visible yet.</li>
<li>Performing <code>select * from Table</code> is not recommended when working with DynamoDB, this will trigger scan operations which are less efficient than other operations in DynamoDB. It should be only used on small tables.</li>
</ol>
<p>Using any key/value store can be tricky at first, especially if you’re used to relational databases. I have put together a list of recommendations and tips which will hopefully help those starting out with this product.</p>
<h2 id="retries">Retries</h2>
<p>When you insert data into DynamoDB not every shard will immediately see your data, an attempt to read the data from the table may not get the value your looking for. If your inserting a new row, then attempting to read immediately afterwards you may get an empty response.</p>
<p>To mitigate this you will need to implement retries, ideally with a back off to avoid exhausting your provisioned throughput.</p>
<p>Global secondary indexes (GSIs) further complicate this, as these are also updated eventually, in our experience even more eventually than the base table. Again be aware when inserting rows you want to access straight afterwards you may need to check if a row is present in the index with a similar retry.</p>
<h2 id="data-modelling">Data Modelling</h2>
<p>The first big thing you need to understand is that DynamoDB doesn&rsquo;t have relationships, in most cases it will be better to start by storing related data denormalised in a given record using the document feature of the client APIs. The reason we do this is it can be difficult keeping related data across tables in sync.</p>
<p>I recommend keeping everything in a single record for as long as you can.</p>
<h2 id="pagination">Pagination</h2>
<p>Although most of the clients provided by amazon have a concept of paging built in, this is really forward only, which makes building a classic paginated list quite a bit harder. This is best illustrated with some excerpts from the DynamoDB API.</p>
<p>Firstly <code>QueryInput</code> from the golang AWS SDK we have the ability to pass in an <code>ExclusiveStartKey</code>.</p>
<pre tabindex="0"><code>type QueryInput struct {
...
    // The primary key of the first item that this operation will evaluate. Use
    // the value that was returned for LastEvaluatedKey in the previous operation.
    //
    // The data type for ExclusiveStartKey must be String, Number or Binary. No
    // set data types are allowed.
    ExclusiveStartKey map[string]*AttributeValue `type:&#34;map&#34;`
...
}
</code></pre><p>And in the <code>QueryOutput</code> we have the <code>LastEvaluatedKey</code>.</p>
<pre tabindex="0"><code>type QueryOutput struct {
...
    // The primary key of the item where the operation stopped, inclusive of the
    // previous result set. Use this value to start a new operation, excluding this
    // value in the new request.
    //
    // If LastEvaluatedKey is empty, then the &#34;last page&#34; of results has been processed
    // and there is no more data to be retrieved.
    //
    // If LastEvaluatedKey is not empty, it does not necessarily mean that there
    // is more data in the result set. The only way to know when you have reached
    // the end of the result set is when LastEvaluatedKey is empty.
    LastEvaluatedKey map[string]*AttributeValue `type:&#34;map&#34;`
...
}
</code></pre><p>Given all we have are some keys, which may or may not be deleted it is very difficult to build a classic paged view.</p>
<p>So it has become clear to me we need to embrace a new strategy for displaying pages of results, luckily lots of others have run into this issue and the common pattern is to:</p>
<ol>
<li>Use infinite scrolling, similar to twitter and other social media sites.</li>
<li>Maintain the state in the client with a cache of pages which have previously been loaded.</li>
</ol>
<p>For more information on this see <a href="https://blog.codinghorror.com/the-end-of-pagination/">The End of Pagination</a>.</p>
<h2 id="sorting">Sorting</h2>
<p>Just a small note on sorting, in more complicated tables you will need to add indexes purely to sort data in a specific way.</p>
<p>Also within the AWS api sorting uses the rather interestingly named <code>ScanIndexForward</code>.</p>
<pre tabindex="0"><code>    // If ScanIndexForward is true, DynamoDB returns the results in the order in
    // which they are stored (by sort key value). This is the default behavior.
    // If ScanIndexForward is false, DynamoDB reads the results in reverse order
    // by sort key value, and then returns the results to the client.
    ScanIndexForward *bool `type:&#34;boolean&#34;`
</code></pre><h2 id="you-are-not-alone">You are not alone</h2>
<p>These challenges presented by DynamoDB not unique, NoSQL databases such as Riak, and Cassandra, share some of the same limitations, again to enable resilience and scalability. When searching for ideas, suggestions or strategies to deal with it you may find answers around these open source projects.</p>
<h2 id="in-closing">In Closing</h2>
<p>I think it is important to note that learning DynamoDB will broaden your horizons, and in some ways change the way you look at persistence, this in my view is a good thing.</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
