<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ugo Palatucci</title>
    <description>The latest articles on DEV Community by Ugo Palatucci (@upalatucci).</description>
    <link>https://dev.to/upalatucci</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1073951%2Fa9b1ab85-739f-4d1b-8ed8-d7593cc6ee76.jpeg</url>
      <title>DEV Community: Ugo Palatucci</title>
      <link>https://dev.to/upalatucci</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/upalatucci"/>
    <language>en</language>
    <item>
      <title>Secure your Dockerfile for SSG with NextJS and Prisma</title>
      <dc:creator>Ugo Palatucci</dc:creator>
      <pubDate>Tue, 02 May 2023 13:17:53 +0000</pubDate>
      <link>https://dev.to/upalatucci/secure-your-dockerfile-for-ssg-with-nextjs-and-prisma-1n8</link>
      <guid>https://dev.to/upalatucci/secure-your-dockerfile-for-ssg-with-nextjs-and-prisma-1n8</guid>
      <description>&lt;p&gt;Hi, everyone!!&lt;br&gt;
This is my first blog post and I'm so happy!!&lt;/p&gt;
&lt;h2&gt;
  
  
  The Project
&lt;/h2&gt;

&lt;p&gt;In this post, I would like to talk about an issue I encountered while writing a dockerfile for a Next.js/Prisma application and the solution that I found.&lt;/p&gt;

&lt;p&gt;I'm developing a project as a volunteer for a non-profit organization (Istituto Buddista Italiano Soka Gakkai) and we'll hit production soon.&lt;br&gt;
The repository is accessible at this &lt;a href="https://github.com/upalatucci/biblioteca-nextjs"&gt;link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project is a website for consulting antique Buddhist scriptures of the Nichiren Daishonin school and conducting advanced research on them.&lt;/p&gt;

&lt;p&gt;Because the organization already has a well-structured infrastructure with databases, ElasticSearch nodes, and other WordPress websites, we've decided to use docker instead of going for the classic Vercel deployment and have everything pretty much in the same location or close to each other. If something changes and we have to migrate our production system, we'll be safe doing so with containers.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Issue
&lt;/h2&gt;

&lt;p&gt;Thanks to the &lt;a href="https://create.t3.gg/en/deployment/docker"&gt;create-t3-app documentation&lt;/a&gt; I was able to set up the Dockerfile pretty quickly, but I've encountered one issue with this setup (the documentation might change after I post this).&lt;/p&gt;

&lt;p&gt;In our case, the Next.js application is fetching data from the database at build time (Server Side Generation) to generate pages and cache them. To do that, we need the database URL available during the docker build.&lt;/p&gt;

&lt;p&gt;This database URL contains password credentials and cannot be passed to the docker build as an &lt;code&gt;ARG&lt;/code&gt;. &lt;code&gt;ARG&lt;/code&gt;s can be easily inspected by everyone if the docker image is publicly available,  and an attacker could find the database URL, username, and password using just &lt;code&gt;docker history&lt;/code&gt; (See documentation about this issue &lt;a href="https://docs.docker.com/engine/reference/builder/#arg"&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;Sensitive information has to be handled through &lt;a href="https://docs.docker.com/engine/reference/builder/#run---mounttypesecret"&gt;docker secrets&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, the best solution that i could find is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;secret,id&lt;span class="o"&gt;=&lt;/span&gt;ENV_WITH_SECRETS,required &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="nb"&gt;source&lt;/span&gt; /run/secrets/ENV_WITH_SECRETS &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$DATABASE_URL&lt;/span&gt; yarn build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this command, docker mounts the environment file with secrets just for this line. The variable is loaded from that file and can be accessed in the code using &lt;code&gt;process.env&lt;/code&gt; by Next.js and Prisma. Prisma by default use the &lt;code&gt;.env&lt;/code&gt; file to load the database url, but in our case we have to modify this behavior with the follow line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;datasources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With my current version of Prisma, the &lt;code&gt;DATABASE_URL&lt;/code&gt; variable even if it's in the secret file, gets removed just at the start of &lt;code&gt;yarn build&lt;/code&gt; from the &lt;code&gt;process.env&lt;/code&gt;, so a workaround is to run &lt;code&gt;DATABASE_URL=$DATABASE_URL yarn build&lt;/code&gt; to enforce the variable in prisma. &lt;/p&gt;

&lt;p&gt;The build command looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--secret&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ENV_WITH_SECRETS,src&lt;span class="o"&gt;=&lt;/span&gt;./.env &lt;span class="nt"&gt;-t&lt;/span&gt; nextjs-prisma-application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The id (&lt;code&gt;ENV_WITH_SECRETS&lt;/code&gt; in this example) is absolutely arbitrary.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;secret&lt;/code&gt; file contain the database url with credentials that we need at build time.&lt;/p&gt;

&lt;p&gt;It is even easier to use secrets with Docker Compose (&lt;a href="https://docs.docker.com/compose/compose-file/compose-file-v3/#secrets"&gt;documentation&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;The syntax depends on your docker compose version. This is the syntax that i used for the &lt;code&gt;2.18.1&lt;/code&gt; version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;platform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;linux/amd64"&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
      &lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ENV_WITH_SECRETS&lt;/span&gt;
    &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/app&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nextjs-app&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
&lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ENV_WITH_SECRETS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I bet you don't build every docker image manually yourself, though, do you?&lt;/p&gt;

&lt;p&gt;Here is how &lt;code&gt;docker/build-push-action&lt;/code&gt; handles secrets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and push&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker_build&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/build-push-action@v4&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tag&lt;/span&gt;
    &lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;"ENV_WITH_SECRETS=${{ secrets.ENV_WITH_SECRETS }}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The use of &lt;code&gt;"&lt;/code&gt; is essential here to assign a multi-line secret file in this way (&lt;a href="https://docs.docker.com/build/ci/github-actions/secrets/"&gt;documentation&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;In this case, &lt;code&gt;ENV_WITH_SECRETS&lt;/code&gt; is the docker secret id used previously.&lt;/p&gt;

&lt;p&gt;At this point, on Github repo settings you can add a secret with the same &lt;code&gt;ENV_WITH_SECRETS&lt;/code&gt; name and copy-paste the &lt;code&gt;.env&lt;/code&gt; file containing multiple secrets. &lt;/p&gt;

&lt;p&gt;For example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ELASTIC_SEARCH_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;*****&lt;/span&gt;
&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;mysql://username:password@host:post/db&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: on github you have to escape double quotes character (&lt;code&gt;"&lt;/code&gt;) with another double quotes character. &lt;/p&gt;

&lt;p&gt;To be able to access the database at runtime, (for revalidating the pages on demand or automatically), we can add an environment variable called &lt;code&gt;DATABASE_URL&lt;/code&gt; just before the &lt;code&gt;CMD&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DATABASE_URL ''&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "server.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Environment variables are only available at runtime and not in the build step, which makes it safe to use them for sensitive information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It was so fun to dig into this issue, learn more about docker secrets, and find a solution.&lt;br&gt;
I also posted a pull request against &lt;a href="https://github.com/t3-oss/create-t3-app/pull/1368"&gt;create-t3-app repo&lt;/a&gt; and they helped me find a suitable solution for many more environments.&lt;br&gt;
It was a great opportunity to write a post!!&lt;br&gt;
Thanks! &lt;br&gt;
I'm looking forward to your suggestions and comments!!&lt;/p&gt;

</description>
      <category>prisma</category>
      <category>nextjs</category>
      <category>docker</category>
      <category>security</category>
    </item>
  </channel>
</rss>
