<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://www.eknert.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.eknert.com/" rel="alternate" type="text/html" /><updated>2025-09-18T11:11:26+00:00</updated><id>https://www.eknert.com/feed.xml</id><title type="html">Anders Eknert</title><subtitle>Thoughts on software, developer advocacy, devops and general technobabble.</subtitle><entry><title type="html">Six months at Styra</title><link href="https://www.eknert.com/tech/2021/05/18/six-months-at-styra.html" rel="alternate" type="text/html" title="Six months at Styra" /><published>2021-05-18T23:22:22+00:00</published><updated>2021-05-18T23:22:22+00:00</updated><id>https://www.eknert.com/tech/2021/05/18/six-months-at-styra</id><content type="html" xml:base="https://www.eknert.com/tech/2021/05/18/six-months-at-styra.html"><![CDATA[<p>Wow, time really does fly! Feels like only yesterday I said <a href="/personal/2020/11/24/thank-you-bisnode-hello-styra.html">goodbye to Bisnode</a>, and hello to <a href="https://www.styra.com/">Styra</a>. But that was back in December! Almost six months later and..</p>

<ul>
  <li>Open Policy Agent is now a <a href="https://www.cncf.io/announcements/2021/02/04/cloud-native-computing-foundation-announces-open-policy-agent-graduation/">graduated</a> CNCF project.</li>
  <li>Styra has been listed as one of the <a href="https://www.inc.com/best-workplaces/2021">best workplaces of 2021</a></li>
  <li>…named as a <a href="https://registration.styra.com/styra-gartner-cool-vendor">cool vendor</a> by Gartner.</li>
  <li>…has <a href="https://techcrunch.com/2021/05/18/styra-the-startup-behind-open-policy-agent-nabs-40m-to-expand-its-cloud-native-authorization-tools/">raised $40 million</a> in series B funding.</li>
</ul>

<p>To call the last six months eventful would be an understatement! While I’d like to believe I’ve played at least a tiny part in the bigger events, this also feels like a good time to note down some of my own work and experiences working with OPA at Styra for the last half of a year.</p>

<h3 id="community">Community</h3>

<p>One thing that wasn’t new to me was the fantastic OPA community. In fact it alone had been a major driver in my decision to work full time on OPA. Getting to work not just on open source, but one of the coolest projects around, was just insanely awesome.. and six months later, it still is. There’s just so much cool going on around OPA that I can barely wait to see where we are just six months or a year from now.</p>

<p>Needless to say I’m somewhat biased at this point, but I believe the clear separation between OPA the open source project and Styra the company has really been well managed by Styra, and while the <a href="https://www.styra.com/pricing">Styra DAS</a> is a kick-ass control plane for managing OPA at scale, I appreciate having a clear line drawn between community work and Styra the product. I’ve come to understand that this is something many developer advocates struggle with at other companies and communities.</p>

<h3 id="team-and-colleagues">Team and Colleagues</h3>

<p>Having worked in and around the OPA community for quite some time, and for a Styra customer even, I knew at least a handful of colleagues before joining. Though I don’t work with everyone in the company I have probably had some interactions with most by now, and I’ve gotta say that Styra has really managed to collect some of the most competent <em>and</em> kind people I’ve had the pleasure of working with in my career so far. Working with so many smart people has been a humbling experience, but since they seem to appreciate what I’m doing I guess I must be doing something good, or they’re not that smart after all :)</p>

<h3 id="coding">Coding</h3>

<p>Already before starting at Styra I had contributed quite a few commits into OPA and the surrounding ecosystem. While I still try to write at least some code each day, I find myself prioritizing other tasks, like blogging, higher. Working closely with people who are way better coders than I am helps some with that too. Not in the sense that I don’t feel like I can contribute, but I find it pretty hard to maintain a balance between my responsibilities if I let myself get too involved in bigger coding tasks or PR discussions. While I enjoy coding on OPA I’ve had just as fun working with side projects in the ecosystem, such as the <a href="https://github.com/anderseknert/clj-opa">Clojure OPA middleware</a>. Need to remind myself to work more on projects like that!</p>

<h3 id="working-from-home-and-timezones">Working From Home and Timezones</h3>

<p>While I, like most of the people in tech during the pandemic, worked from home long before joining Styra, this is my first job where I know there won’t be an office to go to later. While I feel more productive at home most days, having to share an “office” with a newborn kid has been a challenge at times. Having a real office to go to for presentations, meetups and webinars would definitely help, and after the summer and my parental leave is over I’ll look into renting something like a shared workspace with private rooms for that purpose.</p>

<p>With the majority of my colleagues in the US west coast, the timezone difference has been a bit of a problem at times. There’s only really an hour or so of natural overlap in office hours between Stockholm and Pacific Time, but with most communication taking place on Slack or over email, there hasn’t been a need for that many meetings.</p>

