<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Secrets on alikhil</title>
    <link>https://alikhil.dev/tags/secrets/</link>
    <description>Recent content in Secrets on alikhil</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <managingEditor>Alik Khilazhev</managingEditor>
    <lastBuildDate>Sun, 30 Mar 2025 16:01:25 +0300</lastBuildDate><atom:link href="https://alikhil.dev/tags/secrets/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Storing and using secrets in Mikrotik RouterOS</title>
      <link>https://alikhil.dev/posts/saving-and-using-secrets-in-mikrotitk-routeros/</link>
      <pubDate>Sun, 30 Mar 2025 16:01:25 +0300</pubDate>
      <author>Alik Khilazhev</author>
      <guid>https://alikhil.dev/posts/saving-and-using-secrets-in-mikrotitk-routeros/</guid>
      <description>&lt;p&gt;Recently I have replaced my stock ISP router with &lt;a href=&#34;https://mikrotik.com/product/hex_s&#34;&gt;Mikrotik Hex S&lt;/a&gt;. I have been using it for a while and I am very happy with it. It is a very powerful device which can be programmed and automated with built-in scripting language.&lt;/p&gt;
&lt;p&gt;When I started writing my first scripts I faced a problem: how to store and use secrets in my scripts. I have found a solution and I want to share it with you.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Recently I have replaced my stock ISP router with <a href="https://mikrotik.com/product/hex_s">Mikrotik Hex S</a>. I have been using it for a while and I am very happy with it. It is a very powerful device which can be programmed and automated with built-in scripting language.</p>
<p>When I started writing my first scripts I faced a problem: how to store and use secrets in my scripts. I have found a solution and I want to share it with you.</p>
<h2 id="the-problem">The problem</h2>
<p>Let&rsquo;s say I want to write a script that will send me telegram notifications. To do so I need to store my telegram bot token and chat id. Since I keep my RouterOS configuration in a git repository, I don&rsquo;t want to hardcode my secrets in the script.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="p">:</span><span class="n">global</span> <span class="n">sendTelegramMessage</span> <span class="k">do</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">:</span><span class="n">local</span> <span class="n">botToken</span> <span class="s2">&#34;1234567890:ABCDEFGHIJKLMN&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">:</span><span class="n">local</span> <span class="n">chatId</span> <span class="s2">&#34;10000000&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">:</span><span class="n">local</span> <span class="n">message</span> <span class="s2">&#34;$1&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># telegram notification</span>
</span></span><span class="line"><span class="cl">    <span class="o">/</span><span class="k">tool</span> <span class="n">fetch</span> <span class="n">url</span><span class="o">=</span><span class="s2">&#34;https://api.telegram.org/bot$botToken/sendMessage\?chat_id=$chatId&amp;text=$message&#34;</span> <span class="n">keep</span><span class="o">-</span><span class="n">result</span><span class="o">=</span><span class="n">no</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="the-solution">The solution</h2>
<p>RouterOS has low level feature <code>/ppp secret</code> which can be used to store secrets. However, it could be inconvenient and a bit messy to use it directly in scripts. Instead, I would like to have more high level API to store and use secrets.</p>
<p>And, I have one. There is post in <a href="https://forum.mikrotik.com/viewtopic.php?p=916159#p916159">mikrotik forum</a> by user with nickname <strong>Amm0</strong>. Ammo has shared a script of global function which can be used to store and retrieve secrets like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$SECRET set mySecret password=&#34;mySecretPassword&#34;
</span></span><span class="line"><span class="cl">:put [$SECRET get mySecret]
</span></span></code></pre></div><p><img loading="lazy" src="/images/posts/mirotik-secrets/terminal.png" type="" alt="Terminal Screenshot"  /></p>
<p>Now, I modify my script to use this function to keep it clean and secure:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="p">:</span><span class="n">global</span> <span class="n">sendTelegramMessage</span> <span class="k">do</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">:</span><span class="n">local</span> <span class="n">botToken</span>
</span></span><span class="line"><span class="cl">    <span class="p">:</span><span class="n">set</span> <span class="n">botToken</span> <span class="s2">&#34;$[$SECRET get TELEGRAM_TOKEN]&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">:</span><span class="n">local</span> <span class="n">chatId</span> <span class="s2">&#34;$[$SECRET get CHAT_ID]&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">:</span><span class="n">local</span> <span class="n">message</span> <span class="s2">&#34;$1&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># telegram notification</span>
</span></span><span class="line"><span class="cl">    <span class="o">/</span><span class="k">tool</span> <span class="n">fetch</span> <span class="n">url</span><span class="o">=</span><span class="s2">&#34;https://api.telegram.org/bot$botToken/sendMessage\?chat_id=$chatId&amp;text=$message&#34;</span> <span class="n">keep</span><span class="o">-</span><span class="n">result</span><span class="o">=</span><span class="n">no</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><details>
  <summary>global SECRET function source code</summary>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">### $SECRET
