امنیت در Docker
۱۴ اسفند ۱۳۹۹
امروزه اکثر شرکتها حداقل در یک پروژه از Docker استفاده کردهاند زیرا این پلتفرم توانسته با ایزوله کردن محیط توسعه و اجرای هر پروژه توجه زیادی را به خود جلب کند اما بااینحال مبحث امنیت در Docker موضوعی جدی است.
امنیت Docker Host
Docker containerها بر روی یک سرور یا سیستم میزبان راهاندازی میشوند بنابراین ضروری است که Docker Host ما علاوهبر container ایجاد شده، ایمن باشد. بههمین منظور ابزارهای بسیار زیادی برای بررسی ضعفهای امنیتی در سیستمعامل Linux توسعه داده شده که برخی از آنها عبارتند از:
- Lynis: دستور
apt-get install lynis && sudo lynis audit system
را اجرا کنید و منتظر بمانید تا این ابزار یک گزارش برای ارتقا امنیت سیستم در اختیار شما قرار دهد. - SELinux: این ابزار قابلیت MAC (Mandatory Access Control) را بهعنوان یک kernel-module فراهم میکند درصورتی که Linux بهطور پیشفرض از DAC (Discretionary Access Control) استفاده میکند. نقطه نظر SELinux و AppArmor در ارائهی Access control policy است و هر دوی آنها استفاده از MAC را اجباری میکنند.
- AppArmor: این ابزار MAC را بهعنوان یک سرویس، ارائه میدهد بنابراین فرایندهای نامحدود و محدود از هم متمایز شده و همچنین فرایندهای نامشخص نادیده گرفته میشوند. فرایندهای محدود شده فقط میتوانند طبق مجوزهای AppArmor کار کنند.
- Docker Daemon: فرایند Dockerd را بهعنوان یک non-privileged user اجرا کنید.
همچنین بایستی مرتباً برنامههای خود را در برابر آسیبپذیریهای public شده بررسی کنید. علاوهبراین میتوانید از سیستمعاملی استفاده کنید که برای Docker containerها بهینهسازی شده باشد. برای مثال میتوانیم به Googles Container-Optimized OS اشاره کنیم.
امنیت Docker image
پس از Docker Host بایستی از ایمن بودن Docker image استفاده شده در Dockerfile
اطمینان حاصل کنید زیرا بسیاری از Docker imageهایی که ما از آنها استفاده میکنیم توسط افراد دیگری توسعه داده شده است.
بنابراین بایستی Docker imageها را از نظر وجود آسیبپذیری بررسی کنیم. حتی این احتمال وجود دارد که Docker imageهای رسمی نیز دارای آسیبپذیری باشند اما مشکل اکثر آنها با اجرای RUN apt-get update && apt-get upgrade
برطرف میشود.
توجه داشته باشید که نسخههای Alpine فقط ضعفهای امنیتی که قبلا برطرف شده است را منتشر میکنند بنابراین ممکن است اسکن آنها در مبحث امنیت موثر باشد.
Image Hardening
به فرایند کاهش سطح حمله یا افزایش دشواری برای یافتن و استفاده از آسیبپذیری موجود، Hardening میگویند.
فقط فایلهای ضروری را کپی کنید
شما با استفاده از فایل .dockerignore
میتوانید اطمینان حاصل کنید که برخی فایلها کپی نمیشوند.
محدود کردن دسترسی با استفاده از non-privileged user
بهطور پیشفرض هر دستوری که در Docker container اجرا شود با شناسه کاربر صفر یعنی کاربر root اجرا خواهد شد. حال برای افزایش امنیت توصیه میشود که دسترسیها را با روشهای مختلفی محدود کنید.
در Dockerfile
میتوانید بهصورت زیر عمل کنید:
RUN groupadd -r noroot && useradd -r -g noroot noroot
USER noroot
یا میتوانید Docker container خود را بهصورت زیر اجرا کنید:
docker run -u 1000 -it python:3.9.1-buster bash
I have no name!@a70ba4f24042:/$ echo $UID
1000
Multi-stage Build
اگر هر مهاجمی به Docker container شما دسترسی پیدا کند مطمئناً میخواهید تا آنجا که ممکن است ابزارهای کمتری در اختیار داشته باشد. بههمین منظور میتوانید از روش multi-stage build استفاده کنید. برای درک بهتر این موضوع به مثال زیر دقت کنید:
FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]
Container Hardening
Read-Only کردن فایلهای سیستمی
اگر از دستور docker run
استفاده میکنید میتوانید --read-only
را به دستور خود اضافه کنید. این سوئیچ باعث میشود تا فایلهای سیستمی read-only باشند بنابراین اگر یک مهاجم وارد سیستم شد نمیتواند چیزی را روی دیسک ذخیره کند یا فایلهای اجرایی را تغییر دهد. البته بایستی توجه داشته باشید که مهاجمین میتوانند memory را تغییر دهند.
همچنین بایستی به مجوز انجام برخی کارهای استاندارد مانند ایجاد فایلهای temp دقت داشته باشید:
sudo docker run -it --read-only python:3.9.1-buster
Python 3.9.1 (default, Jan 12 2021, 16:45:25)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tempfile
>>> a = tempfile.mkdtemp()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.9/tempfile.py", line 348, in mkdtemp
prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
File "/usr/local/lib/python3.9/tempfile.py", line 118, in _sanitize_params
dir = gettempdir()
File "/usr/local/lib/python3.9/tempfile.py", line 287, in gettempdir
tempdir = _get_default_tempdir()
File "/usr/local/lib/python3.9/tempfile.py", line 219, in _get_default_tempdir
raise FileNotFoundError(_errno.ENOENT,
FileNotFoundError: [Errno 2] No usable temporary directory found in ['/tmp', '/var/tmp', '/usr/tmp', '/']
برای برطرف کردن این اشکال میتوانید مسیر /tmp
را بهعنوان یک volume به container خود mount کنید:
$ sudo docker run -it --mount source=myvol2,target=/tmp --read-only python:3.9.1-buster
Python 3.9.1 (default, Jan 12 2021, 16:45:25)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tempfile; a = tempfile.mkdtemp()
$ sudo docker run --rm -i -v=myvol2:/tmp/v busybox find /tmp/v
/tmp/v
/tmp/v/tmpbhw8djco
حتی میتوانید از مسیر temp fileهای Docker host استفاده کنید:
sudo docker run -it --tmpfs /tmp --read-only python:3.9.1-buster
محدود کردن قابلیتها
شما میتوانید قابلیتهای Linux kernel را محدود کنید:
docker run --cap-drop all -it python:3.9.1-buster bash
root@3c568219116e:/# groupadd -r noroot
groupadd: failure while writing changes to /etc/gshadow
همچنین میتوانید اگر برنامهی شما به مجوز خاصی نیاز داشته باشد، بهصورت دستی مجوز را اعطا کنید:
docker run --cap-drop all --cap-add CHOWN -it python:3.9.1-buster bash
root@3c568219116e:/# groupadd -r noroot
groupadd: failure while writing changes to /etc/gshadow
no-new-privileges
ممکن است همیشه بخواهید --security-opt=no-new-privileges
را تنظیم کنید. این سوئیچ باعث میشود تا فرایندهای موجود در container به privilegeهای جدید دسترسی پیدا نکنند.
اسکن آسیبپذیریها
برای اسکن آسیبپذیریهای containerها میتوانید از Clair استفاده کنید.
ارتباط بین Containerها
یکی از راه حلهای کلیدی defense in depth است یعنی مراحل دستیابی به آسیبپذیری را سختتر کنیم. اگر قابلیتی برای اجرای برنامه کاملا ضروری نباشد بنابراین Container ما نباید به آن قابلیت دسترسی داشته باشد. علاوهبراین محدود کردن ارتباط میان Containerها بخشی از این راه حل است.
اکثر شرکتها میکروسرویسهای زیادی را در Containerها اجرا میکنند. برخی از Containerها نیاز به برقراری ارتباط با یکدیگر دارند اما برخی دیگر به این ارتباط نیازی ندارند.
منبع: https://levelup.gitconnected.com/docker-security-5f4df118948c