<p>Timezone wise I expect things to normalize somewhat as Styra grows in Europe and more colleagues will work closer geographically. Secondly, working from home becomes truly awesome when combined with occasional traveling, as that pretty much provides the best of both worlds, and I am really looking forward able to go to non-virtual conferences, meetups and events soon.</p>

<h3 id="blogging">Blogging</h3>

<p>While I did write the occasional internal blog at Bisnode, and certainly my fair share of wiki pages, documentation, and so on.. I’ve really gotten the chance to ramp up my blogging at Styra. While writing posts for blogs that are not only public, but often have quite a large number of readers, can feel quite intimidating at times, it is also extremely rewarding!</p>

<p>Having people, from both my own team and from Styra’s fantastic marketing team, review my blog posts before they are published and provide corrections, edits and feedback has really been invaluable. I feel like I’ve learnt so much here these past six months and yet I feel like I’ve only just started. Really looking forward to keep learning in this space! Here’s the blogs I’ve authored so far. Some for the <a href="https://blog.openpolicyagent.org/">OPA blog</a>, some for <a href="https://blog.styra.com/blog">Styra</a> and some for external publications:</p>

<ul>
  <li><a href="https://blog.openpolicyagent.org/open-policy-agent-2020-year-in-review-dc25b60308d7">Open Policy Agent 2020, year in review</a></li>
  <li><a href="https://blog.styra.com/blog/integrating-identity-oauth2-and-openid-connect-in-open-policy-agent">Integrating Identity: OAuth2 and OpenID Connect in Open Policy Agent</a></li>
  <li><a href="https://thenewstack.io/5-opa-deployment-performance-models-for-microservices/">5 OPA Deployment Performance Models for Microservices</a>
later republished on the <a href="https://blog.styra.com/blog/5-opa-deployment-performance-models-for-microservices">Styra blog</a></li>
  <li><a href="https://blog.styra.com/blog/kubernetes-authorization-webhook">The Kubernetes Authorization Webhook</a></li>
  <li><a href="https://blog.styra.com/blog/linting-rego-with-rego">Linting Rego with… Rego!</a></li>
  <li><a href="https://blog.styra.com/blog/dynamic-policy-composition-for-opa">Dynamic Policy Composition with OPA</a></li>
  <li><a href="https://blog.container-solutions.com/what-is-policy-as-code">WTF is policy as code</a></li>
  <li><a href="https://blog.openpolicyagent.org/community-spotlight-grant-shively-12903674c28c">Community Spotlight, Grant Shively</a></li>
  <li><a href="https://thenewstack.io/getting-open-policy-agent-up-and-running/">Getting Open Policy Agent Up and Running</a></li>
  <li><a href="https://blog.styra.com/blog/what-is-open-policy-agent">What is Open Policy Agent?</a></li>
</ul>

<h3 id="meetups-and-conferences">Meetups and Conferences</h3>

<p>Besides blogging, presenting OPA at meetups and conferences has really been the main activity on my list of priorities. While this wasn’t something new to me, and I’d much rather meet people in person than the online events we’ve all had to attend this last year and a half, I must say I really enjoyed this.</p>

<p><img src="/assets/rosenheim.jpg" /></p>

<p>I’ve talked at a couple of conferences and more than a dozen public webinars and meetups. On top of that probably as many or more internal meetups at companies. I’ve come to think that the meetup format has been a better fit for online/video than the (especially big) conferences have been. Another observation is that although there is nothing stopping anyone from joining local community meetups online, they have remained surprisingly… local. Presenting for a small local community of peers where almost everyone knows each other by name, that feeling really comes across even online.</p>

<h3 id="twitter">Twitter</h3>

<p>Having worked mainly with internal development communities at companies in the past, I hadn’t really had much use for Twitter. Now working full time with the larger OPA community made Twitter a great choice for interacting with the community just as much as for promoting blogs, events and meetups to people outside of it. In fact Twitter was so engaging that I eventually had to remove the app from my phone, and I’m now only checking in from my computer a couple of times per day. I’ve already made some great connections there and I’m looking forward to growing my network. Find <a href="https://twitter.com/anderseknert">me there</a>, and if we haven’t already I’d be happy to connect!</p>

<h3 id="summary">Summary</h3>

