تأمين الأسرار عند البناء في Docker Compose

تم إعداد ترجمة للمقال قبل بدء دورة Python Web Developer .




عند إنشاء صورة Docker ، قد تحتاج إلى أسرار ، مثل كلمة مرور لمستودع الحزمة الخاصة. لا تريد أن ينتهي هذا السر في الصورة ، لأنه بعد ذلك سيتمكن أي شخص يمكنه الوصول إلى الصورة من الوصول إلى مستودعك الخاص.
ملاحظة : إذا كنت تعتقد "لماذا لا تستخدم متغيرات البيئة فقط؟" والتي يتم استخدامها للأسرار في وقت التشغيل عند إنشاء صورة. تركز هذه المقالة على أسرار البناء التي يتم استخدامها عند إنشاء صورة باستخدام ملف Docker.
تحتفظ الإصدارات الأحدث من Docker بالأسرار باستخدام خدمة BuildKit التجريبية ، وفي Docker Compose 1.25 والإصدارات الأحدث ، يمكنك بالفعل إنشاء صور باستخدام BuildKit. لسوء الحظ ، اعتبارًا من مارس 2020 ، لا تزال القدرة على العمل بأمان مع أسرار Compose قيد التطوير .

اذا ما العمل الآن؟ ماذا نفعل الآن؟

في مقالة اليوم ، سأوضح كيف يمكنك استخدام نفس ملف Dockerfile لإنشاء صور أسرار بشكل آمن دون فقدان مزايا التطور السريع باستخدام Docker Compose.

خياران لاستخدام ملف إرساء الخاص بك


من السهل جدًا استخدام نفس ملف Dockerfile للإنتاج وللتطوير المحلي باستخدام Docker Compose. عادةً ما تستخدم ملف Dockerfile مع وظيفة الإنشاء من Compose:

version: "3.7"
services:
  yourapp:
    build:
      context: "."	

ثم يمكنك القيام بما يلي:

$ docker-compose up

باستخدام هذا الأمر ، يمكنك (إعادة) تجميع الصورة ثم تشغيلها.
للاستخدام في الإنتاج ، تقوم بجمع الصورة وإرسالها بالدفع :

$ docker build -t myimage .
$ docker push myimage

وبينما كل شيء يسير على ما يرام. ولكن ماذا لو كنت بحاجة إلى بناء سري؟

المحاولة الأولى (غير آمنة)


لنفترض أن لديك نصًا برمجيًا يحتاج إلى بنية سرية ، على سبيل المثال ، لتنزيل حزمة Python من مستودع DevPI خاص . من أجل البساطة ، سنستمد السر بكل بساطة بمساعدة use-secret.shلإثبات أننا نمتلكه.

#!/bin/bash
set -euo pipefail

echo "Secret is: $THEPASSWORD"

يمكنك ببساطة تمرير السر باستخدام وسيطات بناء Docker ، حيث يتم دعمها في كل مكان ، بما في ذلك Docker Compose.
ملاحظة : بعد تجاوز نطاق مناقشتنا ، أود أن أقول إن استخدام ملفات Docker في هذه المقالة ليس أفضل ممارسة ، ومع ذلك ، يمكن أن يتداخل التعقيد المفرط مع نقل المعنى الرئيسي للمقالة.
لذلك ، إذا كنت تريد تشغيل تطبيق Python الخاص بك عند الإنتاج باستخدام Docker ، فإليك طريقتان جيدتان للقيام بذلك:


FROM python:3.8-slim-buster
# Using ARG for build secrets is INSECURE!
ARG THEPASSWORD
COPY use_secret.sh .
RUN ./use_secret.sh

يمكننا أن نكتب docker-compose.yml، والتي ستنتقل سرا:

version: "3.7"
services:
  yourapp:
    build:
      context: "."
      args:
        THEPASSWORD: "s3kr!t"

للعمل المحلي ، يمكنك تشغيل أو إنشاء صورة باستخدام Compose:

$ docker-compose build | grep Secret
Secret is: s3kr!t

وكل شيء جيد.

ويمكننا أيضًا تجميع الصورة باستخدام Docker ، استعدادًا لنقلها إلى سجل الصور:

$ docker build -t myimage --build-arg THEPASSWORD=s3krit . | grep Secret
Secret is: s3krit

القيام بذلك غير آمن: لا تفعل ذلك أبدًا . إذا قررنا إلقاء نظرة على طبقات الصورة ، فسنرى السر يكمن فيها!

$ docker history myimage
IMAGE               CREATED              CREATED BY                                      SIZE
c224231ec30b        47 seconds ago       |1 THEPASSWORD=s3krit /bin/sh -c ./use_secre…   0B
6aef62acf0db        48 seconds ago       /bin/sh -c #(nop) COPY file:7aa28bbe6595e0d5…   62B
f88b19ca8e65        About a minute ago   /bin/sh -c #(nop)  ARG THEPASSWORD              0B
...

