TL;DR

Изображение на Docker съдържа приложение и всички негови зависимости. Тъй като съдържа и многобройните двоични файлове и библиотеки на операционна система, важно е да се уверите, че няма уязвимости в основната файлова система - поне не критични или големи. Сканирането на изображение в рамките на CI/CD конвейер може да осигури това допълнително ниво на сигурност.

Прост проект

В предишна статия описах как настроих CI/CD конвейер на много прост страничен проект, използвайки GitLab, Portainer и Docker Swarm.



В този тръбопровод са дефинирани три етапа:

  • Първият изпълнява някои тестове на кода Node.js.
  • Вторият изгражда изображение на Docker и го публикува в регистър на GitLab.
  • Последният етап внедрява новото изображение в Docker Swarm, като използва функцията за уеб кукичка на Portainer.

TK *вътрешности* Изображението на Docker, създадено по време на процеса, е базирано на Nginx 1.14 и се внедрява веднага без никаква проверка на вътрешностите му. Това може да е опасно, така че нека видим как можем да го подобрим.

Добавяне на етап на сканиране на изображения към конвейера

Има няколко решения за сканиране на изображения; търговски и отворен код. В тази статия ще разгледаме „Clair“ и „clair-skener“; два инструмента с отворен код.

„Тази документация“ от GitLab предостави всички инструкции за добавяне на допълнителен етап, посветен на сканирането на изображения. Той основно изпълнява сървър на Clair, който предоставя съществуващите CVE, а след това двоичният файл на скенера на clair проверява всеки слой от изображението, което е изградено по време на предишния етап на конвейера.

Добавих допълнителното съдържание към файла .gitlab-ci.yml на проекта.

Забележка: Направих само някои незначителни модификации на етапа, дефиниран в документацията, така че отговаря на версията на моя GitLab runner (което е необходимо, когато става въпрос за artifact качване).

С този добавен нов етап, нека да видим как върви, като стартираме нов конвейер. Екранната снимка по-долу показва част от резултата от този нов етап на image_sanning.

Можем да видим в горната част, че всеки слой от изображението е анализиран.

Забележка: ако искате да научите повече за вътрешността на дадено изображение и да изследвате всеки слой по страхотен начин, горещо ви препоръчвам да погледнете dive.



Връщайки се към изхода на GitLab, можем да видим, че са открити 100 уязвимости. Това е много! Опасни ли са? Е, съдейки по някои от записите в колоната Сериозност, Критична/Висока, може да са.

Имаме много уязвимости… А сега какво?

Е, освен ако не сте човек по сигурността, шансовете са тези уязвимости да не ви кажат много. Знаейки, че дадено приложение има уязвимости, обаче може да повдигне много въпроси:

  • Безопасно ли е да стартирам приложението така, както е?
  • Кои уязвимости мога да игнорирам и кои приемам на сериозно?
  • Приложението ми не е насочено към потребителя, това трябва да е безопасно за всички тези CVE, нали? Дори и за Критичните?
  • Ще разбере ли шефът ми, ако просто игнорирам всички тези CVE?
  • Има ли някакви прости неща, които мога да направя, за да смекча потенциалните рискове?

В някои случаи всъщност има някои прости стъпки, които могат да помогнат много, както ще видим по-долу.

Първо проверете основното изображение

Примерът, който обмислям, е прост уебсайт, публикуван с официалното изображение nginx:1.14 — последната стабилна версия към датата на писане на тази публикация. Тъй като Dockerfile използва многоетапно изграждане, крайното изображение не съдържа много ненужни Node.js неща, използвани за изграждане на уеб активите. Dockerfile е следният.

Многоетапното изграждане вече е добра отправна точка, тъй като помага да се намали повърхността на атака на изображението. Но все пак окончателното изображение nginx:1.14 е базирано на Debian, така че нека променим това и вместо това да използваме nginx:1.14-alpine.

Забележка: Alpine Linux е малка дистрибуция, тя е фокусирана върху сигурността и излага много малка повърхност за атака. Използването на базово изображение, създадено от Alpine, вероятно би било добър ход - ще проверим това.

Втората част на нашия многоетапен Dockerfile вече е заменена със следното.

Нека да задействаме ново изграждане и да видим как върви.

Е, стана доста добре според екранната снимка по-горе. Етапът на сканиране вече отчита... 0 уязвимости!

Актуализация: Използване на микроскенер Aquasec

Както Łukasz Lach посочи в емисията в Twitter по-долу, Aquasec предлага свой собствен CVE скенер: Aqua Microscanner и е много лесен за използване. Благодаря Łukasz !

Микроскенерът може да сканира изображението по различни начини: по време на създаването на изображението или след като е създадено.

Сканиране при изграждане на изображението

Необходими са някои промени в Dockerfile, за да добавите двоичния файл на микроскенера и да го стартирате, за да може да анализира изградената файлова система на изображението.

Последните 2 инструкции в този Dockerfile са посветени на сканирането:

  • В инструкцията за изграждане трябва да бъде предоставен токен (официалната документация на Aqua Microscanner подробно описва как може да се получи този токен).
  • Двоичният файл на микроскенера се изтегля и се изпълнява срещу файловата система на създаденото изображение.

Тук се използват няколко допълнителни опции:

  • --html генерира html отчет за сканирането
  • --continue-on-failure не връща код за грешка в случай, че бъдат открити CVE, и след това няма да спре конвейера на CI инструмента

Сканиране веднага след изграждането на изображението

Това може да стане чрез добавяне на Dockerfile, посветен на сканирането. Пример за този Dockerfile е даден по-долу.

Инструкцията FROM указва името на изображението, което ще бъде сканирано. Двете инструкции, които следват, са същите като тези, използвани при първия подход (сканиране при изграждане на изображението).

За да илюстрираме този втори подход, ще добавим следната стъпка в нашата CI линия.

Забележка: Няма смисъл да имате няколко сканирания на изображения в един и същ конвейер, целта тук е просто да покажем как това може да бъде поставено на място и също така може да помогне да направите избор между решения за сканиране .

След това можем да задействаме нова компилация на изображението, Clair и Microscanner ще сканират изображението, след като бъде изградено.

Забележка: Тъй като тази компилация се изпълнява няколко седмици след първата версия на тази статия, някои CVE са открити, докато не са присъствали преди.

Интересно тук: резултатите от сканирането са различни. 4 CVE се откриват от Clair, докато 5 се откриват от Aqua Microscanner. Това показва, че CVE скенерите не работят по абсолютно същия начин, например те може да не работят с една и съща версия на CVE базата данни и може да не работят еднакво добре.

Забележка: за да направим използването на микроскенер още по-лесно, можем да използваме клиентските добавки за мениджър за Docker (CLIP).



С този инструмент вече няма нужда да използвате специален Dockerfile за сканиране, тъй като този може да бъде задействан с проста команда „docker microscan“, след като приставката за microscan бъде инсталирана.

Резюме

Тази кратка публикация илюстрира, че добавянето на прост етап на сканиране на изображения в съществуващ CI/CD канал не е толкова сложно. Това предоставя допълнителна информация, като например броя и идентификаторите на уязвимостите, съдържащи се в изображението.

От тази информация все още е трудно да се разбере какво да се прави с тях, но използването на базово изображение, създадено от Alpine, може да бъде първа стъпка за подобряване на сигурността на приложение, без да знаете много за CVE.