<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Ramon Snir]]></title><description><![CDATA[Ramon Snir]]></description><link>https://ramon.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 11 Sep 2026 14:13:54 GMT</lastBuildDate><atom:link href="https://ramon.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[White hat social engineering: How to become an admin of a system]]></title><description><![CDATA[A colleague asked me recently how I got to be an admin of our Jira at work.
He has been trying to become an admin for a while since a lot of his work is related to Jira, but the other Jira admins kept insisting that he either create a change request ...]]></description><link>https://ramon.dev/white-hat-social-engineering-how-to-become-an-admin-of-a-system</link><guid isPermaLink="true">https://ramon.dev/white-hat-social-engineering-how-to-become-an-admin-of-a-system</guid><dc:creator><![CDATA[Ramon Snir]]></dc:creator><pubDate>Mon, 11 May 2020 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>A colleague asked me recently how I got to be an admin of our Jira at work.</p>
<p>He has been trying to become an admin for a while since a lot of his work is related to Jira, but the other Jira admins kept insisting that he either create a change request ticket for every request, or sit with them and do the work together.</p>
<p>All the existing admins, including me, typically respond this way to prevent a slippery slope where there are dozens of admins and no oversight over Jira management. We each have our own domain that the others respect, and whenever we need to change something in another admin’s domain or a shared setting we make sure to clearly communicate what we’re changing. This only works if there’s complete trust between the admins and if they all know each other.</p>
<p>So, how did I manage to get into this “admin clique” while my colleague isn’t able to?</p>
<p>Over the past few years, I’ve managed to consistently become an admin of systems that I care about. Partly, this was because I joined the company early - but then most other early employees aren’t currently admins. Other early employees that were admins for various reasons: they either were part of the selection team for the system, or they asked for it before we had clear policies set, or someone made them an admin by mistake in those early days. Eventually, most lost their admin privileges when we started cleaning up our act as a company.</p>
<p>I thought back and compiled this eight-point plan to become and remain an admin of a system at your work:</p>
<ol>
<li><p>Find a problem with the system or its configuration that the busiest (or laziest) admin wants to fix but doesn’t want to handle on their own. Note: this shouldn’t be something that you care about, but something that <em>they</em> care about.</p>
</li>
<li><p>Convince the admin that you can fix the problem and that you’re responsible enough.</p>
</li>
<li><p>Become an admin! But wait, this is temporary: you’ll lose your access on the next cleanup.</p>
</li>
<li><p>Start making good changes to fix people’s complaints. Still to non-controversial actions so no one tries to revoke your access. Make sure to follow up with people who request changes so that they know you were the one who helped them.</p>
</li>
<li><p>Declare that there are too many admins and that there needs to be a stricter policy to define who can be an admin.</p>
</li>
<li><p>Take it on yourself to define (or redefine) that policy and present it to the system owner in your organization. Make sure you fit the new definition and make sure that <em>staple admins</em> are also included. Staple admins are those who are either actually doing important work as admins or people who will make a lot of noise if you try to kick them out. Noise means chaos - which means it’s you who might end up on the outside.</p>
</li>
<li><p>No one remembers why you’re an admin, but you’re setting the rules now so no one can dispute it. Victory!</p>
</li>
<li><p>Make sure to keep helping out anyone who wants to fix problems with the system. If you become a roadblocker, you will allow someone else to do step #1 and you might lose your access when that person reaches step #6.</p>
</li>
</ol>
<p>This sounds like an evil plan for world domination so make sure to remember:</p>
<ul>
<li><p>You’re doing this because you care, not because you want control.</p>
</li>
<li><p>Leave the system better than you found it: more convenient for users, more secure, and easier to maintain.</p>
</li>
<li><p>Create trust among admins, and between admins and users, in every step of the process.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Elixir UDP Proxy]]></title><description><![CDATA[Long story short, I somehow got to be the main “DevOps” engineer for one of our high-priority projects (doing far more Ops than Dev, on that project at least). Between all the Chef resources, routing tables and EC2 launch configurations, I needed acc...]]></description><link>https://ramon.dev/elixir-udp-proxy</link><guid isPermaLink="true">https://ramon.dev/elixir-udp-proxy</guid><dc:creator><![CDATA[Ramon Snir]]></dc:creator><pubDate>Sat, 16 Jul 2016 16:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Long story short, I somehow got to be the main “DevOps” engineer for one of our high-priority projects (doing far more Ops than Dev, on that project at least). Between all the Chef resources, routing tables and EC2 launch configurations, I needed access to the EC2-VPC private DNS server from outside. It doesn’t like communicating to strangers, and doesn’t regard the VPC routing tables. There are thousands of solutions online for this but I wondered: how hard is it to proxy UDP? It’s just binary packets!</p>
<p>The full code from this blog post can be found on <a target="_blank" href="https://github.com/ramonsnir/udp-proxy/">GitHub</a>.</p>
<p>In essence, the proxy is a GenServer receiving messages from the client that need to be proxied to a dedicated upstream, and messages from upstreams to their matching clients.</p>
<p>The replies from the upstreams are as simple as using :gen_udp and looking up some state maps:</p>
<pre><code class="lang-elixir">  <span class="hljs-class"><span class="hljs-keyword">defmodule</span> <span class="hljs-title">UdpProxy.Server</span></span> <span class="hljs-keyword">do</span>
    <span class="hljs-keyword">use</span> GenServer
    <span class="hljs-keyword">alias</span> UdpProxy.Upstream

    ...

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">receive_data</span></span> downstream, data <span class="hljs-keyword">do</span>
      GenServer.cast downstream[<span class="hljs-symbol">:server_pid</span>], {<span class="hljs-symbol">:receive</span>, downstream, data}
    <span class="hljs-keyword">end</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_cast</span></span> {<span class="hljs-symbol">:receive</span>, downstream, data}, state <span class="hljs-keyword">do</span>
      <span class="hljs-symbol">:ok</span> = <span class="hljs-symbol">:gen_udp</span>.send state[<span class="hljs-symbol">:socket</span>], downstream[<span class="hljs-symbol">:host</span>],
                          downstream[<span class="hljs-symbol">:port</span>], data
      {<span class="hljs-symbol">:noreply</span>, state}
    <span class="hljs-keyword">end</span>

    ...

  <span class="hljs-keyword">end</span>
