<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Geoff Baskwill</title>
    <link>https://geoffbaskwill.ca/</link>
    <description>Geoff Baskwill</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-ca</language>
    <lastBuildDate>Mon, 28 Oct 2024 00:00:00 +0000</lastBuildDate>
    
    <atom:link href="https://geoffbaskwill.ca/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>Custom CloudFormation resource types</title>
      <link>https://geoffbaskwill.ca/posts/custom-cloudformation-resource-types/</link>
      <pubDate>Mon, 13 Nov 2023 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/custom-cloudformation-resource-types/</guid>
      <description>&lt;p&gt;I recently had the opportunity to explore building &lt;a href=&#34;https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-types.html&#34;&gt;custom CloudFormation resource types&lt;/a&gt; as a mechanism to support a stream-aligned team. It was intriguing to play with this new-to-me tool and see how it could reduce complexity for the team.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve written before about &lt;a href=&#34;../cloudformation-custom-resources-with-step-functions/&#34;&gt;using Step Functions to build custom resources in CloudFormation&lt;/a&gt;. This builds on the &lt;a href=&#34;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html&#34;&gt;old-school custom resources mechanism&lt;/a&gt; where you provide a Lambda handler as part of your stack. This is convenient for very small or one-off duct-tape situations, but if you need more complex resource logic or if you want to provide a simple resource interface to a bunch of teams, there is a better way.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/registry.html&#34;&gt;AWS CloudFormation registry&lt;/a&gt; and the &lt;a href=&#34;https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/what-is-cloudformation-cli.html&#34;&gt;CloudFormation command-line interface&lt;/a&gt; are this better way. They allow you to write your own resource provider that will be exposed using the exact same mechanisms that CloudFormation uses for many AWS-provided resource types.&lt;/p&gt;
&lt;p&gt;You can do all kinds of super-neat things with resource types, and there is a &lt;a href=&#34;https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-develop-stabilize.html&#34;&gt;neat pattern&lt;/a&gt; to report progress when your resource may take a while to create or when there are multiple
steps to create your resource.&lt;/p&gt;
&lt;h2&gt;Batteries not always included&lt;/h2&gt;&lt;p&gt;Resource providers can &lt;a href=&#34;https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-model.html#resource-type-howto-configuration&#34;&gt;expose configuration data&lt;/a&gt;; this is super-handy if you want to attach &amp;ldquo;account-level&amp;rdquo; configuration (really region-level configuration) to your type&amp;rsquo;s handler. Unfortunately, while an API exists to programmatically set the configuration data, tragically and ironically there is no CloudFormation support for setting the configuration data on a resource type.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Because of the super-cool open way that AWS CloudFormation resource providers are built,
a person could theoretically open a pull request on the &lt;a href=&#34;https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-cloudformation&#34;&gt;aws-cloudformation/aws-cloudformation-resource-providers-cloudformation&lt;/a&gt; repository, duplicating the &lt;code&gt;aws-cloudformation-hooktypeconfig&lt;/code&gt; folder and refactoring it to implement &lt;code&gt;AWS::CloudFormation::ResourceTypeConfig&lt;/code&gt;, but I haven&amp;rsquo;t gone there yet. Probably should open a &lt;a href=&#34;https://github.com/aws-cloudformation/cloudformation-coverage-roadmap/issues&#34;&gt;roadmap issue&lt;/a&gt; for discussion first.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I used an old-school custom resource to set the configuration for my custom types. 🤦‍♂️&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>About me</title>
      <link>https://geoffbaskwill.ca/about/</link>
      <pubDate>Sun, 29 Oct 2023 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/about/</guid>
      <description>&lt;p&gt;Hi? If you&amp;rsquo;re here and not a robot, a) wow; b) ok? I&amp;rsquo;m flattered and deeply
curious about what brings you to this little corner of the Internets.&lt;/p&gt;
&lt;p&gt;Most of what I do day-to-day is not shareable or even relevant outside a very
tightly-scoped context, but sometimes I get to roll some thoughts together into
a post.&lt;/p&gt;
&lt;p&gt;I hope that what you&amp;rsquo;ll find here is useful or interesting, though the
real point of this site is to keep a bunch of the shareable material I&amp;rsquo;ve
created in one place for easier reference.&lt;/p&gt;
&lt;h2&gt;Work connections&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;m currently employed at &lt;a href=&#34;https://tackle.io&#34;&gt;Tackle.io&lt;/a&gt;, where my role is
&amp;ldquo;software architect&amp;rdquo;, which I see as more &amp;ldquo;enabling&amp;rdquo; than &amp;ldquo;stream-aligned&amp;rdquo; if
you are familiar with &lt;a href=&#34;https://teamtopologies.com/key-concepts&#34;&gt;Team Topologies&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a super-fun role but also super-hard to nail down concisely. You might
get a decent idea from the posts I&amp;rsquo;ve made here. One important aspect is that
&lt;strong&gt;I do not speak on behalf of Tackle&lt;/strong&gt;. For any official commentary, you really
need to go elsewhere.&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&#34;https://ca.linkedin.com/in/geoffbaskwill&#34;&gt;find me on LinkedIn&lt;/a&gt; if
you&amp;rsquo;re curious about my career path, though I&amp;rsquo;ll warn you that it&amp;rsquo;s pretty
sparse over there. If you&amp;rsquo;re looking for details, the best way is to get in
touch directly and we can have a chat.&lt;/p&gt;
&lt;h2&gt;Where I live&lt;/h2&gt;&lt;p&gt;I live just outside of Ottawa, Ontario, Canada, on the &lt;a href=&#34;https://www.mississippimills.ca/en/municipal-hall/land-acknowledgement-statement.aspx&#34;&gt;ancestral and unceded
territory of the Algonquin Anishinaabe Nation&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Fun times with AWS STS AssumeRole</title>
      <link>https://geoffbaskwill.ca/posts/sts-assume-role-fun-times/</link>
      <pubDate>Mon, 21 Aug 2023 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/sts-assume-role-fun-times/</guid>
      <description>&lt;p&gt;I had an AWS STS &lt;code&gt;AssumeRole&lt;/code&gt; problem today when I was working with the AWS SDK; digging
