<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Chase Douglas]]></title><description><![CDATA[Posts about projects I'm working on, interesting tech insights, and navigating the world as a "product engineer" founding startups and working inside companies large and small.]]></description><link>https://chasedouglas.net</link><image><url>https://substackcdn.com/image/fetch/$s_!vxPj!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F947b5297-8cef-4e95-9898-091249fea030_1200x1200.png</url><title>Chase Douglas</title><link>https://chasedouglas.net</link></image><generator>Substack</generator><lastBuildDate>Wed, 15 Apr 2026 08:27:51 GMT</lastBuildDate><atom:link href="https://chasedouglas.net/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Chase Douglas]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[txase@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[txase@substack.com]]></itunes:email><itunes:name><![CDATA[Chase Douglas]]></itunes:name></itunes:owner><itunes:author><![CDATA[Chase Douglas]]></itunes:author><googleplay:owner><![CDATA[txase@substack.com]]></googleplay:owner><googleplay:email><![CDATA[txase@substack.com]]></googleplay:email><googleplay:author><![CDATA[Chase Douglas]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Archodex at KubeCon]]></title><description><![CDATA[Also, give us feedback as part of our soft-public-launch!]]></description><link>https://chasedouglas.net/p/archodex-at-kubecon-na-2025</link><guid isPermaLink="false">https://chasedouglas.net/p/archodex-at-kubecon-na-2025</guid><dc:creator><![CDATA[Chase Douglas]]></dc:creator><pubDate>Tue, 04 Nov 2025 17:36:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BPX8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fdddf9f-26ed-4683-8343-b015bf1d25f9_3838x1996.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It&#8217;s been a while since I <a href="https://chasedouglas.net/p/i-solemnly-swear-i-am-up-to-no-good">last posted</a> about <a href="https://archodex.com">Archodex</a>, my DevSecOps project that <strong>tells you where your secrets / API keys live and which workloads use them</strong>. There have been quite a few updates to Archodex since then!</p><p>But first: I&#8217;ll be at <a href="https://events.linuxfoundation.org/kubecon-cloudnativecon-north-america/">KubeCon North America</a> next week in Atlanta. Can I buy you a coffee/beer/etc there in exchange for insights on your DevSecOps challenges (and maybe some feedback on Archodex)?</p><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://cal.com/chasedouglas/kubecon-2025-na&quot;,&quot;text&quot;:&quot;Let's chat at KubeCon!&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://cal.com/chasedouglas/kubecon-2025-na"><span>Let's chat at KubeCon!</span></a></p><p></p><p>Now, here&#8217;s what we&#8217;ve been up to since my last post:<br></p><ul><li><p>My friend <a href="https://archodex.com/team">Apurva Jantrania has joined the fun</a>! We&#8217;re now two ex-AWS Principal Engineers working to solve secrets management and other DevSecOps challenges. Don&#8217;t worry, this is still a labor of love with no outside investment, which means we get to focus solely on building the best software we can.<br></p></li><li><p>We have a fun new <a href="https://play.archodex.com/">Playground experience</a>. We know you don&#8217;t have time or energy set up new services just to figure out what they can do. This short-circuits trying Archodex to a 3-minute interactive demo.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BPX8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fdddf9f-26ed-4683-8343-b015bf1d25f9_3838x1996.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BPX8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fdddf9f-26ed-4683-8343-b015bf1d25f9_3838x1996.png 424w, https://substackcdn.com/image/fetch/$s_!BPX8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fdddf9f-26ed-4683-8343-b015bf1d25f9_3838x1996.png 848w, https://substackcdn.com/image/fetch/$s_!BPX8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fdddf9f-26ed-4683-8343-b015bf1d25f9_3838x1996.png 1272w, https://substackcdn.com/image/fetch/$s_!BPX8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fdddf9f-26ed-4683-8343-b015bf1d25f9_3838x1996.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BPX8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fdddf9f-26ed-4683-8343-b015bf1d25f9_3838x1996.png" width="1456" height="757" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9fdddf9f-26ed-4683-8343-b015bf1d25f9_3838x1996.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:757,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:586446,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://chasedouglas.net/i/177610465?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fdddf9f-26ed-4683-8343-b015bf1d25f9_3838x1996.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BPX8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fdddf9f-26ed-4683-8343-b015bf1d25f9_3838x1996.png 424w, https://substackcdn.com/image/fetch/$s_!BPX8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fdddf9f-26ed-4683-8343-b015bf1d25f9_3838x1996.png 848w, https://substackcdn.com/image/fetch/$s_!BPX8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fdddf9f-26ed-4683-8343-b015bf1d25f9_3838x1996.png 1272w, https://substackcdn.com/image/fetch/$s_!BPX8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fdddf9f-26ed-4683-8343-b015bf1d25f9_3838x1996.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Archodex Playground showing a Secret with multiple issues</figcaption></figure></div></li><li><p>You can now <a href="https://app.archodex.com/signup">sign up</a> and start using Archodex! Consider this a soft-public-launch where more of our friends can try it out and help us by providing feedback. We&#8217;re not going to be broadcasting about Archodex yet, though feel free to send people our way if we can help them.<br></p></li><li><p>We&#8217;ve released the source code for all our components as <a href="https://archodex.com/licensing">Fair Source</a>. This gives you the right to improve or repair Archodex however you need and allows us to build a sustainable project for the long term. I&#8217;m really excited about developing Archodex in the open!<br></p></li><li><p>You can now <a href="https://archodex.com/docs/self-host">self-host</a> the Archodex service wherever you like. Some folks need their data to remain in their control and/or on their own premises. You can even run the agent in <a href="https://archodex.com/docs/getting-started/logging-only-mode">logging-only mode</a>, which works even when completely firewalled off from all networks.<br></p></li><li><p>If you&#8217;re curious <em>how</em> our agent is able to performantly introspect your API interactions to discover secrets usage, you can take a look at the <a href="https://github.com/Archodex/archodex-agent/blob/main/technical_details.md">technical details documentation</a> of our agent (or even <a href="https://github.com/Archodex/archodex-agent">check out our source code</a>!). We had to really innovate to solve a bunch of tricky eBPF challenges!<br></p></li></ul><p>So that&#8217;s what we&#8217;ve been working on lately. If you&#8217;ll be at KubeCon, please reach out!<br></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://cal.com/chasedouglas/kubecon-2025-na&quot;,&quot;text&quot;:&quot;Let's chat at KubeCon!&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://cal.com/chasedouglas/kubecon-2025-na"><span>Let's chat at KubeCon!</span></a></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://chasedouglas.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for more updates about Archodex and other personal projects (like my post about <a href="https://chasedouglas.net/p/vaultwarden-serverless">Vaultwarden Serverless</a>).</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[I Solemnly Swear I am up to No Good]]></title><description><![CDATA[Platform Observability: What would you do with a map of all your IT resources, what they talked to, how, and why?]]></description><link>https://chasedouglas.net/p/i-solemnly-swear-i-am-up-to-no-good</link><guid isPermaLink="false">https://chasedouglas.net/p/i-solemnly-swear-i-am-up-to-no-good</guid><dc:creator><![CDATA[Chase Douglas]]></dc:creator><pubDate>Fri, 28 Feb 2025 19:19:18 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ERVg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F807c8cad-614a-4c28-a19e-213840063b70_2766x1936.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve focused my career on helping engineers, their teams, and their organizations build better software faster. I built novel observability solutions (<a href="https://newrelic.com/platform/browser-monitoring">New Relic Browser</a>), deep security tech to stop SQL and XSS injection (<a href="https://betakit.com/montreal-based-immunio-acquired-by-trend-micro/">IMMUNIO, now part of Trend Micro</a>), and a developer experience (DX) platform for the cloud (<a href="https://stackery.io">Stackery</a>, now <a href="https://aws.amazon.com/infrastructure-composer/">AWS Infrastructure Composer</a>).</p><p>A common theme emerged from these efforts: It is really hard for engineering organizations to keep track of their IT resources, how they interact, and who accesses them. This post details the problem and provides a teaser of the &#8220;Platform Observability&#8221; solution I&#8217;m building to solve it.</p><h2>New Relic&#8217;s El Dorado</h2><p>I started as employee number ~80 at New Relic. My goal was to architect the first Browser Observability product. Six weeks before the public beta launch we realized we needed to sync with the Ops side of the org about our ingestion requirements. There was already a service, simply named &#8220;Beacon&#8221;, doing a tiny amount of browser telemetry ingestion (e.g. page load latency) for customers. We were extending it to ingest much more observability data (JS errors, XHR timing data, etc.). We needed to confirm that the service could handle this additional load.</p><p>But who owned &#8220;Beacon&#8221;? Thankfully, New Relic engineering fit on one floor of Portland&#8217;s Big Pink tower, so this only took <em><strong>a couple days to nail down.</strong></em> Beacon had become a long forgotten service because it just &#8220;worked&#8221; and hadn&#8217;t been touched for a while. The original code had been written by a few of the first five employees at the company, who now had titles like CTO and CPO. Getting answers to questions that normally might take a quick conversation between engineers became days of back and forth as the organization tried to remember long-forgotten details of the service. Thankfully we nailed down these details and launched on time and without issue.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><p>After I left New Relic in 2014 the company continued on its rapid startup-to-public-company ascent. But the problem of tracking IT resources and who owned them only grew. I&#8217;ve been told of offsites where key engineering leaders attempted to remember and diagram all the microservices that formed the New Relic platform. Inevitably these attempts ended in failure. <a href="https://en.wikipedia.org/wiki/Ward_Cunningham">Ward Cunningham</a>, inventor of Wikis and a Principal Engineer at New Relic at the time, led an effort to solve this challenge. That effort, through a few fits and starts, became <a href="https://www.infoq.com/news/2017/09/el-dorado-released/">El Dorado</a>, New Relic&#8217;s attempt to produce a map of all IT resources.</p><p>El Dorado was a massive undertaking. Unfortunately, only the frontend became open source. The backend was much larger, ingesting information from dozens of sources including git repos, project management tools, and HR systems. Whether or not the project uncovered untold riches is debatable, but it is clear that the problem of understanding New Relic&#8217;s IT footprint was painful enough to spend significant resources on.</p><h2>Stackery&#8217;s Architecture Diagrams</h2><p>In 2017 I co-founded <a href="https://stackery.io">Stackery</a> as a DX platform for serverless cloud applications. A key feature was its visual drag-and-drop interface for editing your Infrastructure-as-Code (IaC) templates. While the editing functionality was useful, it was only near the end of our time as an independent company that we realized one of the most impactful benefits of our solution was simply being able to visualize the architecture embedded within IaC templates. One of our customers said to me: &#8220;We pay $20k/yr for <a href="https://www.lucidchart.com/">Lucidchart</a> just to be able to spend our Architects&#8217; valuable time to maintain all our architecture diagrams by hand.&#8221; Stackery focused on individual serverless applications, but this customer was asking for more: Automatic documention of their entire IT footprint.</p><h2>A (Marauder's) Map of your IT</h2><p>The <a href="https://harrypotter.fandom.com/wiki/Marauder's_Map">Marauder's Map</a> was a magical document in the Harry Potter series. After waving one&#8217;s wand and saying, &#8220;I Solemnly Swear I am up to No Good&#8221;, the map would &#8220;unlock&#8221; to show everyone&#8217;s location, in realtime, at Hogwarts School. What if we could do the same for organizations&#8217; IT footprints?</p><p>This is what I&#8217;m working on. <a href="https://archodex.com">Archodex</a> is the first <em>Platform Observability</em> solution. It efficiently observes traffic between your services, including encrypted HTTPS API requests and responses, picking out the important details that enable automated documentation and deep introspection of your IT footprint.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ERVg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F807c8cad-614a-4c28-a19e-213840063b70_2766x1936.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ERVg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F807c8cad-614a-4c28-a19e-213840063b70_2766x1936.png 424w, https://substackcdn.com/image/fetch/$s_!ERVg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F807c8cad-614a-4c28-a19e-213840063b70_2766x1936.png 848w, https://substackcdn.com/image/fetch/$s_!ERVg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F807c8cad-614a-4c28-a19e-213840063b70_2766x1936.png 1272w, https://substackcdn.com/image/fetch/$s_!ERVg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F807c8cad-614a-4c28-a19e-213840063b70_2766x1936.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ERVg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F807c8cad-614a-4c28-a19e-213840063b70_2766x1936.png" width="1456" height="1019" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/807c8cad-614a-4c28-a19e-213840063b70_2766x1936.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1019,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:608888,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://chasedouglas.net/i/158112818?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F807c8cad-614a-4c28-a19e-213840063b70_2766x1936.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ERVg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F807c8cad-614a-4c28-a19e-213840063b70_2766x1936.png 424w, https://substackcdn.com/image/fetch/$s_!ERVg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F807c8cad-614a-4c28-a19e-213840063b70_2766x1936.png 848w, https://substackcdn.com/image/fetch/$s_!ERVg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F807c8cad-614a-4c28-a19e-213840063b70_2766x1936.png 1272w, https://substackcdn.com/image/fetch/$s_!ERVg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F807c8cad-614a-4c28-a19e-213840063b70_2766x1936.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Let&#8217;s imagine an engineer comes to you and says: &#8220;We need to rotate the staging sprockets DB credentials.&#8221; But now you need to know which services use those credentials to ensure you can rotate them safely. This map shows you that the Kubernetes <em>sprockets</em> service running in the <em>default</em> namespace accesses the <em>stg/sprockets/db_creds</em> secret in the <em>vault.acme.com</em> <a href="https://www.hashicorp.com/en/products/vault">Hashicorp Vault</a> service. Now you have the information you need to make sure your credential rotation can be done safely.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p><p>Let&#8217;s imagine another scenario: A security engineer wants to understand more about who and what can access a secret. Here we see that the GitHub user <a href="https://github.com/txase">@txase</a> (me!) has read the prod DB secret in the vault. Let&#8217;s click the link to find out more details.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7Alm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba59c436-b901-45ad-99ef-a6201661fd0f_1631x1914.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7Alm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba59c436-b901-45ad-99ef-a6201661fd0f_1631x1914.png 424w, https://substackcdn.com/image/fetch/$s_!7Alm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba59c436-b901-45ad-99ef-a6201661fd0f_1631x1914.png 848w, https://substackcdn.com/image/fetch/$s_!7Alm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba59c436-b901-45ad-99ef-a6201661fd0f_1631x1914.png 1272w, https://substackcdn.com/image/fetch/$s_!7Alm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba59c436-b901-45ad-99ef-a6201661fd0f_1631x1914.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7Alm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba59c436-b901-45ad-99ef-a6201661fd0f_1631x1914.png" width="1456" height="1709" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba59c436-b901-45ad-99ef-a6201661fd0f_1631x1914.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1709,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:260166,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://chasedouglas.net/i/158112818?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba59c436-b901-45ad-99ef-a6201661fd0f_1631x1914.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7Alm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba59c436-b901-45ad-99ef-a6201661fd0f_1631x1914.png 424w, https://substackcdn.com/image/fetch/$s_!7Alm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba59c436-b901-45ad-99ef-a6201661fd0f_1631x1914.png 848w, https://substackcdn.com/image/fetch/$s_!7Alm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba59c436-b901-45ad-99ef-a6201661fd0f_1631x1914.png 1272w, https://substackcdn.com/image/fetch/$s_!7Alm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba59c436-b901-45ad-99ef-a6201661fd0f_1631x1914.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The image on the left above is show first, and the image on the right appears when we click &#8220;Show Event Chains&#8221;. The Event Chain details tell us: I, GitHub user @txase, <em>Assumed</em> myself (<a href="https://github.blog/changelog/2022-07-19-differentiating-triggering-actor-from-executing-actor/">a GitHub Actions detail</a>) to <em>Invoke</em> the workflow <em>.github/workflows/deploy.yml</em> in the <em>txase/archodex-demo-sprockets</em> repo, which <em>Read</em> the <em>prod/sprockets/db_creds</em> secret. Archodex provides a rich level of detail to help engineering organizations understand their IT footprint, including how resources and people interact.</p><h2>More to Come</h2><p>This is just a tease of <a href="https://archodex.com">Archodex</a>. You can find out more about planned functionality at its website, and you can <a href="https://archodex.com/signup">request early access</a> if you need to solve painful problems today. Current plans are to make Archodex free for individual and team-sized usage, available for folks to download and run for free themselves, and offer it as a managed service. I&#8217;m polishing it up to share publicly, stay tuned!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://chasedouglas.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">This post was show-and-tell, but with an emphasis on sharing insights from past experiences. I&#8217;ll continue posting a mix of content, and I hope you consider subscribing!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>I&#8217;m particularly proud of this launch. Even though we clearly marked the new features as &#8220;beta&#8221; functionality that should not be enabled on production sites, we had many customers click the button to do so. Services like <a href="https://bitbucket.org">Bitbucket</a> (back then a substantial competitor of GitHub, even if its market share has diminished since) began sending our relatively large and deeply instrumenting JS agent to all their customers&#8217; browsers. The agent and service worked flawlessly. In the first 6 months post-beta-launch we only had one issue to &#8220;fix&#8221;: Making sure that if we were used in combination with a different company&#8217;s browser instrumentation agent the site wouldn&#8217;t break due to a bug in the other company&#8217;s code.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>I lie. This example actually does not give you all the info you need. There may be source repos with the DB credentials hardcoded within them. The secret may exist in multiple secret stores. Etc., etc. These will also be noted in Archodex system maps and records, but are not shown here in order to simplify the example scenario.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Vaultwarden Serverless]]></title><description><![CDATA[or: How I Learned to Stop Worrying and Love AWS Aurora DSQL]]></description><link>https://chasedouglas.net/p/vaultwarden-serverless</link><guid isPermaLink="false">https://chasedouglas.net/p/vaultwarden-serverless</guid><dc:creator><![CDATA[Chase Douglas]]></dc:creator><pubDate>Tue, 18 Feb 2025 22:12:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!298v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32636d57-8732-455f-939f-62be7e4874ae_1260x660.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It&#8217;s been a while since I published anything. While I worked at AWS there was a corporate PR muzzle that meant I was barred from saying much of anything, let along <em>interesting</em> things. I&#8217;ve also been quiet this past year while working on a new project, <strong><a href="https://archodex.com/">Archodex</a></strong>. It&#8217;s not ready to show off publicly, yet, but if you need help finding where your secrets are used across your workloads or anything else it can help you figure out in your platform environment, do get in touch. (You can always reach me at chasedouglas@gmail.com, don&#8217;t be a stranger if I can be of any help!)</p><p>In between things I built a POC side-project to scratch an itch and learn more about <strong><a href="https://aws.amazon.com/rds/aurora/dsql/">AWS Aurora DSQL</a></strong>. I&#8217;m a big believer in the value of a horizontally scalable relational database, and I wanted to find out how well it worked. (If you came here specifically for DSQL takes, you can jump straight to them <strong><a href="https://chasedouglas.net/p/vaultwarden-serverless/#&#167;how-difficult-is-it-to-refactor-a-workload-for-dsql">here</a></strong>.)</p><h2><strong>Motivation</strong></h2><p>My password manager has been bugging me. It&#8217;s become a bit onerous to manage sharing items with family, and it felt like it got really bloated/slow recently. It turns out there was a good reason it got slower<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>, but speed wasn&#8217;t my only issue, and it got me wondering what I could do to solve my daily annoyances with it. I wanted my own password manager solution that worked how I wanted it to. And it turns out I can have my cake and eat it to!</p><p>Password managers aren&#8217;t new. <strong><a href="https://en.wikipedia.org/wiki/Password_manager#History">Bruce Schneier created the first password manager in 1997</a></strong>, and although the tech has changed considerably since then, password managers should be considered a commodity rather than a luxury good at this point. It turns out there is such a &#8220;commodity&#8221; password manager solution via the combination of the official <strong><a href="https://bitwarden.com/blog/quick-guide-bitwarden-client-apps/">Bitwarden clients</a></strong> (e.g. the their browser extensions, iOS and Android apps, and web app) + the community open source <strong><a href="https://github.com/dani-garcia/vaultwarden">Vaultwarden</a></strong> backend service for cross-device syncing.</p><blockquote><p><em>You might be thinking: Hang on, I&#8217;m going to trust a community open source app with all my passwords? This concern is mooted by the fact that <a href="https://bitwarden.com/help/bitwarden-security-white-paper/#data-protection-at-rest">all encryption and decryption occurs inside the official Bitwarden clients</a>. The API service, which is what Vaultwarden provides, merely stores and retrieves already encrypted items. In theory, you could even make your vault database and files public because they cannot be decrypted without your master password.</em></p></blockquote><p><strong>But also,</strong> I wanted to play with the new <strong><a href="https://aws.amazon.com/rds/aurora/dsql/">Amazon Aurora DSQL</a></strong> service, which promises a truly serverless<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> <strong><a href="https://www.postgresql.org/">PostgreSQL</a></strong>-comptible(-ish) database :).</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://chasedouglas.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">BTW, if you like this analysis of new cloud tech, you&#8217;ll want to subscribe. There are more posts in the pipeline!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>A Serverless Password Manager Backend</strong></h2><p>Having my own password manager with cross-device syncing requires operating a cloud service. But I don&#8217;t want to deal with the typical operational headaches of managing an always-on service. I previously <strong><a href="https://chasedouglas.net/about">built a company</a></strong> to help people run cloud apps with less operational headaches using serverless services. I wondered if I could find a password manager with a serverless backend.</p><p>Enter <strong><a href="https://github.com/dani-garcia/vaultwarden">Vaultwarden</a></strong>. Vaultwarden is a reimplementation of the official Bitwarden backend API service. What makes it ideal here is that it is written in <strong><a href="https://www.rust-lang.org/">Rust</a></strong>. Rust software both initializes and executes <em>fast</em>. This is important because serverless APIs (especially low-throughput APIs like a personal Vaultwarden service) often execute with <strong><a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtime-environment.html#cold-start-latency">cold starts</a></strong>, where response latency includes process initialization.</p><h2><strong>Vaultwarden Serverless Architecture</strong></h2><p>The current Vaultwarden implementation is architected as a stateful single-node service. It saves vaults and other files directly to the filesystem, serves the official Bitwarden web app assets (rebranded as &#8220;Vaultwarden&#8221; assets) from a directory on disk, and connects to SMTP servers or uses a local <strong><a href="https://en.wikipedia.org/wiki/Sendmail">Sendmail</a></strong> installation to send emails. And it uses a relational database (Postgres, MySQL, or SQLite) for account records and to store encrypted items. These would all be a pain to operate and maintain long-term as a personal project, and there are AWS Serverless services for each component that greatly reduce this operational toil. Inserting these services results in the following Vaultwarden Serverless architecture:</p><pre><code><code>CloudFront CDN
&#9500;&#9472; API Lambda Function
&#9474;  &#9500;&#9472; Data S3 Bucket (for encrypted file attachments, etc.)
&#9474;  &#9500;&#9472; Aurora DSQL Database
&#9474;  &#9492;&#9472; Amazon Simple Email Service (SES)
&#9492;&#9472; Web App Assets S3 Bucket</code></code></pre><p>You can find the code for this Vaultwarden Serverless POC <strong><a href="https://github.com/txase/vaultwarden/commits/main/">here</a></strong>.</p><h3><strong>AWS Lambda for the API Service</strong></h3><p><strong><a href="https://aws.amazon.com/lambda/">AWS Lambda</a></strong> is used for the API service. Personal password manager workloads don&#8217;t hit the API frequently (vaults are cached client-side), so we can give our Rust function a ton of memory and CPU to reduce execution time while still staying within the monthly free-tier usage limit. We use the <strong><a href="https://docs.aws.amazon.com/lambda/latest/dg/urls-configuration.html">Lambda Function URL</a></strong> feature with the <strong><a href="https://github.com/awslabs/aws-lambda-web-adapter">Lambda Web Adapter</a></strong> so we don&#8217;t have to modify any code to make the API <em>just work</em> inside a Lambda Function.</p><h3><strong>Amazon S3 for Data and Web Assets</strong></h3><p><strong><a href="https://aws.amazon.com/s3/">Amazon S3</a></strong> is the OG serverless service<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>. Although folks will tell you <em>it is not a filesystem</em>, it can be used to replace a filesystem as a general store of files. For example, instead of saving vault item attachments to <em>/app/data/attachments/&lt;encrypted name&gt;</em> on the local disk, we can save it to <em>s3://&lt;data bucket&gt;/attachments/&lt;encrypted name&gt;</em> in an AWS S3 Bucket. Similarly, instead of serving web assets from <em>/app/web-vault/&lt;asset filename&gt;</em>, we can serve them from <em>s3://&lt;web asset bucket&gt;/&lt;asset filename&gt;</em>. There is also support for streaming files from S3 via <strong><a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html">presigned URLs</a></strong>, meaning our API Function is left mostly to process API requests rather than act as a proxy for file downloads.</p><h3><strong>Amazon Simple Email Service (SES) for Sending Emails</strong></h3><p><strong><a href="https://aws.amazon.com/ses/">Amazon SES</a></strong> is used for sending email. Not because sending email is hard, but because sending email that won&#8217;t go straight to spam folders is hard. After SES is configured for sending email from our domain with <strong><a href="https://www.cloudflare.com/learning/email-security/dmarc-dkim-spf/">DKIM, SPF, and DMARC</a></strong>, we can then use it to send email on our behalf.</p><h3><strong>Amazon CloudFront to Combine Routes and Serve from a Custom Domain</strong></h3><p><strong><a href="https://aws.amazon.com/cloudfront/">Amazon CloudFront</a></strong> can be fiddly to work with, but solves a couple challenges for us. It routes web app asset requests straight to our web assets bucket and routes API requests to our Lambda Function URL. CloudFront also makes it easy to serve the backend from a custom domain.</p><h3><strong>Amazon Aurora DSQL for the Database</strong></h3><p>We finally come to <strong><a href="https://aws.amazon.com/rds/aurora/dsql/">Aurora DSQL</a></strong>, AWS&#8217; first truly-Serverless relational database offering. Vaultwarden can speak PostgreSQL. <em>But can it work with DSQL, and how much effort will it take?</em></p><h2><strong>How Difficult is it to Refactor a Workload for DSQL?</strong></h2><p><strong><a href="https://aws.amazon.com/rds/aurora/dsql/">Aurora DSQL</a></strong> is a new service in <em>Preview</em>, meaning most functionality is present and working, but there are both known and unknown issues, some of which will be resolved before GA. The feature scope for GA can also change, meaning we can&#8217;t fully know for sure which features will or will not be supported by then. In rare cases, Preview functionality has been removed before GA due to security or operational concerns. Altogether, this means insights noted here are based on a point-in-time snapshot of service functionality that may or may not be representative of the service at GA. With that caveat, here are my key learnings from refactoring Vaultwarden to use DSQL:</p><h3><strong>Connecting / Authenticating</strong></h3><p>DSQL provides a PostgreSQL-protocol-compatible endpoint, meaning any existing PG client should be able to talk to it. However, DSQL only supports TLS-encrypted connections authenticated via temporary credentials that are valid for only 15 minutes. AWS is absolutely making the right decision here in enforcing authentication and encryption best-practices, but it may not be easy to refactor existing applications and libraries to use this approach. Vaultwarden uses the synchronous <strong><a href="https://crates.io/crates/diesel">Diesel crate</a></strong> for database queries, and adding temporary credentials for authentication required a decent amount of <strong><a href="https://github.com/txase/vaultwarden/commit/3e886e670e7e026c188af1d856ca8ae2cc3113b5#diff-272495002e889af90652bc3fcd7b0949f12910bca56e5f85d7320538f5b461d2">new and complex code</a></strong>. Connection encryption and authentication alone will require significant application developer involvement in order to adopt DSQL for existing workloads. Even if a workload uses <strong><a href="https://aws.amazon.com/rds/aurora/">Amazon Aurora PostgreSQL</a></strong> with IAM authentication today, it will need to be modified to use the new DSQL SDK to generate signed credentials. You cannot simply swap in an Amazon Aurora DSQL endpoint for an existing Amazon Aurora RDS endpoint.</p><h3><strong>Migrations</strong></h3><p><strong><a href="https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-postgresql-compatibility-unsupported-features.html">DSQL only supports one DDL statement per transaction</a></strong>. It is very common for existing migrations to contain multiple DDL statements, however. For example, a migration may move data from columns in one table to a new table by creating the new table, copying the data to the new table, then deleting columns from the original table. The creation of the new table and the deletion of columns from the old table involve (at least) two separate DDL statements. You also want this entire migration to occur within one transaction to ensure either all the data is copied into the new table, or the database is left in its original state. We don&#8217;t want to end up in some half-way state with a new table and some partially copied and/or partially deleted data spread across two tables.</p><p>This is a significant cause for concern, but one that is not necessarily a deal-breaker. It means that migrations have to be performed with even more attention, and that migrations should be written such that an operator can manually complete or revert individual migrations if they fail (for any potential reason) part-way through. The tradeoff is that while DSQL should make day-to-day operations easier (e.g. because it can horizontally scale, it should have less potential for failing at larger data set sizes), it may make migrations more challenging. At least migrations happen at known points in time instead of other kinds of failures that can happen at random times.</p><h3><strong>Foreign Keys</strong></h3><p><strong><a href="https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-postgresql-compatibility-unsupported-features.html">DSQL does not support Foreign Keys (FKs)</a></strong>. This is a more commonly known DSQL limitation, and was the first concern I audited the Vaultwarden codebase for. Many database schemas define FKs to ensure data consistency. For example, a schema could use FKs to ensure that when a user account record is deleted all the other records associated with the user are also deleted. FKs are also often used for <em>upsert</em> (i.e. insert-if-not-exists-otherwise-update) functionality, though there are other ways this can be accomplished.</p><p>Whether FKs are a concern for your workload depends on its schema and existing queries. In Vaultwarden, FKs are defined for all database backends (PostgreSQL, MySQL, and SQLite), and are used in MySQL and SQLite queries for upsertion, but are not used in PostgreSQL queries. The <strong><a href="https://github.com/dani-garcia/vaultwarden/blob/main/src/db/models/two_factor.rs#L75-L112">Vaultwarden 2FA database model </a></strong><code>save()</code><strong><a href="https://github.com/dani-garcia/vaultwarden/blob/main/src/db/models/two_factor.rs#L75-L112"> function</a></strong> demonstrates an example of this implementation difference.</p><p>To make Vaultwarden work on DSQL I needed to remove all FK definitions from the schema. I accomplished this by initializing a local PostgreSQL database for Vaultwarden then running <code>pg_dump</code> to get all the table definitions. I then searched and removed all FK definitions. Lastly, I saved this schema as <strong><a href="https://github.com/txase/vaultwarden/commit/3e886e670e7e026c188af1d856ca8ae2cc3113b5#diff-661c7a708db7ea1f26b1e60b35df76f34c3f1cd3b27f71ba8392a5a529156aa9">one large initial migration</a></strong>.</p><h3><strong>Adding Columns with Default Values or Constraints</strong></h3><p>Later in development I rebased my changes on top of the latest changes from upstream. The upstream changes included a migration that added a column to a table. This is one of the most trivial kinds of migrations that can be performed, as no existing data was touched. However, even this simple migration caused a headache.</p><p>It turns out that DSQL cannot add columns with default values or constraints. This isn&#8217;t clearly and explicitly stated anywhere in the documentation. The only mention of it is within a page that ostensibly describes the &#8220;supported&#8221; subsets of PostgreSQL commands. The <strong><a href="https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-postgresql-compatibility-supported-sql-features.html">Supported PostgreSQL features in Aurora DSQL</a></strong> page currently lists the following as a supported operation:</p><div id="datawrapper-iframe" class="datawrapper-wrap outer" data-attrs="{&quot;url&quot;:&quot;https://datawrapper.dwcdn.net/Jb6a7/1/&quot;,&quot;thumbnail_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/32636d57-8732-455f-939f-62be7e4874ae_1260x660.png&quot;,&quot;thumbnail_url_full&quot;:&quot;&quot;,&quot;height&quot;:343,&quot;title&quot;:&quot;| Created with Datawrapper&quot;,&quot;description&quot;:&quot;Create interactive, responsive &amp; beautiful charts &#8212; no code required.&quot;}" data-component-name="DatawrapperToDOM"><iframe id="iframe-datawrapper" class="datawrapper-iframe" src="https://datawrapper.dwcdn.net/Jb6a7/1/" width="730" height="343" frameborder="0" scrolling="no"></iframe><script type="text/javascript">!function(){"use strict";window.addEventListener("message",(function(e){if(void 0!==e.data["datawrapper-height"]){var t=document.querySelectorAll("iframe");for(var a in e.data["datawrapper-height"])for(var r=0;r<t.length;r++){if(t[r].contentWindow===e.source)t[r].style.height=e.data["datawrapper-height"][a]+"px"}}}))}();</script></div><p>Did you catch the issue when your eyes scanned this row of information, which appears at the end of a long table of &#8220;supported&#8221; statements in the AWS documentation? Let me give you a hint by providing the syntax of the <code>ADD COLUMN</code> clause from the official PostgreSQL docs:</p><pre><code><code>ADD [ COLUMN ] [ IF NOT EXISTS ] column_name data_type [ COLLATE collation ] [ column_constraint [ ... ] ]

...

and column_constraint is:

[ CONSTRAINT constraint_name ]
{ NOT NULL |
  NULL |
  CHECK ( expression ) [ NO INHERIT ] |
  DEFAULT default_expr |
  GENERATED ALWAYS AS ( generation_expr ) STORED |
  GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ] |
  UNIQUE [ NULLS [ NOT ] DISTINCT ] index_parameters |
  PRIMARY KEY index_parameters |
  REFERENCES reftable [ ( refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ]
    [ ON DELETE referential_action ] [ ON UPDATE referential_action ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]</code></code></pre><p>The problem is that the DSQL <em>ADD COLUMN</em> statement cannot have constraints like a <em>DEFAULT</em> value or a requirement that the value be <em>NOT NULL</em> let alone all the other potential constraints one might need.</p><p>I want to be clear that my main concern is not that you cannot add a column with constraints after a table is created. That is a real and significant concern, and I sincerely hope they address it by GA as it is a very common element of database schemas. Instead, my main concern is that <strong>this needs to be documented much better</strong>. AWS will quickly burn a lot of good will if they confuse customers into thinking their workloads can operate on DSQL, and only find out later on that they can&#8217;t. The DSQL docs have two pages where people are likely to look for issues using the service with existing workloads: <strong><a href="https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-postgresql-compatibility-unsupported-features.html">Unsupported PostgreSQL features in Aurora DSQL</a></strong> and <strong><a href="https://docs.aws.amazon.com/aurora-dsql/latest/userguide/known-issues.html">Known issues in Amazon Aurora DSQL</a></strong>. But this significant <em>ADD COLUMN</em> limitation cannot be found on either page, nor is it clearly stated in the &#8220;supported features&#8221; page even though the statement is listed there.</p><p>Both the underlying <em>ADD COLUMN</em> limitation and this documentation issue give me significant concerns in using DSQL for critical workloads.</p><h2><strong>Conclusion</strong></h2><p>There is a lot to love about this Vaultwarden Serverless concept. There are also significant concerns with DSQL, which is a critical piece of the solution. How do we reconcile the concerns with the benefits?</p><p>I&#8217;ll start first with workload-agnostic takeaways. The core Lambda + S3 + CloudFront + SES components are rock-solid. They can also be used with any off-the-shelf database backend, including other AWS solutions like <strong><a href="https://aws.amazon.com/rds/aurora/serverless/">Aurora Serverless</a></strong>. But based on the learnings from this POC it would be hard to recommend DSQL for most workloads due to:</p><ul><li><p>The inability to perform multiple schema changes in a single transaction</p></li><li><p>The lack of support for basic functions like adding a column with constraints</p></li><li><p>Poor information architecture within the DSQL docs that make it hard to assess all the limitations relative to upstream PostgreSQL up front</p></li></ul><p>However, my takeaway for Vaultwarden is more nuanced. The database requirements are well defined (e.g. no current usage of Foreign Keys beyond their definitions in the schema) and the data can be easily backed up via <em><a href="https://www.postgresql.org/docs/current/app-pgdump.html">pg_dump</a></em>. Further, the Bitwarden clients cache database-stored items locally and can re-export them all without needing access to the API service. If my API service went down, I could still migrate all my items to the official Bitwarden service (or other third-party service) from an export from any one of my clients. I also feel comfortable operating on top of DSQL for my own personal use, knowing that I can dig into the details and address issues if they arise. But I also wouldn&#8217;t <em>recommend</em> others deploy Vaultwarden using DSQL unless they can do the same.</p><p>That said, I love the promise of DSQL, and I hope that over time many of these limitations will disappear. It would be great to have a truly serverless relational database that worked for the majority of existing and new workloads.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://chasedouglas.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">If you like this analysis of cloud tech, please subscribe. There are more posts in the pipeline!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>I&#8217;ve since learned that most password managers increased the default number of <strong><a href="https://en.wikipedia.org/wiki/PBKDF2">PBKDF2</a></strong> iterations they use to generate the vault decryption key from your master password, which literally makes it take longer to unlock a vault. The time it takes to unlock your vault is proportional to the difficulty of brute force attacking a vault, and CPUs/GPUs are faster than ever, so increasing the default number of iterations was a good thing. That said, there is a new algorithm on the block, <strong><a href="https://en.wikipedia.org/wiki/Argon2">Argon2</a></strong>, which prevents brute force attacks via larger memory space usage rather than just CPU cycles, meaning vaults unlock faster. My password manager didn&#8217;t support Argon2, giving me another reason to look elsewhere.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>AWS coined the term &#8220;Serverless&#8221; with the launch of Lambda, where the meaning included &#8220;instantaneously scales up <em>and to zero</em>.&#8221; Other orgs within AWS got jealous of Lambda&#8217;s adoption rate and decided to slap &#8220;Serverless&#8221; onto new offerings that merely <em>autoscaled, slowly</em> and oftentimes <em>not to zero</em>. /me looks side-eyed at <strong><a href="https://aws.amazon.com/rds/aurora/serverless/">Aurora Serverless</a></strong>, which lacked scale-to-zero <strong><a href="https://aws.amazon.com/blogs/database/introducing-scaling-to-0-capacity-with-amazon-aurora-serverless-v2/">until recently</a></strong>, and even then takes up to 15 seconds to resume from zero.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>Depending on who you ask. SQS launched in beta first, S3 reached GA first.</p><p></p></div></div>]]></content:encoded></item></channel></rss>