<p>Though I, as I guess most people do, sometimes feel I could have have done more, looking back at the past six months makes me realize I’ve really done a lot! Most importantly, I’ve had a lot of fun and learnt so much along the way. Exciting times, and I’m really looking forward to growing in my role as a developer advocate here, just as much as I enjoy being part of the bigger Styra journey. If you’d like to join me on that, Styra is <a href="https://www.linkedin.com/company/styra/jobs/">hiring</a>!</p>]]></content><author><name></name></author><category term="tech" /><category term="opa" /><category term="openpolicyagent" /><category term="styra" /><summary type="html"><![CDATA[Wow, time really does fly! Feels like only yesterday I said goodbye to Bisnode, and hello to Styra. But that was back in December! Almost six months later and..]]></summary></entry><entry><title type="html">Thank you Bisnode, hello Styra!</title><link href="https://www.eknert.com/personal/2020/11/24/thank-you-bisnode-hello-styra.html" rel="alternate" type="text/html" title="Thank you Bisnode, hello Styra!" /><published>2020-11-24T23:21:00+00:00</published><updated>2020-11-24T23:21:00+00:00</updated><id>https://www.eknert.com/personal/2020/11/24/thank-you-bisnode-hello-styra</id><content type="html" xml:base="https://www.eknert.com/personal/2020/11/24/thank-you-bisnode-hello-styra.html"><![CDATA[<p>In the summer of 2018 I was offered a position at <a href="https://www.bisnode.com/">Bisnode</a> that was too good to turn down. In fact, the description of the role read pretty much exactly like the role I had talked to my manager about being my dream role a couple of years before that when leaving Bisnode to try my luck working in the security space building an identity server on standards such as OAuth2 and OpenID Connect for <a href="https://curity.io/">Curity</a>. Having already worked for Bisnode I knew and liked the company and many of the people in the tech organization, so I knew it was a good fit for me. Simply moving back to something that I felt pretty much done with however wasn’t too appealing. So back to the role then.</p>

<p>Bisnode historically had worked more or less like a big company with independent entities in many European countries with little or no coordination between the units. This worked well for creating products and offerings tailor made for local markets, but obviously made less sense for competing on an increasingly international market. So a few years back Bisnode changed direction towards a model named “One Bisnode” which tried to address this by developing a series of products that would work across borders and markets. From a tech perspective this meant not just merging products and platforms but also that development teams scattered across thirteen countries - all used to working more or less in isolation - now had to work together. Having someone from outside of the teams with both development experience and at least some degree of social skills would surely be useful in that coordination effort. That’s how the role of developer advocate came to be, and I started working in August the same year.</p>

<p>As pretty much all development teams worked in or at least aimed to work on the new platform Bisnode was building, it made sense that I’d be a part of the platform team. While I wasn’t initially that interested in the infrastructure side of things, the enthusiasm and skills of the team quickly had me engaged in various infra, ops and devops issues whenever I got some time outside of my responsibilities as a developer advocate. This paid off immediately not just for my own enjoyment but just as much when getting new teams on-boarded to the platform. Unsurprisingly people tend to listen to someone who knows what they’re talking about, and occasionally I do. That fall I went on a tour through Europe to meet as many Bisnode developers that I possibly could. To learn who they were and what they were working on to some extent, but just as much to talk about and demonstrate the new common systems, platforms and tools. I loved every second. Talking to smart people about code, tech, design, methodologies and whatnot - all things I do whenever I get a chance, and here I was having someone actually pay me to do this? Spending days in front of a whiteboard leading presentations and workshops, often with discussions that continued long into the evening at some local restaurant or bar. Good times!</p>

<p>One of the trips I made wasn’t to one of our offices but to Barcelona together with my platform team. In a huge conference center we spent almost a week listening to some of the brightest (and as is commonly the case, some of the not as bright) minds in the kubernetes community talk about their projects, products and ideas. Some of the talks we attended were about a policy engine one could plug into kubernetes to put guard rails around ones resources - things like “if this application being deployed has too many replicas it will be too expensive and should thus be denied”. Not super interesting to me at the time, but the idea of having policies separate from application code to govern access control and being used as the basis for other types of enforcement - this brought me back to a lot of the problems I faced and ultimately left unsolved when working on the identity side of things. Like, I’ve built all these things to prove who someone is - now what do we <em>do</em> with that information? That’s exactly where Open Policy Agent (OPA) entered the room. Using OPA and its policy language Rego there was finally a way to make use of the identity to make informed decisions in all of these distributed systems, and it didn’t take long before OPA was “everywhere” at Bisnode - mainly because we just had so much fun implementing it in some product or domain that once we were done we just kept on going. Several developers and teams joined in and soon after OPA was officially adopted as the way to work with authorization and other types of policy within the Bisnode tech organization.</p>

<p>Having many of my plans and ambitions around advocacy cancelled due to the ongoing pandemic was disappointing, but cutting down on some of the social activities also meant that I got to direct more focus to.. well, tech. This past year I have tried to spend about half the time contributing to the platform team’s projects and the rest of the time focused on getting OPA out into the hands of our development teams and hopefully have them experience the same joy working with this piece of technology as I have myself. To help me out in this effort a team from Warsaw have acted as my closest allies since the start of the year, and I’m truly proud of what we’ve accomplished together. Not only have we introduced OPA to Bisnode, but we have tried our best to just as much be an active member of the OPA open source community with all that entails - contributing code, participating in meetups and online forums, advocating OPA in public channels, and so on. Working like this was new to all of us, and we’ve learnt more than I could ever try and summarize here, but most of all we’ve just had so much <em>fun</em>. Having worked in the OPA community for this long also opened a lot of doors and opportunities, including a good relationship with Styra, the commercial backer of OPA. Getting to work close to them as a business partner to Bisnode I got to know a whole bunch of enthusiastic and interesting personalities all sharing my interest for this emerging domain and technology. So while I’ve had the best of times at Bisnode and forever will be grateful for the opportunities they offered me, I eventually realized this was too good of an opportunity to pass up on.</p>