in it turned out the problem was that &lt;code&gt;AssumeRole&lt;/code&gt; was not actually being invoked. Poking
around I was unsurprised to find that &lt;a href=&#34;https://mastodon.cloud/@ben11kehoe&#34;&gt;@ben11kehoe&lt;/a&gt;
had already clearly stated the problem and GitHub user &lt;a href=&#34;https://github.com/petitout&#34;&gt;petitout&lt;/a&gt; had example Go code
with the right way to do it (&lt;a href=&#34;https://github.com/aws/aws-sdk-go-v2/issues/1382#issuecomment-1010464182&#34;&gt;link&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Sometimes you need to assume another role than your default execution role in order to
accomplish a task. You can explicitly call STS &lt;code&gt;AssumeRole&lt;/code&gt; yourself and configure the
SDK client to use the returned credentials, or you can configure your SDK client to call
&lt;code&gt;AssumeRole&lt;/code&gt; itself when it needs the credentials. I like the second way because it means
that credentials aren&amp;rsquo;t something that my code has access to.&lt;/p&gt;
&lt;p&gt;Sample code for not assuming a role correctly; you might have stumbled on this the same
way I did:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// almost certainly not what you want
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;cfg&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;LoadDefaultConfig&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WithAssumeRoleCredentialOptions&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;aro&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;stscreds&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AssumeRoleOptions&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;aro&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Client&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;stsClient&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;aro&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RoleARN&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;arn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;aro&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RoleSessionName&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;sessionName&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A person might think that the code above is right, because it has all kinds of the right
keywords that trigger pattern recognition. The comments on &lt;code&gt;WithAssumeRoleCredentialOptions&lt;/code&gt; read:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// WithAssumeRoleCredentialOptions is a helper function to construct functional
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// options that sets a function to use stscreds.AssumeRoleOptions on config&amp;#39;s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// LoadOptions. If assume role credentials options is set to nil, the assume
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// role credentials value will be ignored. If multiple WithAssumeRoleCredentialOptions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// calls are made, the last call overrides the previous call values.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I &lt;em&gt;think&lt;/em&gt; that what this actually does is &amp;hellip; you know, I truly have no idea, and don&amp;rsquo;t
intend to dig into what exactly this does. It definitely does not do what I thought it did.&lt;/p&gt;
&lt;p&gt;Sample code for probably doing what you want:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// almost certainly what you do want instead
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;cfg&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;LoadDefaultConfig&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WithCredentialsProvider&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;stscreds&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewAssumeRoleProvider&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;stsClient&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;arn&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;aro&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;stscreds&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AssumeRoleOptions&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;aro&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RoleSessionName&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;sessionName&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When the SDK needs credentials, this setup uses STS &lt;code&gt;AssumeRole&lt;/code&gt; to obtain credentials
with the STS client and role ARN that you provide. The &lt;code&gt;stsClient&lt;/code&gt; in this example can be
configured to take credentials from the environment.&lt;/p&gt;
&lt;p&gt;Hope posting this helps make the solution findable for other folks.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;re-posting and expanding on &lt;a href=&#34;https://mastodon.cloud/@geoff_baskwill/110929299668099158&#34;&gt;my original Mastodon post&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>SQS, DLQs, and KMS, oh my</title>
      <link>https://geoffbaskwill.ca/posts/sqs-dlqs-and-kms-keys-oh-my/</link>
      <pubDate>Mon, 06 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/sqs-dlqs-and-kms-keys-oh-my/</guid>
      <description>&lt;p&gt;Recently one of the teams I work with had a &lt;em&gt;fun time&lt;/em&gt; (note: it was not fun in the moment) with Amazon Simple Queue
Service (SQS), dead-letter queues (DLQs), and AWS Key Management Service (KMS).&lt;/p&gt;
&lt;p&gt;I thought I&amp;rsquo;d share because we learned something pretty important.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re new to SQS, you may be kind of aware that it&amp;rsquo;s a generalized queue
service that lets you post messages onto the queue and then process queued
messages in a handler, kind of like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/sqs-simplified.png&#34; alt=&#34;Source posting messages onto a queue that are then sent to a handler&#34; title=&#34;Source posting messages onto a queue that are then sent to a handler&#34;&gt;&lt;/p&gt;
&lt;p&gt;There is an
&lt;a href=&#34;https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventsourcemapping.html&#34;&gt;event source mapping&lt;/a&gt;
in between the queue and the handler; we&amp;rsquo;re going to gloss over that detail for
a minute.&lt;/p&gt;
&lt;p&gt;SQS is super-handy, reliable, and amazingly scalable; AWS guides us to use it
anywhere that we need to buffer communications between components of a solution.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s even a mechanism to deal with failures. You can configure a policy on
your queue so that if SQS fails to deliver&lt;sup&gt;1&lt;/sup&gt; a message to the handler
enough times, the message gets moved to another queue for special handling. This
second queue is called a &amp;ldquo;dead-letter&amp;rdquo; queue, named after the
&lt;a href=&#34;https://en.wikipedia.org/wiki/Dead_letter_mail&#34;&gt;post office concept&lt;/a&gt; where
messages that were undeliverable got sent to a special place for handling.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; &lt;em&gt;&amp;ldquo;SQS fails to deliver&amp;rdquo; is not technically accurate, as SQS does
not deliver messages, rather the event source mapping retrieves the message,
attempts to deliver it to the Lambda function, and deletes the message if the
message was handled successfully. If there was an error retrieving or
processing the message, SQS will make the message available again after the
visibility period expires. Eventually the message will expire, either after a
specified time period or after a specified number of retrievals from the
queue.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You may have a mental model of this setup that looks a bit like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/dlqs-simplified.png&#34; alt=&#34;Source posting messages onto a queue that go to a handler and a DLQ for handling&#34; title=&#34;Source posting messages onto a queue that go to a handler and a DLQ for handling&#34;&gt;&lt;/p&gt;
&lt;p&gt;SQS also lets you encrypt messages in the queue; you can use an AWS-managed key
or a customer-managed key. Our teams always use customer-managed keys, so we
have an SQS queue with a KMS CMK and DLQs (say that three times fast!). The
updated model looks a bit like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/dlqs-more-complete.png&#34; alt=&#34;Source posting messages onto a queue with a KMS customer-managed key for encryption and a DLQ with a separate KMS key&#34; title=&#34;Source posting messages onto a queue with a KMS customer-managed key for encryption and a DLQ with a separate KMS key&#34;&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re an SQS expert, someone who has read the documentation carefully, or
someone who read &lt;em&gt;very carefully&lt;/em&gt; through the paragraphs above, you will
&lt;em&gt;instantly&lt;/em&gt; see the problem with this picture. If you didn&amp;rsquo;t catch it, you are
not alone.&lt;/p&gt;
&lt;p&gt;The key phrasing above is that undeliverable messages are &lt;em&gt;moved&lt;/em&gt; from the
primary queue to the dead-letter queue. They&amp;rsquo;re not retrieved from the primary
queue and then sent onto the dead-letter queue, they&amp;rsquo;re &lt;em&gt;moved&lt;/em&gt;. This isn&amp;rsquo;t
explicitly stated in the documentation we have been able to find, but it&amp;rsquo;s clear
from the behaviour we experienced and a couple of other hints in the
documentation.&lt;/p&gt;
&lt;p&gt;Our team discovered that the DLQ handler wasn&amp;rsquo;t processing messages, and in fact
its event source mapping (the invisible thing we agreed to gloss over) was
entirely disabled. An extremely-helpful AWS support person was able to tell us
why.&lt;/p&gt;
&lt;p&gt;When messages are put onto a primary queue that has KMS encryption enabled, they
are encrypted using that queue&amp;rsquo;s KMS key. The handler must also have permissions
to decrypt messages using the key, and we had that all working perfectly.&lt;/p&gt;
&lt;p&gt;The Lambda function does not use the decryption permission itself, but rather
&amp;ldquo;loans&amp;rdquo; that permission to the event source mapping. In our case, the Lambda
function&amp;rsquo;s execution role and therefore event source mapping did not have
sufficient permissions to decrypt the message, so the mapping failed to decrypt
the message after retrieving it from the DLQ and did not invoke the Lambda
function.&lt;/p&gt;
&lt;p&gt;If you have a flawed understanding of the DLQ like we did, you might expect that
messages would be decrypted and then re-encrypted when they are sent on the DLQ.
However, they&amp;rsquo;re not decrypted and re-encrypted. They&amp;rsquo;re not even &lt;em&gt;sent&lt;/em&gt; on the
DLQ. They&amp;rsquo;re &lt;em&gt;moved&lt;/em&gt; from the primary queue to the DLQ.&lt;/p&gt;
&lt;p&gt;We had our DLQ set up with a separate key, and the DLQ handler had permissions
to use the key, and in tests where we sent messages to the DLQ the handler
worked perfectly. However, in a full end-to-end scenario where messages fell off
the primary queue and were moved to the DLQ, the event source mapping failed to
decrypt the message (it was set up with permissions on the DLQ key, not the
primary queue key) and did not invoke the handler.&lt;/p&gt;
&lt;p&gt;AWS is super-smart, and they know not to try things forever when there&amp;rsquo;s
persistent failure. The event source mapping eventually disables itself and
emits a CloudTrail event when it does so. If you&amp;rsquo;re vigilant or, preferably, if
you set up a CloudWatch alarm based on the &lt;code&gt;ApproximateAgeOfOldestMessage&lt;/code&gt;
metric on the DLQ, you&amp;rsquo;ll be able to detect that messages are queuing up in the
DLQ and not getting handled.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/dlqs-fixed.png&#34; alt=&#34;Source posting messages onto a queue with a KMS customer-managed key for encryption and a DLQ that uses the same KMS key&#34; title=&#34;Source posting messages onto a queue with a KMS customer-managed key for encryption and a DLQ that uses the same KMS key&#34;&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s important to remember that because messages are &lt;em&gt;moved&lt;/em&gt; and not re-sent on
the DLQ, your &lt;code&gt;ApproximateAgeOfOldestMessage&lt;/code&gt; does not reflect the time that the
message is in the DLQ but rather the time since the message was originally sent
on the primary queue. This is also an important thing to remember when you are
configuring your DLQ: if you use the same policy to age messages out of your DLQ
as you have in your primary queue, you may find that messages disappear without
getting handled the way you expected.&lt;/p&gt;
&lt;p&gt;I did mention that AWS
&lt;a href=&#34;https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-configure-dead-letter-queue-redrive.html&#34;&gt;documents&lt;/a&gt;
the requirement to use the same key:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Your source queue and its corresponding dead-letter queue need to share the
same KMS key.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Oops. 😳&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re looking into creating a
&lt;a href=&#34;https://github.com/aws-cloudformation/cfn-lint&#34;&gt;cfn-lint&lt;/a&gt; custom rule to
prevent us from tripping over this issue again.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>re:Inforce 2022 - IAM306: Managing B2B identity at scale</title>
      <link>https://geoffbaskwill.ca/posts/reinforce-2022-iam306-managing-b2b-identity-at-scale/</link>
      <pubDate>Wed, 27 Jul 2022 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/reinforce-2022-iam306-managing-b2b-identity-at-scale/</guid>
      <description>&lt;p&gt;I had the amazing opportunity to co-present a session at AWS re:Inforce 2022.
My co-presenter was Suresh Sridharan, a product manager on the Amazon Cognito
team.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re not familiar with AWS re:Inforce, it&amp;rsquo;s an annual Amazon Web Services conference focused on security. It&amp;rsquo;s quite a bit smaller than re:Invent, their conference targeting builders, but that is actually a massive draw for me because I&amp;rsquo;ve found that re:Invent has gotten a bit big. I appreciate the focus and the relative ease of navigating a single site rather than what seems to be the entire Las Vegas Strip.&lt;/p&gt;
&lt;p&gt;Suresh talked about a variety of options that Cognito customers have for
managing multi-tenant solutions, and I talked about the particular choices
that our team has made and what took us down this path.&lt;/p&gt;
&lt;p&gt;For the full details, check out the &lt;a href=&#34;https://d1.awsstatic.com/events/aws-reinforce-2022/IAM306_Managing-B2B-identity-at-scale-Lessons-from-AWS-and-Trend-Micro.pdf&#34;&gt;slides&lt;/a&gt; and the &lt;a href=&#34;https://www.youtube.com/watch?v=3fy9uNtMpjM&#34;&gt;recording&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Enriching Amazon Cognito features with an Amazon API Gateway proxy</title>
      <link>https://geoffbaskwill.ca/posts/enriching-cognito-features-with-apigateway/</link>
      <pubDate>Wed, 30 Mar 2022 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/enriching-cognito-features-with-apigateway/</guid>
      <description>&lt;p&gt;I read a great post about &lt;a href=&#34;https://aws.amazon.com/blogs/security/protect-public-clients-for-amazon-cognito-by-using-an-amazon-cloudfront-proxy/&#34;&gt;protecting Amazon Cognito with an Amazon CloudFront proxy&lt;/a&gt; and wondered if using an Amazon API Gateway proxy instead would work better.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/architecture.png&#34; alt=&#34;&#34; title=&#34;Amazon Cognito protected by a proxy function that rewrites requests using the client secret after they have passed through AWS WAF and Amazon API Gateway for rate limiting and other preventative controls.&#34;&gt;&lt;/p&gt;
&lt;p&gt;It really really did. Being able to use the full power of Lambda was fantastic, and the performance was improved significantly.&lt;/p&gt;
&lt;p&gt;This approach also let us quickly implement a few tiny features that Cognito doesn&amp;rsquo;t have yet, like server-side attribute validation and user lifecycle events.&lt;/p&gt;
&lt;p&gt;I got in touch with the author of the original post and he was generous enough to offer a collaboration on a follow-up post on the AWS architecture blog.&lt;/p&gt;
&lt;p&gt;Check out &lt;a href=&#34;https://aws.amazon.com/blogs/architecture/enriching-amazon-cognito-features-with-an-amazon-api-gateway-proxy/&#34;&gt;the full post&lt;/a&gt; for all the details.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Sustainability and systemic change</title>
      <link>https://geoffbaskwill.ca/posts/sustainability-and-systemic-change/</link>
      <pubDate>Mon, 07 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/sustainability-and-systemic-change/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;images/ross-findon-mG28olYFgHI-unsplash.jpg&#34; alt=&#34;Neon sign reading &amp;ldquo;Change&amp;rdquo;&#34; title=&#34;Neon sign reading &#39;Change&#39;&#34;&gt;
&lt;em&gt;Photo by
&lt;a href=&#34;https://unsplash.com/@rossf?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&#34;&gt;Ross
Findon&lt;/a&gt; on
&lt;a href=&#34;https://unsplash.com/s/photos/change?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&#34;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you&amp;rsquo;re here looking for answers, I&amp;rsquo;m afraid I don&amp;rsquo;t have any. I do have
questions, though, and maybe by putting them out there we can find a next step
on the path forward together.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I have the great fortune of working with
&lt;a href=&#34;https://ca.linkedin.com/in/madelinevdp&#34;&gt;Madeline Van Der Paelt&lt;/a&gt;, and
she sent me a note after a particularly-frustrating meeting recently. It was a
quick one-liner, &amp;ldquo;I&amp;rsquo;m curious what you thought of the meeting this afternoon.&amp;rdquo;
That small prompt turned into an hour-long conversation about how &lt;em&gt;so many&lt;/em&gt; of
our efforts to Do Better™ fail, and why that might be.&lt;/p&gt;
&lt;p&gt;I think that economics is a contributing factor.&lt;/p&gt;
&lt;h2&gt;Behavioural economics&lt;/h2&gt;&lt;p&gt;Behavioural economics tells us that rational people usually make rational
decisions based on the information and incentives presented to them. &lt;em&gt;(Important
note: I am not a behavioural economist and have no training in the field, I
could be completely wrong in my understanding.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As a case in point, &lt;a href=&#34;https://chelseatroy.com&#34;&gt;Chelsea Troy&lt;/a&gt; has a
great article
&lt;a href=&#34;https://chelseatroy.com/2018/05/24/why-your-efforts-to-make-your-company-inclusive-arent-working/&#34;&gt;Why your efforts to make your company inclusive aren&amp;rsquo;t working&lt;/a&gt;.
In it, she says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[E]veryone kind of thinks they are paying attention. But they ain’t. And the
reason they ain’t is that, usually, the information has no bearing on their
career trajectory.&lt;/p&gt;
&lt;p&gt;Bias trainings are interesting, but after they’re over employees don’t focus
there because they’re not evaluated on their inclusion literacy. Instead,
employees focus on the skills they need to get ahead—writing code, appeasing
the boss, establishing influence.&lt;/p&gt;
&lt;p&gt;Individual people treat inclusion like an elective because the company’s
incentive system treats inclusion like an elective.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Replace &amp;ldquo;bias training&amp;rdquo; with &amp;ldquo;security training&amp;rdquo;, &amp;ldquo;architecture reviews&amp;rdquo;, or
pretty much anything that is not explicitly on a team&amp;rsquo;s quarterly objectives,
and we often see the same pattern. With few exceptions, quarterly objectives
win, because that is what all of our incentives are tied to. In some ways,
that&amp;rsquo;s kind of the point of those objectives in the first place: providing folks
with the tools to focus on what&amp;rsquo;s important and rewarding people for meeting
goals. However, we need to make sure that we&amp;rsquo;re making conscious decisions about
what we&amp;rsquo;re leaving off the list, and ask ourselves whether we&amp;rsquo;re making the
right choices.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s important to remember that lots of organizational values will never show up
on an OKR (Objectives and Key Results) list, because they&amp;rsquo;re supposed to be
overriding concerns that everyone knows to do. However, sometimes in the effort
of pursuing an OKR, or when working with a rapidly-growing team, we can forget
some of those fundamental values.&lt;/p&gt;
&lt;p&gt;When this happens, we can end up with the same results that Chelsea describes: a
flurry of activity to check off a box, with no follow-up or real systemic
improvement. An hour of training doesn&amp;rsquo;t address systemic problems: we need to
change the system.&lt;/p&gt;
&lt;h2&gt;Our objectives reflect what we think is important&lt;/h2&gt;&lt;p&gt;It seems silly and obvious to point this out, but our objectives are the
definition of what we think is important. In the presence of infinite resources,
we can do everything, but in more realistic situations, we often have to make
trade-offs.&lt;/p&gt;
&lt;p&gt;In order for us to make real change that sticks, we need to make sure that our
objectives reflect not only &amp;ldquo;Ship feature X and get feedback from N customers&amp;rdquo;
but also the other activities that are important to running the business
successfully, while being decent humans.&lt;/p&gt;
&lt;h2&gt;Mechanisms are a key to success&lt;/h2&gt;&lt;p&gt;&lt;a href=&#34;https://hachyderm.io/@adhorn&#34;&gt;Adrian Hornsby&lt;/a&gt;, a principal engineer at Amazon Web
Services, writes about how Amazon achieves
&lt;a href=&#34;https://medium.com/the-cloud-architect/towards-operational-excellence-part-3-8b727f06a4b6&#34;&gt;operational excellence through mechanisms&lt;/a&gt;
that encode their processes. He quotes Thomas Edison, saying:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A good intention, with a bad approach, often leads to a poor result.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We can have all the good intentions in the world, but unless we have supporting
processes in place, it can be &lt;em&gt;very difficult&lt;/em&gt; to make those intentions reality.&lt;/p&gt;
&lt;p&gt;In the article, Adrian talks about the virtuous cycle of tools, adoption, and
audits. I&amp;rsquo;m extrapolating a bit, but my understanding of the essence is: Create
a tool, encourage adoption through education, and audit its use. Use the audit
results to improve the tool and increase adoption.&lt;/p&gt;
&lt;h2&gt;Making change sustainable&lt;/h2&gt;&lt;p&gt;There are &lt;em&gt;so many&lt;/em&gt; things that I can be better at, and I often feel so
overwhelmed that I &amp;hellip; do nothing. I fall into the trap of wanting to be perfect
and I let that get in the way of being better. One motivational image I&amp;rsquo;ve seen
that sometimes helps me get past being overwhelmed has an equation:&lt;/p&gt;
&lt;p style=&#34;text-align: center&#34;&gt;
1.01&lt;sup&gt;365&lt;/sup&gt; = 37.8
&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re not mathematically inclined, this might look a bit confusing, but it
says &amp;ldquo;if you take a number greater than one, even a little bit, and multiply it
by itself a lot, you get a much bigger number&amp;rdquo;. If you improve &lt;em&gt;a little bit&lt;/em&gt;
every day, at the end of a year you will be &lt;em&gt;a lot&lt;/em&gt; better.&lt;/p&gt;
&lt;p&gt;What mechanism can I use to avoid being overwhelmed and trick myself into making
that 1% daily improvement that will compound over years?&lt;/p&gt;
&lt;h2&gt;Can we nudge ourselves towards the changes we want?&lt;/h2&gt;&lt;p&gt;I have a list of questions that I ask myself every week. It&amp;rsquo;s a tool I picked up
from working with Madeline and her team. Their questions are a bit different,
but mine are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;What did you do for our customers this week?&lt;/li&gt;
&lt;li&gt;What did you do for other Trenders this week?&lt;/li&gt;
&lt;li&gt;What did you do for yourself this week?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Every week I open a new document, paste in these questions, and as the week
progresses I add answers. I find it helps me keep my head in the right place.&lt;/p&gt;
&lt;p&gt;I wonder what would happen if I set up a bot to nudge me with an extra question,
maybe a new one each week, that helped remind me of the behaviours I want to
improve? What if I took all of the items in Chelsea Troy&amp;rsquo;s rubric for
inclusiveness, turned them into &amp;ldquo;how did you demonstrate X&amp;rdquo; questions, and used
a different question each week to help me remember to be more inclusive? What if
I added in questions for other behaviours? There are all kinds of examples:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How did you build up a team&amp;rsquo;s capacity to be more self-sufficient this week?&lt;/li&gt;
&lt;li&gt;How did you help someone become a better code reviewer this week?&lt;/li&gt;
&lt;li&gt;How did you help a team improve their operational effectiveness this week?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These work well for my role, your set of prompts might be different!&lt;/p&gt;
&lt;h2&gt;I&amp;rsquo;m going to give it a try&lt;/h2&gt;&lt;p&gt;We&amp;rsquo;ve got a hack day coming up, so I think my project is going to be a nudge-bot
that sends me a question of the week to add to my list. I&amp;rsquo;m curious to see how
it works out. I&amp;rsquo;m hopeful that this mechanism will help me make small
sustainable changes in my behaviour and surface some of the things that aren&amp;rsquo;t
always included in the big-O Objectives.&lt;/p&gt;
&lt;p&gt;What questions do you think I should ask? What behaviours are you looking to
amplify in your teams and organizations? I&amp;rsquo;d love to hear your thoughts.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Many thanks to Madeline Van Der Paelt for her thoughts on the initial draft of
this post.&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Using Step Functions to build CloudFormation custom resources</title>
      <link>https://geoffbaskwill.ca/posts/cloudformation-custom-resources-with-step-functions/</link>
      <pubDate>Sat, 24 Apr 2021 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/cloudformation-custom-resources-with-step-functions/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;images/serban-mestecaneanu-1Cwj7JowUHA-unsplash.jpg&#34; alt=&#34;Steps leading up&#34; title=&#34;Steps leading up&#34;&gt;
&lt;em&gt;Photo by
&lt;a href=&#34;https://unsplash.com/@meste?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&#34;&gt;Serban
Mestecaneanu&lt;/a&gt; on
&lt;a href=&#34;https://geoffbaskwill.ca/s/photos/steps?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&#34;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;My team uses &lt;a href=&#34;https://aws.amazon.com/cloudformation/&#34;&gt;AWS CloudFormation&lt;/a&gt; to
provision our cloud infrastructure using code. Most of the time we can get what
we need with the set of resources that AWS provides.&lt;/p&gt;
&lt;p&gt;However, sometimes CloudFormation support for a service or a particular feature
takes a while to arrive, and we need to fill in the gap ourselves.
CloudFormation gives us the ability to fill these gaps by building
&lt;a href=&#34;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html&#34;&gt;&amp;ldquo;custom resources&amp;rdquo;&lt;/a&gt;
that can literally run any logic you need in
&lt;a href=&#34;https://aws.amazon.com/lambda/&#34;&gt;AWS Lambda&lt;/a&gt;, and we&amp;rsquo;ve used these when we
needed to.&lt;/p&gt;
&lt;h2&gt;Sometimes Lambda isn&amp;rsquo;t the right answer&lt;/h2&gt;&lt;p&gt;Sometimes even Lambda fails us, though, as some resources can potentially take a
long time to set up, and we don&amp;rsquo;t particularly want to have a Lambda function
sitting idle or potentially timing out halfway through the resource setup.&lt;/p&gt;
&lt;p&gt;The great thing about Lambda functions is that you only pay for them when
they&amp;rsquo;re running. This makes them great for places where you need to run a quick
task or handle an API request. You lose some of the benefits when your Lambda
function looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;start_something()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; not_done():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    time&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;sleep(&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;finish()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;because you&amp;rsquo;re paying for the Lambda to run while you&amp;rsquo;re waiting for your
operation to complete. Worse, Lambda functions have a maximum lifetime of 15
minutes, so if your process takes longer than 15 minutes, you have to do weird
hacks to make it work with a pure Lambda solution.&lt;/p&gt;
&lt;p&gt;When we found out that
&lt;a href=&#34;https://github.com/aws-cloudformation/aws-cloudformation-coverage-roadmap/issues/57&#34;&gt;CloudFormation didn&amp;rsquo;t have support for creating DynamodDB Global Tables&lt;/a&gt;,
our first thought was &amp;ldquo;we know how to do this, a Lambda function custom resource
can handle it.&amp;rdquo; However, as we dug into the details and tried it out, we quickly
learned that we could get into a scenario where creating the initial replica set
or updating the replicas could easily exceed the 15-minute Lambda timeout.&lt;/p&gt;
&lt;h2&gt;Step Functions to the rescue!&lt;/h2&gt;&lt;p&gt;Here&amp;rsquo;s where &lt;a href=&#34;https://aws.amazon.com/step-functions/&#34;&gt;AWS Step Functions&lt;/a&gt; comes
in. Step Functions make the task of orchestrating processes easier. They have
built-in support for looping, waiting, and integrating with different functions
and services, which makes them perfect for this sort of thing.&lt;/p&gt;
&lt;p&gt;One of our team members put together this Step Function definition for creating
a DynamoDB global table. It starts out by checking the state of the table,
waiting until the table is ready for updates, then comparing the set of replicas
with the desired set. You can only add one replica at a time, so the step
function repeats the &lt;code&gt;UpdateReplicas&lt;/code&gt; step until the actual state matches the
desired state. Each step is very small and self-contained, usually only one or
two API calls, and all of the waiting is done by Step Functions instead of in
the Lambda function, so we&amp;rsquo;re not paying for idle time! Best of all, Step
Functions can run for up to a week, so we didn&amp;rsquo;t need to worry about the
15-minute timeout any more.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/replication-state-machine.png&#34; alt=&#34;Replication state machine&#34; title=&#34;Replication state machine&#34;&gt;&lt;/p&gt;
&lt;h2&gt;There&amp;rsquo;s a small catch&amp;hellip;&lt;/h2&gt;&lt;blockquote&gt;&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;I wish I could use Step Functions directly to build CloudFormation custom resources instead of having to have a Lambda function that triggers the Step Function. #awswishlist&lt;/p&gt;&amp;mdash; Geoff Baskwill (@geoff_baskwill) February 24, 2021&lt;/blockquote&gt;
&lt;p&gt;CloudFormation doesn&amp;rsquo;t support direct integration with Step Functions as a
custom resource provider yet, but we can use our old Lambda function trick to
trigger the Step Function execution, and send the response back to
CloudFormation when we get to an end state.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/step-function-overview.png&#34; alt=&#34;Invoking Step Functions as a custom resource using Lambda as a shim&#34; title=&#34;Invoking Step Functions as a custom resource using Lambda as a shim&#34;&gt;&lt;/p&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;&lt;p&gt;When you love infrastructure-as-code and need a custom resource for something
that CloudFormation doesn&amp;rsquo;t support, Lambda is usually a great solution. When
you need a bigger hammer for complex orchestration or operations with lots of
idle time, Step Functions can help get you there.&lt;/p&gt;
&lt;p&gt;The goal is to retire this particular resource soon, as AWS tells us that
they&amp;rsquo;ll have built-in support in CloudFormation for DynamoDB Global Tables
&lt;a href=&#34;https://github.com/aws-cloudformation/aws-cloudformation-coverage-roadmap/issues/57#issuecomment-758200567&#34;&gt;in the very near future&lt;/a&gt;.
That said, my team is happy that we were able to deliver an initial
implementation with this workaround and provide value to our customers!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>CloudFormation, Route 53, and ... EKS?</title>
      <link>https://geoffbaskwill.ca/posts/cloudformation-route53-and-eks/</link>
      <pubDate>Thu, 22 Apr 2021 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/cloudformation-route53-and-eks/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;images/down-the-rabbit-hole.jpg&#34; alt=&#34;Falling down the rabbit hole into Wonderland&#34; title=&#34;Falling down the rabbit hole into Wonderland&#34;&gt;&lt;/p&gt;
&lt;p&gt;The other day I got halfway through writing a &lt;em&gt;very irate&lt;/em&gt; support ticket to
AWS, stopped to do some fact checking, and learned something deeply annoying.&lt;/p&gt;
&lt;p&gt;One of the teams I work manages a bunch of services. One of these “services” is
some common &lt;a href=&#34;https://aws.amazon.com/route53/&#34;&gt;Amazon Route 53&lt;/a&gt; infrastructure
that is set up using
&lt;a href=&#34;https://aws.amazon.com/cloudformation/&#34;&gt;AWS CloudFormation&lt;/a&gt;, and over the
history of the project the deployment in the development account the team uses
has been a little flaky. Each time we hit a deployment problem, the problem
always turned out to be rate limiting. It never happened in production, so the
flakiness didn&amp;rsquo;t quite get the attention that it could have.&lt;/p&gt;
&lt;h2&gt;Rate limiting in Route 53&lt;/h2&gt;&lt;p&gt;Some background: Route 53 has a hard limit of 5 control plane requests per second per AWS
account. For most folks, this is fine. However, it wasn&amp;rsquo;t working well for this
team.&lt;/p&gt;
&lt;p&gt;The team had raised support tickets and gotten advice like “CloudFormation will
attempt to create your resources in parallel. One option to avoid rate limiting
is to add &lt;code&gt;DependsOn&lt;/code&gt; links to serialize the resource creation.” We weren&amp;rsquo;t
super-happy with that answer, and there&amp;rsquo;s a
&lt;a href=&#34;https://github.com/aws-cloudformation/aws-cloudformation-coverage-roadmap/issues/573&#34;&gt;CloudFormation roadmap item&lt;/a&gt;
to fix it, but we needed something in the interim, and it worked &amp;hellip; mostly.&lt;/p&gt;
&lt;p&gt;On this day a deployment had failed again, and after going after the usual
suspects and making sure that the resources were properly serialized, I got
&lt;em&gt;very irate&lt;/em&gt;. I was halfway through writing a support ticket:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We are still encountering Route 53 rate limits and our CloudFormation stack
deployment / updates are intermittently failing, sometimes after only two
resources are created. There are no Route 53 API calls being made by our
applications, only through CloudFormation.&lt;/p&gt;
&lt;p&gt;We are &lt;em&gt;quite frustrated&lt;/em&gt; at this point and would like to request a session
with a solution architect to help us understand how we should be doing this
and&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and I paused.&lt;/p&gt;
&lt;h2&gt;Check yourself before you wreck yourself&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;“There is no point in using the word &amp;lsquo;impossible&amp;rsquo; to describe something that
has clearly happened.” — Douglas Adams, &lt;em&gt;Dirk Gently&amp;rsquo;s Holistic Detective
Agency&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;“Is it true that there are no other Route 53 API calls being made?” I asked
myself. A quick jaunt into &lt;a href=&#34;https://aws.amazon.com/cloudtrail/&#34;&gt;AWS CloudTrail&lt;/a&gt;
told me the answer, and also opened a gaping pit beneath my feet.&lt;/p&gt;
&lt;p&gt;There were &lt;strong&gt;436&lt;/strong&gt; Route 53 API calls made in the 2-minute period surrounding our
CloudFormation failure. If you do the math, that&amp;rsquo;s 3.6 requests per second on
average, so it&amp;rsquo;s not at all surprising that we maybe tipped over the limit of 5
at some point in there.&lt;/p&gt;
&lt;p&gt;“But where are these coming from?” was my immediate question, and it was
immediately answered.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/cloudtrail-route53.png&#34; alt=&#34;CloudTrail console showing Route 53 calls from an EC2 instance&#34; title=&#34;CloudTrail console showing Route 53 calls from an EC2 instance&#34;&gt;&lt;/p&gt;
&lt;p&gt;Virtually all of these requests were being made by an EC2 instance that was part
of an &lt;a href=&#34;https://aws.amazon.com/eks/&#34;&gt;Amazon Elastic Kubernetes Service (EKS)&lt;/a&gt;
cluster.&lt;/p&gt;
&lt;p&gt;Talking through this with some other folks, I learned that they&amp;rsquo;d configured
&lt;a href=&#34;https://github.com/kubernetes-sigs/external-dns&#34;&gt;external-dns&lt;/a&gt; on the cluster,
and that this behaviour is
&lt;a href=&#34;https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md#throttling&#34;&gt;actually documented&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The production account doesn&amp;rsquo;t have the EKS cluster, so it&amp;rsquo;s not overwhelmed
with Route 53 API calls, which explains why deployment never failed there.&lt;/p&gt;
&lt;h2&gt;Buh-bye&lt;/h2&gt;&lt;p&gt;I wanted to decommission the cluster immediately, but unfortunately some teams
still need it, so I wasn&amp;rsquo;t able to.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;external-dns&lt;/code&gt; documentation says that one workaround for the issue of the
controller eating your entire Route 53 request budget is to extend the interval
that the controller reconciliation loop runs at. In this particular cluster, the
reconciliation loop was running &lt;em&gt;every minute&lt;/em&gt; (the default!) to reconcile a set
of records that change approximately never. I followed the instructions, set the
&lt;code&gt;interval&lt;/code&gt; to a week, and settled in to see what happened.&lt;/p&gt;
&lt;p&gt;The first thing I noticed was that immediately the calls to Route 53 stopped. Not
surprising, but great to see the confirmation. Several hours after the change,
there were still no calls from the previously-misbehaving cluster.&lt;/p&gt;
&lt;p&gt;All is well now, and I get to put away my detective hat for another day.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“The light works,” he said, indicating the window, “the gravity works,” he
said, dropping a pencil on the floor. “Anything else we have to take our
chances with.” — Douglas Adams, &lt;em&gt;Dirk Gently&amp;rsquo;s Holistic Detective Agency&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;What I learned&lt;/h2&gt;&lt;p&gt;First, CloudTrail was instrumental here. I&amp;rsquo;m still a novice, but I&amp;rsquo;m learning
how powerful a tool it is. Once I knew what to look for, it was &lt;em&gt;immediately&lt;/em&gt;
obvious what the source of the rate limiting was. The events in CloudTrail
identified the EC2 instance and even made it clear that the source of the
requests was in an EKS cluster.&lt;/p&gt;
&lt;p&gt;Second, I was reminded that Kubernetes is not a get-out-of-ops-free card. There
is a lot of expertise involved in running Kubernetes well, even when you&amp;rsquo;re
using a managed service like EKS. I knew this before, but this was an example of
a cluster I didn&amp;rsquo;t even know existed (don&amp;rsquo;t worry: someone more responsible did
know!) having side effects way outside its scope.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Why I Use Go (for now)</title>
      <link>https://geoffbaskwill.ca/posts/why-i-use-go/</link>
      <pubDate>Thu, 03 Dec 2020 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/why-i-use-go/</guid>
      <description>&lt;p&gt;Recently someone asked me why I prefer using Go to build services instead of Python.&lt;/p&gt;
&lt;p&gt;It struck me as an odd question, mostly because the way it was phrased and how I skimmed it made me think they were asking why I recommended using Python to build services, which is something I have never done. Once we got past my misunderstanding and I had apologized for not reading carefully, I took a few minutes to think about it.&lt;/p&gt;
&lt;p&gt;The first point to keep in mind is that I would not call myself a competent Python programmer. It is entirely possible that if I were more comfortable with Python, I would pick it up as a tool more often. Some Very Smart People™ I know use Python for Real Services In Production™. I wouldn’t, but as I mentioned, I’m not exactly well-versed. I expect that if I were dropped into an environment where I could learn from those Very Smart People, I might grow to understand why they have made that choice.&lt;/p&gt;
&lt;p&gt;It would be fairer to ask why I use Go instead of Java, as there was a time that I considered myself not-incompetent in Java, and I railed mightily against the project lead who decreed that I would learn Go.&lt;/p&gt;
&lt;p&gt;I use and recommend Go these days because it has a lot of tools for writing robust, predictable, and reliable code, concisely. I have found over the last few years of learning Go that I can write better services than I ever did in Java, and I can do it faster and more easily. The end product is also more performant and more predictable with less effort on my part, not to mention ridiculously small compared to stuff built on the Java Virtual Machine.&lt;/p&gt;
&lt;p&gt;As a tool, Go fits well with the problems that I am trying to solve today.&lt;/p&gt;
&lt;p&gt;Are there things that are annoying and things I really don’t understand all that well yet? For sure. These things don’t really get in the way of creating value for customers, though.&lt;/p&gt;
&lt;p&gt;Your Mileage May Vary.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Behaviour of background goroutines in AWS Lambda</title>
      <link>https://geoffbaskwill.ca/posts/background-goroutines-in-lambda/</link>
      <pubDate>Mon, 02 Nov 2020 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/background-goroutines-in-lambda/</guid>
      <description>&lt;p&gt;I was curious what would happen with a &lt;code&gt;time.Ticker&lt;/code&gt; running in an AWS Lambda function.&lt;/p&gt;
&lt;p&gt;It was pretty obvious that the ticker wouldn’t tick while the container was hibernating, but what about when it woke up? Would a bunch of ticks happen if the container had been hibernating for a long time? Would you get a tick at all?&lt;/p&gt;
&lt;h2&gt;tl;dr&lt;/h2&gt;&lt;p&gt;It looks like you get one tick when the function comes out of hibernation (assuming the ticker duration has passed at least once), and if the function never hibernates the ticks happen on time, which for my purposes is pretty much perfect.&lt;/p&gt;
&lt;h2&gt;The code&lt;/h2&gt;&lt;p&gt;I set up a small AWS Lambda function that responds to API Gateway requests and has a goroutine running with a &lt;code&gt;time.Ticker&lt;/code&gt; that ticks every minute:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;package main

import (
  &amp;#34;context&amp;#34;
  &amp;#34;fmt&amp;#34;
  &amp;#34;net/http&amp;#34;
  &amp;#34;sync&amp;#34;
  &amp;#34;time&amp;#34;

  &amp;#34;github.com/aws/aws-lambda-go/events&amp;#34;
  &amp;#34;github.com/aws/aws-lambda-go/lambda&amp;#34;
)

func main() {
  wg := &amp;amp;sync.WaitGroup{}

  ticker := time.NewTicker(time.Second * 60)
  go func() {
    for t := range ticker.C {
      // let the WaitGroup know that we&amp;#39;re working
      wg.Add(1)

      // tell the observer that the ticker actually ticked
      fmt.Println(&amp;#34;tick at&amp;#34;, t)
      
      // simulate a background process that takes a bit to complete
      time.Sleep(time.Second)
      
      // let the WaitGroup know that we&amp;#39;re done
      wg.Done()
    }
  }()

  lambda.Start(func(ctx context.Context, req events.APIGatewayProxyRequest)(events.APIGatewayProxyResponse, error) {
    resp, err := realHandler(ctx, req)
    
    // If the ticker is running, wait for it.
    wg.Wait()

    return resp, err
  })
}

func realHandler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
  return events.APIGatewayProxyResponse{
    StatusCode: http.StatusPaymentRequired,
  }, nil
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You’ll see how I’ve split out the real handler and the ticker-waiting “middleware” &amp;hellip; this keeps the handler logic separated from the bit that waits for the background goroutine to complete what it’s doing before returning.&lt;/p&gt;
&lt;h2&gt;The test&lt;/h2&gt;&lt;p&gt;I called the function a couple of times, waited a few minutes, and called the function again. The logs told me what happened:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;2020-11-02T14:11:51.061-05:00 START RequestId: f2604bb1-8bc2-445a-b7b2-3893d8d3416d Version: $LATEST
2020-11-02T14:11:51.063-05:00 END RequestId: f2604bb1-8bc2-445a-b7b2-3893d8d3416d
2020-11-02T14:11:51.063-05:00 REPORT RequestId: f2604bb1-8bc2-445a-b7b2-3893d8d3416d Duration: 1.39 ms Billed Duration: 100 ms Memory Size: 1024 MB Max Memory Used: 35 MB Init Duration: 66.79 ms XRAY TraceId: 1-5fa059f6-10e9a1715cb581111721b9a8 SegmentId: 0467a00a5d719145 Sampled: true
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;2020-11-02T14:11:54.171-05:00 START RequestId: 7a39872e-4b18-42da-b2ff-315a6590a1b6 Version: $LATEST
2020-11-02T14:11:54.174-05:00 END RequestId: 7a39872e-4b18-42da-b2ff-315a6590a1b6
2020-11-02T14:11:54.174-05:00 REPORT RequestId: 7a39872e-4b18-42da-b2ff-315a6590a1b6 Duration: 0.68 ms Billed Duration: 100 ms Memory Size: 1024 MB Max Memory Used: 42 MB XRAY TraceId: 1-5fa059fa-0be52e2845702dd0365eeb74 SegmentId: 5d5f37f527b7de1a Sampled: true
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first two log blocks show the first two calls, at &lt;code&gt;14:11:51-05:00&lt;/code&gt; and at &lt;code&gt;14:11:54-05:00&lt;/code&gt;. We wouldn’t expect to see a tick log here, and as expected we do not.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;2020-11-02T14:16:28.076-05:00 START RequestId: 488123cd-43bc-4567-9970-00c35bfc91b8 Version: $LATEST
2020-11-02T14:16:28.076-05:00 tick at 2020-11-02 19:16:28.076072523 +0000 UTC m=+277.052607202
2020-11-02T14:16:28.078-05:00 END RequestId: 488123cd-43bc-4567-9970-00c35bfc91b8
2020-11-02T14:16:28.078-05:00 REPORT RequestId: 488123cd-43bc-4567-9970-00c35bfc91b8 Duration: 0.59 ms Billed Duration: 100 ms Memory Size: 1024 MB Max Memory Used: 42 MB XRAY TraceId: 1-5fa05b0c-35afecef72dc3fb25cf4eeef SegmentId: 045243422ccaea72 Sampled: true
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;2020-11-02T14:20:15.133-05:00 START RequestId: 2dc415ef-f53f-4e35-865d-21b89cd9147e Version: $LATEST
2020-11-02T14:20:15.133-05:00 tick at 2020-11-02 19:20:15.133194003 +0000 UTC m=+504.107026404
2020-11-02T14:20:15.137-05:00 END RequestId: 2dc415ef-f53f-4e35-865d-21b89cd9147e
2020-11-02T14:20:15.137-05:00 REPORT RequestId: 2dc415ef-f53f-4e35-865d-21b89cd9147e Duration: 0.62 ms Billed Duration: 100 ms Memory Size: 1024 MB Max Memory Used: 43 MB XRAY TraceId: 1-5fa05bef-5e8453ea22ff3fa4454e0af6 SegmentId: 183982d42c0b3848 Sampled: true
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The next two log blocks show calls at &lt;code&gt;14:16:28-05:00&lt;/code&gt; and &lt;code&gt;14:20:15-05:00&lt;/code&gt; and one tick happening each time the code is invoked. This would seem to indicate that even if multiple ticks would normally have happened in the time period, they are consolidated into one.&lt;/p&gt;
&lt;p&gt;Neat!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>API versioning</title>
      <link>https://geoffbaskwill.ca/posts/api-versioning/</link>
      <pubDate>Wed, 09 Sep 2020 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/api-versioning/</guid>
      <description>&lt;p&gt;There are lots of ways to implement API versioning. Picking one is an exercise in balance: what voices will you listen to?&lt;/p&gt;
&lt;p&gt;For us, the most important voice is the voice of the customer. There are lots of customers, though, and many of them just want to get the job done. They are expecting us to be the experts and make it easy for them to build integrations that Just Work™.&lt;/p&gt;
&lt;p&gt;People using our APIs don&amp;rsquo;t really care whether we&amp;rsquo;re 100% &lt;a href=&#34;https://en.wikipedia.org/wiki/Roy_Fielding&#34;&gt;Fielding&lt;/a&gt;-Certified REST™ (not a real thing). They want something that&amp;rsquo;s simple and predictable.&lt;/p&gt;
&lt;p&gt;How can we generally meet people where they&amp;rsquo;re at, and give everyone the benefit of versioning without creating work for them?&lt;/p&gt;
&lt;p&gt;I consider &lt;a href=&#34;https://stripe.com/blog/api-versioning&#34;&gt;Stripe&amp;rsquo;s API versioning strategy&lt;/a&gt; to be the gold standard. If you read their post, you&amp;rsquo;ll see how they carefully balance the ideal of &amp;ldquo;we will never break your integration with us&amp;rdquo; with &amp;ldquo;sometimes we need to make breaking changes&amp;rdquo;.&lt;/p&gt;
&lt;h2&gt;When do we need a new version?&lt;/h2&gt;&lt;p&gt;Most people agree that you need a new API version every time you have a breaking change.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s a breaking change? It depends. Some people are really strict: if there is a new attribute, that&amp;rsquo;s a breaking change in their minds. I tend to be more lenient. If an attribute changes type (for example, from a simple type to an object) or if a required attribute in a response goes away, that&amp;rsquo;s a breaking change. It gets a little trickier when you modify an enumerated type, so you need to understand your audience and how they are using your API.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://imgs.xkcd.com/comics/workflow.png&#34; alt=&#34;XKCD 1162 - Workflow&#34; title=&#34;XKCD 1162 - Workflow&#34;&gt;&lt;/p&gt;
&lt;h2&gt;What&amp;rsquo;s a good version string look like?&lt;/h2&gt;&lt;p&gt;The Stripe folks use a date to represent an API version; it&amp;rsquo;s handy as people generally understand how to compare dates. Some people get confused when they see an &amp;ldquo;old&amp;rdquo; API version and think that your documentation is out of date, but those people are rare.&lt;/p&gt;
&lt;p&gt;Other folks prefer to use semantic versioning (&lt;code&gt;v1.0.3&lt;/code&gt;), or use a simple string like &lt;code&gt;v1&lt;/code&gt; and move on.&lt;/p&gt;
&lt;p&gt;I feel like &lt;code&gt;v1&lt;/code&gt; isn&amp;rsquo;t particularly granular, semantic versioning is a bit sketchy from an API perspective and too much like a release number, and prefer date strings.&lt;/p&gt;
&lt;h2&gt;Options&lt;/h2&gt;&lt;h3&gt;Just put a version in the URL&lt;/h3&gt;&lt;p&gt;&lt;em&gt;also known as &amp;ldquo;What&amp;rsquo;s wrong with &lt;code&gt;/v1/widgets/123456&lt;/code&gt;?&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Some people love putting the API version in the path portion of the URL. I don&amp;rsquo;t particularly like this myself. If I have one resource one day that has a breaking change, then I have to break out &lt;code&gt;/v2&lt;/code&gt;. The next day, another breaking change to a resource, &lt;code&gt;/v3&lt;/code&gt;. Where does it end? What do you do with the resources that didn&amp;rsquo;t change?&lt;/p&gt;
&lt;p&gt;From a dogmatic perspective, putting the API version in the URL path means that your resources at &lt;code&gt;/v1/*&lt;/code&gt; and at &lt;code&gt;/v2/*&lt;/code&gt; and at &lt;code&gt;/v3/*&lt;/code&gt; are &lt;em&gt;different things&lt;/em&gt;, not &lt;em&gt;different representations of the same things&lt;/em&gt;. People with a Job To Be Done won&amp;rsquo;t care, but it&amp;rsquo;s a bit irksome to have something so flagrantly against how the Web is supposed to work. It&amp;rsquo;s handy from a service developer&amp;rsquo;s perspective, as you can &amp;ldquo;just&amp;rdquo; put a new endpoint handler in place, but if only one resource has changed then it gets messy.&lt;/p&gt;
&lt;h3&gt;Use content negotiation like Fielding intended&lt;/h3&gt;&lt;p&gt;&lt;em&gt;also known as &amp;ldquo;What&amp;rsquo;s wrong with &lt;code&gt;Accept: application/x-widget+json;v=1&lt;/code&gt;? &lt;code&gt;Accept: application/x-widget.v1+json&lt;/code&gt;?&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For a long time I believed that content negotiation was Totally Awesome™. Imagine: something built into the HTTP standards that lets you not only discover what potential representation options exist for any given resource, but also transparently negotiate upgrades on either the client or the server side.&lt;/p&gt;
&lt;p&gt;I was so enamoured with this idea I did a conference talk on it, claiming that using content negotiation was level π of the &lt;a href=&#34;https://martinfowler.com/articles/richardsonMaturityModel.html&#34;&gt;Richardson Maturity Model&lt;/a&gt; (because it&amp;rsquo;s transcendent and slightly greater than 3).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve mellowed since then. I still believe that content negotiation is an awesome mechanism, but it&amp;rsquo;s a bit too clever for some folks, and unfortunately framework support is rather sparse for parameterized content types on both the client and server side.&lt;/p&gt;
&lt;p&gt;Forcing people to learn about content negotiation before they can use your API also means that some people will just walk away.&lt;/p&gt;
&lt;h3&gt;Use an API version header&lt;/h3&gt;&lt;p&gt;&lt;em&gt;also known as &amp;ldquo;What&amp;rsquo;s wrong with &lt;code&gt;Api-Version: 2020-04-01&lt;/code&gt;?&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t managed to find any concrete reasons why you shouldn&amp;rsquo;t use a custom header for passing the API version. The best people have been able to give me is &amp;ldquo;it&amp;rsquo;s harder to set up header-based routing&amp;rdquo;, which is sometimes true and totally valid for people in that position.&lt;/p&gt;
&lt;p&gt;If you allow caching of API responses, you should include a &lt;code&gt;Vary: Api-Version&lt;/code&gt; header in your responses if you go this route; it will tell any caching infrastructure that the response may be different if the API version in the request is different.&lt;/p&gt;
&lt;p&gt;The Stripe folks have a really smart mechanism: if you don&amp;rsquo;t specify the API version in your request, they look at what API version your account is pinned at. If it&amp;rsquo;s your first time calling the API, they pin you to the current version. You can change your pinned API version through the console (and presumably through the account management API as well).&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t yet gone so far as to implement API version pinning. The best I&amp;rsquo;ve been able to do is default to the latest version when the header isn&amp;rsquo;t present &amp;ndash; this gives folks the most chance of seeing responses that match the current API docs, but it means that folks who don&amp;rsquo;t provide an API version header are more vulnerable to breaking changes.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Pagination and cursors</title>
      <link>https://geoffbaskwill.ca/posts/pagination-and-cursors/</link>
      <pubDate>Wed, 07 Mar 2018 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/pagination-and-cursors/</guid>
      <description>&lt;p&gt;Whenever you retrieve a list of things in an API I&amp;rsquo;ve managed to influence, unless the size of the list is internally capped at an incredibly small number, you&amp;rsquo;ll see that the API supports &lt;code&gt;limit&lt;/code&gt; and &lt;code&gt;cursor&lt;/code&gt; query parameters to allow you to page through the results. This post will explore what those parameters do, how they work, and some of the limitations of the approach.&lt;/p&gt;
&lt;h2&gt;Why pagination?&lt;/h2&gt;&lt;p&gt;Before we get into the details of how the solution works, we should properly understand the problem. Most APIs start out very simple, with a trivial &lt;code&gt;GET&lt;/code&gt; operation on a container resource that returns a list of objects, and everyone is happy:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;GET /widgets HTTP/1.1
Accept: application/json
...

HTTP/1.1 200 OK
...
Content-Type: application/json

[ { widget 1 }, { widget 2 }, ... ]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The happiness starts to go away when the server starts handling hundreds or thousands of widgets. API response times start getting long, payloads are huge, and memory usage on the server gets really spiky as it tries to serialize the entire contents of the database in response to every request.&lt;/p&gt;
&lt;p&gt;Most people come to the quick realization that it&amp;rsquo;s better to only ask for a smaller amount of data to start, and only load additional data on demand:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;GET /widgets?limit=10 HTTP/1.1
Accept: application/json
...

HTTP/1.1 200 OK
...
Content-Type: application/json

[ { widget 1, { widget 2 }, ... ]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But wait! With this data structure, how is the client supposed to know whether there&amp;rsquo;s more data to load?&lt;/p&gt;
&lt;p&gt;Some APIs simply say &amp;ldquo;Give me the start point and page size, and I&amp;rsquo;ll figure out the rest.&amp;rdquo; OK, no problem. But what&amp;rsquo;s the start point? Primary key? What if you&amp;rsquo;re sorting on something else? Things get complicated quickly. Some folks try to use an &lt;code&gt;offset&lt;/code&gt; parameter, but that can also get complicated.&lt;/p&gt;
&lt;h2&gt;Cursors can help&lt;/h2&gt;&lt;p&gt;Inspired by &lt;a href=&#34;https://slack.engineering/evolving-api-pagination-at-slack&#34;&gt;a very detailed post by the kind folks at Slack&lt;/a&gt;, I tried implementing cursors in an API framework I was building. Briefly, in this context a cursor is a token that can be used to resume the query when more than one page of results is available.&lt;/p&gt;
&lt;p&gt;When someone makes a request to list resources, our API returns a structure that contains one attribute with the list of requested resources, and if there is more than one page of results, it will also include a &lt;code&gt;next&lt;/code&gt; attribute containing an encoded token that can be used in a subsequent request to get the next page of results.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;GET /widgets?limit=10 HTTP/1.1
Accept: application/json
...

HTTP/1.1 200 OK
Content-Type: application/json
...

{ &amp;#34;widgets&amp;#34;: [...], &amp;#34;next&amp;#34;: &amp;#34;bmljZSB0cnkK&amp;#34; }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the &lt;code&gt;next&lt;/code&gt; attribute isn&amp;rsquo;t there, there is no more data to be had.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;next&lt;/code&gt; attribute is a base64-encoded token that the server knows how to decode into a database query that corresponds to the next page of data. It includes information about the sort order, starting point, and anything else that the server needs in order to do its job. The API consumer doesn&amp;rsquo;t need to know anything other than &amp;ldquo;as long as there&amp;rsquo;s a &lt;code&gt;next&lt;/code&gt; field, take the value out of the result and paste it into the &lt;code&gt;cursor&lt;/code&gt; query parameter in the next request&amp;rdquo;, and I&amp;rsquo;m free to make changes to the internal logic at any time without affecting consumers, which is pretty amazing from a service development perspective. Different resources can use different logic internally without exposing the details to the API user.&lt;/p&gt;
&lt;p&gt;Even better, the &lt;code&gt;next&lt;/code&gt; attribute is self-contained. The server doesn&amp;rsquo;t have to maintain any state about the query or the cursor, so no resources are consumed if the caller never comes back.&lt;/p&gt;
&lt;h2&gt;Other ways to communicate the cursor&lt;/h2&gt;&lt;p&gt;Some folks use a &lt;code&gt;Link&lt;/code&gt; header to carry the full URL for the next page; I think that is a fantastic idea and recommend implementing that as well:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Link: &amp;lt;/api/widgets?cursor=aGFwcHkgZWFzdGVyIQo&amp;gt;; rel=&amp;#34;next&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Security considerations&lt;/h2&gt;&lt;p&gt;If someone weren&amp;rsquo;t careful, they could easily take the idea above and say &amp;ldquo;I&amp;rsquo;ll just base64-encode a JSON blob with a bunch of parameters, call it a cursor, and take the rest of the day off!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Of course, we want to keep our attack surface to a minimum. To help with this, we encrypt the cursor with an algorithm that verifies the integrity of the protected content, and we salt the input to make it harder to attack with known plaintext. For added protection, we also rotate the encryption key regularly, so that if someone does manage to break the key they can only attempt further attacks for a limited period of time.&lt;/p&gt;
&lt;h2&gt;Limitations&lt;/h2&gt;&lt;p&gt;The main limitation in this scheme is that it&amp;rsquo;s pretty focused on unidirectional scrolling – the cursor only goes forward (or back, depending on the sort order). There are ways to deal with this, but they&amp;rsquo;re far more complicated than I wanted to get into, and more importantly they&amp;rsquo;re not relevant to our current use cases.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>AWS re:Invent 2017</title>
      <link>https://geoffbaskwill.ca/posts/aws-reinvent-2017/</link>
      <pubDate>Tue, 05 Dec 2017 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/aws-reinvent-2017/</guid>
      <description>&lt;h2&gt;tl;dr&lt;/h2&gt;&lt;p&gt;If I had to pick one word to describe AWS re:Invent 2017, it would be “popular”. There were over 43 000 attendees this year. The conference organizers and staff did an amazing job rising to the challenge, keeping folks corralled and working hard to manage expectations. I had a fun time; it was great to meet up with old friends, make a few new ones, and learn stuff at the same time.&lt;/p&gt;
&lt;p&gt;Sessions had about 75% reserved seating and about 25% of the seats available for walk-ups, but with so many folks at the conference, popular sessions had a lot of waiting in line and a lot of unhappy faces on the people who didn’t make it in.&lt;/p&gt;
&lt;p&gt;The conference was spread over a massive campus: 6 properties from the MGM at one end to the Venetian at the other; a good 30-minute hike if you’re fast and don’t get lost or caught in construction. Shuttles were available, but lines were long and people reported transit times of 60–90 minutes, so other than an early-morning trip on Monday, I just walked. A lot. I put in just over 60km during the week and am very happy to have had good shoes.&lt;/p&gt;
&lt;p&gt;There were lots of interesting breakout sessions, chalk talks, and workshops; reports are favourable on the jams and hackathons. Based on this year, if I get to go again I’m going to try to go to chalk talks exclusively and fill in remaining time with a hackathon and a jam or two. The sessions are great, but they’re recorded and you can watch them in your copious spare time once you get home.&lt;/p&gt;
&lt;h2&gt;General activities&lt;/h2&gt;&lt;h3&gt;Registration&lt;/h3&gt;&lt;p&gt;Registration opened just before 1pm on Sunday and was incredibly efficient. There were tons of folks available to hand out badges, and they had a separate section for people to try on this year’s hoodie before heading over to pick up their size, which eliminated a bottleneck from last year. I was in and out in single-digit minutes.&lt;/p&gt;
&lt;p&gt;Sadly, I lost my hoodie in the crush of the crowd on Monday and had to use last year’s instead. Life is pain.&lt;/p&gt;
&lt;h3&gt;Midnight Madness&lt;/h3&gt;&lt;p&gt;Modeled after &lt;a href=&#34;https://en.wikipedia.org/wiki/Midnight_Madness_(basketball)&#34;&gt;an NCAA basketball tradition&lt;/a&gt;, AWS had a big party and then hit the court at midnight exactly with a new service annoucement: &lt;a href=&#34;https://aws.amazon.com/sumerian/&#34;&gt;Amazon Sumerian&lt;/a&gt;, a 3D, VR, and AR service that lets folks create interactive environments. So far environments are single-user, but it’s not hard to see multi-user coming. There will be a marketplace for folks to create and sell 3D models that anyone can use in their environments, and there’s already support for chatbot actors called Hosts that can interact with users.&lt;/p&gt;
&lt;p&gt;At 1am, Amazon announced support for &lt;a href=&#34;https://aws.amazon.com/digital-media/aws-elemental/&#34;&gt;AWS Elemental&lt;/a&gt;, a full suite of media services targeting folks who broadcast live and pre-recorded video.&lt;/p&gt;
&lt;p&gt;This is the last time I’m going to mention new releases; you can get a full list from the &lt;a href=&#34;https://aws.amazon.com/new/reinvent/&#34;&gt;AWS product announcements&lt;/a&gt; page. Be prepared to scroll.&lt;/p&gt;
&lt;h3&gt;Welcome Reception&lt;/h3&gt;&lt;p&gt;The expo hall opened at 5pm Tuesday for the usual welcome reception; it had been open for most of the day but the reception added food and drinks. It’s very popular and there’s always a mad rush for swag. I had some good chats with vendors and the very smart folks in the AWS section, including the Education folks hidden away in the back corner. The most interesting thing I took away was that AWS has a &lt;a href=&#34;https://aws.amazon.com/education/awseducate/&#34;&gt;program for high-school and college students&lt;/a&gt; that students can sign up for themselves or with a teacher’s help and learn all kinds of stuff about the cloud, with tons of content and credits available.&lt;/p&gt;
&lt;p&gt;Sadly, I wasn’t able to say the right things to the Yubico folks to snag a free key. I want to get a &lt;a href=&#34;https://www.yubico.com/product/yubikey-4-series/#yubikey-4&#34;&gt;4&lt;/a&gt; so that I can experiment with U2F, and I doubt they were handing those out.&lt;/p&gt;
&lt;h3&gt;Tuesday Night Live with Peter DeSantis &lt;a href=&#34;https://www.youtube.com/watch?v=dfEcd3zqPOA&#34;&gt;(video)&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This was a very interesting update on the vast networking infrastructure that AWS has around the world, and segued into a description of the incredible work they’ve done in compute.&lt;/p&gt;
&lt;p&gt;The most inspiring part of the evening, though, was the Autodesk presenter talking about how advances in compute have enabled entirely new ways of working for &lt;em&gt;their&lt;/em&gt; customers and how that’s going to help the world be a better place for the 10 billion people that will soon be here.&lt;/p&gt;
&lt;h3&gt;Wednesday Keynote with Andy Jassy &lt;a href=&#34;https://www.youtube.com/watch?v=1IxDLeFQKPk&#34;&gt;(video)&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;This keynote came with a lot of mind-bubbling announcements, but I promised not to list them. It was a fun time and clearly Andy Jassy was excited to share the news with the world.&lt;/p&gt;
&lt;h3&gt;Thursday Keynote with Werner Vogels &lt;a href=&#34;https://www.youtube.com/watch?v=nFKVzEAm-ts&#34;&gt;(video)&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Werner Vogels’ keynote was more retrospective. I didn’t hike over to the MGM to watch the show and elected to stay in a remote viewing room. I think this was a mistake as I missed out on the energy and wasn’t as engaged.&lt;/p&gt;
&lt;h3&gt;re:Play&lt;/h3&gt;&lt;p&gt;I’m not a big party person, so I just picked up a T-shirt for the folks at home and toured around the megastructures. Yes, megastructures — if you’re going to put on a party for 43 000 people, you need space. There were 3 huge tents and tons of activities, from video games to mini-golf to archery tag to dodgeball to a ball pit and many more, all set to the soothing tones of Team Ezy, Jen Lasher, and DJ Snake.&lt;/p&gt;
&lt;h2&gt;Breakout sessions and workshops &lt;a href=&#34;https://www.youtube.com/user/AmazonWebServices/playlists?sort=dd&amp;amp;shelf_id=27&#34;&gt;(AWS video catalog)&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;I’m just going to dump in the list of sessions that I wanted to go to for future reference; there will be some sparse commentary for the ones that I actually made it to. There were over 1300 breakout sessions spread out over the five properties, so there was really no way to cover even a noticeable fraction of the ones I wanted to see.&lt;/p&gt;
&lt;h3&gt;Community Day&lt;/h3&gt;&lt;h4&gt;DVC202 — The Open Guide to AWS: A GitHub-Based Resource for Practitioners&lt;/h4&gt;&lt;p&gt;&lt;em&gt;The Open Guide to AWS is an open source writing project, which over the past year has become one of the most popular AWS resources on the web. It’s both a written resource on…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;DVC302 — And You Thought You Knew Amazon EC2&lt;/h4&gt;&lt;p&gt;&lt;em&gt;When is the last time you explored the nooks and crannies of Amazon EC2? While you weren’t looking, AWS leveled it up with more features and capabilities than you can shake a…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;DVC304 — Compliance and Top Security Threats in the Cloud — Are You Protected?&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Compliance is necessary and a good thing. However, many compliant companies are still getting breached. In this talk, we discuss the importance of using a risk model to…&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Enterprise&lt;/h3&gt;&lt;h4&gt;ENT346 — How AWS Runs Our Weekly Operations Meetings (Chalk Talk)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;For more than 10 years, AWS has held a weekly meeting to review the operational performance of our services, identify new best practices, and share lessons learned from the…&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;IoT&lt;/h3&gt;&lt;h4&gt;IOT311 — Customer Stories of Things, Cloud, and Analytics on AWS&lt;/h4&gt;&lt;p&gt;&lt;em&gt;In this session, AWS IoT customers talk about the nuances, successes, and challenges of running large-scale IoT deployments on AWS. Hear from customers who have been…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I stumbled into this talk accidentally; I was waiting for a friend who was going to the session, so decided to wait in the walk-up line and ended up going in. The talk was a great discussion of how iRobot does IoT, I really enjoyed seeing the details and challenges that they encountered.&lt;/p&gt;
&lt;h3&gt;Containers&lt;/h3&gt;&lt;h4&gt;CON201 — Containers on AWS — State of the Union&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Just over four years after the first public release of Docker, and three years to the day after the launch of Amazon EC2 Container Service, the use of containers has surged…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This was an interesting outline of what’s come out and what’s coming soon for containers in AWS. Container product manager &lt;a href=&#34;https://twitter.com/mndoci&#34;&gt;Deepak Singh&lt;/a&gt; hinted that AWS Fargate, the new container cluster service, was only a step towards what they really want to do, which is allow customers to run containers without worrying at all about the servers that they’re running on.&lt;/p&gt;
&lt;h4&gt;CON213 — Hands-on Deployment of Kubernetes on AWS (Workshop)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;In this workshop, attendees get hands-on experience using Kubernetes and Kops (Kubernetes Operations), as described in our recent blog. Attendees learn how to provision a…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;CON302 — Building a CI/CD Pipeline for Containers on Amazon ECS&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Containers can make it easier to scale applications in the cloud, but how do you set up your CI/CD workflow to automatically test and deploy code to containerized apps? In…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;CON402 — Advanced Patterns in Microservices Implementation with Amazon ECS&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Scaling a microservice-based infrastructure can be challenging in terms of both technical implementation and developer workflow. In this talk, AWS Solutions Architect Pierre…&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Media&lt;/h3&gt;&lt;h4&gt;MAE401 — Designing for Disney/Marvel Studio-Grade Security &lt;a href=&#34;https://www.youtube.com/watch?v=0VBlhboXRF0&#34;&gt;(video)&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Security is paramount for media storage and workloads and can directly impact a studio’s bottom line. As core media workloads move to the cloud, it’s imperative to examine…&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Content Distribution&lt;/h3&gt;&lt;h4&gt;CTD301 — Amazon CloudFront Flash Talks: Best Practices on Configuring, Securing, Customizing, and Monitoring Your Distribution. &lt;a href=&#34;https://www.youtube.com/watch?v=8U3QdNSFJDU&#34;&gt;(video)&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;em&gt;In this series of technical flash talks, learn directly from Amazon CloudFront engineers about best practices on security, caching, measuring performance using Real User…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;CTD401 — Taking DevOps Closer to the AWS Edge&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Since last year’s ‘Taking DevOps to the Edge’, and with the introduction of AWS Lambda@Edge, the tools available to apply DevOps practices to your application edge have…&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Serverless&lt;/h3&gt;&lt;h4&gt;SRV213 — Thirty Serverless Architectures in 30 Minutes (Chalk Talk)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Don’t blink because in this session, we quickly show you thirty different architectural patterns that you can use with AWS Lambda to solve everything from basic…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This talk was &lt;em&gt;insanely&lt;/em&gt; popular. There were multiple repeats and I didn’t make any of them, but I really wanted to. Maybe there’s a recorded version of this talk somewhere out there? 爛&lt;/p&gt;
&lt;h4&gt;SRV301 — Optimizing Serverless Application Data Tiers with Amazon DynamoDB&lt;/h4&gt;&lt;p&gt;&lt;em&gt;As a fully managed database service, Amazon DynamoDB is a natural fit for serverless architectures. In this session, we dive deep into why and how to use DynamoDB in…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This was a cool session that covered (among other things) how to solve a couple of use cases that I’ve always struggled with, so I walked out a more-informed person.&lt;/p&gt;
&lt;h4&gt;SRV302 — Building CI/CD Pipelines for Serverless Applications &lt;a href=&#34;https://www.youtube.com/watch?v=dCDZ7HR7dms&#34;&gt;(video)&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Building and deploying serverless applications introduces new challenges for developers whose development workflows are optimized for traditional VM-based applications. In…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;SRV305 — What’s New in Serverless &lt;a href=&#34;https://www.youtube.com/watch?v=i_3Xlbu6jls&#34;&gt;(video)&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Join us to learn what’s new in serverless computing and AWS Lambda. Dr. Tim Wagner, General Manager of AWS Lambda and Amazon API Gateway, will share the latest developments…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Fun times are always had in serverless-town. This session started off with cutting a server in half.&lt;/p&gt;
&lt;p&gt;One thing I walked away from the session with is that cold start times have been cut by 80% this year, which is amazing. In a post-session chat, I found out that VPC cold starts are still going to be slow until they re-architect how Lambda attaches the ENI; I’d hoped that some of the container networking work released this year would help but apparently the sausage isn’t made that way.&lt;/p&gt;
&lt;h4&gt;SRV307 — Operating Your Serverless API in Production at Scale &lt;a href=&#34;https://www.youtube.com/watch?v=tIfqpM3o55s&#34;&gt;(video)&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;em&gt;In this session, you will learn how to deploy, monitor and manage your serverless APIs in production. We will deep dive into advanced capabilities of API Gateway that enable…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;SRV308 — Securing Serverless Applications Step-by-step &lt;a href=&#34;https://www.youtube.com/watch?v=B3j4xql7we0&#34;&gt;(video)&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;em&gt;You need a new approach to security for serverless applications. Classic approaches just don’t make sense, because tools and process can only take you so far…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This was an excellent talk. &lt;a href=&#34;https://twitter.com/marknca&#34;&gt;Mark Nunnikhoven&lt;/a&gt;’s practical, clear approach to application security made this a fun walk-through of practical steps that developers and organizations can take to make their serverless applications more secure. 100% recommended.&lt;/p&gt;
&lt;h4&gt;SRV310 — Designing Microservices with Serverless&lt;/h4&gt;&lt;p&gt;&lt;em&gt;When designing microservices there are a number of things to think about. Just for starters, the bounds of their functionality, how they communicate with their dependencies,…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;SRV320 — Best Practices for Using AWS Lambda with RDS/RDBMS Solutions (Chalk Talk)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Are you considering using AWS Lambda with your RDS/RDBMS solutions, but don’t know where to start? In this session, we look at recommended architectural patterns and best…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;SRV321 — Serverless Reactive Microservices on AWS (Chalk Talk)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;In this talk, we will cover the concepts of Reactive Microservices Architecture, a set of patterns and best practices for implementing backend systems with very high scaling…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;SRV329 — Lessons in Serverless Architecture for IoT from iRobot (Chalk Talk)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;The event-driven nature of serverless architecture is a natural fit for IoT use cases. In this chalk talk, we cover iRobot’s use case and requirements, detail the serverless…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;SRV401 — Become a Serverless Black Belt: Optimizing Your Serverless Applications &lt;a href=&#34;https://www.youtube.com/watch?v=oQFORsso2go&#34;&gt;(video)&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Are you an experienced serverless developer who wants a handy guide to unleash the full power of serverless architectures for your production workloads? Do you have questions…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;SRV403 — Serverless Authentication and Authorization: Identity Management for Serverless Applications&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Many serverless applications need a way to manage end user identities and support sign-ups and sign-ins. Join this session to learn real-world design patterns for…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;SRV425 — Serverless OAuth: Authorizing Third-Party Applications to Your Serverless API (Workshop)&lt;/h4&gt;&lt;p&gt;By using serverless architectures, startups, and enterprises are building and running modern applications and services with increased agility and simplified scalability, all…&lt;/p&gt;
&lt;h3&gt;Security&lt;/h3&gt;&lt;h4&gt;SID205 — Building the Largest Repo for Serverless Compliance-as-Code &lt;a href=&#34;https://www.youtube.com/watch?v=VR_4209ewIo&#34;&gt;(video)&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;em&gt;When you use the cloud to enable speed and agility, how do you know if you did it right? We are on a mission to help builders follow industry best practices within security…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;SID312 — DevSecOps Capture the Flag (Workshop)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Notice: This Workshop requires a laptop computer and an active AWS account with Administrator privileges. In this Capture the Flag workshop, we divide groups into teams and…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;SID332 — Identity Management for Your Users and Apps: A Deep Dive on Amazon Cognito &lt;a href=&#34;https://www.youtube.com/watch?v=jLQjQpUYw6g&#34;&gt;(video)&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Learn how to set up an end-user directory, secure sign-up and sign-in, manage user profiles, authenticate and authorize your APIs, federate from enterprise and social…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;SID343 — User Management and App Authentication with Amazon Cognito (Workshop)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Notice: This Workshop requires a laptop computer and an active AWS account with Administrator privileges. Are you curious about how to authenticate and authorize your…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;SID401 — Let’s Dive Deep Together: Advancing Web Application Security (Chalk Talk)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Beginning with a recap of best practices in CloudFront, AWS WAF, Route 53, and Amazon VPC security, we break into small teams to work together on improving the security of a…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;SID402 — An AWS Security Odyssey: Implementing Security Controls in the World of Internet, Big Data, IoT and E-Commerce Platforms (Workshop)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Notice: This Workshop requires a laptop computer and an active AWS account with Administrator privileges. This workshop will give participants the opportunity to take a…&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Financial Services&lt;/h3&gt;&lt;h4&gt;FSV301 — Security Anti-Patterns: Mistakes to Avoid&lt;/h4&gt;&lt;p&gt;&lt;em&gt;At AWS, security is job zero. Our infrastructure is architected for the most data-sensitive, financial services companies in the world. We have worked with global enterprises…&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Big Data&lt;/h3&gt;&lt;h4&gt;ABD301 — Analyzing Streaming Data in Real Time with Amazon Kinesis&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Amazon Kinesis makes it easy to collect, process, and analyze real-time, streaming data so you can get timely insights and react quickly to new information. In this session,…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;ABD401 — How Netflix Monitors Applications in Near Real-Time with Amazon Kinesis&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Thousands of services work in concert to deliver millions of hours of video streams to Netflix customers every day. These applications vary in size, function, and technology,…&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Architecture&lt;/h3&gt;&lt;h4&gt;ARC316 — Getting from Here to There: A Journey from On-premises to Serverless Architecture&lt;/h4&gt;&lt;p&gt;&lt;em&gt;In this session, go on a journey from traditional, on-premises applications and architecture to pure cloud-native environments. This transformative approach highlights the…&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;ARC401 — Serverless Architectural Patterns and Best Practices&lt;/h4&gt;&lt;p&gt;&lt;em&gt;As serverless architectures become more popular, customers need a framework of patterns to help them identify how they can leverage AWS to deploy their workloads without…&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Networking&lt;/h3&gt;&lt;h4&gt;NET203 — Using Amazon VPC Flow Logs to Do Predictive Security Analytics (Workshop)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Ready to secure your network and application in near real-time using Amazon VPC flow logs and AWS Web Application Firewall (WAF)? In this workshop, we incorporate advanced…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This seemed like it was going to be a really interesting workshop; unfortunately the majority of the time was spent in lead-up and very little time was spent on the parts that I was interested in. I’m hoping to put together something that covers the data enrichment parts of the process and gets into the machine learning — certainly not an area of expertise for me, but perhaps something I can post about as I learn.&lt;/p&gt;
&lt;h4&gt;NET403 — Deep Dive: AWS Direct Connect and VPNs&lt;/h4&gt;&lt;p&gt;&lt;em&gt;As enterprises move to the cloud, robust connectivity is often an early consideration. AWS Direct Connect provides a more consistent network experience for accessing your AWS…&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;DevOps&lt;/h3&gt;&lt;h4&gt;DEV401 — Advanced DevOps Practices for AWS (Workshop)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Advanced DevOps Practices for AWS is designed to provide concise and prescriptive guidance on how to build proper DevOps solutions in AWS using common patterns and best…&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Mobile&lt;/h3&gt;&lt;h4&gt;MBL305 — Implement User Onboarding, Sign-Up, and Sign-In for Mobile and Web Applications with Amazon Cognito&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Learn how to use Amazon Cognito to build the user identity management workflows, including user on-boarding, sign-up, and sign-on for mobile and web applications.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Machine Learning&lt;/h3&gt;&lt;h4&gt;MCL212 — AWS DeepLens workshop: Building Computer Vision Applications (Workshop)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;In this workshop, developers have the opportunity to learn how to build and deploy computer vision models, such as face detection and object analysis using the AWS DeepLens…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There was no way that I was going to make it into one of these sessions; they were easily the most popular workshops of the week, announced during the Andy Jassy keynote, with 15 repeat sessions throughout Wednesday and Thursday. Two lucky colleagues did get in and had fun with their new DeepLens devices; I’m hoping they share their experience with the rest of us.&lt;/p&gt;
&lt;h3&gt;Databases&lt;/h3&gt;&lt;h4&gt;DAT405 — Workshop on Advanced Design Patterns for Amazon DynamoDB (Workshop)&lt;/h4&gt;&lt;p&gt;&lt;em&gt;Join us for the first-ever Amazon DynamoDB practical hands-on workshop. This session is designed for developers, engineers, and database administrators who are involved in…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I am so bummed that I missed this. It would have been fantastic to get some non-trivial practical experience with DynamoDB. I wish AWS posted their workshop material online so that folks could play around with the examples.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>I feel like a traitor. Or a fool.</title>
      <link>https://geoffbaskwill.ca/posts/i-feel-like-a-traitor-or-a-fool/</link>
      <pubDate>Sun, 18 Jun 2017 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/i-feel-like-a-traitor-or-a-fool/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;images/networking.webp&#34; alt=&#34;&#34;&gt;&lt;a href=&#34;https://www.flickr.com/photos/andrewfhart/8106200690&#34;&gt;https://www.flickr.com/photos/andrewfhart/8106200690&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Recently I signed up for the A Cloud Guru &lt;a href=&#34;https://acloud.guru/learn/aws-certified-advanced-networking-specialty&#34;&gt;AWS advanced networking certification prep course&lt;/a&gt; put together by Adrian Cantrill.&lt;/p&gt;
&lt;p&gt;After the obligatory OSI 7-layer modules, which I watched because &lt;em&gt;you never know&lt;/em&gt;, things rapidly got interesting. I found myself learning about BGP, AWS VPC peering, how to multi-home EC2 instances with ENIs, how to set up a shared-services network that could talk to peered VPCs with overlapping CIDR ranges (turns out it’s not even that difficult), and all kinds of really cool stuff.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I got nerd-sniped.&lt;/strong&gt; Big time. Networking was a big part of my early career, and the course scraped a bunch of rust off and added a whole new layer of awesome things to learn about. My brain was all hopped up on learning-juice, spinning and carousing and saying to itself “THIS IS SO COOL.”&lt;/p&gt;
&lt;p&gt;Then something hit me like a cross-town bus.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Everything I’d just been geeking out about is completely irrelevant in the serverless world.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Last year I went to the first &lt;a href=&#34;https://serverlessconf.io&#34;&gt;Serverlessconf&lt;/a&gt;. It was great, tons of fun; I met some really smart folks and learned that people are doing real work in a whole new way. There is a whole new solution space becoming available, a solution space where, as &lt;a href=&#34;https://www.linkedin.com/in/timawagner&#34;&gt;Tim Wagner&lt;/a&gt; put it, you don’t have to worry about whether you have cattle or pets, you just show up at the drive-through and get the burger you were looking for. It’s arguable that the vast majority of problems people are trying to solve today fit into this space: take an event, do some transforms on it, send it somewhere else, maybe do some aggregation and correlation later. It’s a way to focus on your core competency and let other folks worry about the servers, the mechanics of routing those events to your code, instantiating it, and keeping everything available.&lt;/p&gt;
&lt;p&gt;As someone who’s pretty keenly interested in the future of serverless, it seems either traitorous or foolish to be taking a course on advanced networking.&lt;/p&gt;
&lt;p&gt;What faithful, intelligent person would invest time in learning all sorts of networking shenanigans when there’s so much to learn in serverless space?&lt;/p&gt;
&lt;p&gt;It’s a week later now, and I’ve realized that the answer to my question is “people like me.” People who think that even though there is a huge bright shiny serverless future out there, someone still has to know how it all fits together. People who think that the road between today and that shiny future will have more than one bump in it. People who just like learning new things every day.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>AWS Certified Security Specialty</title>
      <link>https://geoffbaskwill.ca/posts/aws-certified-security-specialty/</link>
      <pubDate>Mon, 21 Nov 2016 00:00:00 +0000</pubDate>
      
      <guid>https://geoffbaskwill.ca/posts/aws-certified-security-specialty/</guid>
      <description>&lt;p&gt;A good friend of mine has a habit of &lt;a href=&#34;https://en.wikipedia.org/wiki/Gauntlet_(glove)#%22Throwing_down_the_gauntlet%22&#34;&gt;throwing gauntlets around&lt;/a&gt; like they’re nothing. “So, Geoff,” he’ll start casually, “did you know there are some new AWS specialty certifications in beta now?”&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;images/gauntlet.png&#34; alt=&#34;&#34; title=&#34;Thanos holding up the Infinity Gauntlet&#34;&gt;&lt;/p&gt;
&lt;p&gt;This is usually about the time that I realize I’m in for a world of pain, uh, learning. It turns out that this time AWS has come up with three exams that I’ll conservatively call pro-level.&lt;/p&gt;
&lt;p&gt;I’ve been learning a lot over the past year and a bit, negotiating a career transition from telecom to security, so I’d consider myself a firm novice when it comes to all this stuff, but it’s not like we were doing nothing over in the old world, so I figured I’d check out the landscape for the security certification. I find that preparing for certifications is a great way to learn at least the theory, and sometimes get a bit of practice in as well. When some detail doesn’t click right away, it’s easy enough to spin something up and try it out to figure out how things are working.&lt;/p&gt;
&lt;p&gt;Keep in mind that the “AWS recommendations” includes, as a single bullet point among several, “AWS documentation.” So, since we’re talking about security, let’s take that as the reference docs, programmers’ guides, and best practices for 50+ services.&lt;/p&gt;
&lt;p&gt;Next is the alphabet soup: as &lt;a href=&#34;https://markn.ca/&#34;&gt;@marknca&lt;/a&gt; says, “candidates should be familiar with &lt;a href=&#34;http://www.iso.org/iso/home/standards/management-standards/iso27001.htm&#34;&gt;ISO 27001&lt;/a&gt;, &lt;a href=&#34;https://www.pcisecuritystandards.org/pci_security/&#34;&gt;PCI DSS&lt;/a&gt;, &lt;a href=&#34;https://www.hhs.gov/hipaa/for-professionals/security/laws-regulations/&#34;&gt;HIPAA&lt;/a&gt;, &lt;a href=&#34;http://sas70.com/sas70_overview.html&#34;&gt;SAS 70&lt;/a&gt;, &lt;a href=&#34;https://www.ssae-16.com/soc-1/&#34;&gt;SOC 1&lt;/a&gt;, &lt;a href=&#34;https://www.dhs.gov/fisma&#34;&gt;FISMA&lt;/a&gt;, and &lt;a href=&#34;http://csrc.nist.gov/&#34;&gt;NIST&lt;/a&gt;.” That’s “and”, not “or”, folks.&lt;/p&gt;
&lt;p&gt;Right now I’m on the edge. The reading so far has been pretty much stuff I’ve seen before one way or another, so maybe, just maybe, I’ll give the exam a shot.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