</code></pre>
<p>Sending the messages to the designated upstream (if exists) is pretty simple, and uses the process messages from :gen_udp’s active mode:</p>
<pre><code class="lang-elixir">  ...

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_info</span></span> {<span class="hljs-symbol">:udp</span>, _socket, ip, port, data}, state <span class="hljs-keyword">do</span>
    map_key = {ip, port}
    server = <span class="hljs-keyword">self</span>
    upstream = Map.get_lazy state[<span class="hljs-symbol">:map</span>], map_key, <span class="hljs-keyword">fn</span> -&gt;
      downstream = %{<span class="hljs-symbol">server_pid:</span> server,
                     <span class="hljs-symbol">host:</span> ip,
                     <span class="hljs-symbol">port:</span> port}
      {<span class="hljs-symbol">:ok</span>, pid} = Upstream.start_link state[<span class="hljs-symbol">:upstream_host</span>],
                                       state[<span class="hljs-symbol">:upstream_port</span>], downstream
      %{<span class="hljs-symbol">pid:</span> pid}
    <span class="hljs-keyword">end</span>
    map = Map.put state[<span class="hljs-symbol">:map</span>], map_key, upstream
    state = Map.put state, <span class="hljs-symbol">:map</span>, map
    Upstream.send_data upstream[<span class="hljs-symbol">:pid</span>], data
    {<span class="hljs-symbol">:noreply</span>, state}
  <span class="hljs-keyword">end</span>

  ...
</code></pre>
<p>Similarly the upstream communicates both with the UdpProxy.Server and with its own connection via :gen_udp.</p>
<p>To make sure that stale connections don’t end up eating too much memory and sockets, I introduced a GC loop that cleans clients that didn’t send messages through the proxy for 5 seconds. Specifically for my use case, extending the connection’s lifetime on replies was not needed. The loop is using Process.send_after self, … and I’m not sure that that’s the correct way to implement this.</p>
<p>This is actually one of the few times I have worked directly with OTP in Elixir, as most of my hobby work with Elixir is either for scripting or CLI applications, or through deep abstractions. I know that there’s a lot of error-detection missing around the Upstream processes, that aren’t supervised at all and won’t be replaced on failure, but it was definitely a fun two-hour exercise with Elixir.</p>
]]></content:encoded></item></channel></rss>