<p>Beginning December I will start my new position as the first developer advocate of Styra. What exactly awaits me remains to be seen, but from what I’ve experienced so far I know I will be in the best company possible. Getting to work on - and spread my enthusiasm for the things I enjoy doing the most, together with some of the best people in this space - I can’t beliebe my luck.</p>

<p>I wish I could thank all the people I’ve worked with at Bisnode for the last couple of years, but the list would just be way too long. Thank you Bisnode, and thank you all smart, kindhearted people who have been there with me along the way. You’ve easily made this time the best in my career so far, and many of you will remain some of my best friends. Keep up the good work, and I hope to see you soon.</p>

<p>A new journey awaits, and I can’t wait to get started. Styra, here I come!</p>]]></content><author><name></name></author><category term="personal" /><category term="opa" /><category term="openpolicyagent" /><category term="styra" /><category term="personal" /><category term="career" /><summary type="html"><![CDATA[In the summer of 2018 I was offered a position at Bisnode that was too good to turn down. In fact, the description of the role read pretty much exactly like the role I had talked to my manager about being my dream role a couple of years before that when leaving Bisnode to try my luck working in the security space building an identity server on standards such as OAuth2 and OpenID Connect for Curity. Having already worked for Bisnode I knew and liked the company and many of the people in the tech organization, so I knew it was a good fit for me. Simply moving back to something that I felt pretty much done with however wasn’t too appealing. So back to the role then.]]></summary></entry><entry><title type="html">RDS Aurora Postgres root user is a wimp</title><link href="https://www.eknert.com/tech/2020/09/07/rds-aurora-postgres-root-user-is-a-wimp.html" rel="alternate" type="text/html" title="RDS Aurora Postgres root user is a wimp" /><published>2020-09-07T23:21:00+00:00</published><updated>2020-09-07T23:21:00+00:00</updated><id>https://www.eknert.com/tech/2020/09/07/rds-aurora-postgres-root-user-is-a-wimp</id><content type="html" xml:base="https://www.eknert.com/tech/2020/09/07/rds-aurora-postgres-root-user-is-a-wimp.html"><![CDATA[<p>One of the better named tickets I’ve had the pleasure to work with this season, the “RDS Aurora Postgres root user is a wimp” issue turned out to be quite a challenge. Since resources on the topic online seem scarce to say the least, I thought I’d note them down for others, or if nothing more at least myself should I need to remind myself about this in the future. The original issue was this - doing a routine database maintainenace task some days before I found myself having to delete a few rows in one of the databases created in an AWS Aurora Postgres cluster.</p>

<p>As the cluster is shared by many teams and products the provisioning of each database follows a quite traditional pattern. A user notifies the platform/database team who runs a script to setup the database and user, stores the credentials somewhere safe and then notifies the user who ordered it. This script is run as the root user of the cluster, and that user is the only one allowed access across databases. So when assigned the task of deleting a few misplaced rows in one these databases, this was naturally done as the root user. Here’s where the problems starts:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">postgres</span><span class="o">=&gt;</span> <span class="se">\c</span> example
You are now connected to database <span class="s2">"example"</span> as user <span class="s2">"root"</span><span class="nb">.</span>
<span class="nv">example</span><span class="o">=&gt;</span> DELETE FROM sometable WHERE somedata <span class="o">=</span> <span class="s1">'shouldnotbehere'</span><span class="p">;</span>
ERROR:  permission denied <span class="k">for </span>relation sometable
</code></pre></div></div>

<p>OK, so that’s unusual. Logging in as the root user would mean “anything goes” in pretty much any system I’ve worked with, so what’s going on here? Turns out that the RDS Aurora clusters have a somewhat different idea on that. Since “anything goes” includes things such as configuring (and possibly breaking) replication - and this is a managed product after all - the root user has been severly limited in what it is allowed to do. Checking the available roles with <code class="language-plaintext highlighter-rouge">\du</code> confirms this:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>                                                                  List of roles
       Role name       |                         Attributes                         |                          Member of
<span class="nt">-----------------------</span>+------------------------------------------------------------+-------------------------------------------------------------
 rds_superuser         | Cannot login                                               | <span class="o">{</span>pg_monitor,pg_signal_backend,rds_replication,rds_password<span class="o">}</span>
 rdsadmin              | Superuser, Create role, Create DB, Replication, Bypass RLS+| <span class="o">{}</span>
                       | Password valid <span class="k">until </span>infinity                              |
 root                  | Create role, Create DB                                    +| <span class="o">{</span>rds_superuser<span class="o">}</span>
                       | Password valid <span class="k">until </span>infinity                              |
