<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Patrick Cable</title><link>https://pcable.net/posts/</link><description>Recent content in Posts on Patrick Cable</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>&lt;a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener">CC BY-NC 4.0&lt;/a></copyright><lastBuildDate>Sat, 24 Sep 2022 23:52:00 -0400</lastBuildDate><atom:link href="https://pcable.net/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Writing a Golang Serverless App That Processes Form Uploads</title><link>https://pcable.net/posts/2022-09-24-lambda-app/</link><pubDate>Sat, 24 Sep 2022 23:52:00 -0400</pubDate><guid>https://pcable.net/posts/2022-09-24-lambda-app/</guid><description>&lt;p>&lt;em>FYI: this post talks briefly about tracking food intake. Some folks have a complex relationship with that! Also I wrote it nearly a year ago, but I never published it until now. Enjoy.&lt;/em>&lt;/p>
&lt;p>In the past I was a &lt;a href="https://getbitesnap.com">bitesnap&lt;/a> user. It was an okay(?) enough app to capture what I eat without focusing too much on the nutritional facts label. But getting the data out of the app has two options: JSON or CSV. Ultimately I&amp;rsquo;d like to be able to build a nice-ish styled report from the app, but it seems like the folks who build it are busy working on their main &lt;a href="https://bite.ai">bite.ai&lt;/a> product.&lt;/p></description><content type="html"><![CDATA[<p><em>FYI: this post talks briefly about tracking food intake. Some folks have a complex relationship with that! Also I wrote it nearly a year ago, but I never published it until now. Enjoy.</em></p>
<p>In the past I was a <a href="https://getbitesnap.com">bitesnap</a> user. It was an okay(?) enough app to capture what I eat without focusing too much on the nutritional facts label. But getting the data out of the app has two options: JSON or CSV. Ultimately I&rsquo;d like to be able to build a nice-ish styled report from the app, but it seems like the folks who build it are busy working on their main <a href="https://bite.ai">bite.ai</a> product.</p>
<p>&ldquo;I can probably get a layout that works well enough for &lsquo;print to PDF&rsquo; with some javascript and a single HTML file&rdquo; was my first thought. But then I realized that I am a child when it comes to the front-end JS ecosystem. It&rsquo;s not that I couldn&rsquo;t figure it out, but it was going to take a bit longer to make that magic happen. So I did what people do when they need a drill but instead have a wacky-waving inflatable arm-flailing tube thing: I wrote a lambda function in golang, deployed it using lambda + api gateway and lived to tell the tale.</p>
<p>This didn&rsquo;t actually seem like it would have been that challenging, except between outputting a HTML template that worked well enough and then figuring out how to get it to play nice with an HTTP API Gateway was a bit of a challenge!</p>
<h2 id="what-challenge">What Challenge?</h2>
<p>My app worked OK when I ran <code>fmt.Printf</code> on a template - but when that HTML was returned through the Lambda handler I saw a bunch of unicode codepoints (think <code>\u003c</code> and <code>\u003e</code> everywhere). Turns out the API Gateway Proxy event types give more flexibility on what my function would return. At one point I got my HTML out of the app, but none of the other bits. Progress!</p>
<p>OK, so&hellip; output. I had been testing my API with <code>curl -d@bitesnap-data.json</code> and not <code>curl -F 'data=@bitesnap-data.json</code> &ndash; which, the latter would have better emulated a web form. This lead me down a quite the journey of multipart mime/form processing in Go. An extremely helpful block of code from Adam Drake&rsquo;s <a href="https://adamdrake.com/serverless-with-lambda-api-gateway-and-go.html">Serverless with Lambda, API Gateway, and Go</a> saved me a ton of time. Recreating the incoming request parameters inside of an <code>http.Request{}</code> struct made it easier to use the built-in Golang functions for parsing multipart forms.</p>
<p>Lastly: S3 still doesn&rsquo;t do HTTPS on the edge! I tried to proxy the S3 bucket with the static pages in it but it&rsquo;d only work if I didnt verify TLS end-to-end. That might be OK-enough for this use case, except the only way the API gateway would work with a fancy hostname and proxying is if I <em>did</em> verify TLS. So, I got forced into setting up some Cloudfront.</p>
<p>Anyways, it works now.</p>
<h2 id="is-is-it-safe">Is&hellip; Is it safe?</h2>
<p>Probably? Like, the lambda only has a max execution time of 1 sec, and 128mb of RAM, an extremely low rate limit. Folks are welcome to set up their own rube goldberg machines since you can <a href="https://github.com/patcable/eater">view the source</a> on GitHub.</p>
]]></content></item><item><title>RabbitMQ, Erlang, TLS Validation, and Your LDAP Server</title><link>https://pcable.net/posts/2021-02-10-rmq-ldap/</link><pubDate>Wed, 10 Feb 2021 23:45:56 -0500</pubDate><guid>https://pcable.net/posts/2021-02-10-rmq-ldap/</guid><description>&lt;p>&lt;em>This is on RabbitMQ 3.8.11 with Erlang OTP 23.2.3. I was running OpenLDAP 2.4.48 without any load balancing.&lt;/em>&lt;/p>
&lt;p>Recently I had the pleasure of upgrading RabbitMQ from an older version to something more recent. On the plus side: all the super important bits worked fine. Data comes in, data goes out - AMQP continued to be extremely AMQP. But there was one annoyance: the web management UI wouldn&amp;rsquo;t accept my LDAP-backed login.&lt;/p></description><content type="html"><![CDATA[<p><em>This is on RabbitMQ 3.8.11 with Erlang OTP 23.2.3. I was running OpenLDAP 2.4.48 without any load balancing.</em></p>
<p>Recently I had the pleasure of upgrading RabbitMQ from an older version to something more recent. On the plus side: all the super important bits worked fine. Data comes in, data goes out - AMQP continued to be extremely AMQP. But there was one annoyance: the web management UI wouldn&rsquo;t accept my LDAP-backed login.</p>
<p>It&rsquo;s not often that folks need to log into a web interface for a queuing system. If one&rsquo;s doing it, it&rsquo;s probably because there&rsquo;s some sort of incident going on. A service account could have been used, but getting those credentials might be &ldquo;2am challenging&rdquo; in a world where every system in my infrastructure ties in with LDAP somehow and has named user access. So, uh: how do?</p>
<h2 id="issue-1-sweet-cipher-suites">Issue 1: Sweet Cipher Suites</h2>
<p>The initial issue was that RabbitMQ wouldn&rsquo;t connect to LDAP server at all. Logs showed:</p>
<pre tabindex="0"><code>error,{tls_alert,{handshake_failure,&#34;TLS client: In state hello received SERVER ALERT: Fatal - Handshake Failure\n&#34;}}}
</code></pre><p>Yet, <code>openssl s_client</code> had no issue connecting to this server, and with that I mistakenly thought this was a client issue. Yep, I know it says SERVER ALERT in big ol&rsquo; capital letters, but it worked on RabbitMQ 3.6.x on Erlang 19.1 and now it doesn&rsquo;t.</p>
<p>It broke because Erlang 21 changed the default cipher suites that are enabled for all TLS connections, and none of the RSA ones made the cut. This <a href="https://github.com/processone/ejabberd/issues/3496">ejabberd issue</a> was similar to what I was seeing. Anyways, this is an easy fix once you know what it is. To have OpenLDAP advertise cipher suites that will work with Erlang 21+:</p>
<ol>
<li>Generate a dhparams file</li>
<li>Tell OpenLDAP to use it (Set <code>olcTLSDHParamFile</code>)</li>
<li>Restart and continue to live life</li>
</ol>
<p>After that, the connection worked! Except now there&rsquo;s a new error&hellip;</p>
<h2 id="issue-2-wildcard-certificate-verification">Issue 2: Wildcard Certificate Verification</h2>
<p>After I got that issue solved, I still couldn&rsquo;t log in - but at least I did get a new error message:</p>
<pre tabindex="0"><code>{error,{tls_alert,{handshake_failure,&#34;TLS client: In state certify at ssl_handshake.erl:1889 generated CLIENT ALERT: Fatal - Handshake Failure\n {bad_cert,hostname_check_failed}&#34;}}}
</code></pre><p>At least it was definitely a CLIENT issue this time (those caps are the hint). Running <code>openssl x509</code> on the certificate presented it seemed like the Subject Alternative Names were correct. It was a wildcard certificate, and the hostname matched the wildcard and FQDN.</p>
<p>Turns out, later versions of Erlang require SNI information on connections, which is fine - except if that certificate is a wildcard certificate. The folks who work on Erlang made a decision to not validate wildcard certificates <em>unless you specifically allow it</em>. You can do this by specifying a matching function in a connection&rsquo;s <code>ssl_options</code> block. That function is:</p>
<pre tabindex="0"><code>{customize_hostname_check,[{match_fun, public_key:pkix_verify_hostname_match_fun(https)}]}
</code></pre><p>Nice, good to go! Except: as you might imagine, referencing a function in a configuration file won&rsquo;t work. On RabbitMQ 3.8.11 and earlier, you could just turn SNI off - toss <code>{server_name_indication,disable}</code> into the <code>ssl_options</code> block and move on. I don&rsquo;t love this, but it could be OK depending on your threat model and how your LDAP servers are load balanced<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>Good news, though: thanks to <a href="https://twitter.com/michaelklishin">Michael Klishin</a>&rsquo;s work, RabbitMQ 3.8.12 will have a couple new settings:</p>
<ul>
<li><code>auth_ldap.ssl_options.hostname_verification</code> can be set to <code>wildcard</code> or <code>none</code>. In my opinion,
<code>wildcard</code> is probably fine even if not using a wildcard certificate, but <code>none</code> is the default.
In the advanced config, this parameter is <code>rabbitmq_auth_backend_ldap.ssl_hostname_verification</code>.</li>
<li><code>auth_ldap.ssl_options.sni</code> can be used to set the hostname to use for SNI. It should match your
server name. This could prove to be a challenge if you set multiple LDAP server names in your
configuration file. Anyways, if you&rsquo;re using the advanced config,
<code>rabbitmq_auth_backend_ldap.ssl_options.server_name_indication</code> is the option you&rsquo;re looking for.</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>Another day, another rabbit hole, but this was a fun dive into a language and system I hadn&rsquo;t explored very much of. I owe Michael a huge thanks for helping dig into the issue and the super quick patch for this. Hopefully, this is helpful to anyone else encountering this issue - it&rsquo;s a particularly challenging thing to search for!</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>You can read more about some of the details in the Github <a href="https://github.com/rabbitmq/rabbitmq-server/issues/2805">issue</a>.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content></item><item><title>The macOS Big Sur SSH Keychain Provider is Broken</title><link>https://pcable.net/posts/2020-11-15-bigsur-ssh-agent/</link><pubDate>Sun, 15 Nov 2020 14:55:00 -0500</pubDate><guid>https://pcable.net/posts/2020-11-15-bigsur-ssh-agent/</guid><description>&lt;p>&lt;em>&lt;strong>Hey! Listen!&lt;/strong>&lt;/em> This looks like it&amp;rsquo;s been fixed in macOS 11.4! You can read the rest of
the post for a fun deep-dive though.&lt;/p>
&lt;hr>
&lt;p>Using a Yubikey for user identity is great. Your Yubikey generates a private key that never
leaves the device, outputs a CSR that your IT org can sign, and boom you&amp;rsquo;ve got a pretty
solid story around user identity. For a while macOS has shipped an SSH agent
that (I think?) accesses the Yubikey&amp;rsquo;s certificates through the Keychain and/or
CryptoTokenKit API. It is helpfully named &lt;code>/usr/lib/ssh-keychain.dylib&lt;/code>.&lt;/p></description><content type="html"><![CDATA[<p><em><strong>Hey! Listen!</strong></em> This looks like it&rsquo;s been fixed in macOS 11.4! You can read the rest of
the post for a fun deep-dive though.</p>
<hr>
<p>Using a Yubikey for user identity is great. Your Yubikey generates a private key that never
leaves the device, outputs a CSR that your IT org can sign, and boom you&rsquo;ve got a pretty
solid story around user identity. For a while macOS has shipped an SSH agent
that (I think?) accesses the Yubikey&rsquo;s certificates through the Keychain and/or
CryptoTokenKit API. It is helpfully named <code>/usr/lib/ssh-keychain.dylib</code>.</p>
<p>I had successfully tested that my Yubikey worked with my VPN, and that in-browser mutual
TLS auth worked as expected. It seemed like a slam dunk to give SSH the old college try, until&hellip;</p>
<pre tabindex="0"><code>$ ssh-add -s /usr/lib/ssh-keychain.dylib
Enter passphrase for PKCS#11:
Could not add card &#34;/usr/lib/ssh-keychain.dylib&#34;: agent refused operation
</code></pre><p>Oh, uh&hellip; ok&hellip; why&rsquo;s that?</p>
<pre tabindex="0"><code>$ ssh-agent -d
...
debug1: process_message: socket 1 (fd=4) type 20
failed PKCS#11 add of &#34;/usr/lib/ssh-keychain.dylib&#34;: realpath: No such file or directory
</code></pre><p>Fascinating. So, the library is not in /usr/lib (or anywhere in /usr). Yet, you could run
<code>man ssh-keychain</code> and read more about using this PKCS11 Provider. I found this amusing and tweeted something to the effect of &ldquo;haha, macos 11 kills /usr/lib/ssh-keychain.dylib but keeps the developer documentation. at least i can read about what used to work!&rdquo;</p>
<p>I posted about this in a few places, and fortunately <a href="https://twitter.com/mendel">mendel</a>
chimed in to say &ldquo;some libraries live only in the cache in macOS 11, but not in the filesystem,
might it be that?&rdquo; and linked me to two blog posts:</p>
<ul>
<li><a href="https://mjtsai.com/blog/2020/06/26/reverse-engineering-macos-11-0/">Reverse Engineering macOS 11.0</a></li>
<li><a href="https://lapcatsoftware.com/articles/bigsur.html">Extract the system libraries on macOS Big Sur</a></li>
</ul>
<p>It turns out a thing that changed in macOS Big Sur is that all the system libraries live in a
cache located in <code>/System/Library/dyld/dyld_shared_cache_x86_64</code>. When an application calls <code>dlopen()</code>,
libc goes and pulls the library from the cache instead of the file system. This is interesting
from a security perspective, but: is my SSH provider hiding in that cache too?</p>
<p>I ended up doing the steps in the second post to build <code>dyld_shared_cache_util</code>, which was a lot of fun
as a first time Xcode user<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. But, fortunately the effort paid off because I did find <code>ssh-keychain.dylib</code>
in the cache. The existence of the man page (and the bug) now made way more sense.</p>
<p>In OpenSSH 7.5 and later, OpenSSH checks that whatever PKCS11 libraries you pass it are
on an allowlist to mitigate <a href="https://nvd.nist.gov/vuln/detail/CVE-2016-10009">CVE-2016-10009</a>.
If the library or it&rsquo;s path is on the allowlist, <code>ssh-agent</code> passes the library to <code>ssh-pkcs11-helper</code>
which actually calls libc&rsquo;s <code>dlopen()</code>. But, since the library doesn&rsquo;t exist in <code>/usr/lib</code>
in the first place, my guess is that it never makes it that far.</p>
<p>Hopefully Apple has a fix for this in an upcoming release, since I preferred relying on the OS
for token access. In the meantime, dropping OpenSC&rsquo;s OnePIN PKCS11 library into /usr/local/lib
works fine.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>It was not fun.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content></item><item><title>Adding Info.plist Information Into a Binary</title><link>https://pcable.net/posts/2020-11-14-inetaccesspolicy/</link><pubDate>Sat, 14 Nov 2020 23:53:00 -0500</pubDate><guid>https://pcable.net/posts/2020-11-14-inetaccesspolicy/</guid><description>&lt;p>At the beginning of the pandemic I wrote a tool called &lt;a href="https://github.com/patcable/onair">OnAir&lt;/a> that changes
the color of a Philips Hue light when you&amp;rsquo;re on some sort of audio or video call. It&amp;rsquo;s a helpful signal
to your loved ones, roommates, or kids that you&amp;rsquo;re stuck in Videoconferencing Hell&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>.&lt;/p>
&lt;p>It&amp;rsquo;s a neat tool, but I&amp;rsquo;m pretty sure I&amp;rsquo;m still the only user. That makes sense: some assembly is required, it
requires Micro Snitch, and I don&amp;rsquo;t have a UI to go with it. But also: I didn&amp;rsquo;t have a package download for it;
adventurous users had to download a Golang toolchain to build OnAir. Making someone download a build toolchain
to use your app is mean in the year 2020 I&amp;rsquo;m told, so I wanted to fix that.&lt;/p></description><content type="html"><![CDATA[<p>At the beginning of the pandemic I wrote a tool called <a href="https://github.com/patcable/onair">OnAir</a> that changes
the color of a Philips Hue light when you&rsquo;re on some sort of audio or video call. It&rsquo;s a helpful signal
to your loved ones, roommates, or kids that you&rsquo;re stuck in Videoconferencing Hell<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>It&rsquo;s a neat tool, but I&rsquo;m pretty sure I&rsquo;m still the only user. That makes sense: some assembly is required, it
requires Micro Snitch, and I don&rsquo;t have a UI to go with it. But also: I didn&rsquo;t have a package download for it;
adventurous users had to download a Golang toolchain to build OnAir. Making someone download a build toolchain
to use your app is mean in the year 2020 I&rsquo;m told, so I wanted to fix that.</p>
<p>While reading about how the code signature and notarization processes work on macOS, somehow I came across
<a href="https://www.obdev.at/products/littlesnitch/index.html">Little Snitch</a>&rsquo;s
<a href="https://obdev.at/iap/index.html">Internet Access Policies</a> and thought it&rsquo;d be cool to include one.
The tl;dr on IAPs are: you can compile your application with some added context about what calls it makes
out to the Internet, and that context will show up when Little Snitch prompts you about a connection your
application is making. It looks like this:</p>
<p><img alt="Example IAP" src="/images/posts/iap/iap.png"></p>
<p>Little Snitch tells you that OnAir wants to connect to <code>discovery.meethue.com</code> on port <code>443</code>. It also
mentions what OnAir does (&ldquo;OnAir changes the color of IP-based lighting when you are on a audio or video
call&rdquo;), a link to the Github page, and a specific statement about connections to the <code>meethue.com</code> domain. In
the image above, it reads &ldquo;OnAir uses the Hue Broker Server to discover Hue Bridge devices on your network. If
denied, OnAir will not be able to find the Hue Bridge device on your network.&rdquo;</p>
<p>Useful security information is useful. More applications should probably have useful information. Except,
getting that useful information into a single binary when you&rsquo;re not using Xcode is trickier than I
anticipated. So how do? Enough of the recipe intro: here&rsquo;s how to do the thing.</p>
<h1 id="building-your-personal-plist-pizza">Building Your Personal Plist Pizza</h1>
<p>An Info.plist file has attributes about the application. You&rsquo;ll need to make one.</p>
<p>There are tools that can help with this like <a href="https://www.fatcatsoftware.com/plisteditpro/">PlistEdit Pro</a>.
In this case &ldquo;it&rsquo;s just xml&rdquo; so you&rsquo;d be able to use <a href="https://github.com/patcable/onair/blob/master/Info.plist">what I threw together</a>
as a template for your project. PlistEdit Pro was nice to use, though.</p>
<p>If you&rsquo;re wondering what some of the CoreFoundation (CF) keys and values are, Apple&rsquo;s
<a href="https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html">Core Foundation Keys</a> page has the answer. Though, you probably only need the ones listed in the
<a href="https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/Procedures/Procedures.html#//apple_ref/doc/uid/TP40005929-CH4-SW6">Code Signing Tasks</a> doc.</p>
<p>We&rsquo;re here to talk about IAPs, though: so take a look at the specification on Little Snitch&rsquo;s
<a href="https://help.obdev.at/littlesnitch5/ra-developers">Research Assistant developer documentation</a>. To summarize,
you&rsquo;ll need to add a dictionary entry for each endpoint your application connects to. The text that shows up for the
IAP is put into the <code>Purpose</code> and <code>DenyConsequences</code> fields.</p>
<p>You can also reference a string that is localized, which is a nice thing to do in general.
The OnAir Info.plist does this - though only for English today<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p>
<h1 id="the-one-weird-linker-trick">The One Weird Linker Trick</h1>
<p>OK, so you&rsquo;ve made your XML. How can you build it into your application?</p>
<p>Generally, an <code>Info.plist</code> lives as inside of an app bundle. However, it is also possible for the data to live as
a text segment in a Mach-O binary. We&rsquo;re going to do that with the power of some linker flags.</p>
<ol>
<li>Add something like <code>-ldflags='-extldflags &quot;-sectcreate __TEXT __info_plist $(shell pwd)/Info.plist&quot;'</code> to your <code>go build</code> command.
I copied this from my Makefile, you may need to do something special to get the full path to the file.</li>
<li>Toss an <code>import &quot;C&quot;</code> into your application&rsquo;s imports.</li>
</ol>
<p>The <code>import &quot;C&quot;</code> thing is important, even if you&rsquo;re not doing Cgo things in your application. If you don&rsquo;t import
it, the <code>ldflags</code> component will be ignored, and you won&rsquo;t see your IAP.</p>
<p>You can confirm that the text segment made it in to the binary by running
<code>otool -s __TEXT __info_plist ./path/to/your/binary</code>. Convert it to human-readable text by piping the output to <code>xxd -r</code>.</p>
<p>I talk about this in the context of a Golang application - but this is a linker flag. I imagine you can pass the <code>sectcreate</code>
flag to whatever your build toolchain uses and you&rsquo;ll get that <code>__info_plist</code> section.</p>
<h1 id="license-to-distribute">License to Distribute</h1>
<p>Little Snitch will only display an IAP for a signed application, so get your credit card out. Apple&rsquo;s Developer Program
costs $99 a year, but: you get unlimited certificates! This is an unverified claim, but I have at least two (2)
certificates now, which feels like a lot for me.</p>
<p>After your account is approved (it took ~10 min for me on a Saturday morning), open up Xcode, go to Preferences, pop into
the Accounts tab, and add your Apple ID. Then, click <code>Manage Certificates...</code> and generate you a <code>Developer ID Application</code>
certificate, and possibly a <code>Developer ID Installer</code> certificate. These will be saved directly into your keychain, though
you should export them with a secure password and put them somewhere safe.</p>
<p>I should note that the certificate generation step is different if you have an enterprise account; I think you&rsquo;ll need to send
a Certificate Signing Request (CSR) to the person who manages your account. I gleaned this from googling, so at least something
has been written about it if you find yourself lost at this point. You&rsquo;ll probably need the <code>--acr-provider</code> option with <code>altool</code>
later.</p>
<p>Since you probably have MFA turned on for your Apple ID, you&rsquo;ll need an &ldquo;Application Password&rdquo; which you can make
over on the (Apple ID Management Portal](<a href="https://appleid.apple.com">https://appleid.apple.com</a>). Kinda funny that the developer tools don&rsquo;t support
native MFA, but security is hard. Anyways, once you&rsquo;ve got that one-time password, get it into your keychain under
the id <code>appleid</code> by running:</p>
<pre tabindex="0"><code>xcrun altool --store-password-in-keychain-item appleid -u my@cool.email -p asdf-asdf-asdf-asdf
</code></pre><h1 id="signing-your-binary">Signing Your Binary</h1>
<p>Run <code>security find-identity -v</code> and get the hash for your <code>Developer ID Application</code> certificate. Sign your binary
with <code>codesign -s DEV_APP_HASH_HERE -f -v --timestamp --options runtime BINARY_PATH_HERE</code>. Congratulations: you made a
signed binary on macOS.</p>
<p>At this point, if you delete the Little Snitch rules that exist for your program and then run it, you&rsquo;ll probably
see the words that you wrote in the Little Snitch alert dialog box. Congrats!</p>
<h1 id="notarizing-your-binary">Notarizing Your Binary</h1>
<p>That&rsquo;s fine and good, but let&rsquo;s say you want to distribute your application. Apple&rsquo;s notarization process seems to
be a very quick static analysis pass on your binary to make sure that you&rsquo;re not distributing obvious malware. So I
tried to zip up my binary and ship it off to Apple&hellip; without much luck. It worked once, at least?</p>
<p>So instead I built a package. I moved my signed binary into an empty folder creatively named <code>package/</code> and made an
installer with this pkgbuild:</p>
<pre tabindex="0"><code>pkgbuild --root package --identifier com.example.yourapp.dontusethis.makeyourown --version $(VERSION:v%=%) --install-location /usr/local/bin onair-$(VERSION)-raw.pkg
</code></pre><p>Signed the package with my developer installer key (grab that hash using <code>security find-identity -v</code>):</p>
<pre tabindex="0"><code>productsign -s DEV_INSTALL_HASH_HERE --timestamp onair-$(VERSION)-raw.pkg onair-$(VERSION).pkg
</code></pre><p>And submitted for notarization <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<pre tabindex="0"><code>xcrun altool --notarize-app --primary-bundle-id com.example.yourapp.dontusethis.makeyourown --username &#39;my@cool.email&#39; --password &#34;@keychain:appleid&#34; --file onair-$(VERSION).pkg
</code></pre><p>Notarization takes a little bit of time: generally &lt;5 min, but could be longer than an hour, too. Your request will get a UUID,
which you can use to check on the status of notarization, or you can wait for the email. For the impatient, keep asking Apple
for an update using this command:</p>
<pre tabindex="0"><code>xcrun altool --notarization-info UUID_HERE -u &#39;my@cool.email&#39; --password &#34;@keychain:appleid&#34;
</code></pre><p>If it passes, then staple your notarization to your package (<code>xcrun stapler staple onair-$(VERSION).pkg</code>) and
distribute. I just uplodaded my package as part of a Github release.</p>
<h1 id="embedded-data-in-a-binary">Embedded Data? In A Binary?</h1>
<p>Well, that&rsquo;s about it. If you&rsquo;re building a tool for users who might use Little Snitch, this is a nice way
to give additional context on what your app is connecting to. Maybe there are other things you can put in this
header that get parsed by the OS too! &#x1f61c;</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Maybe they&rsquo;ll save you, maybe they&rsquo;ll let you suffer - but at least they&rsquo;ll know what the situation is.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>I&rsquo;d absolutely accept localization PRs if you wanted to make one.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>That <code>appleid</code> should say something else if you used a different value when you saved your credentials with <code>altool</code> earlier.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content></item><item><title>Making Netflix's Dispatch work with Open ID Connect</title><link>https://pcable.net/posts/2020-10-11-dispatch/</link><pubDate>Sun, 11 Oct 2020 16:30:00 -0400</pubDate><guid>https://pcable.net/posts/2020-10-11-dispatch/</guid><description>&lt;p>Netflix&amp;rsquo;s &lt;a href="https://github.com/Netflix/dispatch">&lt;em>Dispatch&lt;/em>&lt;/a> looks like a neat tool to
manage incidents. It glues together a ton of things that one probably uses during availability incidents,
like video calls, Google Docs, Slack, PagerDuty&amp;hellip; all of which are relevant to my interests. I&amp;rsquo;m not a huge fan of
pulling other people&amp;rsquo;s processes into my own org, but Dispatch looked like it might be customizable enough to build
something else off of, and I want a little more structure around incidents. Seems promising!&lt;/p></description><content type="html"><![CDATA[<p>Netflix&rsquo;s <a href="https://github.com/Netflix/dispatch"><em>Dispatch</em></a> looks like a neat tool to
manage incidents. It glues together a ton of things that one probably uses during availability incidents,
like video calls, Google Docs, Slack, PagerDuty&hellip; all of which are relevant to my interests. I&rsquo;m not a huge fan of
pulling other people&rsquo;s processes into my own org, but Dispatch looked like it might be customizable enough to build
something else off of, and I want a little more structure around incidents. Seems promising!</p>
<p>Just one thing: before I dive into using this tool, it&rsquo;s definitely <em>not</em> going to work for my needs if I can&rsquo;t tie
it in with an authentication provider. The documentation hints at supporting Open ID Connect (OIDC)/Proof Key for
Code Exchange (PKCE), but&hellip; how? And with <em>my</em> Open ID Connect provider? I&rsquo;ve never OIDC&rsquo;ed before, what config
values does Dispatch actually need? What do they look like? Why is the app ignoring the OIDC codepath for this
even though I (thought I) set the right environment variables? Is what I&rsquo;m trying to do impossible?</p>
<p>Well, It wasn&rsquo;t impossible. It did, however, feel like pushing a boat up a mountain. I definitely lost
<em>at least</em> an hour (it was more than an hour) because I put a trailing slash on a URL. This resulted in a
CORS error, which was a very exciting, new, and fun way to pull my hair out. Thankfully my hair has regrown
since.</p>
<h1 id="oidc-setup">OIDC Setup</h1>
<p>Right, the first step is getting an OIDC connector set up.</p>
<p>You&rsquo;ll want to set up a new OIDC connector. Perhaps you use an enterprisey authentication provider like
OneLogin - which separates out connectors from the apps that use connectors. Go set up a connector, or
ask the person who can set up connectors and apps in your enterprisey authentication provider to do that.
You&rsquo;ll need your base URL for your Dispatch setup to set up a connector. These values should do:</p>
<table>
  <thead>
      <tr>
          <th>Key</th>
          <th>Value</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Redirect URI</td>
          <td><a href="https://your.dispatch.url/implicit/callback">https://your.dispatch.url/implicit/callback</a></td>
      </tr>
      <tr>
          <td>Login URI</td>
          <td><a href="https://your.dispatch.url">https://your.dispatch.url</a></td>
      </tr>
  </tbody>
</table>
<p>Then, create a new &ldquo;app&rdquo; using that connector. On the SSO page, set:</p>
<table>
  <thead>
      <tr>
          <th>Key</th>
          <th>Value</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Application Type</td>
          <td>Native</td>
      </tr>
      <tr>
          <td>Login URI</td>
          <td>None (PKCE)</td>
      </tr>
  </tbody>
</table>
<p>And then copy your <strong>Client ID</strong>, and the URL for the <strong>OIDC &ldquo;Well Known Configuration&rdquo;</strong>, which you&rsquo;ll need later.</p>
<h1 id="patching-dispatch">Patching Dispatch</h1>
<p>Now for the code bits. We&rsquo;re going to make a &ldquo;custom&rdquo; authentication provider and patch in an option for
decoding JWTs. I say &ldquo;custom&rdquo; because it&rsquo;s a pretty small change to the provided PKCE authentication
provider.</p>
<p>Go clone the <a href="https://github.com/Netflix/dispatch">Dispatch</a> repository for these next steps.</p>
<h2 id="making-your-custom-authentication-provider">Making Your Custom Authentication Provider</h2>
<p>I absolutely missed that big ol&rsquo; warning in the Dispatch documentation that <code>VUE_APP</code> settings are used
during the <strong>build</strong> of the UI/frontend, so I kept trying to set these parameters as part of the backend&rsquo;s
environment. Don&rsquo;t be like me! Instead, put these values in <code>src/dispatch/static/dispatch/.env</code>:</p>
<pre tabindex="0"><code>VUE_APP_DISPATCH_AUTHENTICATION_PROVIDER_SLUG=&#34;&#34;
VUE_APP_DISPATCH_AUTHENTICATION_PROVIDER_PKCE_CLIENT_ID=(the client id from earlier, without these parenthesis)
VUE_APP_DISPATCH_AUTHENTICATION_PROVIDER_PKCE_OPEN_ID_CONNECT_URL=https://your-cool-org.onelogin.com/oidc/2
</code></pre><p>You&rsquo;ll notice that <code>VUE_APP_DISPATCH_AUTHENTICATION_PROVIDER_SLUG</code> is empty - this allows the use of a custom authentication
provider. Speaking of a custom authentication provider, you can drop
<a href="https://github.com/patcable/dispatch/blob/customAuthProvider/src/dispatch/static/dispatch/src/auth/customAuthProvider.js">this</a>
in <code>src/dispatch/static/dispatch/src/auth/</code>. It&rsquo;s just about the same as the <code>pkceAuthProvider.js</code> with some more values added to
the request that makes it to the backend, I think. You should diff the two though, since I am a stranger on the internet who is
giving you authentication code.</p>
<h2 id="one-weird-jwt-decode-trick">One Weird JWT Decode Trick</h2>
<p>You may also need to incorporate changes that are in <a href="https://github.com/patcable/dispatch/compare/master...patcable:at-verify-flag">my branch</a> of Dispatch. I made a PR to
get those into the main project; we&rsquo;ll see where it goes. I added a <code>log.debug()</code> on the JWT decode as well, so if you run into JWT issues you can bump the log level
and get some valuable information.</p>
<h2 id="docker-docker-docker">Docker Docker Docker</h2>
<p>Once you&rsquo;ve gotten the bits in place, build the container. Put it somewhere it can be used, etc.</p>
<h1 id="app-runtime-config">App Runtime Config</h1>
<p>Since our &ldquo;custom auth provider&rdquo; is still OIDC/PKCE, we can use the existing backend variables.</p>
<p>Set these parameters in the app config. <code>DISPATCH_PKCE_DONT_VERIFY_AT_HASH</code> is from the patch I mentioned in the other section.</p>
<pre tabindex="0"><code>DISPATCH_AUTHENTICATION_PROVIDER_SLUG: dispatch-auth-provider-pkce
DISPATCH_AUTHENTICATION_PROVIDER_PKCE_JWKS: https://myorg.onelogin.com/oidc/2/certs
DISPATCH_JWT_AUDIENCE: (the client id from earlier, without these parenthesis. But you don&#39;t have to specify this, and you may not need to.)
DISPATCH_PKCE_DONT_VERIFY_AT_HASH: &#34;true&#34;
</code></pre><p>Start your app. Go to the main page. You should be logged in! Wow!</p>
<h1 id="fin">Fin</h1>
<p>Funny enough, I set this up as a way to get more familiar with some kubernetes infrastructure that I&rsquo;ve been playing
with. Mission accomplished: debugging an application in a brand new environment is definitely one way to learn the joys
of debugging. But honestly, I would not have figured any of this out without <a href="https://github.com/Netflix/dispatch/issues/492">this</a> issue and
<a href="https://github.com/Netflix/dispatch/pull/535">this</a> PR.</p>
<p>Happy Incidenting!</p>
]]></content></item><item><title>A macOS Yubikey and OpenSC Package</title><link>https://pcable.net/posts/2020-10-08-yubikey-mac-tools/</link><pubDate>Tue, 06 Oct 2020 18:30:00 -0400</pubDate><guid>https://pcable.net/posts/2020-10-08-yubikey-mac-tools/</guid><description>&lt;p>I manage many Yubikeys that act as smart cards for a technical user base. Every so often
folks need to reset their keys (they typed their PIN in wrong enough times, aaagh!) or I
need to find out the status of the PIV app on the Yubikey. &lt;code>yubico-piv-tool&lt;/code> is my handy
multitool for debugging those kind of things.&lt;/p>
&lt;p>But, distributing &lt;code>yubico-piv-tool&lt;/code> on the mac is a pain because it links against OpenSSL.
You can get OpenSSL through Homebrew, but, maybe you don&amp;rsquo;t want to force everyone
to install homebrew. And, maybe you need OpenSC to let other tools that speak PKCS11 use
the Yubikey. Also, maybe you have Jamf and just want to give folks a one-click install. Many
maybes here.&lt;/p></description><content type="html"><![CDATA[<p>I manage many Yubikeys that act as smart cards for a technical user base. Every so often
folks need to reset their keys (they typed their PIN in wrong enough times, aaagh!) or I
need to find out the status of the PIV app on the Yubikey. <code>yubico-piv-tool</code> is my handy
multitool for debugging those kind of things.</p>
<p>But, distributing <code>yubico-piv-tool</code> on the mac is a pain because it links against OpenSSL.
You can get OpenSSL through Homebrew, but, maybe you don&rsquo;t want to force everyone
to install homebrew. And, maybe you need OpenSC to let other tools that speak PKCS11 use
the Yubikey. Also, maybe you have Jamf and just want to give folks a one-click install. Many
maybes here.</p>
<p>Anyways, if this is your world, <a href="https://gist.github.com/patcable/d8897babae004bad804ce094a4a92e1a">this script</a>
will build a macOS package file that installs all the things into <code>/usr/local/vpnkit</code> and <code>/Library/OpenSC</code>.</p>
]]></content></item><item><title>EKS, Terraform, and Bottlerocket</title><link>https://pcable.net/posts/2020-09-30-bottlerocket/</link><pubDate>Wed, 30 Sep 2020 12:00:00 -0400</pubDate><guid>https://pcable.net/posts/2020-09-30-bottlerocket/</guid><description>&lt;p>You can use the &lt;a href="https://github.com/terraform-aws-modules/terraform-aws-eks">terraform-aws-eks&lt;/a> terraform
module to deploy some self-managed Bottlerocket hosts. All you have to do is override the AMI and the
userdata script.&lt;/p>
&lt;p>The userdata script is a toml file. Save this as &lt;code>userdata-bottlerocket.tpl&lt;/code> in your terraform folder:&lt;/p>
&lt;pre tabindex="0">&lt;code>[settings.kubernetes]
api-server = &amp;#34;${endpoint}&amp;#34;
cluster-certificate =&amp;#34;${cluster_auth_base64}&amp;#34;
cluster-name = &amp;#34;${cluster_name}&amp;#34;
&lt;/code>&lt;/pre>&lt;p>Then, in the place you call the terraform-aws-eks module, fill in the &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami-bottlerocket.html">AMI&lt;/a>
(or use the search parameters option) and reference the userdata file:&lt;/p></description><content type="html"><![CDATA[<p>You can use the <a href="https://github.com/terraform-aws-modules/terraform-aws-eks">terraform-aws-eks</a> terraform
module to deploy some self-managed Bottlerocket hosts. All you have to do is override the AMI and the
userdata script.</p>
<p>The userdata script is a toml file. Save this as <code>userdata-bottlerocket.tpl</code> in your terraform folder:</p>
<pre tabindex="0"><code>[settings.kubernetes]
api-server = &#34;${endpoint}&#34;
cluster-certificate =&#34;${cluster_auth_base64}&#34;
cluster-name = &#34;${cluster_name}&#34;
</code></pre><p>Then, in the place you call the terraform-aws-eks module, fill in the <a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami-bottlerocket.html">AMI</a>
(or use the search parameters option) and reference the userdata file:</p>
<pre tabindex="0"><code>module &#34;my-cluster&#34; {
  cluster_version        = &#34;1.17&#34;
  ...
  worker_ami_name_filter = &#34;bottlerocket-aws-k8s-1.17-x86_64-v*&#34;
  worker_ami_owner_id    = &#34;092701018921&#34;
  worker_groups = [
    {
      ...
      userdata_template_file = file(&#34;userdata-bottlerocket.tpl&#34;)
      ...
    }
  ]
}
</code></pre>]]></content></item><item><title>The Curious Case of the Sunday Morning Alarm: Debugging Disk Performance in the Cloud</title><link>https://pcable.net/posts/2020-06-09-curious-case/</link><pubDate>Tue, 09 Jun 2020 12:00:00 -0500</pubDate><guid>https://pcable.net/posts/2020-06-09-curious-case/</guid><description>&lt;p>Threat Stack has an event processing pipeline that processes millions of messages per second sent to us by customer agents, our internal services, cloud providers, and more. Some of these messages turn into alerts, others get written to a database to provide deep context into what is happening in a customer environment. When a Threat Stack user or a Security Analyst in our SOC finds a concerning alert, the next step is to dig a little deeper and use our platform to analyze if the behavior is expected or not.&lt;/p></description><content type="html"><![CDATA[<p>Threat Stack has an event processing pipeline that processes millions of messages per second sent to us by customer agents, our internal services, cloud providers, and more. Some of these messages turn into alerts, others get written to a database to provide deep context into what is happening in a customer environment. When a Threat Stack user or a Security Analyst in our SOC finds a concerning alert, the next step is to dig a little deeper and use our platform to analyze if the behavior is expected or not.</p>
<p>Recently, we noticed that every Sunday morning we’d encounter a backup in writing these raw events to one of our databases. Writes would stop for about 10 minutes, our processing queues would back up, and our on-call engineer for that week would get paged. Generally, this kind of thing would clear itself up with some light human interaction… until the following week. Ideally, you want on-call activities to be actionable and infrequent, so this was a fast ticket to engineer burnout. How’d we fix the event?</p>
<h2 id="weekly-events">Weekly Events</h2>
<p>It’s easy to get used to looking at the application code for bugs when you’re lucky enough to have access to it, as is the case for our internal services. But this was a red herring: in the end, the issue was related to lower-level system configuration. After we determined that the system wasn’t receiving any load spikes from customers, we started poking around the system itself, and that’s where we found a few weekly cron jobs that run by default.</p>
<p>One of these jobs will update the <code>man</code> page database, another one would check to see if there was a new distribution version available, and the third one ran a command called <code>fstrim</code>. This was initially unremarkable to us – we were running in a cloud environment where we’re not selecting our own disks or controllers, so surely something outside of the OS was handling this important function.</p>
<p>As you may guess, this post is here to tell you: the OS was handling this important function in a way that we did not expect – the <code>fstrim</code> weekly cron command!</p>
<h2 id="a-brief-history-of-deleting-files">A Brief History of Deleting Files</h2>
<p>When you delete a file on an actual spinning hard drive, the file gets marked with an identifier that the position on the disk is available for use. Over time, the bits that make up your file get overwritten with the bits of your new files, regardless of their physical position on the disk.  Sometimes you could run an optimization tool like a disk defragmenter to make sure that all the individual blocks that made up a file were in order. This would increase read performance, and keep users happy with their desktop systems. In the server space, people running specialized commercial database software could (and did) increase performance by putting frequently accessed data as close to the platter as possible.</p>
<p>Solid State Drives changed this dynamic. SSD controllers abstracted away much of the “physical drive” bits to be compatible with existing computers. SSD’s store files in “pages” vs. block locations on a spinning platter. And, pages need to be contiguous – so the SSD needs to reserve some space to be able to move files around when you create (or delete) files. To facilitate this action, a new hardware operation called TRIM was implemented. This operation was a way to let your operating system tell your SSD to free up space for a file that was no longer needed.</p>
<h2 id="implementing-trim">Implementing TRIM</h2>
<p>The TRIM operation can be sent to the SSD with every delete (run continuously) or it can be run in batches. On a Linux system, you can use the mount option <code>discard</code> to run the TRIM operation continuously. Alternatively, you can use the <code>fstrim</code> command to run it all at once. We had not mounted our drive with the discard option, and had thought a controller might be handling this operation for us – on our directly attached storage provided to us by our cloud provider. We ran fstrim on a single database node, and writes stopped for a certain amount of time. We realized two things at this point:</p>
<ol>
<li>CPU IO Wait spiked up as did drive writes.</li>
<li>There wasn’t any sort of more advanced storage controller between us and the drives – they were in fact (and as advertised) directly attached.</li>
<li>Running <code>fstrim</code> weekly was the source of our Sunday morning pain.</li>
</ol>
<p>We deployed configuration to add that flag, and the issue was fixed. Right? Well, not quite – in fact, we posted a <a href="https://status.threatstack.com/incidents/514lhxnwbmqh">service availability note</a>, because deploying that configuration caused delays in making raw events searchable. We reverted and processed the backlog at expected speeds, but we were disappointed: wasn’t continuous TRIM the solution to our Sunday morning wake up call? It was only part of the issue.</p>
<h2 id="how-to-store-an-event">How to Store an Event</h2>
<p>We leverage a search-optimized database for storing events for later analysis. This database supports storing data across multiple folders – however, we found that writes were not evenly balanced across the drives in that configuration, so we made a RAID 0 array of both drives and had the database use that. We chose RAID 0 because we built the system to replicate data across availability zones and different nodes. Disk errors on one or many nodes can be solved in software – when a node fails, a new node replaces it and any replicas are recreated on the new node.</p>
<p>When initially investigating the disk issue, I wanted to know if the drives actually supported the TRIM operation in the first place. Documentation said yes, but it’s always good to double check. When we ran <code>lsblk -D</code>, the linux command which prints information about a drive’s support for the TRIM operation, the output looked like this:</p>
<pre tabindex="0"><code>NAME        DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO
nvme0n1            0        0B       0B         0
└─nvme0n1p1        0        0B       0B         0
nvme1n1          512      512B       2T         0
└─md0              0      512B      32K         0
nvme2n1          512      512B       2T         0
└─md0              0      512B      32K         0
</code></pre><p>We had implemented our RAID 0 array using Linux’s multi-device RAID driver, which creates a single logical device (/dev/md0 in this case) that can be formatted and accessed like a normal disk. We expected the root drive to not support the TRIM operation, since it is network attached block storage. Seeing this confirmed that we did have actual drives attached directly to the system.</p>
<p>In another part of our infrastructure, we had used LVM to set up a RAID 0 device. Interestingly to us the <code>lsblk -D</code> output showed:</p>
<pre tabindex="0"><code>NAME                     DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO
nvme0n1                         0        0B       0B         0
└─nvme0n1p1                     0        0B       0B         0
nvme1n1                       512      512B       2T         0
└─vg--data-disk                 0      512B       2T         0
nvme2n1                       512      512B       2T         0
└─vg--data-disk                 0      512B       2T         0
</code></pre><p>While the drives support up to 2TB as part of a TRIM operation, the way in which we created the multi-device raid0 had limited the maximum size of a TRIM operation to 32KB. This made our performance degradation make a lot of sense: we saw many thousands of IO requests per second when the <code>fstrim</code> command would run, and our database would experience degradation while performing writes. This didn’t happen elsewhere in our infrastructure.</p>
<p>We brought the LVM provisioning code into this database’s provisioning system, tested our changes, and finally applied in production. Finally, the issue was resolved! Indeed, LVM sits on top of the multi-device RAID driver in Linux, so it’s possible we might have been able to address this issue without switching to LVM. Fortunately, one other benefit of this work is that it introduced some consistency in how storage is provisioned on hosts with multiple directly-attached storage devices.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>The cloud abstracts a lot away from us in terms of hardware – most of the issues we encounter these days don’t involve optimizing the interaction between the OS and hardware. After all, cloud service providers do a good job of optimizing their hypervisors to be “out of the way,” and things function well enough that further optimization can result in diminishing returns. Every so often, however, an interesting behavior comes up and we like to write about it. If you find yourself in the same situation, remember to poke around the physical systems you’re running on. Beyond that, books like <a href="http://www.brendangregg.com/sysperfbook.html">Brendan Gregg’s <em>Systems Performance: Enterprise and the Cloud</em></a> can help provide valuable methodologies and tools to help debug these kinds of problems.</p>
<p><em>This was originally posted on the <a href="https://www.threatstack.com/blog/the-curious-case-of-the-sunday-morning-alarm-debugging-disk-performance-in-the-cloud">Threat Stack blog</a>.</em></p>
]]></content></item><item><title>The Heaviness of Maintaining Systems</title><link>https://pcable.net/posts/2020-02-29-heaviness-of-systems/</link><pubDate>Sat, 29 Feb 2020 12:00:00 -0500</pubDate><guid>https://pcable.net/posts/2020-02-29-heaviness-of-systems/</guid><description>&lt;p>The way people end up in operations has always intrigued me. Operations
always felt like &amp;ldquo;the things around the Thing&amp;rdquo; - a supporting cast that is important to
making something happen. I suppose without &amp;ldquo;the Thing&amp;rdquo; there isn&amp;rsquo;t as much of a need for
Ops work to be done. How do ops people thrive and grow as those who take care of the systems
around us, without letting the systems consume us?&lt;/p></description><content type="html"><![CDATA[<p>The way people end up in operations has always intrigued me. Operations
always felt like &ldquo;the things around the Thing&rdquo; - a supporting cast that is important to
making something happen. I suppose without &ldquo;the Thing&rdquo; there isn&rsquo;t as much of a need for
Ops work to be done. How do ops people thrive and grow as those who take care of the systems
around us, without letting the systems consume us?</p>
<p>Over the years I have noticed something in friends<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> who perform similar work: the skills that
make one particularly effective at this role often are picked up outside of tech. Things like
navigating unstable infrastructure, unstable personal relationships, or other unstable systems and
situations. Whether tech or personal, there is overlap in quickly understanding how systems come
together, reverse engineering, distilling clarity from complex code (or humans), communicating
calmly during incidents/emergency situations. But, the development of those skills come at a cost to
the person who had to learn and deploy these tools to create their own stability.</p>
<p>The &ldquo;good news&rdquo; is that these skills are often seen as ones &ldquo;senior&rdquo; engineers have, and under
the right conditions mixed with technical knowledge turns out to be in demand.
Robustness and resilience are things that People Are Very Interested In™ and anxiety (or trauma, or both)
can be synthesized into a career. It is good that these things contribute to keeping a roof
over one&rsquo;s head in the economic system we currently exist in today. The flip side of this is that
there seems to be an inevitable march towards getting burnt out, especially for those who juggle
all these demands on the regular.</p>
<p>I am left with a lot of questions: In what ways are the systems we maintain mirrors of ourselves?
The system designs we push for (or don&rsquo;t push for) or the debug mechanisms we try (or don&rsquo;t try) are
collected over years of technical, familial, and social encounters. Is there a safe way to perform
this work for a lifetime and not burn out? Self-introspection is challenging for many reasons.
I&rsquo;ve tried to start reflecting on what forces are motivating me
when I take on extra work, or jump into an incident, or engage in
<a href="http://noidea.dog/glue">glue work</a>. After that, though: what&rsquo;s next? I don&rsquo;t have any answers.</p>
<p><em>A number of people reviewed this post before I published it. I am thankful for their edits, thoughts, and insights.</em></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Yes, a limited sample size, correlation is not causation, etc. Also, endnotes work on my blog now! Neat.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content></item><item><title>Enabling EMR Self-Service With ChatOps</title><link>https://pcable.net/posts/2020-02-27-chatbots/</link><pubDate>Thu, 27 Feb 2020 12:00:00 -0500</pubDate><guid>https://pcable.net/posts/2020-02-27-chatbots/</guid><description>&lt;p>The Threat Stack Security Operations Center loves data. And Threat Stack has a lot of data! Our SOC analysts leverage &lt;a href="https://aws.amazon.com/emr/">Amazon Elastic MapReduce&lt;/a> and &lt;a href="https://jupyter.org/">Jupyter notebooks&lt;/a> to query the raw data that the &lt;a href="https://www.threatstack.com/technology">Threat Stack Cloud Security Platform®&lt;/a> receives to develop new detection and analysis mechanisms. Making something so powerful available to our analysts is a cross-team effort. From a security standpoint, the Platform Security team wondered how analysts could safely spin up an EMR cluster in our production environment to perform advanced analysis.&lt;/p></description><content type="html"><![CDATA[<p>The Threat Stack Security Operations Center loves data. And Threat Stack has a lot of data! Our SOC analysts leverage <a href="https://aws.amazon.com/emr/">Amazon Elastic MapReduce</a> and <a href="https://jupyter.org/">Jupyter notebooks</a> to query the raw data that the <a href="https://www.threatstack.com/technology">Threat Stack Cloud Security Platform®</a> receives to develop new detection and analysis mechanisms. Making something so powerful available to our analysts is a cross-team effort. From a security standpoint, the Platform Security team wondered how analysts could safely spin up an EMR cluster in our production environment to perform advanced analysis.</p>
<p>To start: An EMR lifecycle manager is extremely helpful here, and we were fortunate to have one that our architecture team wrote. Our lifecycle manager takes a JSON-based configuration and handles spinning up a cluster with a configuration that can be controlled via a collection of HTTP endpoints. But that API only works for internal machines that want EMR clusters. If we&rsquo;re adhering to the principle of least privilege (and we are), giving access to that API would allow analysts to affect other clusters that exist to process customer data.</p>
<p>So how can we solve this problem? Surprisingly: ChatOps and AWS Lambda. We wrote a function that consumed events from the Slack Events API, and depending on the use of a certain phrase, it would either start, get the status of, or destroy a cluster used for data exploration.</p>
<p>This method fits our security requirements in a few ways, specifically:</p>
<ul>
<li>The function can only affect one specific cluster, as opposed to all of them.</li>
<li>The analyst doesn&rsquo;t have direct access to the customer data.</li>
<li>Accidental destruction of the cluster doesn&rsquo;t affect the delivery of the Threat Stack service.</li>
</ul>
<p>Access to the notebooks analysts use is authenticated using SSO, so we&rsquo;re able to maintain positive control over that as well. Ultimately, it lets the SOC analyze the data they need when they want, without a platform engineer having to submit the request — which is how it is done today.</p>
<p>While many examples for Slack bots are in Node.js and Python, much of our security tooling at Threat Stack is written in Go, so we naturally used that. This presented a small challenge in that existing examples were built around a Go application running on a server full time (leveraging <code>net/http</code>&rsquo;s <code>http.ListenAndServe</code>). After a bit of experimentation, we got a sample function working, which is shared below.</p>
<p>Setting up Slack
Before you get started, you&rsquo;ll need some authentication information available from Slack. To do this, you&rsquo;ll visit the <a href="https://api.slack.com/">Slack API center</a> and <a href="https://api.slack.com/apps">list your applications</a> — then, click &ldquo;Create App&rdquo; and name your Slack bot. At this point you can modify how the application will show up in your Slack instance. You can also specify how you want Slack to interact with your application. We&rsquo;ll do that a bit later, but for now, copy the &ldquo;Signing Secret,&rdquo; and then go to &ldquo;OAuth &amp; Permissions&rdquo; to give your bot the following OAuth scopes:</p>
<ul>
<li>channels:history</li>
<li>chat:write
&amp; groups:history</li>
</ul>
<p>Feel free to modify these scopes. For example, if you expect your bot to work over direct message versus public or private chats, adjust the permissions accordingly. You&rsquo;ll still need the <code>chat:write</code> permission since that&rsquo;s how the bot can communicate what it&rsquo;s doing. After you update the OAuth scopes, you can click the &ldquo;Install App to Workspace&rdquo; button, which will generate a bot user access OAuth token. Copy that as well. Both the signing secret and access token (which generally starts with <code>xoxb</code>) will be useful to you later.</p>
<p>Building the Go integration
The whole integration is available on the <a href="https://github.com/threatstack/go-lambda-slackbot">Threat Stack GitHub account</a>. The code has comments, but we&rsquo;ll describe it here at a high level, too. Our sample application relies on the <a href="https://github.com/aws/aws-lambda-go">AWS Lambda library</a>, which has you pass in a function you want to run. The receiveSlackEvent function performs the work, with a handful of functions to improve readability of that main function. One of those functions makes it easier to set the log level if you&rsquo;re working in a development environment: <code>setLogLevel</code>. Another function validates the message we receive from Slack: <code>verifyReq</code>. Verifying that the request comes from Slack is very important to ensure that an adversary didn&rsquo;t craft a malicious request. There are some risks here, but given our threat model, we&rsquo;re OK with them.</p>
<p>The sample application code leverages the <a href="https://github.com/slack-go/slack">slack-go</a> library, which has a built-in parser for the Slack Events API messages. A variety of messages can come in through the Events API, but the ones we care about are challenge events and callback events. Challenge events are how Slack verifies that the URL you tell Slack to send these events to is ready for Slack API events — so you don&rsquo;t send a bunch of API events to someone who doesn&rsquo;t expect them. Callback events contain the events you&rsquo;re listening for. Slack has a variety of events you can subscribe to, but the ones you care about for this sample application are:</p>
<ul>
<li>message.channel</li>
<li>message.groups (if your bot will be in private rooms)</li>
</ul>
<p>Once you receive a callback event, you parse the event that&rsquo;s sent to you. The <code>InnerEvent</code> data contains the actual event that you&rsquo;ve subscribed to above. This application specifically listens for a <code>MessageEvent</code> with the text &ldquo;It&rsquo;s showtime!&rdquo; and responds with &ldquo;Yes, it is!&rdquo;</p>
<p>Deploying your code
Running <code>GOOS=linux GOARCH=amd64 go build &amp;&amp; zip slackevent.zip slackevent</code> will get you a zip archive that you can upload to AWS Lambda. We leveraged the beta HTTP API Gateway — which worked well enough for what we wanted to accomplish. Once everything&rsquo;s uploaded to AWS and you have an API Gateway URL, head on back to the <a href="https://api.slack.com/apps">Slack application listing</a> and click on your application. Then go to &ldquo;Event Notifications&rdquo; and enable it. Paste in your API Gateway URL, and then under &ldquo;Subscribe to Bot Events,&rdquo; add the scopes we listed above.</p>
<p>At this point, you should invite your new Slack bot into a channel and write some messages into the channel. For each message, you should see a Lambda invocation — and if you write &ldquo;It&rsquo;s showtime!&rdquo; you should get a response. If you did: Congratulations! If you didn&rsquo;t, start retracing step by step. Did the API Gateway get your request? Did the Lambda function invoke? Are there places you could add in <code>fmt.Printf</code> statements to see what went wrong? This was a big part of how we debugged this in our development environment.</p>
<p><em>This was originally posted on the <a href="https://www.threatstack.com/blog/enabling-emr-self-service-with-chatops">Threat Stack blog</a>.</em></p>
]]></content></item><item><title>Protecting Infrastructure With TLS Client Authentication</title><link>https://pcable.net/posts/2019-09-19-mutual-tls/</link><pubDate>Thu, 19 Sep 2019 12:00:00 -0400</pubDate><guid>https://pcable.net/posts/2019-09-19-mutual-tls/</guid><description>&lt;p>Here at Threat Stack we really like Yubikeys — and they’re a critical part of our security program. Many folks know Yubikeys for their ability to generate one-time codes for use as a second factor. Did you also know you can store certificates on them and use them in your operating system? I’ve written about using the Personal Identity Verification applet on the Yubikey in the past, but now I’d like to take that one step further and use it to identify yourself to a web application. We’ll cover how to do this with a Mac OS X Mojave client — which works nicely with the OpenSC library and an HAProxy reverse proxy.&lt;/p></description><content type="html"><![CDATA[<p>Here at Threat Stack we really like Yubikeys — and they’re a critical part of our security program. Many folks know Yubikeys for their ability to generate one-time codes for use as a second factor. Did you also know you can store certificates on them and use them in your operating system? I’ve written about using the Personal Identity Verification applet on the Yubikey in the past, but now I’d like to take that one step further and use it to identify yourself to a web application. We’ll cover how to do this with a Mac OS X Mojave client — which works nicely with the OpenSC library and an HAProxy reverse proxy.</p>
<h2 id="what-is-client-authentication">What is Client Authentication?</h2>
<p>Likely, you are already aware of TLS (sometimes called SSL) — this is the technology your computer uses to securely communicate with websites. But TLS supports <em>client authentication</em> as well. Client authentication is a means to provide an identity for yourself — after you verify that the server you’re talking to has the right DNS and a certificate you trust. It’s a handy way to limit access to servers to individuals or devices without having to entirely rely on firewalls.</p>
<h2 id="getting-started">Getting Started</h2>
<p>To begin, you’ll need an already existing public key infrastructure. We know this isn’t a small weekend project, so you may want to check out another article about <a href="http://sysadvent.blogspot.com/2017/12/day-4-this-christmas-build-your-own-pki.html">building your own PKI</a>. This article will still be here when you need it. Crucially, the security of your system will depend on you collecting your hardware certificates after employees leave, and maintaining certificate revocation lists. All of that is outside the scope of this guide, but the article above will help you get started.</p>
<p>You should have a client running macOS Mojave, and a recent version of HAProxy (we tested against 1.8) that is compiled with OpenSSL support.</p>
<h2 id="configuring-the-server">Configuring the Server</h2>
<p>You’ll want to make a few files in your HAProxy configuration directory (besides haproxy.cfg):</p>
<ul>
<li>/etc/haproxy/server.pem has your server TLS information. It should be in the order of public certificate, private key, and then any intermediate certificates.</li>
<li>/etc/haproxy/verify.pem has your client CA TLS public certificate, along with the appropriate root certificate. So if you issue keys from &ldquo;Contoso Users CA-1&rdquo; then you’ll put that along with the &ldquo;Contoso Root CA&rdquo;.</li>
<li>/etc/haproxy/crl.pem has your CRL — for all CAs. If &ldquo;Contoso Users CA-1&rdquo; is an intermediate CA, make sure you have the CRL for &ldquo;Contoso Root CA&rdquo; in this file</li>
</ul>
<p>In your frontend balancers, add these parameters to your bind line:</p>
<pre tabindex="0"><code>bind 10.0.0.1:443 ssl crt /etc/haproxy/server.pem ca-file /etc/haproxy/verify.pem crl-file /etc/haproxy/crl.pem verify required
These options set up the mutual TLS authentication:
</code></pre><ul>
<li><strong>ssl</strong> enables TLS for this port.</li>
<li><strong>crt [path]</strong> defines the server TLS private key/certificate/certificate chain.</li>
<li><strong>ca-file [path]</strong> defines the client CA verifier.</li>
<li><strong>crl-file [path]</strong> defines where HAProxy can find information on certificate revocations.</li>
<li><strong>verify required</strong>  tells HAProxy that it must require a certificate from a client before the request moves on.</li>
</ul>
<p>Other headers you can add to incoming requests include:</p>
<pre tabindex="0"><code>http-request set-header X-SSL                       %[ssl_fc]
http-request set-header X-SSL-Client-Verify         %[ssl_c_verify]
http-request set-header X-SSL-Client-SHA1           %{+Q}[ssl_c_sha1]
http-request set-header X-SSL-Client-DN             %{+Q}[ssl_c_s_dn]
http-request set-header X-SSL-Client-CN             %{+Q}[ssl_c_s_dn(cn)]
http-request set-header X-SSL-Issuer                %{+Q}[ssl_c_i_dn]
http-request set-header X-SSL-Client-Not-Before     %{+Q}[ssl_c_notbefore]
http-request set-header X-SSL-Client-Serial         %{+Q}[ssl_c_serial,hex]
http-request set-header X-SSL-Client-Version        %{+Q}[ssl_c_version]
</code></pre><p>These headers get passed to your application and can be used to infer certain information about the client’s certificate, like the CN, DN, the output from openssl verify — all helpful for debugging. We’ll talk more about that later.</p>
<p>Your backend configuration can remain the same — these changes only affect the frontend.</p>
<h2 id="configuring-the-client">Configuring the Client</h2>
<p>macOS Mojave ships with support to read the certificates off recent Yubikeys, making it easy to roll this change out to your users. To ensure that’s the case, check the Keychain Access application when you connect a Yubikey configured with certificates. The token should appear as a separate keychain.</p>
<h2 id="trying-it-out">Trying It Out</h2>
<p>If your HAProxy is running, and you’ve got your Yubikey showing up in Keychain Access, try to go to your webserver! Your browser should prompt you for a certificate that matches the CA that signed it, and let you through. Here’s an example of that prompt:</p>
<p>If it’s your first time using the Yubikey during this session, Chrome will ask you to enter your PIN:</p>
<p>If all goes well, you should get to where you were going — in this case, a test page I set up to output X-SSL-Client-CN and X-SSL-Client-DN:</p>
<p>This is a simple Sinatra application that prints out some headers:</p>
<pre tabindex="0"><code>require &#39;bundler&#39; ; Bundler.require
get &#39;/&#39; do
  client_cn = request.env[&#39;HTTP_X_SSL_CLIENT_CN&#39;]
  client_dn = request.env[&#39;HTTP_X_SSL_CLIENT_DN&#39;]
  &#34;Hello #{client_cn} (#{client_dn})&#34;
end
get &#39;/ping&#39; do
  &#34;Hello&#34;
end
</code></pre><h2 id="debugging-issues">Debugging Issues</h2>
<p>Sometimes this doesn’t work the first time around — and it can be frustrating to debug something new. One way to begin debugging is to turn off client CA verification on the server side, and then look at the output of the X-SSL-Client-Verify header. Be warned: This will let anyone who presents a certificate through to your application. It’s important in this case to ensure that proper firewalls are in place to limit that access while you debug.</p>
<p>To begin, add <code>ca-ignore-err all</code> to your HAProxy frontend bind line, and make sure you log that header to the HAProxy log with:</p>
<pre tabindex="0"><code>http-request capture req.hdr(X-SSL-Client-Verify) len 2
</code></pre><p>This will capture the output of the OpenSSL verify functions that HAProxy is calling. You can use these to figure out what exactly OpenSSL is having trouble processing to guide your further debugging. Depending on your threat model, <code>ca-ignore-err</code> can allow you to ignore specific OpenSSL error codes. Alternatively, you could log out the headers on the application side as well; outputting <code>request.env</code> with the Ruby application above can help get that information out of headers as well.</p>
<h2 id="using-openssls-s_client">Using OpenSSL’s s_client</h2>
<p>Unsure if you’re running into a browser or other client issue? Want to get a ton of information about your TLS session? OpenSSL’s <code>s_client</code> is an extremely handy tool to debug TLS connections — and can also help you debug client authentication. One problem with OpenSSL is that it does not have native support for PKCS11 — and the OpenSC libraries are too low level for OpenSSL to just use them. Fortunately, the OpenSC folks made libp11 — a higher level library that can be used with OpenSSL to add PKCS11 support in.</p>
<p>To begin, you’ll need to install GnuTLS, libp11, a recent version of OpenSSL. The yubico-piv-tool is handy, as well. All of these are available in Homebrew. GnuTLS is important because it ships with a handy utility called p11tool — which is the first thing we’ll use to find our <a href="https://tools.ietf.org/html/rfc7512">RFC7512-compliant</a> PKCS11 URI — an identifier for the key we’ll want to use off the smart card.</p>
<p>Running <code>p11tool --provider=/Library/OpenSC/lib/opensc-pkcs11.so --login --list-privkeys</code> will output the URI of the object on the token you’ll need for future steps. The output will look something like:</p>
<pre tabindex="0"><code>Token &#39;cable&#39; with URL &#39;pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=12341234a12341b;token=cable&#39; requires user PIN
Enter PIN:
Object 0:
URL: pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=12341234a12341b;token=cable;id=%01;object=PIV%20AUTH%20key;type=private
Type: Private key (RSA-2048)
Label: PIV AUTH key
Flags: CKA_WRAP/UNWRAP; CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE;
ID: 01
</code></pre><p>Next, export the certificate on your device. OpenSSL’s engine support works with private keys, but does not pull a certificate from a key as well. We’ll use <code>yubico-piv-tool -a read-certificate -s 9a &gt; mycert.pem</code> for this purpose.</p>
<p>Finally, you can enter the OpenSSL console. Make sure to point to your newer version of OpenSSL that supports engines and you can run:</p>
<pre tabindex="0"><code>$ /usr/local/Cellar/openssl@1.1/1.1.1c/bin/openssl
OpenSSL&gt; engine dynamic -pre SO_PATH:/usr/local/Cellar/libp11/0.4.10/lib/engines-1.1/pkcs11.dylib -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:/Library/OpenSC/lib/opensc-pkcs11.so
(dynamic) Dynamic engine loading support
[Success]: SO_PATH:/usr/local/Cellar/libp11/0.4.10/lib/engines-1.1/pkcs11.dylib
[Success]: ID:pkcs11
[Success]: LIST_ADD:1
[Success]: LOAD
[Success]: MODULE_PATH:/Library/OpenSC/lib/opensc-pkcs11.so
Loaded: (pkcs11) pkcs11 engine
OpenSSL&gt; s_client -engine pkcs11 -keyform engine -key &#34;pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=12341234a12341b;token=cable;id=%01;object=PIV%20AUTH%20key;type=private&#34; -cert mycert.pem -connect neato.tls.zone:443 -servername neato.tls.zone -state -debug
engine &#34;pkcs11&#34; set.
CONNECTED(00000005)
(Lots of output removed - all good for debug however)
---
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: 4D87C5D67DBB35A72EC56A3963AB9E455865739BFA1B142643D9616E483C071E
Session-ID-ctx:
Master-Key: DD107AAEB642FDCEFA54A27E112AE6176D004AB4D78B81237863E2D3B08FE018CCD015D35942FF91DA21F3E8565000B6
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1568128169
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: no
---
GET / HTTP/1.1
Host: neato.tls.zone
Connection: close
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: 75
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Server: WEBrick/1.4.2 (Ruby/2.6.4/2019-08-28)
Date: Tue, 10 Sep 2019 15:31:50 GMT
Connection: close
Strict-Transport-Security: max-age=16000000; includeSubDomains; preload;
Hello cable (/C=US/ST=Massachusetts/L=Boston/O=Threat Stack, Inc./CN=cable)
SSL3 alert read:warning:close notify
closed
SSL3 alert write:warning:close notify
OpenSSL&gt;
</code></pre><p>If there are issues negotiating the TLS connection, OpenSSL’s s_client will tell you what happened, and your HAProxy logs will be helpful here as well.</p>
<h2 id="putting-it-together">Putting It Together</h2>
<p>Client authentication over TLS has a lot of prerequisites — and you may not have them today. If you do happen to be leveraging PKI and hardware keys for other purposes like VPN or SSH key management, this is a nice way to give access to web resources without forcing the use of a VPN.</p>
<p>This was a fairly technical deep dive, but if it’s interesting to you, we’re always happy to talk to customers who are doing interesting security things!</p>
<p><em>This was originally posted on the <a href="https://www.threatstack.com/blog/protecting-infrastructure-with-tls-client-authentication">Threat Stack blog</a>.</em></p>
]]></content></item><item><title>Trash Taxi: Taking Out the Garbage in Your Infrastructure</title><link>https://pcable.net/posts/2019-08-29-trash-taxi/</link><pubDate>Thu, 29 Aug 2019 12:00:00 -0400</pubDate><guid>https://pcable.net/posts/2019-08-29-trash-taxi/</guid><description>&lt;p>One of the security challenges we had at Threat Stack was managing developer access to production infrastructure. We already have a set of controls around managing scoped access depending on role (and if you’re on-call), and we have a provisioning system that uses hardware-backed keys for all access, which is great as well.&lt;/p>
&lt;p>An edge case around all of this is the ability for our developers to run arbitrary privileged commands in Production. At face value, this is scary! What if an insider leaves something behind? What if they cause more damage to the infrastructure in the process of running arbitrary privileged commands? But the reality is: When your infrastructure is processing tens of billions of events per day, you are absolutely going to find debugging issues that become impossible to debug in a development or QA environment. How can we ensure that engineers can run commands in Production while maintaining the cleanliness of our infrastructure?&lt;/p></description><content type="html"><![CDATA[<p>One of the security challenges we had at Threat Stack was managing developer access to production infrastructure. We already have a set of controls around managing scoped access depending on role (and if you’re on-call), and we have a provisioning system that uses hardware-backed keys for all access, which is great as well.</p>
<p>An edge case around all of this is the ability for our developers to run arbitrary privileged commands in Production. At face value, this is scary! What if an insider leaves something behind? What if they cause more damage to the infrastructure in the process of running arbitrary privileged commands? But the reality is: When your infrastructure is processing tens of billions of events per day, you are absolutely going to find debugging issues that become impossible to debug in a development or QA environment. How can we ensure that engineers can run commands in Production while maintaining the cleanliness of our infrastructure?</p>
<p>At Threat Stack, our Platform Security team’s job is to figure out solutions to problems like this one. Our solution to this was developing a tool called Trash Taxi. Users who would potentially run a command like <code>sudo -i</code> or <code>sudo bash</code> are no longer allowed to run that command; instead they run <code>sudo nt</code>. Running this command will register the server as having had the “seal broken,” and on the next Trash Taxi pickup, the machine will be terminated.</p>
<p>There are a few safety controls on this kind of collection — the end user can specify certain “trash holidays” either by an EC2 <code>Role</code> or <code>Type</code> tag that you may use in your infrastructure. This allows you to track when your developers may need to execute commands on a sensitive database host — so you can go and have a conversation about why that may have needed to happen (or not). Some infrastructures will have hosts that are challenging to terminate — that’s okay! You can use this data to justify spending engineering time in the right places to improve those processes if necessary.</p>
<p>Trash Taxi Resources
Trash Taxi was released at Black Hat Arsenal this year. If you’re interested in hearing more about it, I did an interview with Dark Reading that you can listen to <a href="https://livestream.com/accounts/25023121/events/8767686/videos/195239118/player?width=640&height=360&autoPlay=true&mute=false">here</a>. More information, including documentation and configuration information, is available at <a href="https://trash.taxi">https://trash.taxi</a>.</p>
<p><em>This was originally posted on the <a href="https://www.threatstack.com/blog/trash-taxi-taking-out-the-garbage-in-your-infrastructure">Threat Stack blog</a>.</em></p>
]]></content></item><item><title>VPNNotify - A VPN Notification bot for Slack</title><link>https://pcable.net/posts/2017-09-17-vpnnotify/</link><pubDate>Sun, 17 Sep 2017 12:00:00 -0400</pubDate><guid>https://pcable.net/posts/2017-09-17-vpnnotify/</guid><description>&lt;p>In an earlier post, we talked about how we implemented centralized authentication at Threat Stack. This project initially allowed us to create clearer access control for our servers. A side benefit of this work has allowed us to write tooling around common authentication processes.&lt;/p>
&lt;p>One thing we’ve wanted to do is create an alert when folks are using a VPN to connect to one of our environments. In the event of a stolen laptop and stolen credentials, a user could be alerted to someone logging in with their credentials. With OpenVPN, performing actions on a client connect is possible using a client-connect script, so in the tradition of writing small Go applications to improve visibility, we did just that.&lt;/p></description><content type="html"><![CDATA[<p>In an earlier post, we talked about how we implemented centralized authentication at Threat Stack. This project initially allowed us to create clearer access control for our servers. A side benefit of this work has allowed us to write tooling around common authentication processes.</p>
<p>One thing we’ve wanted to do is create an alert when folks are using a VPN to connect to one of our environments. In the event of a stolen laptop and stolen credentials, a user could be alerted to someone logging in with their credentials. With OpenVPN, performing actions on a client connect is possible using a client-connect script, so in the tradition of writing small Go applications to improve visibility, we did just that.</p>
<p>For the last few months our Slack bot VPN Notifier has been letting our engineers know when they connect into a Threat Stack environment. We’ve now done the work to open source the tool so that others can use and improve on it. We specifically mention improve, because our tool has limitations: The current version does extremely basic environment checking, and extremely basic alert suppression. Our hope is that we can collaborate with others who want to take this tool the extra mile.</p>
<p>Using VPNNotify
Our <a href="https://github.com/threatstack/vpnnotify/blob/master/README.md">README.md</a> has full instructions on using the tool, along with requirements. In summary, you will:</p>
<ol>
<li>Use a configuration management tool to place a configuration file (/etc/vpnnotify.json is the default) on your OpenVPN host.</li>
<li>Use a configuration management tool to distribute a VPNnotify package. (We use FPM to make our own.)</li>
<li>Set the client-connect option in your OpenVPN Server configuration to where you installed VPNNotify — it will read in the VPN/user details over environment variables that OpenVPN provides.</li>
</ol>
<p><em>This was originally posted on the <a href="https://www.threatstack.com/blog/vpnnotify-a-vpn-notification-bot-for-slack">Threat Stack blog</a>.</em></p>
]]></content></item><item><title>Authkeys: Making Key-Based LDAP Authentication Faster</title><link>https://pcable.net/posts/2017-04-21-authkeys/</link><pubDate>Fri, 21 Apr 2017 12:00:00 -0400</pubDate><guid>https://pcable.net/posts/2017-04-21-authkeys/</guid><description>&lt;p>You may recall from an earlier post that we’ve set up centralized authentication here at Threat Stack. Our motivation for doing so centered on the desire to achieve clearer access control for the servers that power our platform. By doing this, we no longer need to use Chef to deploy the majority of users to servers. Rather, we can use an internal application to add, lock, and update users and their associated metadata.&lt;/p></description><content type="html"><![CDATA[<p>You may recall from an earlier post that we’ve set up centralized authentication here at Threat Stack. Our motivation for doing so centered on the desire to achieve clearer access control for the servers that power our platform. By doing this, we no longer need to use Chef to deploy the majority of users to servers. Rather, we can use an internal application to add, lock, and update users and their associated metadata.</p>
<p>One piece of metadata that we want to control is the engineering team member’s SSH key, which is tied to their YubiKey. This asymmetric key is what authenticates a specific user to a specific server (authorization to access that server is handled with special PAM configuration). We don’t use passwords to log into machines, except in emergencies which require multiple people to be present (and even then, an SSH key is involved).</p>
<p>When we were using Chef to set up all user accounts, Chef would set up their home directory and place an authorized_keys file which contained the public component of the user’s private key. Now that we’re using LDAP, a question remained: How do we distribute these keys to the machine?</p>
<p>Fortunately, OpenSSH has a configuration option that allows the use of an external application on login that returns the appropriate keys for a user. This configuration option is called AuthorizedKeysCommand. A few open-source options exist for performing an LDAP lookup of SSH keys, but they rely on interpreters like Lua and Python to run. Lua and Python are great languages, but we felt more confident in putting an application into the mix that didn’t rely on an interpreter. So we created Authkeys, a small application written in Go that will perform a lookup and return the appropriate keys so that SSH can make an authentication decision.</p>
<p>Using Authkeys
Our README.md has full instructions on using the tool, along with requirements. In summary:</p>
<ul>
<li>You’ll use a configuration management tool to place a configuration file (<code>/etc/authkeys.json</code> is the default) on each host containing information about your LDAP setup.</li>
<li>You’ll also use a configuration management tool to distribute an Authkeys package. (We use <a href="https://github.com/jordansissel/fpm">FPM</a> to make our own.)</li>
<li>Then, you’ll set the <code>AuthorizedKeysCommand</code> option in your <code>sshd_config</code> to wherever path you installed Authkeys to, and you’re off and authenticating in no time.</li>
</ul>
<p><em>This was originally posted on the <a href="https://www.threatstack.com/blog/authkeys-making-key-based-ldap-authentication-faster">Threat Stack blog</a>.</em></p>
]]></content></item><item><title>Balancing Security and Your On-Call Rotation Using Deputize</title><link>https://pcable.net/posts/2017-04-14-oncall/</link><pubDate>Fri, 14 Apr 2017 12:00:00 -0400</pubDate><guid>https://pcable.net/posts/2017-04-14-oncall/</guid><description>&lt;p>Threat Stack, like many other Software-as-a-Service providers, has an on-call rotation. During any week, two members of our engineering organization are tasked with responding to alerts across the platform they build and maintain. These two engineers are also responsible for a myriad of other services as well that provide support to the infrastructure: services that provide metrics and monitoring, log capture and collection, authentication, etc.&lt;/p>
&lt;p>This presents a security issue with regard to access control: should all staff have access to all servers all the time? In early start-up life this is unavoidable. But as an organization matures and grows, it becomes a bigger risk. Administrator and similarly scoped credential theft is a goldmine for attackers, so we wanted to improve our story around internal access control.&lt;/p></description><content type="html"><![CDATA[<p>Threat Stack, like many other Software-as-a-Service providers, has an on-call rotation. During any week, two members of our engineering organization are tasked with responding to alerts across the platform they build and maintain. These two engineers are also responsible for a myriad of other services as well that provide support to the infrastructure: services that provide metrics and monitoring, log capture and collection, authentication, etc.</p>
<p>This presents a security issue with regard to access control: should all staff have access to all servers all the time? In early start-up life this is unavoidable. But as an organization matures and grows, it becomes a bigger risk. Administrator and similarly scoped credential theft is a goldmine for attackers, so we wanted to improve our story around internal access control.</p>
<p>Unwrapping who needs access to what is always an evolving task, but we put in the work to figure out who goes where and why, and then created groups to control that access. Since we already use groups as a way to control who can log into specific machines, and we use PagerDuty to assign on-call rotations, it seemed like we could create a tool that would query PagerDuty and update our on-call group. So we did! And as a gift to you, we’ve open sourced it.</p>
<p><a href="https://github.com/threatstack/deputize">Deputize</a> is the tool that we created and use to manage our on-call rotation. Deputize uses PagerDuty’s API to get the email addresses of the engineers on call, then compares that to the named users in the on-call group, and updates accordingly. When changes occur, we’ve added in integration to notify Slack and log to a tool like Graylog as well. This allows us to ensure that everyone who needs to access all hosts can (in an automated fashion), while keeping that access limited to the time they’re on-call.</p>
<h2 id="using-deputize">Using Deputize</h2>
<p>Deputize has a few prerequisites:</p>
<ol>
<li>Deputize builds on PagerDuty, so you’ll need to be using PagerDuty to manage your on-call rotation.</li>
<li>We use LDAP to manage authentication and group access.</li>
<li>Secrets such as the Slack API key, the PagerDuty API key, and the password of the LDAP user authorized to make changes to the on-call group are stored in Vault.</li>
</ol>
<p>We provide information on how to configure Deputize in the README.md file located with the Deputize source, but the summary of it is that you’ll provide a path to a JSON config file via an environment variable. You can run Deputize on a schedule in a variety of ways — we have Sensu run Deputize like a “check” on an interval, but you could also run the tool via cron as well. Then, sit back and watch Slack for your on-call schedule to change automatically.</p>
<p><em>This was originally posted on the <a href="https://www.threatstack.com/blog/balancing-security-and-your-on-call-rotation-using-deputize">Threat Stack blog</a>.</em></p>
]]></content></item><item><title>Securing User Credentials With the YubiKey 4</title><link>https://pcable.net/posts/2016-12-20-yubikey-4/</link><pubDate>Tue, 20 Dec 2016 12:00:00 -0500</pubDate><guid>https://pcable.net/posts/2016-12-20-yubikey-4/</guid><description>&lt;p>I&amp;rsquo;m a big fan of the YubiKey 4.&lt;/p>
&lt;p>The &lt;a href="https://www.yubico.com/why-yubico/for-individuals/">YubiKey&lt;/a> is a security device that originally outputted a 44-character &amp;ldquo;one time password&amp;rdquo; that could be decoded and mathematically verified and used as a second factor for authentication. Over the last few years, improvements to the devices mean that they can also perform other important functions, such as storing:&lt;/p>
&lt;ul>
&lt;li>Identity, Signature, and Encryption Certificates&lt;/li>
&lt;li>U2F data for websites (GitHub and GMail, among others, support this)&lt;/li>
&lt;li>GPG Keys&lt;/li>
&lt;/ul>
&lt;p>If you&amp;rsquo;re looking to set this up on your own, read on to learn how this extra functionality helps your security game, and how you can configure services to use it.&lt;/p></description><content type="html"><![CDATA[<p>I&rsquo;m a big fan of the YubiKey 4.</p>
<p>The <a href="https://www.yubico.com/why-yubico/for-individuals/">YubiKey</a> is a security device that originally outputted a 44-character &ldquo;one time password&rdquo; that could be decoded and mathematically verified and used as a second factor for authentication. Over the last few years, improvements to the devices mean that they can also perform other important functions, such as storing:</p>
<ul>
<li>Identity, Signature, and Encryption Certificates</li>
<li>U2F data for websites (GitHub and GMail, among others, support this)</li>
<li>GPG Keys</li>
</ul>
<p>If you&rsquo;re looking to set this up on your own, read on to learn how this extra functionality helps your security game, and how you can configure services to use it.</p>
<h2 id="whats-in-an-identity">What&rsquo;s In An Identity?</h2>
<p>The YubiKey 4 can store four types of certificates — authentication (identity), digital signature, key management (encryption), and card authentication. Each of these has a different use as prescribed by the National Institute of Technology FIPS 200-2 standard. That&rsquo;s because YubiKey&rsquo;s certificate support is implemented in a way that&rsquo;s similar to the way smart card certificate support works.</p>
<p>The identity certificate can be used for authenticating to any service that supports another standard: PKCS11. PKCS11 describes an interface to be used (regardless of platform) to talk to cryptographic tokens such as smart cards, YubiKeys, or Hardware Security Modules (HSMs). Fortunately, software such as OpenVPN, SSH, and MacOS Sierra have support for talking to such devices — which means you can move your SSH key off the laptop and onto a physical device.</p>
<p>These identity certificates don&rsquo;t need to be kept in escrow (unlike an encryption certificate, for example) since they aren&rsquo;t storing data to be retrieved and decrypted later — they&rsquo;re just making a point-in-time assertion that the certificate is present on the hardware device. We&rsquo;re not going to cover making encryption certificates, but the main point to remember is to have a safe place to store such keys in escrow.</p>
<h2 id="managing-your-keys">Managing Your Keys</h2>
<p>To begin, you&rsquo;ll need to create a PKI. While we won&rsquo;t get into too much detail here, there are tools that make this easier than it was once upon a time. <a href="https://github.com/cloudflare/cfssl">CFSSL</a> is a handy tool to help create a PKI. While making a PKI isn&rsquo;t necessary for SSH or MacOS support, it is important if you want to use your certificates with tools like OpenVPN that rely on a Certificate Authority to authenticate clients.</p>
<p>It&rsquo;s worth thinking about the physical security of your CA — any compromise to your CA can result in an adversary generating valid certificates to access your infrastructure. Using a machine that restores from an original state each time it boots is a good first step, with state stored on a secure external drive like an IronKey. A Live CD with the tooling you need on it would work; guides <a href="https://help.ubuntu.com/community/LiveCDCustomization">exist</a> for customizing an Ubuntu LiveCD.</p>
<p>These instructions for provisioning the key work on a Linux machine with the most recent version of the yubico-piv-tool application (1.4 or greater). On a Mac you can install this tool with brew install yubico-piv-tool.</p>
<p>To begin, we&rsquo;re going to initialize the YubiKey with a set of IDs for the card itself. We&rsquo;ll also block resetting the PIN. It&rsquo;s easy enough to provision keys and reset them so that it makes more sense to reprovision the key in the event someone enters the PIN incorrectly a number of times:</p>
<pre tabindex="0"><code>yubico-piv-tool -a set-chuid -a set-ccc
yubico-piv-tool -a unblock-pin -P 000000 -N 000000
yubico-piv-tool -a unblock-pin -P 000000 -N 000000
yubico-piv-tool -a unblock-pin -P 000000 -N 000000
</code></pre><p>Next, we&rsquo;ll tell the key to generate a new private key. The public key will be pasted to standard out. Keep that key (for now).</p>
<p><strong>Caution:</strong> Following this procedure may overwrite your existing setup.</p>
<pre tabindex="0"><code>yubico-piv-tool -a generate -s 9a -A RSA2048 -o pubkey.temp
</code></pre><p>You&rsquo;ll then want to generate a certificate signing request:</p>
<pre tabindex="0"><code>yubico-piv-tool -s 9a -S &#34;/C=US/ST=STATE_NAME/L=CITY_NAME/O=ORG_NAME/CN=USER_NAME&#34; -a verify -a request -i pubkey.temp -o username.csr
</code></pre><p>Now, we mentioned having a CSR. We&rsquo;re going to sign this with our Users CA. It is possible to create a self-signed certificate as well, using a different set of yubico-piv-tool options — some documentation is available as well. The CA configuration that CFSSL provides out of the box has a client option that should work for this purpose.</p>
<pre tabindex="0"><code>cfssl sign -ca ca.pem -ca-key ca-key.pem -config ca-config.json -profile client username.csr | cfssljson -bare username
</code></pre><p>Add the certificate to the card:</p>
<pre tabindex="0"><code>yubico-piv-tool -a import-certificate -s 9a -i username.pem
</code></pre><p>Finally, set a management key for the card and change the PIN. The management key will be required to make future device changes unless you reset the device:</p>
<pre tabindex="0"><code>yubico-piv-tool -a change-pin
</code></pre><p>(The default pin is: 123456)</p>
<pre tabindex="0"><code>yubico-piv-tool -a set-mgm-key -n (48 character 0-9a-f string)
</code></pre><p>At this point, you will have a key that can be used to provide identity for SSH and/or MacOS Sierra.</p>
<p>Configuring MacOS Sierra
This part is easy — pull the YubiKey out and reinsert it into the computer. MacOS will ask if you want to pair the key with your local account, and you&rsquo;ll be good to go. You&rsquo;ll notice that authentication boxes ask for the PIN you set earlier, rather than an account password. If you run into issues, the <code>sc_auth</code> command can be helpful.</p>
<h2 id="configuring-ssh">Configuring SSH</h2>
<p>SSH requires a PKCS11 provider — fortunately, when we installed the yubico-piv-tool we installed a provider as well. The easiest way to use SSH with a PKCS11 provider is to use an ssh-agent.</p>
<p>To get your SSH key, run:</p>
<pre tabindex="0"><code>ssh-keygen -D /usr/local/opt/yubico-piv-tool/lib/libykcs11.dylib
</code></pre><p>To add the identity to your SSH agent, run:</p>
<pre tabindex="0"><code>ssh-add -e /usr/local/opt/yubico-piv-tool/lib/libykcs11.dylib
</code></pre><p>Once you&rsquo;ve done that, try connecting to another machine. You should be authenticated and ready to go.</p>
<h3 id="configuring-openvpn">Configuring OpenVPN</h3>
<p>On the server side, you&rsquo;ll need to point the OpenVPN server towards your CA and any applicable CRL, as you would do if you weren&rsquo;t using tokens. This configuration doesn&rsquo;t change.</p>
<p>OpenVPN does support using PKCS11 identities. We found that it works better on Macintosh and Windows clients by using the 32-bit OpenSC PKCS11 provider and a GUI client like Viscosity. The OpenSC libraries are available via <a href="http://brew.sh/">homebrew</a>, or directly from them.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>Moving user credentials off the laptop and onto dedicated hardware provides you and your users with peace of mind. Since the token generates the actual private key, you can be confident that the key is not floating around your client endpoint. There&rsquo;s a little more user education involved in the proper use of the security token, but we&rsquo;ve found this to be a small cost for a big security win.</p>
<p><em>This was originally posted on the <a href="https://www.threatstack.com/blog/securing-user-credentials-with-the-yubikey-4">Threat Stack blog</a>.</em></p>
]]></content></item><item><title>Five Lessons We Learned on Our Way to Centralized Authentication</title><link>https://pcable.net/posts/2016-10-25-five-auth-lessons/</link><pubDate>Tue, 25 Oct 2016 12:00:00 -0400</pubDate><guid>https://pcable.net/posts/2016-10-25-five-auth-lessons/</guid><description>&lt;p>In many startups, centralized authentication is a &amp;ldquo;future us&amp;rdquo; problem. Setting up centralized auth is useful for managing your network, but requires time, domain knowledge, and patience to get many of the technical solutions working. Compare this with the ease of user management via configuration management (CM) tools that your DevOps teams are already using - they work well enough (and, did we mention, are already in place?) - so it makes total sense that many organizations &amp;ldquo;punt&amp;rdquo; on this issue.&lt;/p></description><content type="html"><![CDATA[<p>In many startups, centralized authentication is a &ldquo;future us&rdquo; problem. Setting up centralized auth is useful for managing your network, but requires time, domain knowledge, and patience to get many of the technical solutions working. Compare this with the ease of user management via configuration management (CM) tools that your DevOps teams are already using - they work well enough (and, did we mention, are already in place?) - so it makes total sense that many organizations &ldquo;punt&rdquo; on this issue.</p>
<p>However, once your organization grows to a certain size, managing users through CM can be a hassle. For one thing, not all systems are going to rely on UNIX authentication (such as Jenkins, Grafana, etc.), so you’ll need to start configuring those separately and possibly outside of your CM platform. As you add monitoring and oversight into your network, this can get confusing quickly - and keeping passwords in sync would be difficult at best. On the security side, you may forget to disable an account after an employee has left. Or, onboarding can take longer than it should as you add accounts to a variety of systems.</p>
<p>Read on to find out what we learned deploying LDAP at Threat Stack - complete with a few bits of open source code!</p>
<h2 id="lesson-1-go-with-what-you-know-if-it-makes-sense">Lesson #1: Go with what you know (if it makes sense)</h2>
<p>One of the de facto standards for storing and querying directory data is LDAP, the Lightweight Directory Access Protocol - and conveniently, it can store passwords and handle authentication as well. Other protocols, such as Kerberos, may be better for this purpose, but deploying Kerberos is a larger and more complicated project. We felt that LDAP would allow us to achieve some quicker wins as long as we ensured a secure deployment with enforced TLS. We also have pretty simple requirements for identity management, and don’t need to integrate with anything that uses a proprietary authentication system, which simplifies our needs.</p>
<p>Having worked with 389DS and OpenLDAP in the past, we ended up selecting OpenLDAP. OpenLDAP seemed like it would be easier to automate deployment and maintenance tasks. We prefer to rely on open source tooling because, generally speaking, that means we can support, debug, and most importantly, automate it easier than we would a proprietary solution. The #openldap channel on the Freenode IRC network also has people who are knowledgeable and respond to questions generally - as long as you have demonstrated that you’ve gone through the documentation. This can be frustrating at times, since the OpenLDAP documentation can be lacking and inconsistent. For those looking to begin with a test deployment, the Ubuntu OpenLDAP Server Guide is a helpful place to begin your journey.</p>
<h2 id="lesson-2-build-your-own-openldap-package">Lesson #2: Build your own OpenLDAP package</h2>
<p>We initially started using the version of OpenLDAP that ships with Ubuntu. This allowed us to get going quickly, but presented issues. First, Ubuntu and Debian packages automatically configure the server and start it after installation. This makes managing its installation with Chef a little more difficult than it needs to be. More importantly though: the distros can lag behind in updates. Trying to get help from the OpenLDAP community while running a distribution-provided version of OpenLDAP is difficult at best.</p>
<p>This became a factor for us when we were trying to debug an interaction between our Chef Custom Resource for managing replication and OpenLDAP. Creating our own version of the OpenLDAP server that installed into /opt allows us to run the latest version of the server, while leaving the Ubuntu userspace alone - and capture useful debugging information to boot.</p>
<p>We created our own package by compiling OpenLDAP and using FPM, then handled post-install configuration with Chef. It’s helpful to look at how Ubuntu handles its post-install configuration by downloading the package source by running apt-get source slapd. Our Chef cookbook writes out the initial configuration to disk, then runs the appropriate slapadd command, then sets a node attribute saying the configuration has been done. This ensures the action is idempotent.</p>
<h2 id="lesson-3-replication-is-a-hard-thing-to-get-right-the-first-time">Lesson #3: Replication is a hard thing to get right the first time</h2>
<p>The Ubuntu guide we referenced above is decent for getting your first deployment up and running. It has a few downsides, however, one of which includes the fact that writes to the directory must go to the producer server. This presents a problem: do you have a way of tagging which server in your infrastructure does writes and reads? Clever application of Chef roles could accomplish this, but this is not the future we were promised in 2016. Instead, we set up Multi-Master Replication (MMR) so we can send writes to either server and not have to add complexity to our setup.</p>
<p>Setting up MMR can be complicated, and the documentation and guides available online vary in quality. At a high level, you’ll need to enable the accesslog and syncprov overlay. The syncprov overlay is what actually performs replication - and it uses the accesslog as a signal to know when to perform replication and what to replicate. Then you’ll need to configure your olcSyncrepl entries on the LDAP database you want to replicate so that OpenLDAP knows where to send changes.</p>
<p>It’s best to look towards examples that work in production, and we found one in the Zimbra project’s zmldapenable-mmr script, specifically lines 145–191. This gives an example of attributes required to set up a new database, configure the new database to store accesslog information, and enable the target database (the LDAP root that your records are stored in) for replication. A key part of this is the setup of olcSyncrepl attributes on line 205. This is how your server knows what peers to replicate with.</p>
<p>One place we chose to deviate from Zimbra’s configuration was using certificates rather than passwords for replication. We wanted to use certificates to avoid having a password with replication permissions in plaintext on our host. To do this, you’ll need to generate a client certificate signed by a CA you trust - a good use for Vault or CFSSL.</p>
<h2 id="lesson-4-managing-ldap-with-cm-tooling-is-complicated">Lesson #4: Managing LDAP with CM tooling is complicated</h2>
<p>One thing that makes handling the configuration of OpenLDAP complicated is the fact that it stores its configuration in its own database (cue the &ldquo;inception&rdquo; noise here). This presents a problem: Modern CM tooling has lots of tooling around for writing and reading files and restarting or signaling services as necessary. This is a bit harder with OpenLDAP and Chef.</p>
<p>To make this easier for you, we’re open sourcing the providers (and helpers) we wrote to interface with LDAP. We use the Syncrepl resource we developed and Chef’s search functionality to figure out what olcSyncrepl entries each host needs to have. For every Chef run, we also get the list of existing ones and compare it to our Chef search results so we can remove ones that no longer need to be there. We also have a basic LDAPModify resource that functions like the execute provider to set attributes required after olcSyncrepl entries exist (i.e., olcMirrorMode). You’ll find some of this logic in our helper library.</p>
<p>When we originally deployed OpenLDAP with Chef, we just cleared all the olcSyncrepl entries and added new ones every Chef run. What we found was an interesting condition: sometimes the Chef run would hang when adding the olcSyncrepl entry. This only happened when Chef would add an entry for replicating with the local host - not what we needed. When we cleared that up, another bug appeared: clearing and readding syncrepl entries for hosts that OpenLDAP was still replicating with would result in having too many open file handles. The Syncrepl resource we open-sourced above handles everything nicely so you avoid these issues.</p>
<h2 id="lesson-5-deploy-carefully">Lesson #5: Deploy carefully</h2>
<p>Many of our internal services are running in AWS and take advantage of auto-scaling groups. This means we can test a deployment, and if it doesn’t work out, we can quickly replace the host into a known working state. That said, we still ran into issues along the way, and not all of our services are stateless. Screwing up authentication on a Cassandra host could mean many GB of data to resync, so it’s important to try deploying to a few hosts and slowly grow from there. Most of our issues revolved around allowing all of our hosts access to the LDAP security group. We also needed to make sure we configured our pam_access setup to allow for local service users (i.e., cassandra, elasticsearch, etc.). The existence of our (secure) emergency account proved to be useful for us as well.</p>
<h2 id="is-centralized-authentication-for-you">Is centralized authentication for you?</h2>
<p>Well, we can’t answer that specific question - though from a cloud infrastructure security standpoint, we do see a lot of benefit. More information on the code we released (including how to use it) can be found on GitHub. If you decide to deploy OpenLDAP, hopefully we’ll have saved you a few hours of frustration!</p>
<p><em>This was originally posted on the <a href="https://www.threatstack.com/blog/five-lessons-we-learned-on-our-way-to-centralized-authentication">Threat Stack blog</a>.</em></p>
]]></content></item><item><title>Protecting Sensitive Credentials by Sharing Secrets in the Cloud</title><link>https://pcable.net/posts/2016-10-06-sharing-secrets/</link><pubDate>Thu, 06 Oct 2016 12:00:00 -0400</pubDate><guid>https://pcable.net/posts/2016-10-06-sharing-secrets/</guid><description>&lt;p>In the life of many organizations, developers and operations people need
credentials that they can use in case of emergency — when, for example,
your external authentication services (either your multi-factor service
or your internal directory) experience an outage. The existence of these
accounts presents a problem, however: one of the best ways for an adversary
to ruin your organization is to compromise the login credentials of an
account that is on every machine in your infrastructure.&lt;/p></description><content type="html"><![CDATA[<p>In the life of many organizations, developers and operations people need
credentials that they can use in case of emergency — when, for example,
your external authentication services (either your multi-factor service
or your internal directory) experience an outage. The existence of these
accounts presents a problem, however: one of the best ways for an adversary
to ruin your organization is to compromise the login credentials of an
account that is on every machine in your infrastructure.</p>
<p>With teams becoming larger and more distributed, keeping the password in an
envelope for one person to use probably won&rsquo;t work in an emergency. And making
the password easy enough to remember is definitely not secure in an age when
your adversary can rent a password-cracking cluster for dollars per hour. We
also want to trust our internal admins to do the right thing, but we should
ensure that adequate technical controls are in place to enforce that. So what
can we do?</p>
<h2 id="how-to-share-a-secret">How to Share a Secret</h2>
<p>Back in 1979, Adi Shamir (the &ldquo;S&rdquo; in &ldquo;RSA&rdquo; for folks familiar with
cryptography) published a paper titled
&ldquo;<a href="http://wenke.gtisc.gatech.edu/survivable-systems-readings/secret.pdf">How to Share a Secret</a>.&rdquo;
The problem Shamir was considering was presented in a combinatorial
mathematics text:</p>
<blockquote>
<p>Eleven scientists are working on a secret project. They wish to lock up the
documents in a cabinet so that the cabinet can be opened if and only if six
or more of the scientists are present. What is the smallest number of locks
needed? What is the smallest number of keys to the locks each scientist must
carry?</p>
</blockquote>
<p>&ldquo;A minimal solution uses 462 locks and 252 keys per scientist. These numbers are
clearly impractical, and they become exponentially worse when the number of
scientists increases,&rdquo; Shamir wrote. Indeed, that is a large keyring. He would
later go on and describe an algorithm called Secret Sharing that allows
someone to break a secret into several “shares” that can be distributed
amongst many people, such that when a certain number of shares (defined
by the organization) are combined, they reveal a secret value and that
if you don&rsquo;t have enough of the shares, you won&rsquo;t get any information.</p>
<p>We&rsquo;ll save you the deep dive on the details - if you have an interest in polynomial
mathematics, Shamir&rsquo;s paper is short, and worth reading. What is exciting, though,
is that we can use the solution to the &ldquo;secret project&rdquo; example to protect our
Administrator Account. People have turned Shamir&rsquo;s secret sharing algorithm from
1979 into libraries that you can use today to enforce that your developers or
operations staff can only get your emergency account&rsquo;s password if a quorum of
them get together and agree to do so.</p>
<h2 id="sharing-a-secret">Sharing a Secret</h2>
<p>Here&rsquo;s a sample program written in Ruby that uses the
<a href="https://github.com/SSSaaS/sssa-ruby">sssa-ruby</a> library we found on GitHub. In
this example, we&rsquo;re imagining that we have four staff members, and any two of
them can get together and recreate the password.</p>
<pre tabindex="0"><code>#!/usr/bin/env ruby
require &#39;securerandom&#39;
require &#39;sssa&#39;
random_string = SecureRandom.hex
puts &#34;* Random string is #{random_string}&#34;
shares = SSSA::create(2, 4, random_string)
shares.each do |e| puts &#34;* Share: #{e}&#34; end
combine_shares = [shares[rand(0..1)], shares[rand(2..3)]]
puts &#34;* Reconstructed string: #{SSSA::combine(combine_shares)}&#34;
</code></pre><p>Our program generates a random string, separates it into four parts (these are
the individual parts you&rsquo;d distribute to your staff), and picks a random entry
from the first two and the second two to combine them.</p>
<p>When we run this program, our random string is separated into four shares, and
then reconstructed from a semi-random selection:</p>
<pre tabindex="0"><code>* Random string is 92b7d4bf87fd82916c2d234a3c1769ca
* Share: ZqjMrDRCN_hwgPrxe_zVLHkQ0QtZLKIwst6HlFu5HZ8=OEaUQ8CdEtFptF0Gm8_GzY2b5O1x6PV8DfWDZVyC-p4=
* Share: JcscmxQaO-wi7_5HvxoWIynYf9jik5jrQkGxC4jkAIg=u9Yy5iZe5NKBbxkQtTPTlvK0MZqQErX7Vugc8ghv6_4=
* Share: QDCcIDJu9T7wwFGtihj9INzmCZnFrMBGXwHvErjny04=RL3YiggPfDeDsobRG_d7DfGind3g1a7x1GMx00H_cks=
* Share: djKNQW9esYZyH2gIjWulP_muIJzbh_EL0UU9Dor4YcU=zvdasiwQxldYSawPc9FkXqJiLpV0VBWz2_Kl8v8Kjb4=
* Reconstructed string: 92b7d4bf87fd82916c2d234a3c1769ca
</code></pre><p>Now, before you go off and use this technique, you may want to consider a few
things. You may want to explore ways to encrypt this secret so that only a
named recipient can open it, or not even display the password to begin with
and update the target system directly with your application. Because this
involves a security-sensitive library, it&rsquo;s definitely a good idea to have one
of your security folks review the library and how it works. These exercises
are left up to you. But even starting with our sample, you&rsquo;ve gained the
ability to enforce that using a certain password requires multiple people to
begin with, which is a good thing.</p>
<h2 id="tying-it-all-together-with-threat-stack">Tying it all Together With Threat Stack</h2>
<p>But now there’s another issue: You really only want the &ldquo;emergency account&rdquo; to
be used in emergencies. How can you discourage the use of this account for
non-emergency use? That’s where Threat Stack comes in. With Threat Stack,
you can create an alert that is triggered when someone attempts to use this
account — or when any action is triggered on its behalf. Simply make a rule
of <code>user = &quot;emerg&quot;</code>. Now when any event is triggered involving your backdoor
account (named “emerg” in this case), you will see it in any of the services
you’ve configured for alerting.</p>
<p><em>This was originally posted on the <a href="https://www.threatstack.com/blog/protecting-sensitive-credentials-by-sharing-secrets-in-the-cloud-1">Threat Stack blog</a>.</em></p>
]]></content></item><item><title>Software is Eating the Ops World</title><link>https://pcable.net/posts/2016-05-02-programming/</link><pubDate>Mon, 02 May 2016 12:00:00 -0400</pubDate><guid>https://pcable.net/posts/2016-05-02-programming/</guid><description>&lt;p>One thing I&amp;rsquo;ve thought a lot about is how the role of the system administrator
is changing. This reflection was prompted by a couple of things: one, I&amp;rsquo;m a
co-chair for talks at one of the &lt;a href="https://usenix.org/lisa16">longest running system administration conferences&lt;/a>, so I should
probably think about this kind of thing seriously when planning what talks we&amp;rsquo;ll
accept, etc. The other thing, though, is that I&amp;rsquo;ve read what some peers have had to say about the
tone of the Google Site Reliability Engineering (SRE) book. My own interpretation is that the book thinks
of traditional system administrators as &amp;ldquo;button pushers&amp;rdquo; who solely operate
something that someone else gave them; similar to what you see in many large
organization IT departments. There&amp;rsquo;s a heavy emphasis on Engineering™, which
isn&amp;rsquo;t present in large organization IT departments. I haven&amp;rsquo;t
really dug in to the book &amp;ndash; so I&amp;rsquo;m going to leave those thoughts here and circle
back in a few.&lt;/p></description><content type="html"><![CDATA[<p>One thing I&rsquo;ve thought a lot about is how the role of the system administrator
is changing. This reflection was prompted by a couple of things: one, I&rsquo;m a
co-chair for talks at one of the <a href="https://usenix.org/lisa16">longest running system administration conferences</a>, so I should
probably think about this kind of thing seriously when planning what talks we&rsquo;ll
accept, etc. The other thing, though, is that I&rsquo;ve read what some peers have had to say about the
tone of the Google Site Reliability Engineering (SRE) book. My own interpretation is that the book thinks
of traditional system administrators as &ldquo;button pushers&rdquo; who solely operate
something that someone else gave them; similar to what you see in many large
organization IT departments. There&rsquo;s a heavy emphasis on Engineering™, which
isn&rsquo;t present in large organization IT departments. I haven&rsquo;t
really dug in to the book &ndash; so I&rsquo;m going to leave those thoughts here and circle
back in a few.</p>
<p>The idea that administrators don&rsquo;t program reminds me of my first interview for
a system administration internship back in May 2007. This
is funny to me because one thing I remember clear as day was stating that I  was
<em>not</em> a programmer. Code was
not something that I did. I just made computers work well and do useful things for
people. Other people wrote code, I just lived in their world.</p>
<p>Yet, in the last week I found and patched a bug<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> in Debian apt (a minor one at that, but
nonetheless something installed on many Linux machines across the world) and added
functionality to the software we&rsquo;re using to review submissions for LISA &lsquo;16<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.
This does not correlate with the 2007 me, who decided to be so resolute in
what he could do and could (would?) not do. What gives?</p>
<hr>
<p>I was one of those stereotypical kids who was good at computers. In short,
I ended up making my town&rsquo;s website at a young age, could fix
computers and their software issues, played with Linux at a young age, life was good.
What
was more difficult to wrap my head around was learning how to actually program. I
was given a copy of Visual Basic growing up; I wasn&rsquo;t quite sure what to do with
it. Our basic CS classes in high school had us reading in values and printing out
algorithmically generated Christmas trees. I was not exceptional at math,
a skill that people often referred to as <em>extremely important</em> to being able to
write programs.</p>
<p>Here&rsquo;s the thing, though: I <em>was</em> able to run my high school&rsquo;s email server, and make sure backups worked for
a small elementary school in the school district, and I was later asked to help
my town buy and maintain computers at town hall and basically be the IT manager there.
In considering my future, system  administration didn&rsquo;t seem like it got the same respect that developers did, but
I felt decent at it. I felt decent at making systems reliable and avoiding data loss and
working around the issues that developers seemed to throw at their users (both
end users and administrators). Additionally, people seemed to find value in these
skills, and even paid for this. I was a lucky high schooler, and undergrad student,
no doubt. Speaking of undergrad, I sucked it up and did what I could to pass C++ and
Java (the only coding requirements for my major) but wasn&rsquo;t particularly stellar at either.</p>
<p>I remember being interested in automation &ndash; it was important to figure out
out Windows Deployment Services because there was no way I was going to install
Windows by hand on 20+ machines. Reducing patterns into shell scripts was a lot
more palatable than going around doing things by hand. During my internship, I wrote a provisioning
system in Perl because one of my first assignments was to get Red Hat Enterprise
Linux 4 onto 14 machines. There was parsing to be done to move the infrastructure
from NIS+ to LDAP. User accounts were previously done by email - we moved to a web-based
system after I made one.</p>
<p>The entire time I was working on these things it never felt like programming-with-a-capital-P.
I was writing in Perl, PHP, BASH and TCSH &ndash; not the compiled languages I had struggled
with earlier. But I wasn&rsquo;t a developer, I wasn&rsquo;t mathing (is that a word?) and so
it never felt real. No complicated algorithmic sorts here - just some SQL and outputting HTML
and moving text around when I had to.</p>
<hr>
<p>I think that I would have been a lot better off if I started with a different
mindset: if you made a computer do something, congrats! you did a code. I&rsquo;m not
going to say this is the same as building a complex distributed system for
production use, for sure (maybe someday!). I do think I would have been more
comfortable with such a thing earlier (rather than now) if I had a few wins early
on. Alas.</p>
<p>Today I mostly write in Ruby, and have reached the point where I can jump to
another language and flail around enough to get something done. I &ldquo;get&rdquo; types now,
thanks to toying around with writing something in Go. A few weeks ago I wrote an
internal signup form in node.js. I still experience a certain amount of angst when
I start writing something, but once I get going it&rsquo;s okay.</p>
<p>I wrote this because I don&rsquo;t think I&rsquo;m
the only person in the world who has learned how to code as a system administrator or
operations engineer or whatever it&rsquo;s called today. As software continues to
eat the world, I don&rsquo;t think the operations side of the house is going to get a free
pass on continuing to maintain the status quo just because these issues are hard to write logic
around. Indeed, some places are figuring out how to remove the human out of the loop as we speak.
I see this change in the interview stories that people share in various ops-heavy
communities (hangops, etc.), and in the kind of work that people at the middle or top
of the field (that I look up to) are doing.</p>
<hr>
<p>Which brings me back to the SRE book. I can understand the frustration with the way in which they
write of (write off?) system administration, especially for those who have cut their teeth and evolved over time.
But even 10 years ago, I didn&rsquo;t have the impression that system administration  involved
actual engineering so much as just MacGuyver-ing around the decisions of folks who may or may not have run
a system in production. Perhaps I was too naive. As the pendulum
swings towards larger organizations being more comfortable running their own systems, more organizations
are going to look at processes and techniques that have worked for others and try to apply
the ones <em>that make sense</em> to their organization. Obviously, not everyone is a large organization
that makes everything from scratch, but there are broader lessons to be learned here.</p>
<p>Administrators (myself included!) have complained about the disconnect between people who write software
and us for <em>decades</em>. Now we finally have a chance to sit at the table in some organizations. My own hangups
about code ability aside: this is actually exciting! We get to care about
the things that are important to us! This shift carries
with it some baggage<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, but I suppose sitting at the table ain&rsquo;t
free, either.</p>
<p>I&rsquo;m looking forward to a future of working with (and contributing to)
systems that care about ops the way I always have, regardless of what it&rsquo;s called. That&rsquo;s pretty cool
in my book.</p>
<hr>
<p><em>Thanks to Julie Hansbrough, Jarrod Pooler, Karen Rivera, and Carolyn Rowland for their thoughts and corrections.</em></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="http://anonscm.debian.org/git/apt/apt.git/commit/?id=8707edd9e4684ed68856cd8eeff15ebd1e8c88ea">Shameless feel goodery</a>.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Jason Dixon&rsquo;s work on <a href="https://github.com/obfuscurity/judy">Judy</a> has been a lifesaver as a conference organizer. Thanks Jason!&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="http://programmingisterrible.com/post/116698171738/nothing-is-more-indicative-of-a-bullshit-job-than">tef&rsquo;s writing</a> on whiteboard interviews comes to mind when thinking of baggage.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content></item><item><title>Docker and CentOS4</title><link>https://pcable.net/posts/2014-07-06-docker-and-centos4/</link><pubDate>Sun, 06 Jul 2014 12:00:00 -0400</pubDate><guid>https://pcable.net/posts/2014-07-06-docker-and-centos4/</guid><description>&lt;p>As much as we would want a world in which all applications were updated
regularly and licensed sanely, that is not the world we live in. Some
applications cost several hundreds of thousands of dollars (per seat!) and
their users expect to be able to use them into the future, even after the
vendor has moved on.&lt;/p>
&lt;p>One solution to let these applications run and not have to keep older OS
machines on your network is Docker. Docker does have a
variety of base images available through their site, however typically they
are newer OSes.&lt;/p></description><content type="html"><![CDATA[<p>As much as we would want a world in which all applications were updated
regularly and licensed sanely, that is not the world we live in. Some
applications cost several hundreds of thousands of dollars (per seat!) and
their users expect to be able to use them into the future, even after the
vendor has moved on.</p>
<p>One solution to let these applications run and not have to keep older OS
machines on your network is Docker. Docker does have a
variety of base images available through their site, however typically they
are newer OSes.</p>
<p>If you find yourself in the sad position of making a CentOS4 base image,
here are some helpful pointers:</p>
<ol>
<li>CentOS4 used <code>up2date</code> to pull down system updates and new RPMS. However,
it also supports Yum, and the CentOS4 repos do have a
<code>repodata</code> folder for yum use. Grab the appropriate repodata folder,
and put it in your /etc/yum.repos.d folder. Make sure to add a line for
<code>enabled=0</code>.</li>
<li>You will find the script <a href="https://github.com/dotcloud/docker/blob/master/contrib/mkimage-yum.sh">here</a>
to be of particular value. I cut out the <code>usage()</code>, <code>yum_config</code>,
and <code>getops</code> stuff.</li>
<li>Add in a test to make sure <code>$target</code> exists. What if you accidentally
kill off <code>/tmp</code> and then run the script and you forget to test for if
<code>$target</code> exists? This exercise is left to the reader (but see #7)</li>
<li>You will need to modify the first <code>yum (...) install</code> line to include
<code>--enablerepo=centos4 --disablerepo=*</code>.</li>
<li>Need extra packages? Make sure to copy in your repo definition from
<code>/etc/yum.repos.d</code> to <code>$target/etc/yum.repos.d</code> as the the groupinstall
will provide a repo that may not be what you want it to be.</li>
<li>You will likely need to add in some important .i386/.i686 RPMs,
especially if you are running the build script on a RHEL6 machine. Some
good ones to include include libgcc and glibc.</li>
<li>Kill off the RPM repository.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> <code>rm -Rf $target/var/lib/rpm</code> &ndash; the reason
for this is that you are likely running this on a newer RHEL machine.
Older versions of RPM will not be able to read the RPM database that
you have created. If you really need the ability to do development and
install RPMs in a docker repo to figure out what you need, after you
have built a base image, run <code>rpm --initdb</code> and re-run your groupinstall
command. Then, tar the RPM library and put it into the script so that
you may experiment without having to perform this step manually. I do
suggest that once you are done with dev, you just kill off the RPM
library to begin with &ndash; no one should be installing RPMs inside your
artisanal container, right?</li>
<li>Since you know your OS name, it may be beneficial to just set
<code>name=centos</code> up front.</li>
<li>Bam. You have a CentOS4 image now!</li>
</ol>
<p>There are arguments to be made for being able to use <code>yum</code> in a <code>Dockerfile</code>
however, given that only one application i know of needs to be run like
this, I find that building this once and keeping the scripts in revision
control work well enough for me.</p>
<p>My <code>Dockerfile</code> is fairly simple - I have a <code>FROM</code> and <code>MAINTAINER</code> line,
with an <code>ADD</code> and an <code>ENTRYPOINT</code> - the <code>ADD</code> simply drops in an init
script that adds a local-to-container user with the appropriate uid/gid,
then switches to that user and runs the application. X11 use is handled
by proper management of the <code>DISPLAY</code> variable and/or by exposing
<code>/tmp/X11-Unix</code> to the container.</p>
<p>Hopefully you find yourself not needing to support older apps. But, in the
event you do, maybe this will help.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://twitter.com/katzj">katzj</a> notes
that he has a solution to this. See <a href="https://twitter.com/katzj/status/485944800034951168">his tweet</a> for more info.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content></item><item><title>Solaris &amp; TLS, Best Friends</title><link>https://pcable.net/posts/2013-06-12-solaris-ldap-tls/</link><pubDate>Sun, 02 Jun 2013 12:12:00 -0500</pubDate><guid>https://pcable.net/posts/2013-06-12-solaris-ldap-tls/</guid><description>&lt;p>I got TLS LDAP authentication working in Solaris 10 today. Hooray!&lt;/p>
&lt;p>Realistically, this is not really that big of a deal, except that finding the
appropriate instructions to do so is near impossible. People say &amp;ldquo;use
certutil!&amp;rdquo; or &amp;ldquo;load up firefox go to https://ldapserver:636 and save the cert
then copy the files&amp;rdquo; and this and that and ugh.&lt;/p>
&lt;p>So here are some notes. I hope they help you.&lt;/p>
&lt;ul>
&lt;li>The NSS certificate DB for LDAP on Solaris lives in &lt;code>/var/ldap&lt;/code> — with the
rest of the ldap settings.&lt;/li>
&lt;li>The easiest way to &amp;ldquo;just make it work&amp;rdquo; is to load up firefox, import your
CAs, go to https://yourldapserver:636 and permanently accept the certificate.&lt;/li>
&lt;li>Firefox will complain that this is not a port you rock HTTP on. So go to
&lt;code>about:config&lt;/code>, right click, make a new string value called
&lt;code>network.security.ports.banned.override&lt;/code> and add 636 to it.&lt;/li>
&lt;li>Go back to that site again.&lt;/li>
&lt;li>Copy ~/.mozilla/firefox/profilename/*db to /var/ldap&lt;/li>
&lt;/ul>
&lt;p>You’re done. Run ldapclient to set up LDAP and it should work fine.
Do this, then use &lt;code>certutil -d /var/ldap -L&lt;/code> and figure out how you may be able
to script it. Or just run with it. Your call.&lt;/p></description><content type="html"><![CDATA[<p>I got TLS LDAP authentication working in Solaris 10 today. Hooray!</p>
<p>Realistically, this is not really that big of a deal, except that finding the
appropriate instructions to do so is near impossible. People say &ldquo;use
certutil!&rdquo; or &ldquo;load up firefox go to https://ldapserver:636 and save the cert
then copy the files&rdquo; and this and that and ugh.</p>
<p>So here are some notes. I hope they help you.</p>
<ul>
<li>The NSS certificate DB for LDAP on Solaris lives in <code>/var/ldap</code> — with the
rest of the ldap settings.</li>
<li>The easiest way to &ldquo;just make it work&rdquo; is to load up firefox, import your
CAs, go to https://yourldapserver:636 and permanently accept the certificate.</li>
<li>Firefox will complain that this is not a port you rock HTTP on. So go to
<code>about:config</code>, right click, make a new string value called
<code>network.security.ports.banned.override</code> and add 636 to it.</li>
<li>Go back to that site again.</li>
<li>Copy ~/.mozilla/firefox/profilename/*db to /var/ldap</li>
</ul>
<p>You’re done. Run ldapclient to set up LDAP and it should work fine.
Do this, then use <code>certutil -d /var/ldap -L</code> and figure out how you may be able
to script it. Or just run with it. Your call.</p>
<p>Note: This was posted a year ago. I should mention, you should use a fresh
Firefox profile for this &ndash; no use in accidentially carrying over unnecessary
secrets to a config that may be distributed out to many systems.</p>
]]></content></item></channel></rss>