<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>emre şahin's digital garden 🍃 - security</title>
    <link>https://emresahin.net/tags/security/</link>
    <description>Posts in the security tag</description>
    <language>en</language>
    <managingEditor>contact@emresahin.net (Emre Şahin)</managingEditor>
    <lastBuildDate>Tue, 15 Sep 2026 19:46:32 +0000</lastBuildDate>
    <atom:link href="https://emresahin.net/tags/security/rss.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>Using SSH Private Keys in Dockerfile aimed for Google Cloud Run</title>
      <published>2020-05-12T18:46:51+00:00</published>
      <updated>2020-05-12T18:46:51+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Tue, 12 May 2020 18:46:51 +0000</pubDate>
      <link>https://emresahin.net/using-ssh-private-keys-in-dockerfile-aimed-for-google-cloud-run--24390/</link>
      <guid isPermaLink="true">https://emresahin.net/using-ssh-private-keys-in-dockerfile-aimed-for-google-cloud-run--24390/</guid>
      <description>I had a one-user software application that I had wanted to deploy to Google Cloud Run for some time. It was on Python 3.5, and when I updated the system it lives on, the virtual environment stopped working. It also depended on lxml-3.7 , and that particular version didn’t compile on my new stable...</description>
      <category>DevOps</category>
      <category>Docker</category>
      <category>Cloud Computing</category>
      <category>Docker</category>
      <category>Google Cloud Run</category>
      <category>SSH</category>
      <category>Security</category>
      <category>Python</category>
      <category>Bitbucket</category>
      <content:encoded><![CDATA[<p>I had a one-user software application that I had wanted to deploy to Google Cloud Run for some time. It was on
Python 3.5, and when I updated the system it lives on, the virtual environment stopped working. It
also depended on <code>lxml-3.7</code>, and that particular version didn’t compile on my new stable Debian
installation.</p>
<p>This motivated me to learn Docker and gcloud rather quickly.</p>
<p>I was able to create a new Docker container in a short time. However, as I don’t want to share my Git
SSH key publicly, I needed a way to put an SSH private key (<code>~/.ssh/id_rsa</code>) into this new container
securely, without leaving any trace.</p>
<p>I tried a few things, but in the end, I decided to do something like:</p>
<pre><code class="language-Dockerfile">FROM python:3.5-stretch as intermediate

# add credentials on build
RUN mkdir /root/.ssh/
# To use docker --build-arg, you can uncomment the following two lines and comment out the COPY line below.
# ARG SSH_PRIVATE_KEY
# RUN echo "${SSH_PRIVATE_KEY}" &gt; /root/.ssh/id_rsa
COPY application_sshkey /root/.ssh/id_rsa
RUN chmod 0600 /root/.ssh/id_rsa

# make sure your domain is accepted
RUN touch /root/.ssh/known_hosts
RUN ssh-keyscan bitbucket.org &gt;&gt; /root/.ssh/known_hosts

RUN git clone git@bitbucket.org:username/application /root/application

FROM python:3.5-stretch
COPY --from=intermediate /root/application /root/application

RUN pip3 install -r /root/application/requirements.txt

EXPOSE 9090/tcp

WORKDIR /root/application/

CMD python3 manage.py runserver 0.0.0.0:9090
</code></pre>
<p>Here, <code>application_sshkey</code> is a file I created using <code>ssh-keygen</code> and granted read-only access to on
Bitbucket.</p>
<p>As you can see, the Dockerfile has two <code>FROM</code> statements. It creates a container to clone the
application repository. Then it starts again with a new container and copies the repository to this new
container. This way, it is not possible to peek into the private key using the <code>docker history</code> command.</p>
<p>By the way, I included two methods in the Dockerfile because <code>gcloud builds</code> does not accept a
<code>--build-arg</code> parameter similar to <code>docker build</code>. I’m sure there are other workarounds for passing
secrets to <code>gcloud</code> builds, but instead of digging for them, I found a solution that works for both
Docker and Google Cloud Run.</p>]]></content:encoded>
    </item>
    <item>
      <title>Query Logging in Databases when using Parameters</title>
      <published>2018-11-06T19:41:10+00:00</published>
      <updated>2018-11-06T19:41:10+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Tue, 06 Nov 2018 19:41:10 +0000</pubDate>
      <link>https://emresahin.net/query-logging-in-python-sqlite-14359-20562/</link>
      <guid isPermaLink="true">https://emresahin.net/query-logging-in-python-sqlite-14359-20562/</guid>
      <description>We avoid constructing database queries using string formatting to prevent security issues. SQL injection attacks stem from a lack of proper escaping and building queries directly from untrusted input strings. Instead, we use parameter passing to the database engine. For example: SELECT * FROM peo...</description>
      <category>Databases</category>
      <category>Python</category>
      <category>sqlite</category>
      <category>query-logging</category>
      <category>debugging</category>
      <category>sql-injection</category>
      <category>security</category>
      <content:encoded><![CDATA[<p>We avoid constructing database queries using string formatting to prevent security issues. SQL injection attacks stem from a lack of proper escaping and building queries directly from untrusted input strings.</p>
<p>Instead, we use parameter passing to the database engine. For example:</p>
<pre><code class="language-sql">SELECT * FROM people WHERE name = ?
</code></pre>
<p>We send this query and the parameters separately to the database. Most modern database systems support this approach.</p>
<p>In SQLite 3 with Python, we use it like this:</p>
<pre><code class="language-python">query = "SELECT * FROM people WHERE name = ?"
params = (name,)
db_result = cursor.execute(query, params)
</code></pre>
<p>However, when debugging, we may need to see the actual queries sent to the database—for instance, when data types are important or when we suspect a column is receiving a string instead of an integer.</p>
<p>In these cases, rather than manually reconstructing the query, we can use the <code>set_trace_callback</code> feature available in Python 3.3 and later:</p>
<pre><code class="language-python">connection.set_trace_callback(print)
</code></pre>
<p>The argument can be any function (such as <code>print</code> or a logger function) or <code>None</code> to disable tracing. This makes it easy to integrate with Python’s standard <code>logging</code> module.</p>]]></content:encoded>
    </item>
  </channel>
</rss>