</code></pre></div></div>
<p>Good news first - at least we can use the <code class="language-plaintext highlighter-rouge">root</code> role to login! The only attributes assigned to the role however is <code class="language-plaintext highlighter-rouge">Create role</code> and <code class="language-plaintext highlighter-rouge">Create DB</code>. Alright, I suppose we can live with that. What doesn’t really follow though is how the same root user is unable to modify, or even read, database resources itself created. Looking at the database and user creation script it all looked pretty standard. As the root user something like the below got executed:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">example</span>
<span class="k">CREATE</span> <span class="k">USER</span> <span class="n">someuser</span> <span class="k">WITH</span> <span class="k">ENCRYPTED</span> <span class="n">PASSWORD</span> <span class="s1">'somepassword'</span>
<span class="k">GRANT</span> <span class="k">ALL</span> <span class="k">PRIVILEGES</span> <span class="k">ON</span> <span class="k">DATABASE</span> <span class="n">example</span> <span class="k">TO</span> <span class="n">someuser</span>
</code></pre></div></div>

<p>Surely the root user creating both the user and database here would be granted access to the very same resource? Turns out, well yes <em>and</em> no. The root user has access to the database, and may list tables, etc. It is however <strong>not</strong> allowed acceess to resources later created by the <code class="language-plaintext highlighter-rouge">someuser</code> user in the <code class="language-plaintext highlighter-rouge">example</code> database, even if it created both of them. Trying to grant these privileges to the root user, <em>as</em> the root user also turned out to be pointless - the root user would still be denied access. Only by logging in as the user just created, and having <em>that</em> user grant table level privileges to the root account would allow the root user subsequent access to the tables there:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">GRANT</span> <span class="k">ALL</span> <span class="k">PRIVILEGES</span> <span class="k">ON</span> <span class="k">ALL</span> <span class="n">TABLES</span> <span class="k">IN</span> <span class="k">SCHEMA</span> <span class="k">public</span> <span class="k">TO</span> <span class="n">root</span>
<span class="k">ALTER</span> <span class="k">DEFAULT</span> <span class="k">PRIVILEGES</span> <span class="k">FOR</span> <span class="k">USER</span> <span class="n">someuser</span> <span class="k">IN</span> <span class="k">SCHEMA</span> <span class="k">public</span> <span class="k">GRANT</span> <span class="k">ALL</span> <span class="k">ON</span> <span class="n">example</span> <span class="k">TO</span> <span class="n">root</span>
</code></pre></div></div>

<p>The last <code class="language-plaintext highlighter-rouge">ALTER</code> statement is crucial - granting privileges in postgres only applies to existing resources, not those created at some point in the future. So unless you want to repeat the process every now and then you’ll need to ensure that the default privileges are altered as well. Running this procedure for the database in need of maintenance and updating the user and database provisioning scripts means the problem is solved for now and the ticket could be closed. The root (hah!) of the problem however remains - the AWS Aurora Postgres root user is still a wimp!</p>]]></content><author><name></name></author><category term="tech" /><category term="postgres" /><category term="rds" /><category term="aurora" /><category term="aws" /><category term="database" /><category term="devops" /><category term="sysadmin" /><summary type="html"><![CDATA[One of the better named tickets I’ve had the pleasure to work with this season, the “RDS Aurora Postgres root user is a wimp” issue turned out to be quite a challenge. Since resources on the topic online seem scarce to say the least, I thought I’d note them down for others, or if nothing more at least myself should I need to remind myself about this in the future. The original issue was this - doing a routine database maintainenace task some days before I found myself having to delete a few rows in one of the databases created in an AWS Aurora Postgres cluster.]]></summary></entry><entry><title type="html">Pre-commit hooks for OPA</title><link href="https://www.eknert.com/tech/2020/08/31/pre-commit-hooks-for-opa.html" rel="alternate" type="text/html" title="Pre-commit hooks for OPA" /><published>2020-08-31T23:01:00+00:00</published><updated>2020-08-31T23:01:00+00:00</updated><id>https://www.eknert.com/tech/2020/08/31/pre-commit-hooks-for-opa</id><content type="html" xml:base="https://www.eknert.com/tech/2020/08/31/pre-commit-hooks-for-opa.html"><![CDATA[<p>One of the things that’s <em>really</em> improved my workflow in recent years is using pre-comit hooks for git. Tools that help with code quality and style are everywhere these days and obviously help tremendously in both catching bugs as well as enforcing agreed upon style rules. And while these tools should be included as a natural part of any build pipeline, having to wait for the CI/CD server to build your branch and report back on any code quality issues can be both time consuming and annoying. While it’s obvious how to avoid that - by running tests, code quality checks and formatters locally before pushing commits, or at least preparing PR’s - I just constantly forget about it. Pre-commit hooks to the rescue!</p>

