Cara lan conto implementasine utilitas mriksa keamanan Docker

Cara lan conto implementasine utilitas mriksa keamanan Docker
Hey Habr!

Ing kasunyatan saiki, amarga nambah peran containerization ing proses pangembangan, masalah njamin keamanan macem-macem tahapan lan entitas sing ana gandhengane karo kontainer ora ana ing pungkasan. Nindakake mriksa kanthi manual minangka tugas sing angel, mula luwih becik njupuk paling ora langkah awal kanggo ngotomatisasi proses iki.

Ing artikel iki, aku bakal nuduhake skrip sing wis siyap kanggo ngetrapake sawetara utilitas keamanan Docker lan instruksi babagan carane nyiyapake demo cilik kanggo nyoba proses iki. Sampeyan bisa nggunakake bahan kanggo eksprimen carane ngatur proses testing keamanan gambar Dockerfile lan instruksi. Cetha yen infrastruktur pangembangan lan implementasine beda kanggo saben wong, mula ing ngisor iki aku bakal menehi sawetara opsi sing bisa ditindakake.

Utilitas Priksa Keamanan

Ana macem-macem aplikasi helper lan skrip sing nindakake mriksa ing macem-macem aspek infrastruktur Docker. Sawetara iku wis diterangake ing artikel sadurunge (https://habr.com/ru/company/swordfish_security/blog/518758/#docker-security), lan ing artikel iki aku pengin fokus ing telu, sing nutupi akeh syarat keamanan kanggo gambar Docker sing dibangun sajrone proses pangembangan. Kajaba iku, aku uga bakal nuduhake conto carane telung keperluan iki bisa digabungake dadi siji pipa kanggo nindakake mriksa keamanan.

Hadolin
https://github.com/hadolint/hadolint

Utilitas konsol sing cukup prasaja sing mbantu ngevaluasi kabeneran lan safety instruksi Dockerfile (contone, mung nggunakake registri gambar sing diidini utawa nggunakake sudo).

Cara lan conto implementasine utilitas mriksa keamanan Docker

Dokel
https://github.com/goodwithtech/dockle

Utilitas konsol sing bisa digunakake ing gambar (utawa ing tarball gambar sing disimpen) sing mriksa bener lan keamanan gambar tartamtu kanthi nganalisa lapisan lan konfigurasi - apa pangguna digawe, instruksi apa sing digunakake, volume apa sing dipasang , anane tembung sandhi kosong, lsp. e. Nalika jumlah mriksa ora akeh banget lan adhedhasar sawetara pamriksa lan rekomendasi dhewe. CIS (Pusat Keamanan Internet) Benchmark kanggo docker.
Cara lan conto implementasine utilitas mriksa keamanan Docker

trivy
https://github.com/aquasecurity/trivy

Utilitas iki ditujokake kanggo nemokake rong jinis kerentanan - masalah mbangun OS (Alpine, RedHat (EL), CentOS, Debian GNU, Ubuntu didhukung) lan masalah dependensi (Gemfile.lock, Pipfile.lock, composer.lock, package-lock .json , yarn.lock, Cargo.lock). Trivy bisa mindai loro gambar ing gudang lan gambar lokal, lan uga mindai adhedhasar file .tar ditransfer karo gambar Docker.

Cara lan conto implementasine utilitas mriksa keamanan Docker

Opsi Implementasi Utilitas

Kanggo nyoba aplikasi sing diterangake ing kahanan sing terisolasi, aku bakal menehi pandhuan kanggo nginstal kabeh keperluan minangka bagean saka proses sing disederhanakake.

Ide utama yaiku kanggo nduduhake carane sampeyan bisa ngetrapake mriksa konten otomatis kanggo gambar Dockerfiles lan Docker sing digawe sajrone pembangunan.

Verifikasi dhewe kalebu langkah-langkah ing ngisor iki:

  1. Priksa bener lan safety instruksi Dockerfile kanthi sarana linter Hadolin
  2. Priksa bener lan keamanan gambar final lan penengah - sarana Dokel
  3. Priksa Kerentanan Umum (CVE) ing gambar dhasar lan sawetara dependensi - dening sarana trivy

Mengko ing artikel aku bakal menehi telung opsi kanggo ngetrapake langkah-langkah iki:
Sing pertama yaiku kanthi ngatur pipa CI / CD nggunakake conto GitLab (kanthi katrangan babagan proses ngunggahake conto tes).
Kapindho nggunakake skrip cangkang.
Katelu yaiku mbangun gambar Docker kanggo mindhai gambar Docker.
Sampeyan bisa milih pilihan sing paling cocog karo sampeyan, nransfer menyang infrastruktur lan adaptasi karo kabutuhan sampeyan.

Kabeh file sing dibutuhake lan instruksi tambahan uga ana ing gudang: https://github.com/Swordfish-Security/docker_cicd

Integrasi GitLab CI/CD

Ing pilihan pisanan, kita bakal ndeleng carane mriksa keamanan bisa dileksanakake nggunakake sistem repositori GitLab minangka conto. Kene kita bakal mbukak liwat langkah lan ndeleng carane nyiyapake lingkungan test karo GitLab saka ngeruk, nggawe proses scan lan mbukak keperluan kanggo test Dockerfile test lan gambar acak - aplikasi JuiceShop.

Nginstal GitLab
1. Instal Docker:

sudo apt-get update && sudo apt-get install docker.io

2. Tambah pangguna saiki menyang grup docker supaya sampeyan bisa nggarap docker tanpa nggunakake sudo:

sudo addgroup <username> docker

3. Temokake IP sampeyan:

ip addr

4. Instal lan bukak GitLab ing wadhah kasebut, ganti alamat IP ing jeneng host nganggo jeneng sampeyan dhewe:

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

Kita nunggu GitLab ngrampungake kabeh prosedur instalasi sing dibutuhake (sampeyan bisa ngetutake proses kasebut liwat output file log: docker logs -f gitlab).

5. Bukak IP lokal sampeyan ing browser lan deleng kaca sing nawakake kanggo ngganti tembung sandhi kanggo pangguna root:
Cara lan conto implementasine utilitas mriksa keamanan Docker
Setel sandhi anyar lan pindhah menyang GitLab.

6. Nggawe proyek anyar, contone cicd-test lan initialize karo file wiwitan README.md:
Cara lan conto implementasine utilitas mriksa keamanan Docker
7. Saiki kita kudu nginstal GitLab Runner: agen sing bakal mbukak kabeh operasi perlu ing request.
Download versi paling anyar (ing kasus iki, ing Linux 64-bit):

sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64

8. Nggawe bisa dieksekusi:

sudo chmod +x /usr/local/bin/gitlab-runner

9. Tambah pangguna OS kanggo Runner lan miwiti layanan:

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

Iku kudu katon kaya iki:

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. Saiki kita ndhaftar Runner supaya bisa sesambungan karo conto GitLab kita.
Kanggo nindakake iki, bukak kaca Setelan-CI/CD (http://OUR_ IP_ADDRESS/root/cicd-test/-/settings/ci_cd) lan ing tab Runners golek URL lan token Registrasi:
Cara lan conto implementasine utilitas mriksa keamanan Docker
11. Ndhaptar Pelari kanthi ngganti URL lan token Registrasi:

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"

AkibatΓ©, kita entuk GitLab sing wis siap, sing kudu ditambahake instruksi kanggo miwiti utilitas. Ing demo iki, kita ora duwe aplikasi mbangun lan langkah containerization, nanging ing lingkungan nyata padha bakal ndhisiki langkah scan lan generate gambar lan Dockerfile kanggo analisis.

konfigurasi pipa

1. Tambah file menyang gudang mydockerfile.df (iki Dockerfile tes sing bakal dites) lan file konfigurasi proses GitLab CI / CD .gitlab-cicd.yml, sing nampilake pandhuan kanggo scanner (cathetan titik ing jeneng berkas).

File konfigurasi .yaml ngemot instruksi kanggo mbukak telung keperluan (Hadolint, Dockle, lan Trivy) sing bakal ngurai Dockerfile sing dipilih lan gambar sing ditemtokake ing variabel DOCKERFILE. Kabeh file sing dibutuhake bisa dijupuk saka gudang: https://github.com/Swordfish-Security/docker_cicd/

Ekstrak saka mydockerfile.df (iki minangka file abstrak kanthi sakumpulan instruksi sewenang-wenang mung kanggo nduduhake cara kerjane sarana kasebut). Link langsung menyang file: mydockerfile.df

Isi 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 <[email protected]>"
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

Konfigurasi YAML katon kaya iki (file kasebut bisa dijupuk saka tautan langsung ing kene: .gitlab-ci.yml):

Isi .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

Yen perlu, sampeyan uga bisa mindhai gambar sing disimpen minangka arsip .tar (Nanging, sampeyan kudu ngganti parameter input kanggo keperluan ing file YAML)

NB: Trivy mbutuhake diinstal Rpm ΠΈ Go. Yen ora, bakal ngasilake kesalahan nalika mindhai gambar berbasis RedHat lan nganyari database kerentanan.

2. Sawise nambahake file menyang repositori, miturut pandhuan ing file konfigurasi kita, GitLab bakal kanthi otomatis miwiti proses mbangun lan mindai. Ing tab CI / CD β†’ Pipelines, sampeyan bisa ndeleng kemajuan instruksi kasebut.

AkibatΓ©, kita duwe papat tugas. Telu mau langsung melu mindhai, lan pungkasan (Laporan) ngumpulake laporan prasaja saka file kasebar karo asil scan.
Cara lan conto implementasine utilitas mriksa keamanan Docker
Kanthi gawan, Trivy mungkasi eksekusi yen kerentanan KRITIKAL ditemokake ing gambar utawa dependensi. Ing wektu sing padha, Hadolint tansah ngasilake Sukses ing kode eksekusi, amarga eksekusi kasebut tansah nduweni komentar, sing nyebabake mbangun mandheg.

Gumantung ing syarat tartamtu, sampeyan bisa ngatur kode metu supaya keperluan iki uga mungkasi proses mbangun nalika masalah kritisitas tartamtu dideteksi. Ing kasus kita, mbangun bakal mandheg mung yen Trivy ndeteksi kerentanan kanthi keruwetan sing wis ditemtokake ing variabel SHOWSTOPPER ing .gitlab-ci.yml.
Cara lan conto implementasine utilitas mriksa keamanan Docker

Asil operasi saben utilitas bisa dideleng ing log saben tugas pemindaian, langsung ing file json ing bagean artefak, utawa ing laporan HTML sing prasaja (liyane ing ngisor iki):
Cara lan conto implementasine utilitas mriksa keamanan Docker

3. Kanggo nampilake laporan sarana ing wangun sing rada bisa diwaca manungsa, skrip Python cilik digunakake kanggo ngowahi telung file json dadi siji file HTML kanthi tabel cacat.
Skrip iki dibukak dening tugas Report kapisah, lan artefak final sawijining file HTML karo laporan. Sumber skrip uga ana ing repositori lan bisa dicocogake karo kabutuhan, warna, lsp.
Cara lan conto implementasine utilitas mriksa keamanan Docker

Skrip cangkang

Pilihan kapindho cocok kanggo kasus sing kudu mriksa gambar Docker ora ing CI / sistem CD, utawa sampeyan kudu duwe kabeh instruksi ing wangun sing bisa kaleksanan langsung ing inang. Pilihan iki dijamin dening script Nihan siap-digawe sing bisa mbukak ing virtual resik (utawa malah nyata) mesin. Skrip kasebut ngetutake instruksi sing padha karo gitlab-runner ing ndhuwur.

Supaya skrip bisa sukses, Docker kudu diinstal ing sistem lan pangguna saiki kudu ana ing grup docker.

Skrip dhewe bisa ditemokake ing kene: docker_sec_check.sh

Ing wiwitan file, variabel nemtokake gambar endi sing kudu dipindai lan keruwetan cacat sing bakal nyebabake utilitas Trivy metu kanthi kode kesalahan sing ditemtokake.

Sajrone eksekusi skrip, kabeh keperluan bakal diundhuh menyang direktori docker_tools, asil karya - ing direktori docker_tools/json, lan HTML karo laporan bakal ana ing file asil.html.

Tuladha skrip output

~/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

Gambar Docker karo kabeh keperluan

Minangka alternatif katelu, aku nyawiji loro Dockerfiles prasaja kanggo nggawe gambar karo keperluan keamanan. Siji Dockerfile bakal mbantu mbangun set kanggo mindhai gambar saka gudang, sing kapindho (Dockerfile_tar) bakal mbangun set kanggo mindhai file tar nganggo gambar kasebut.

1. Kita njupuk file lan skrip Docker sing cocog saka gudang https://github.com/Swordfish-Security/docker_cicd/tree/master/Dockerfile.
2. Jalanake kanggo perakitan:

docker build -t dscan:image -f docker_security.df .

3. Sawise mbangun rampung, nggawe wadhah saka gambar. Ing wektu sing padha, kita ngliwati variabel lingkungan DOCKERIMAGE kanthi jeneng gambar sing kita minati lan pasang file Docker sing pengin dianalisis saka mesin menyang file kasebut. /dockerfile (Elinga yen path mutlak menyang berkas iki dibutuhake):

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

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹

Kita wis nutupi mung siji set dhasar utilitas pemindaian artefak Docker, sing dakanggep cukup efektif kanggo syarat keamanan gambar. Ana akeh alat liyane sing mbayar lan gratis sing bisa nindakake pemeriksaan sing padha, nggambar laporan sing apik utawa bisa digunakake ing mode konsol, nutupi sistem manajemen wadhah, lsp. Ringkesan alat kasebut lan cara nggabungake bisa uga katon mengko.

Sisih positif saka set alat sing diterangake ing artikel kasebut yaiku kabeh dibangun ing open source lan sampeyan bisa nyoba karo piranti kasebut lan alat liyane sing padha kanggo nemokake apa sing cocog karo kabutuhan lan fitur infrastruktur sampeyan. Mesthine, kabeh kerentanan sing ditemokake kudu ditliti kanggo ditrapake ing kahanan tartamtu, nanging iki minangka topik kanggo artikel gedhe ing mangsa ngarep.

Muga-muga pandhuan, skrip lan utilitas iki bakal mbantu sampeyan lan dadi titik wiwitan kanggo nggawe infrastruktur sing luwih aman ing bidang containerization.

Source: www.habr.com

Add a comment