مرحبا هبر!
في الواقع الحديث ، نظرًا للدور المتزايد للحاويات في عمليات التطوير ، فإن مسألة ضمان أمن مختلف المراحل والكيانات المرتبطة بالحاويات ليست في المقام الأخير. يستغرق إجراء الفحوصات اليدوية وقتًا طويلاً ، لذلك سيكون من الجيد اتخاذ الخطوات الأولية على الأقل لأتمتة هذه العملية.
في هذه المقالة ، سوف أشارك نصوصًا جاهزة لتنفيذ العديد من أدوات Docker الأمنية المساعدة والتعليمات حول كيفية نشر منصة تجريبية صغيرة لاختبار هذه العملية. يمكنك استخدام الموارد لتجربة كيفية تنظيم عملية اختبار الأمان للصور وتعليمات Dockerfile. من الواضح أن البنية التحتية للتطوير والتنفيذ تختلف من شخص لآخر ، لذا سأقدم أدناه عدة خيارات ممكنة.
أدوات فحص الأمان
هناك العديد من التطبيقات والبرامج النصية المساعدة المختلفة التي تختبر جوانب مختلفة من بنية Docker الأساسية. بعضها سبق وصفه في المقال السابق ( https://habr.com/ru/company/swordfish_security/blog/518758/#docker-security ) ، وفي هذه المادة أود التركيز على ثلاثة منها تغطي الرئيسي جزء من متطلبات الأمان لصور Docker التي تم إنشاؤها أثناء التطوير. بالإضافة إلى ذلك ، سأعرض أيضًا مثالًا على كيفية توصيل هذه المرافق الثلاثة في خط أنابيب واحد لإجراء فحوصات أمنية.
Hadolint
https://github.com/hadolint/hadolint
أداة مساعدة بسيطة إلى حد ما لوحدة التحكم تساعد ، كتقريب أولي ، على تقييم صحة وأمان تعليمات Dockerfile (على سبيل المثال ، استخدام سجلات الصور المصرح بها فقط أو استخدام sudo).
Dockle
https://github.com/goodwithtech/dockle
أداة مساعدة لوحدة التحكم تعمل مع صورة (أو بأرشيف tar محفوظ للصورة) يتحقق من صحة وأمن صورة معينة على هذا النحو ، وتحليل طبقاتها وتكوينها - التي أنشأها المستخدمون ، والإرشادات تستخدم وحدات التخزين التي تم تركيبها ، ووجود كلمة مرور فارغة ، وما إلى ذلك. في حين أن عدد عمليات التحقق ليس كبيرًا جدًا ويستند إلى العديد من عمليات التحقق والتوصيات الخاصة بـ CIS (مركز أمان الإنترنت) Benchmark for Docker.
تافه
https://github.com/aquasecurity/trivy
تهدف هذه الأداة إلى العثور على نوعين من نقاط الضعف - مشاكل بناء نظام التشغيل (مدعومة من قبل Alpine و RedHat (EL) و CentOS و Debian GNU و Ubuntu) ومشكلات التبعية (Gemfile.lock و Pipfile. lock ، composer.lock ، package-lock.json ، yarn.lock ، Cargo.lock). يمكن لـ Trivy مسح كل من الصورة الموجودة في المستودع والصورة المحلية ، بالإضافة إلى المسح الضوئي بناءً على ملف .tar الذي تم نقله مع صورة Docker.
خيارات التنفيذ للمرافق
لتجربة التطبيقات الموصوفة في ظروف منعزلة ، سأقدم إرشادات لتثبيت جميع الأدوات المساعدة في عملية مبسطة.
الفكرة الرئيسية هي توضيح كيف يمكنك تنفيذ التحقق التلقائي من صحة المحتوى لصور Dockerfile و Docker التي تم إنشاؤها أثناء التطوير.
يتكون الشيك نفسه من الخطوات التالية:
- التحقق من صحة وسلامة تعليمات Dockerfile - باستخدام Hadolint اللنت
- التحقق من صحة وأمان الهدف والصور الوسيطة - باستخدام الأداة المساعدة Dockle
- التحقق من الثغرات الأمنية المعروفة (CVE) في الصورة الأساسية وعدد من التبعيات - باستخدام الأداة المساعدة Trivy
علاوة على ذلك في المقالة ، سأقدم ثلاثة خيارات لتنفيذ هذه الخطوات:
أولاً ، من خلال تكوين خط أنابيب CI / CD باستخدام مثال GitLab (مع وصف لعملية رفع مثيل الاختبار).
والثاني هو استخدام برنامج شل النصي.
والثالث هو إنشاء صورة Docker لمسح صور Docker ضوئيًا.
يمكنك اختيار الخيار الذي يناسبك ، ونقله إلى بنيتك التحتية وتكييفه مع احتياجاتك.
جميع الملفات الضرورية والإرشادات الإضافية موجودة أيضًا في المستودع: https://github.com/Swordfish-Security/docker_cicd
الاندماج في GitLab CI / CD
في الخيار الأول ، سننظر في كيفية تنفيذ فحوصات الأمان باستخدام مثال نظام مستودع GitLab. سننتقل هنا إلى الخطوات ونحلل كيفية إعداد بيئة اختبار باستخدام GitLab من البداية ، وإنشاء عملية مسح ضوئي وتشغيل الأدوات المساعدة للتحقق من Dockerfile التجريبي وصورة عشوائية - تطبيق JuiceShop.
تثبيت GitLab
1. تثبيت Docker:
sudo apt-get update && sudo apt-get install docker.io
2. أضف المستخدم الحالي إلى مجموعة عامل الإرساء بحيث يمكنك العمل مع عامل الإرساء وليس عبر sudo:
sudo addgroup <username> docker
3. ابحث عن عنوان IP الخاص بك:
ip addr
4. قم بتثبيت وتشغيل GitLab في حاوية ، واستبدال عنوان IP في اسم المضيف بعنوانك:
docker run --detach \
--hostname 192.168.1.112 \
--publish 443:443 --publish 80:80 \
--name gitlab \
--restart always \
--volume /srv/gitlab/config:/etc/gitlab \
--volume /srv/gitlab/logs:/var/log/gitlab \
--volume /srv/gitlab/data:/var/opt/gitlab \
gitlab/gitlab-ce:latest
نحن ننتظر GitLab لإكمال جميع إجراءات التثبيت الضرورية (يمكنك متابعة العملية من خلال إخراج ملف السجل: docker logs -f gitlab).
5. افتح عنوان IP المحلي في المتصفح
وشاهد صفحة بها اقتراح لتغيير كلمة المرور للمستخدم الجذر: قم بتعيين كلمة مرور جديدة وانتقل إلى GitLab.
6. أنشئ مشروعًا جديدًا ، على سبيل المثال cicd-test وقم بتهيئته باستخدام ملف البدء README.md :
7. الآن نحن بحاجة إلى تثبيت GitLab Runner: وكيل سيبدأ جميع العمليات الضرورية عند الطلب.
قم بتنزيل أحدث إصدار (في هذه الحالة ، لنظام التشغيل Linux 64 بت):
sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
8. اجعله قابلاً للتنفيذ:
sudo chmod +x /usr/local/bin/gitlab-runner
9. أضف مستخدم نظام التشغيل للمشغل وابدأ الخدمة:
sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
sudo gitlab-runner start
يجب أن يبدو مثل هذا:
local@osboxes:~$ sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
Runtime platform arch=amd64 os=linux pid=8438 revision=0e5417a3 version=12.0.1
local@osboxes:~$ sudo gitlab-runner start
Runtime platform arch=amd64 os=linux pid=8518 revision=0e5417a3 version=12.0.1
10. نقوم الآن بتسجيل Runner بحيث يمكنه التفاعل مع مثيل GitLab الخاص بنا.
للقيام بذلك ، افتح صفحة Settings-CI / CD (http: // OUR_ IP_ADDRESS / root / cicd-test / - / settings / ci_cd) وفي علامة التبويب Runners ، ابحث عن عنوان URL والرمز المميز للتسجيل:
11. قم بتسجيل Runner عن طريق استبدال URL ورمز التسجيل:
sudo gitlab-runner register \
--non-interactive \
--url "http://<URL>/" \
--registration-token "<Registration Token>" \
--executor "docker" \
--docker-privileged \
--docker-image alpine:latest \
--description "docker-runner" \
--tag-list "docker,privileged" \
--run-untagged="true" \
--locked="false" \
--access-level="not_protected"
نتيجة لذلك ، نحصل على GitLab جاهز للعمل ، والذي نحتاج فيه إلى إضافة تعليمات لبدء تشغيل أدواتنا المساعدة. في هذه الحالة التجريبية ، ليس لدينا خطوات لبناء التطبيق وحاوياته ، ولكن في بيئة حقيقية سوف يسبقون خطوات المسح وينشئون الصور وملف Dockerfile للتحليل.
تكوين خط الأنابيب
1. أضف إلى المستودع الملفات mydockerfile.df (هذا هو ملف Docker للاختبار الذي سنقوم بفحصه) وملف تكوين عملية GitLab CI / CD .gitlab-cicd.yml ، الذي يسرد تعليمات الماسحات الضوئية (لاحظ النقطة في اسم الملف ).
يحتوي ملف تكوين YAML على إرشادات لتشغيل ثلاثة أدوات مساعدة (Hadolint و Dockle و Trivy) من شأنها تحليل ملف Dockerfile المحدد والصورة المحددة في متغير DOCKERFILE. يمكن أخذ جميع الملفات الضرورية من المستودع: https://github.com/Swordfish-Security/docker_cicd/
مقتطفات من mydockerfile.df (هذا ملف تجريدي يحتوي على مجموعة من الإرشادات العشوائية فقط لتوضيح كيفية عمل الأداة المساعدة). ارتباط مباشر بالملف: mydockerfile.df
محتوى mydockerfile.df
FROM amd64/node:10.16.0-alpine@sha256:f59303fb3248e5d992586c76cc83e1d3700f641cbcd7c0067bc7ad5bb2e5b489 AS tsbuild
COPY package.json .
COPY yarn.lock .
RUN yarn install
COPY lib lib
COPY tsconfig.json tsconfig.json
COPY tsconfig.app.json tsconfig.app.json
RUN yarn build
FROM amd64/ubuntu:18.04@sha256:eb70667a801686f914408558660da753cde27192cd036148e58258819b927395
LABEL maintainer="Rhys Arkins <rhys@arkins.net>"
LABEL name="renovate"
...
COPY php.ini /usr/local/etc/php/php.ini
RUN cp -a /tmp/piik/* /var/www/html/
RUN rm -rf /tmp/piwik
RUN chown -R www-data /var/www/html
ADD piwik-cli-setup /piwik-cli-setup
ADD reset.php /var/www/html/
## ENTRYPOINT ##
ADD entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
USER rootيبدو تكوين YAML على هذا النحو (يمكن أخذ الملف نفسه من الرابط المباشر هنا: .gitlab-ci.yml ):
محتوى .Gitlab-ci.yml
variables:
DOCKER_HOST: "tcp://docker:2375/"
DOCKERFILE: "mydockerfile.df" # name of the Dockerfile to analyse
DOCKERIMAGE: "bkimminich/juice-shop" # name of the Docker image to analyse
# DOCKERIMAGE: "knqyf263/cve-2018-11235" # test Docker image with several CRITICAL CVE
SHOWSTOPPER_PRIORITY: "CRITICAL" # what level of criticality will fail Trivy job
TRIVYCACHE: "$CI_PROJECT_DIR/.cache" # where to cache Trivy database of vulnerabilities for faster reuse
ARTIFACT_FOLDER: "$CI_PROJECT_DIR"
services:
- docker:dind # to be able to build docker images inside the Runner
stages:
- scan
- report
- publish
HadoLint:
# Basic lint analysis of Dockerfile instructions
stage: scan
image: docker:git
after_script:
- cat $ARTIFACT_FOLDER/hadolint_results.json
script:
- export VERSION=$(wget -q -O - https://api.github.com/repos/hadolint/hadolint/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
- wget https://github.com/hadolint/hadolint/releases/download/v${VERSION}/hadolint-Linux-x86_64 && chmod +x hadolint-Linux-x86_64
# NB: hadolint will always exit with 0 exit code
- ./hadolint-Linux-x86_64 -f json $DOCKERFILE > $ARTIFACT_FOLDER/hadolint_results.json || exit 0
artifacts:
when: always # return artifacts even after job failure
paths:
- $ARTIFACT_FOLDER/hadolint_results.json
Dockle:
# Analysing best practices about docker image (users permissions, instructions followed when image was built, etc.)
stage: scan
image: docker:git
after_script:
- cat $ARTIFACT_FOLDER/dockle_results.json
script:
- export VERSION=$(wget -q -O - https://api.github.com/repos/goodwithtech/dockle/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
- wget https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.tar.gz && tar zxf dockle_${VERSION}_Linux-64bit.tar.gz
- ./dockle --exit-code 1 -f json --output $ARTIFACT_FOLDER/dockle_results.json $DOCKERIMAGE
artifacts:
when: always # return artifacts even after job failure
paths:
- $ARTIFACT_FOLDER/dockle_results.json
Trivy:
# Analysing docker image and package dependencies against several CVE bases
stage: scan
image: docker:git
script:
# getting the latest Trivy
- apk add rpm
- export VERSION=$(wget -q -O - https://api.github.com/repos/knqyf263/trivy/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
- wget https://github.com/knqyf263/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz && tar zxf trivy_${VERSION}_Linux-64bit.tar.gz
# displaying all vulnerabilities w/o failing the build
- ./trivy -d --cache-dir $TRIVYCACHE -f json -o $ARTIFACT_FOLDER/trivy_results.json --exit-code 0 $DOCKERIMAGE
# write vulnerabilities info to stdout in human readable format (reading pure json is not fun, eh?). You can remove this if you don't need this.
- ./trivy -d --cache-dir $TRIVYCACHE --exit-code 0 $DOCKERIMAGE
# failing the build if the SHOWSTOPPER priority is found
- ./trivy -d --cache-dir $TRIVYCACHE --exit-code 1 --severity $SHOWSTOPPER_PRIORITY --quiet $DOCKERIMAGE
artifacts:
when: always # return artifacts even after job failure
paths:
- $ARTIFACT_FOLDER/trivy_results.json
cache:
paths:
- .cache
Report:
# combining tools outputs into one HTML
stage: report
when: always
image: python:3.5
script:
- mkdir json
- cp $ARTIFACT_FOLDER/*.json ./json/
- pip install json2html
- wget https://raw.githubusercontent.com/shad0wrunner/docker_cicd/master/convert_json_results.py
- python ./convert_json_results.py
artifacts:
paths:
- results.htmlإذا لزم الأمر ، يمكنك أيضًا مسح الصور المحفوظة كأرشيف .tar (ومع ذلك ، ستحتاج إلى تغيير معلمات الإدخال للأدوات المساعدة في ملف YAML)
NB: Trivy rpm git. RedHat-based .
2. بعد إضافة الملفات إلى المستودع ، وفقًا للإرشادات الواردة في ملف التكوين الخاص بنا ، سيبدأ GitLab تلقائيًا عملية الإنشاء والمسح الضوئي. في علامة التبويب CI / CD → Pipelines ، يمكنك رؤية تقدم التعليمات.
نتيجة لذلك ، لدينا أربع مهام. ثلاثة منهم يتعاملون مباشرة مع المسح ، وآخر (تقرير) يجمع تقريرًا بسيطًا من الملفات المتناثرة مع نتائج المسح.
بشكل افتراضي ، يتوقف Trivy عن التنفيذ إذا تم العثور على ثغرات خطيرة في الصورة أو التبعيات. في نفس الوقت ، تقوم Hadolint دائمًا بإرجاع Success رمز التنفيذ ، لأنه نتيجة لتنفيذه ، هناك دائمًا تعليقات ، مما يؤدي إلى إيقاف الإنشاء.
بناءً على متطلباتك المحددة ، يمكنك تكوين كود الخروج بحيث توقف هذه الأدوات المساعدة أيضًا عملية الإنشاء عندما تكتشف مشكلات ذات خطورة معينة. في حالتنا ، سيتوقف الإصدار فقط إذا اكتشف Trivy ثغرة أمنية خطيرة حددناها في متغير SHOWSTOPPER في .gitlab-ci.yml .
يمكن عرض نتيجة تشغيل كل أداة مساعدة في سجل كل مهمة مسح ، مباشرة في ملفات json في قسم القطع الأثرية ، أو في تقرير HTML بسيط (المزيد حول هذا الموضوع أدناه):
3. لتقديم تقارير الأداة المساعدة في نموذج أكثر قابلية للقراءة من قبل الإنسان ، يتم استخدام برنامج نصي صغير من Python تحويل ثلاثة ملفات json إلى ملف HTML واحد مع جدول العيوب.
يتم تشغيل هذا البرنامج النصي من خلال مهمة تقرير منفصلة ، والتأثير النهائي الخاص به هو ملف HTML مع تقرير. يوجد مصدر البرنامج النصي أيضًا في المستودع ويمكنك تكييفه وفقًا لاحتياجاتك وألوانك وما إلى ذلك.
شيل
الخيار الثاني مناسب للحالات التي تحتاج فيها إلى التحقق من صور Docker خارج نظام CI / CD ، أو تحتاج إلى الحصول على جميع التعليمات في نموذج يمكن تنفيذه مباشرة على المضيف. تتم تغطية هذا الخيار بواسطة برنامج نصي شيل جاهز يمكن تشغيله على جهاز ظاهري نظيف (أو حتى حقيقي). يتبع البرنامج النصي نفس التعليمات الواردة أعلاه gitlab-runner.
لكي يعمل البرنامج النصي بنجاح ، يجب تثبيت Docker على النظام ويجب أن يكون المستخدم الحالي في مجموعة عامل الإرساء.
يمكن أخذ البرنامج النصي نفسه هنا: docker_sec_check.sh
في بداية الملف ، يتم استخدام المتغيرات لتعيين الصورة التي يجب مسحها ضوئيًا وأي عيوب الحرجة ستؤدي إلى إنهاء الأداة المساعدة Trivy برمز الخطأ المحدد.
أثناء تنفيذ البرنامج النصي ، سيتم تنزيل جميع الأدوات المساعدة إلى دليل docker_tools ، ونتائج عملها - إلى دليل docker_tools / json ، وسيكون HTML مع التقرير في ملف results.html .
عينة من إخراج البرنامج النصي
~/docker_cicd$ ./docker_sec_check.sh
[+] Setting environment variables
[+] Installing required packages
[+] Preparing necessary directories
[+] Fetching sample Dockerfile
2020-10-20 10:40:00 (45.3 MB/s) - ‘Dockerfile’ saved [8071/8071]
[+] Pulling image to scan
latest: Pulling from bkimminich/juice-shop
[+] Running Hadolint
...
Dockerfile:205 DL3015 Avoid additional packages by specifying `--no-install-recommends`
Dockerfile:248 DL3002 Last USER should not be root
...
[+] Running Dockle
...
WARN - DKL-DI-0006: Avoid latest tag
* Avoid 'latest' tag
INFO - CIS-DI-0005: Enable Content trust for Docker
* export DOCKER_CONTENT_TRUST=1 before docker pull/build
...
[+] Running Trivy
juice-shop/frontend/package-lock.json
=====================================
Total: 3 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 2, CRITICAL: 0)
+---------------------+------------------+----------+---------+-------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | VERSION | TITLE |
+---------------------+------------------+----------+---------+-------------------------+
| object-path | CVE-2020-15256 | HIGH | 0.11.4 | Prototype pollution in |
| | | | | object-path |
+---------------------+------------------+ +---------+-------------------------+
| tree-kill | CVE-2019-15599 | | 1.2.2 | Code Injection |
+---------------------+------------------+----------+---------+-------------------------+
| webpack-subresource | CVE-2020-15262 | LOW | 1.4.1 | Unprotected dynamically |
| | | | | loaded chunks |
+---------------------+------------------+----------+---------+-------------------------+
juice-shop/package-lock.json
============================
Total: 20 (UNKNOWN: 0, LOW: 1, MEDIUM: 6, HIGH: 8, CRITICAL: 5)
...
juice-shop/package-lock.json
============================
Total: 5 (CRITICAL: 5)
...
[+] Removing left-overs
[+] Making the output look pretty
[+] Converting JSON results
[+] Writing results HTML
[+] Clean exit ============================================================
[+] Everything is done. Find the resulting HTML report in results.htmlصورة عامل ميناء مع جميع المرافق
كبديل ثالث ، قمت بتجميع ملفين Dockerfiles بسيطين لإنشاء صورة باستخدام أدوات الأمان. سيساعد ملف Dockerfile واحد في إنشاء مجموعة لمسح صورة من المستودع ، والثاني (Dockerfile_tar) - إنشاء مجموعة لمسح ملف tar مع صورة.
1. نأخذ ملف Docker والبرامج النصية المقابلة من المستودع https://github.com/Swordfish-Security/docker_cicd/tree/master/Dockerfile .
2. قم بتشغيله للتجميع:
docker build -t dscan:image -f docker_security.df .
3. بعد انتهاء التجميع ، قم بإنشاء حاوية من الصورة. في الوقت نفسه ، نقوم بتمرير متغير بيئة DOCKERIMAGE باسم الصورة التي نهتم بها ونقوم بتركيب Dockerfile الذي نريد تحليله من جهازنا إلى الملف / Dockerfile (لاحظ أن المسار المطلق لهذا الملف مطلوب):
docker run --rm -v $(pwd)/results:/results -v $(pwd)/docker_security.df:/Dockerfile -e DOCKERIMAGE="bkimminich/juice-shop" dscan:image
[+] Setting environment variables
[+] Running Hadolint
/Dockerfile:3 DL3006 Always tag the version of an image explicitly
[+] Running Dockle
WARN - DKL-DI-0006: Avoid latest tag
* Avoid 'latest' tag
INFO - CIS-DI-0005: Enable Content trust for Docker
* export DOCKER_CONTENT_TRUST=1 before docker pull/build
INFO - CIS-DI-0006: Add HEALTHCHECK instruction to the container image
* not found HEALTHCHECK statement
INFO - DKL-LI-0003: Only put necessary files
* unnecessary file : juice-shop/node_modules/sqlite3/Dockerfile
* unnecessary file : juice-shop/node_modules/sqlite3/tools/docker/architecture/linux-arm64/Dockerfile
* unnecessary file : juice-shop/node_modules/sqlite3/tools/docker/architecture/linux-arm/Dockerfile
[+] Running Trivy
...
juice-shop/package-lock.json
============================
Total: 20 (UNKNOWN: 0, LOW: 1, MEDIUM: 6, HIGH: 8, CRITICAL: 5)
...
[+] Making the output look pretty
[+] Starting the main module ============================================================
[+] Converting JSON results
[+] Writing results HTML
[+] Clean exit ============================================================
[+] Everything is done. Find the resulting HTML report in results.html
النتائج
لقد قمنا بتغطية مجموعة أساسية واحدة فقط من الأدوات لمسح عناصر Docker الأثرية ، والتي ، في رأيي ، تغطي بشكل فعال جزءًا لائقًا من متطلبات أمان الصور. هناك العديد من الأدوات المجانية والمدفوعة التي يمكنها إجراء نفس الفحوصات أو رسم تقارير جميلة أو العمل فقط في وضع وحدة التحكم وأنظمة إدارة حاوية الغطاء وما إلى ذلك. قد تظهر نظرة عامة على هذه الأدوات وكيفية دمجها بعد قليل.
الجانب الإيجابي من مجموعة الأدوات ، الموضحة في المقالة ، هو أنها كلها مبنية على كود مفتوح المصدر ويمكنك تجربتها وغيرها من الأدوات المماثلة للعثور على ما يناسب تمامًا متطلباتك وميزات البنية التحتية. بالطبع ، يجب دراسة جميع نقاط الضعف التي سيتم العثور عليها من أجل قابلية التطبيق في ظروف محددة ، ولكن هذا موضوع لمقال كبير في المستقبل.
آمل أن يساعدك هذا البرنامج التعليمي والنصوص والأدوات المساعدة وأن تصبح نقطة انطلاق لإنشاء بنية تحتية أكثر أمانًا في مجال النقل بالحاويات.