<h2 id="the-pre-commit-framework">The pre-commit framework</h2>

<p><img src="/assets/pre-commit.svg" width="180" /></p>

<p>Running hooks in response to events is functionality <a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">built into git</a>, but having to manually manage shell scripts for each repository being worked on quickly becomes a real chore, and the idea here is to make us <em>more</em> effective after all. The <a href="https://pre-commit.com/">pre-commit framework</a> is a “framework for managing and maintaining multi-language pre-commit hooks” and does just that. Though it’s called a “framework” it’s dead simple to use, simply by following these three steps:</p>

<ol>
  <li>Install <a href="https://pre-commit.com/#install">pre-commit</a>.</li>
  <li>Place a config file (<code class="language-plaintext highlighter-rouge">.pre-commit-config.yaml</code>) in your project’s root directory, pointing out any pre-commit hooks you want to include. There’s a <a href="https://pre-commit.com/hooks.html">long list</a> of ready-made hooks available, so for any language or technology you’re working with, chances are good that there’s one for your needs.</li>
  <li>Run <code class="language-plaintext highlighter-rouge">pre-commit install</code> to install the pre-commit hooks configured in the step above.</li>
</ol>

<p>That’s it! Anytime you run <code class="language-plaintext highlighter-rouge">git commit</code> from now on, the hooks will be called and any errors reported in hooks like test runners, linters or formatters will now abort the commit, let you fix the issues before re-adding the files to the staging area and reattempt the commit.</p>

<h2 id="pre-commit-hooks-for-opa">Pre-commit hooks for OPA</h2>

<p>Having spent considerable time with <a href="https://www.openpolicyagent.org/">Open Policy Agent</a> (OPA) in the last year or so, one thing I’ve really come to miss when authoring and testing policies is pre-commit hooks. OPA comes with a few command line tools to help out during developoment, such as <code class="language-plaintext highlighter-rouge">opa check</code> to verify syntax, <code class="language-plaintext highlighter-rouge">opa fmt</code> to format rego policies, and <code class="language-plaintext highlighter-rouge">opa test</code> to run unit tests. Not having these run by default before commiting has occasionally meant forgetting about it, only to be reminded either by the CI/CD server or a colleague reviewing the policy. We can’t have that! So a couple of weeks ago I looked into writing my hooks for this purpose, and it turned out to be dead simple. Adding some fixes based off of real usage in my OPA repos since, and I think they’re now in a state where they’re good enough for general use. I hope you’ll find the <a href="https://github.com/anderseknert/pre-commit-opa">pre-commit-opa</a> hooks useful in your OPA projects.</p>

<p><img src="/assets/opa-pre-commit.png" width="450" /></p>]]></content><author><name></name></author><category term="tech" /><category term="pre-commit" /><category term="pre-commit-hooks" /><category term="opa" /><category term="open-policy-agent" /><category term="tooling" /><category term="devops" /><category term="development" /><category term="code-quality" /><summary type="html"><![CDATA[One of the things that’s really improved my workflow in recent years is using pre-comit hooks for git. Tools that help with code quality and style are everywhere these days and obviously help tremendously in both catching bugs as well as enforcing agreed upon style rules. And while these tools should be included as a natural part of any build pipeline, having to wait for the CI/CD server to build your branch and report back on any code quality issues can be both time consuming and annoying. While it’s obvious how to avoid that - by running tests, code quality checks and formatters locally before pushing commits, or at least preparing PR’s - I just constantly forget about it. Pre-commit hooks to the rescue!]]></summary></entry><entry><title type="html">Kubernetes 1.19</title><link href="https://www.eknert.com/tech/2020/08/28/kubernetes-1-19.html" rel="alternate" type="text/html" title="Kubernetes 1.19" /><published>2020-08-28T06:06:00+00:00</published><updated>2020-08-28T06:06:00+00:00</updated><id>https://www.eknert.com/tech/2020/08/28/kubernetes-1-19</id><content type="html" xml:base="https://www.eknert.com/tech/2020/08/28/kubernetes-1-19.html"><![CDATA[<p>Kubernetes 1.19 just released, with a <a href="https://github.com/kubernetes/kubernetes/pull/91745">fix</a> for an annoying <a href="https://github.com/kubernetes/kubernetes/issues/87369">bug</a> encountered at Bisnode contributed by yours truly. The fix itself is something like 3(!) lines of code - yet, managing to reproduce it reliably - and writing extensive tests to trigger that condition - took weeks of both effort and conversations back and forth with the kubernetes maintainers. Good thing I’m not paid per line of code produced, or I’d probably be the worst paid programmer in the industry.</p>