</span></span><span class="line"><span class="cl">#   get &lt;name&gt;
</span></span><span class="line"><span class="cl">#   set &lt;name&gt; password=&lt;password&gt;
</span></span><span class="line"><span class="cl">#   remove &lt;name
</span></span><span class="line"><span class="cl">#   print
</span></span><span class="line"><span class="cl">:global SECRET
</span></span><span class="line"><span class="cl">:set $SECRET do={
</span></span><span class="line"><span class="cl">    :global SECRET
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    # helpers
</span></span><span class="line"><span class="cl">    :local fixprofile do={
</span></span><span class="line"><span class="cl">        :if ([/ppp profile find name=&#34;null&#34;]) do={:put &#34;nothing&#34;} else={
</span></span><span class="line"><span class="cl">            /ppp profile add bridge-learning=no change-tcp-mss=no local-address=0.0.0.0 name=&#34;null&#34; only-one=yes remote-address=0.0.0.0 session-timeout=1s use-compression=no use-encryption=no use-mpls=no use-upnp=no
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">    :local lppp [:len [/ppp secret find where name=$2]]
</span></span><span class="line"><span class="cl">    :local checkexist do={
</span></span><span class="line"><span class="cl">        :if (lppp=0) do={
</span></span><span class="line"><span class="cl">            :error &#34;\$SECRET: cannot find $2 in secret store&#34;
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    # $SECRET
</span></span><span class="line"><span class="cl">    :if ([:typeof $1]!=&#34;str&#34;) do={
</span></span><span class="line"><span class="cl">        :put &#34;\$SECRET&#34;
</span></span><span class="line"><span class="cl">        :put &#34;   uses /ppp/secrets to store stuff like REST apikeys, or other sensative data&#34;
</span></span><span class="line"><span class="cl">        :put &#34;\t\$SECRET print - prints stored secret passwords&#34;
</span></span><span class="line"><span class="cl">        :put &#34;\t\$SECRET get &lt;name&gt; - gets a stored secret&#34;
</span></span><span class="line"><span class="cl">        :put &#34;\t\$SECRET set &lt;name&gt; password=\&#34;YOUR_SECRET\&#34; - sets a secret password&#34;
</span></span><span class="line"><span class="cl">        :put &#34;\t\$SECRET remove &lt;name&gt; - removes a secret&#34;
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    # $SECRET print
</span></span><span class="line"><span class="cl">    :if ($1~&#34;^pr&#34;) do={
</span></span><span class="line"><span class="cl">        /ppp secret print where comment~&#34;\\\$SECRET&#34;
</span></span><span class="line"><span class="cl">        :return [:nothing]
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    # $SECRET get
</span></span><span class="line"><span class="cl">    :if ($1~&#34;get&#34;) do={
</span></span><span class="line"><span class="cl">        $checkexist
</span></span><span class="line"><span class="cl">       :return [/ppp secret get $2 password]
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    # $SECRET set
</span></span><span class="line"><span class="cl">    :if ($1~&#34;set|add&#34;) do={
</span></span><span class="line"><span class="cl">        :if ([:typeof $password]=&#34;str&#34;) do={} else={:error &#34;\$SECRET: password= required&#34;}
</span></span><span class="line"><span class="cl">        :if (lppp=0) do={
</span></span><span class="line"><span class="cl">            /ppp secret add name=$2 password=$password
</span></span><span class="line"><span class="cl">        } else={
</span></span><span class="line"><span class="cl">            /ppp secret set $2 password=$password
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">        $fixprofile
</span></span><span class="line"><span class="cl">        /ppp secret set $2 comment=&#34;used by \$SECRET&#34;
</span></span><span class="line"><span class="cl">        /ppp secret set $2 profile=&#34;null&#34;
</span></span><span class="line"><span class="cl">        /ppp secret set $2 service=&#34;async&#34;
</span></span><span class="line"><span class="cl">        :return [$SECRET get $2]
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    # $SECRET remove
</span></span><span class="line"><span class="cl">    :if ($1~&#34;rm|rem|del&#34;) do={
</span></span><span class="line"><span class="cl">        $checkexist
</span></span><span class="line"><span class="cl">        :return [/ppp secret remove $2]
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">    :error &#34;\$SECRET: bad command&#34;
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div></details>
<h2 id="conclusion">Conclusion</h2>
<p>The good thing about this approach is that secrets storing and retrieving mechanism encapsulated and can be easily changed in the future without changing the scripts. Also, it is easy to use and understand.</p>
<p>Keep your secrets safe and happy scripting!</p>]]></content:encoded>
    </item>
    
  </channel>
</rss>