أي شخص يمكنه الوصول إلى هذه الصورة سيتعرف على كلمة مرورك. ما الذي يمكن فعله عندئذ؟

أسرار BuildKit (حل جزئي)


BuildKit هو حل جديد (ولا يزال تجريبيًا) لإنشاء صور Docker ، والتي تضيف ، من بين أمور أخرى ، دعمًا للاستخدام الآمن للأسرار أثناء التجميع . تتمتع Docker Compose بدعم BuildKit منذ الإصدار v1.25.

ولكن هناك مشكلة واحدة: لا يزال Docker Compose لا يدعم وظيفة أسرار BuildKit. يجري العمل الآن على هذا ، ولكن اعتبارًا من مارس 2020 ، لا توجد حلول جاهزة ، ناهيك عن إصدار مستقر.

لذلك ، سنقوم بدمج هذين النهجين:

  • ستواصل Docker Compose استخدام وسيطات الإنشاء لتمرير الأسرار ؛
  • للحصول على صورة إنتاج تم إنشاؤها باستخدام بناء عامل الميناء ، نستخدم BuildKit لتمرير الأسرار.

بهذه الطريقة يمكننا استخدام نفس ملف Dockerfile للعمل محليًا وعلى الإنتاج.
يعمل BuildKit مع الأسرار كما يلي: تم تحميل الملف مع الأسرار في دليل مؤقت أثناء تنفيذ الأمر RUN ، على سبيل المثال ، في /var/secrets/thepassword. نظرًا لأنه تم تحميله أثناء تنفيذ الأمر RUN ، فلن تتم إضافته إلى الصورة النهائية.

سنقوم بتعديل الملف use_secret.shللتحقق من وجود مثل هذا الملف المؤقت. إذا كان موجودًا ، فإنه يستخدم إعدادات متغير البيئة الخاصة به $THEPASSWORD. إذا لم يكن الملف موجودًا ، فسنعود إلى متغير البيئة. أي أنه $THEPASSWORDيمكن تثبيته باستخدام BuildKit أو بناء الوسائط:

#!/bin/bash
set -euo pipefail
if [ -f /run/secrets/thepassword ]; then
   export THEPASSWORD=$(cat /run/secrets/thepassword)
fi

echo "Secret is: $THEPASSWORD"

ثم سنقوم بتعديل ملف Dockerfile لإضافة BuildKit وتركيب السر:

# syntax = docker/dockerfile:1.0-experimental
FROM python:3.8-slim-buster
# Only use the build arg for local development:
ARG THEPASSWORD
COPY use_secret.sh .
# Mount the secret to /run/secrets:
RUN --mount=type=secret,id=thepassword ./use_secret.sh

docker-compose.ymlنحن لا نغير الملف :

version: "3.7"
services:
  yourapp:
    build:
      context: "."
      args:
        THEPASSWORD: "s3kr!t"

الآن تحتاج إلى تحديد متغيرين للبيئة ، أحدهما سيخبر Docker أنك بحاجة إلى استخدام BuildKit ، والثاني الذي يحتاج Compose إلى استخدام إصدار CLI من Docker ، وبالتالي BuildKit. سنكتب أيضًا سر الملف:

$ export DOCKER_BUILDKIT=1
$ export COMPOSE_DOCKER_CLI_BUILD=1
$ echo 's3krit' > /tmp/mypassword

باستخدام Compose ، نستخدم وسائط البناء:

$ docker-compose build --progress=plain \
    --no-cache 2>&1 | grep Secret
#12 0.347 Secret is: s3kr!t

يرجى ملاحظة أنه من --no-cacheالضروري أن نفهم أن الصورة ستعاد بناءها حقًا إذا قمت بنفسك بتشغيل كل ما سبق. في الواقع ، يمكن حذف هذه المعلمة. 2>&1إعادة التوجيه stderrإلى stdoutالعملية الصحيحة grep.

عندما نكون مستعدين للبناء على الإنتاج ، نستخدم بناء عامل الميناء مع وظائف الأسرار من BuildKit:

$ docker build --no-cache -t myimage \
    --secret id=thepassword,src=/tmp/mypassword \
    --progress=plain . 2>&1 | grep Secret
#12 0.359 Secret is: s3krit

هل هو آمن؟


دعونا نتأكد من أن السر غير مرئي:

$ docker history myimage
IMAGE               CREATED             CREATED BY                                      SIZE
a77f3c32b723        25 seconds ago      RUN |1 THEPASSWORD= /bin/sh -c ./use_secret.…   0B
<missing>           25 seconds ago      COPY use_secret.sh . # buildkit                 160B
...

مرحى! قمنا بتمرير السر إلى ملف Dockerfile نفسه باستخدام Compose docker build، وفي الحالة الأخيرة لم نكشف عن السر من التجميع.



تعلم المزيد عن الدورة.



All Articles