<p><img src="/assets/kubernetes-1.19-fix.jpg" width="450" /></p>]]></content><author><name></name></author><category term="tech" /><category term="kubernetes" /><category term="opensource" /><category term="devops" /><summary type="html"><![CDATA[Kubernetes 1.19 just released, with a fix for an annoying bug encountered at Bisnode contributed by yours truly. The fix itself is something like 3(!) lines of code - yet, managing to reproduce it reliably - and writing extensive tests to trigger that condition - took weeks of both effort and conversations back and forth with the kubernetes maintainers. Good thing I’m not paid per line of code produced, or I’d probably be the worst paid programmer in the industry.]]></summary></entry><entry><title type="html">Nginx TLS terminator</title><link href="https://www.eknert.com/tech/2020/08/05/nginx-tls-terminator.html" rel="alternate" type="text/html" title="Nginx TLS terminator" /><published>2020-08-05T12:37:00+00:00</published><updated>2020-08-05T12:37:00+00:00</updated><id>https://www.eknert.com/tech/2020/08/05/nginx-tls-terminator</id><content type="html" xml:base="https://www.eknert.com/tech/2020/08/05/nginx-tls-terminator.html"><![CDATA[<p><img src="/assets/nginx_logo.svg" width="300" /></p>

<p>Sometimes you’ll want/need to use TLS for connections to internal kubernetes services where TLS isn’t supported or used by the original application, or where you’d normally terminate TLS in the ingress but don’t want to have internal kubernetes traffic routed through that. Cases like that are a great fit for the <a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/sidecar">sidecar pattern</a>, injecting a small proxy inside a pod to terminate TLS and forward the requests to the original application. Having configured a few of these sidecars for various projects, I started to compile a common configuration for nginx which I could reuse for this purpose. Hence the <a href="https://github.com/anderseknert/nginx-tls-terminator">nginx-tls-terminator</a> project was born.</p>

<p>From the project’s decription:</p>

<blockquote>
  <p>Single-purpose TLS terminating nginx proxy.</p>

  <p>Primary function is to run as a sidecar container in kubernetes pods where the app running in the main container either does not support TLS, or it’s inconvenient to add it - such as for legacy apps or where the code is not under your control. Another common use case is when external traffic has TLS terminated by the ingress controller, but some internal services need to reach the same services from the inside on the same URL. One example of this is the issuer URL provided in OAuth2 and OpenID Connect, where both external and internal applications will need to query the same endpoints over a secure channel.</p>
</blockquote>

<blockquote>
  <p>Features:</p>
</blockquote>

<blockquote>
  <ul>
    <li>Small single-purpose container at ~9 MB with minimal configuration needed.</li>
    <li>Does not require root privileges and runs as non-root user by default. Runs with strictest securityContext configured on the container.</li>
    <li>Running with a read-only root filesystem as easy as mounting a volume on /tmp.</li>
    <li>Exposed TLS port as well as target upstream port configurable through environment variables.</li>
  </ul>
</blockquote>

<p>Check it out on <a href="https://github.com/anderseknert/nginx-tls-terminator">Github</a> and <a href="https://hub.docker.com/r/eknert/nginx-tls-terminator">Docker Hub</a>.</p>]]></content><author><name></name></author><category term="tech" /><category term="nginx" /><category term="tls" /><category term="https" /><category term="openssl" /><category term="security" /><category term="docker" /><category term="kubernetes" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Incremental rules in Rego</title><link href="https://www.eknert.com/tech/2020/02/04/incremental-rules-in-opa.html" rel="alternate" type="text/html" title="Incremental rules in Rego" /><published>2020-02-04T12:37:00+00:00</published><updated>2020-02-04T12:37:00+00:00</updated><id>https://www.eknert.com/tech/2020/02/04/incremental-rules-in-opa</id><content type="html" xml:base="https://www.eknert.com/tech/2020/02/04/incremental-rules-in-opa.html"><![CDATA[<p>So a lot of the stuff I’ve been working on lately has revolved around Open Policy Agent (OPA). Though I’m planning a longer writeup on the subject
I’ll use this blog to post some of my notes while I exlore this great piece of tehnology.</p>

<h3 id="incremental-rule---sets">Incremental rule - sets</h3>

<p>A common pattern when writing Rego policies is to use <a href="https://www.openpolicyagent.org/docs/latest/policy-cheatsheet/#incremental">incremental rules</a> to build a set of values. This is tremendously useful for e.g. returning a message for each violation of a defined policy:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>deny[reason] {
    input.role != "admin"
    reason = "User not an admin"
}

deny[reason] {
    time.weekday(time.now_ns()) == "Sunday"
    reason = "Access not allowed on Sundays"
}
</code></pre></div></div>
<p>Any non-admin trying to access the requested resource on a Sunday would now not only be denied, but could also be given an explanation as to why:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"deny": [
    "Access not allowed on Sundays",
    "User not an admin"
]
</code></pre></div></div>
<p>See full example on the <a href="https://play.openpolicyagent.org/p/sAG0hfF1Fd">Rego Playground</a>.</p>

<h3 id="incremental-rules---maps">Incremental rules - maps</h3>

<p>Not as commonly used, but certainly just as useful - incremental rules can also be used to build up maps. This could be used similarily to build up key/value pairs of reasons or violations, but might just as well be used for data transformations. Consider the following input provided to OPA:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
    "street": "High street 32",
    "zip": "11766"
}
</code></pre></div></div>
<p>We could create an incremental map rule to gradually build a structured address object with values in a normalized format:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>address["zip"] = zip_numeric {
    zip_numeric = to_number(input.zip)
}

address["street_name"] = streetname {
    streetname = trim(concat(" ", regex.find_n(`[^\d]+`, input.street, -1)), " ")
}

address["street_number"] = streetnumber {
    numbers := regex.find_n(`\d+$`, input.street, 1)
    streetnumber = to_number(numbers[0])
}
</code></pre></div></div>
<p>Which would increment the address rule map as follows:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
    "address": {
        "street_name": "High street",
        "street_number": 32,
        "zip": 11766
    }
}
</code></pre></div></div>
<p>Again, see full example on the <a href="https://play.openpolicyagent.org/p/5DvgKi3Y1x">Rego Playground</a>.</p>]]></content><author><name></name></author><category term="tech" /><category term="opa" /><category term="open-policy-agent" /><summary type="html"><![CDATA[So a lot of the stuff I’ve been working on lately has revolved around Open Policy Agent (OPA). Though I’m planning a longer writeup on the subject I’ll use this blog to post some of my notes while I exlore this great piece of tehnology.]]></summary></entry><entry><title type="html">New year, new blog!</title><link href="https://www.eknert.com/meta/2020/01/01/new-year-new-blog!.html" rel="alternate" type="text/html" title="New year, new blog!" /><published>2020-01-01T14:44:22+00:00</published><updated>2020-01-01T14:44:22+00:00</updated><id>https://www.eknert.com/meta/2020/01/01/new-year-new-blog!</id><content type="html" xml:base="https://www.eknert.com/meta/2020/01/01/new-year-new-blog!.html"><![CDATA[<p>So, the twenties are finally back! And what better way to start a decade than to try and kickstart that late new years
resolution about blogging? Not that it was something I came up with just as the new year approached us - I had started
looking at a platform for blogging some months ago already but other things got in the way. Oh well.</p>

<p>From a tech perspective this blog is powered by <a href="https://jekyllrb.com/">Jekyll</a> and hosted as a
“<a href="https://github.com/anderseknert/anderseknert.github.io">GitHub Pages</a>” page - pretty much just markdown files and some
stylesheets that Jekyll is kind enough to transform into something resembling a blog. The (ruby based) tech behind it is
old and uninteresting enough that I might just get time for writing rather than trying to hack the actual blogging
software, something that has stopped at least a handful of previous attempts to start blogging.</p>

<p>About Jekyll being old - I was especially amused by the documentation section on
<a href="https://jekyllrb.com/docs/posts/#creating-posts">creating posts</a> where the example post is named
“2011-12-31-new-years-eve-is-awesome.md” - that’s almost a decade ago now! Just as GitHub repositories with a
“last modified” dating a few years back in time, that would have been a huge warning flag to me had you asked me just
a few years ago. Now I consider “slow moving, old and boring” a feature, at least for software like this where it’s
not the actual code itself that’s of interest but rather something I approach as an end user.</p>

<p>Hoping to focus on writing down my thoughts rather than coding the blog itself, but given this is all very new there
<em>are</em> a few things that I’ll need to look into before I can do so:</p>

<ul>
  <li>Should poke around in themes and stylesheets and pick a theme for the blog as the minima theme certainly was minimal.</li>
  <li>Analytics. There’s Google Analytics of course, but I’d rather use something that respects user privacy, doesn’t do
tracking outside of the blog, etc. Piwik/Matomo seems to be a contender here, but not sure yet how to use it with a statically
generated blog.</li>
  <li>Setup something for post comments. Unsurprisingly this is a little trickier to pull off on a statically generated site. <a href="https://disqus.com/">Disqus</a> seemed to have ruled this space for long, but their popularity has declined since they introduced (allegedly, annoying) ads in their free model. <a href="https://staticman.net/docs/">Staticman</a> seems to be a great free alternative - will check it out as soon as possible.</li>
</ul>

<p></p>
<p>Will look into my options for any of the above as soon as I get an opportunity to do so, and perhaps I’ll write some
about it here as well. For now just happy to finally get something out the door!</p>]]></content><author><name></name></author><category term="meta" /><summary type="html"><![CDATA[So, the twenties are finally back! And what better way to start a decade than to try and kickstart that late new years resolution about blogging? Not that it was something I came up with just as the new year approached us - I had started looking at a platform for blogging some months ago already but other things got in the way. Oh well.]]></summary></entry></feed>