Zabezpieczanie kompilacji kontenerów

1. Wprowadzenie

ead1609267034bf7.png

Luki w oprogramowaniu to słabe punkty, które mogą spowodować przypadkową awarię systemu lub umożliwić osobom o złych zamiarach naruszenie bezpieczeństwa oprogramowania. Usługa Container Analysis udostępnia 2 rodzaje skanowania systemu operacyjnego w celu wykrywania luk w zabezpieczeniach kontenerów:

  • Interfejs On-Demand Scanning API umożliwia ręczne skanowanie obrazów kontenerów pod kątem luk w zabezpieczeniach systemu operacyjnego lokalnie na komputerze lub zdalnie w Container Registry lub Artifact Registry.
  • Interfejs Container Scanning API umożliwia automatyzację wykrywania luk w zabezpieczeniach systemu operacyjnego poprzez skanowanie za każdym razem, gdy przesyłasz obraz do Container Registry lub Artifact Registry. Włączenie tego interfejsu API włącza też skanowanie pakietów językowych pod kątem luk w zabezpieczeniach Go i Javy.

Interfejs On-Demand Scanning API umożliwia skanowanie obrazów przechowywanych lokalnie na komputerze lub zdalnie w Container Registry lub Artifact Registry. Dzięki temu możesz szczegółowo kontrolować, które kontenery chcesz skanować pod kątem luk w zabezpieczeniach. Za pomocą skanowania na żądanie możesz skanować obrazy w potoku CI/CD, zanim zdecydujesz, czy chcesz je przechowywać w rejestrze.

Czego się nauczysz

W tym laboratorium:

  • Tworzenie obrazów za pomocą Cloud Build
  • Używanie Artifact Registry na potrzeby kontenerów
  • Korzystanie z automatycznego skanowania pod kątem luk w zabezpieczeniach
  • Konfigurowanie skanowania na żądanie
  • Dodawanie skanowania obrazów w CICD w Cloud Build

2. Konfiguracja i wymagania

Samodzielne konfigurowanie środowiska

  1. Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub użyj istniejącego. Jeśli nie masz jeszcze konta Gmail ani Google Workspace, musisz je utworzyć.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • Nazwa projektu to wyświetlana nazwa uczestników tego projektu. Jest to ciąg znaków, który nie jest używany przez interfejsy API Google. Możesz ją zaktualizować w dowolnym momencie.
  • Identyfikator projektu jest unikalny we wszystkich projektach Google Cloud i nie można go zmienić po ustawieniu. Konsola Cloud automatycznie generuje unikalny ciąg znaków. Zwykle nie musisz się nim przejmować. W większości ćwiczeń z programowania musisz odwoływać się do identyfikatora projektu (zwykle jest on oznaczony jako PROJECT_ID). Jeśli wygenerowany identyfikator Ci się nie podoba, możesz wygenerować inny losowy identyfikator. Możesz też spróbować własnej nazwy i sprawdzić, czy jest dostępna. Po tym kroku nie można go zmienić i będzie obowiązywać przez cały czas trwania projektu.
  • Warto wiedzieć, że istnieje też trzecia wartość, czyli numer projektu, z której korzystają niektóre interfejsy API. Więcej informacji o tych 3 wartościach znajdziesz w dokumentacji.
  1. Następnie musisz włączyć płatności w konsoli Cloud, aby korzystać z zasobów i interfejsów API Google Cloud. Ukończenie tego laboratorium nie powinno wiązać się z dużymi kosztami, a nawet z żadnymi. Aby wyłączyć zasoby i uniknąć naliczania opłat po zakończeniu tego samouczka, możesz usunąć utworzone zasoby lub cały projekt. Nowi użytkownicy Google Cloud mogą skorzystać z bezpłatnego okresu próbnego, w którym mają do dyspozycji środki w wysokości 300 USD.

Konfiguracja środowiska

W Cloud Shell ustaw identyfikator projektu i numer projektu. Zapisz je jako zmienne PROJECT_IDPROJECT_ID.

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
    --format='value(projectNumber)')

Włączanie usług

Włącz wszystkie niezbędne usługi:

gcloud services enable \
  cloudkms.googleapis.com \
  cloudbuild.googleapis.com \
  container.googleapis.com \
  containerregistry.googleapis.com \
  artifactregistry.googleapis.com \
  containerscanning.googleapis.com \
  ondemandscanning.googleapis.com \
  binaryauthorization.googleapis.com 

3. Tworzenie obrazów za pomocą Cloud Build

W tej sekcji utworzysz automatyczny potok kompilacji, który skompiluje obraz kontenera, przeskanuje go, a następnie oceni wyniki. Jeśli nie zostaną znalezione żadne luki w zabezpieczeniach o krytycznym znaczeniu, obraz zostanie przesłany do repozytorium. Jeśli zostaną znalezione luki w zabezpieczeniach o krytycznym poziomie ważności, kompilacja zakończy się niepowodzeniem.

Przyznawanie dostępu kontu usługi Cloud Build

Cloud Build będzie potrzebować uprawnień dostępu do interfejsu API skanowania na żądanie. Udziel dostępu za pomocą tych poleceń.

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/iam.serviceAccountUser"
        
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/ondemandscanning.admin"

Tworzenie katalogu roboczego i przechodzenie do niego

mkdir vuln-scan && cd vuln-scan

Określanie przykładowego obrazu

Utwórz plik o nazwie Dockerfile z tą zawartością.

cat > ./Dockerfile << EOF
FROM gcr.io/google-appengine/debian9@sha256:ebffcf0df9aa33f342c4e1d4c8428b784fc571cdf6fbab0b31330347ca8af97a

# System
RUN apt update && apt install python3-pip -y

# App
WORKDIR /app
COPY . ./

RUN pip3 install Flask==1.1.4
RUN pip3 install gunicorn==20.1.0

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

EOF

Utwórz plik o nazwie main.py z tą zawartością:

cat > ./main.py << EOF
import os
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    name = os.environ.get("NAME", "Worlds")
    return "Hello {}!".format(name)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
EOF

Tworzenie potoku Cloud Build

To polecenie utworzy w Twoim katalogu plik cloudbuild.yaml, który będzie używany w procesie automatycznym. W tym przykładzie czynności są ograniczone do procesu kompilacji kontenera. W praktyce jednak oprócz kroków dotyczących kontenera należy uwzględnić instrukcje i testy dotyczące konkretnej aplikacji.

Utwórz plik za pomocą tego polecenia.

cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']


EOF

Uruchamianie potoku CI

Przesyłanie kompilacji do przetworzenia

gcloud builds submit

Sprawdzanie szczegółów kompilacji

Po rozpoczęciu procesu kompilacji sprawdź postęp w panelu Cloud Build.

  1. Otwórz Cloud Build w Cloud Console.
  2. Kliknij kompilację, aby wyświetlić jej zawartość.

4. Artifact Registry na potrzeby kontenerów

Tworzenie repozytorium Artifact Registry

W tym laboratorium będziesz używać Artifact Registry do przechowywania i skanowania obrazów. Utwórz repozytorium za pomocą tego polecenia.

gcloud artifacts repositories create artifact-scanning-repo \
  --repository-format=docker \
  --location=us-central1 \
  --description="Docker repository"

Skonfiguruj Dockera tak, aby podczas uzyskiwania dostępu do Artifact Registry korzystał z Twoich danych logowania gcloud.

gcloud auth configure-docker us-central1-docker.pkg.dev

Aktualizowanie potoku Cloud Build

Zmodyfikuj potok kompilacji, aby przesłać wynikowy obraz do Artifact Registry.

cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']

# push to artifact registry
- id: "push"
  name: 'gcr.io/cloud-builders/docker'
  args: ['push',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image']

images:
  - us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image
EOF

Uruchamianie potoku CI

Przesyłanie kompilacji do przetworzenia

gcloud builds submit

5. Automatyczne skanowanie pod kątem luk w zabezpieczeniach

Skanowanie artefaktów jest uruchamiane automatycznie za każdym razem, gdy przesyłasz nowy obraz do Artifact Registry lub Container Registry. Informacje o lukach w zabezpieczeniach są stale aktualizowane, gdy zostaną wykryte nowe luki. W tej sekcji sprawdzisz obraz, który został utworzony i przesłany do Artifact Registry, oraz zapoznasz się z wynikami skanowania pod kątem luk w zabezpieczeniach.

Sprawdzanie szczegółów obrazu

Po zakończeniu poprzedniego procesu kompilacji sprawdź obraz i wyniki skanowania pod kątem luk w zabezpieczeniach w panelu Artifact Registry.

  1. Otwórz Artifact Registry w Cloud Console.
  2. Kliknij repozytorium skanowania artefaktów, aby wyświetlić jego zawartość.
  3. Kliknij szczegóły obrazu.
  4. Kliknij najnowsze podsumowanie obrazu
  5. Po zakończeniu skanowania kliknij kartę luk w zabezpieczeniach dla obrazu.

Na karcie luk w zabezpieczeniach zobaczysz wyniki automatycznego skanowania utworzonego właśnie obrazu.

361be7b3bf293fca.png

Automatyzacja skanowania jest domyślnie włączona. Zapoznaj się z ustawieniami Artifact Registry, aby dowiedzieć się, jak włączyć lub wyłączyć automatyczne skanowanie.

6. Skanowanie na żądanie

Istnieją różne sytuacje, w których przed przekazaniem obrazu do repozytorium musisz przeprowadzić skanowanie. Na przykład programista kontenerów może przeskanować obraz i rozwiązać problemy przed przesłaniem kodu do kontroli źródła. W przykładzie poniżej skompilujesz i przeanalizujesz obraz lokalnie, zanim podejmiesz działania na podstawie wyników.

Tworzenie obrazu

W tym kroku użyjesz lokalnego Dockera, aby utworzyć obraz w lokalnej pamięci podręcznej.

docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image .

Skanowanie obrazu

Po utworzeniu obrazu poproś o jego skanowanie. Wyniki skanowania są przechowywane na serwerze metadanych. Zadanie kończy się lokalizacją wyników na serwerze metadanych.

gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --format="value(response.scan)" > scan_id.txt

Sprawdzanie pliku wyjściowego

Poświęć chwilę na przejrzenie wyników poprzedniego kroku, które zostały zapisane w pliku scan_id.txt. Zwróć uwagę na lokalizację raportu z wynikami skanowania na serwerze metadanych.

cat scan_id.txt

Sprawdzanie szczegółowych wyników skanowania

Aby wyświetlić rzeczywiste wyniki skanowania, użyj polecenia list-vulnerabilities w lokalizacji raportu podanej w pliku wyjściowym.

gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) 

Dane wyjściowe zawierają znaczną ilość informacji o wszystkich lukach w zabezpieczeniach obrazu.

Oznaczanie problemów krytycznych

Ludzie rzadko korzystają bezpośrednio z danych przechowywanych w raporcie. Wyniki są zwykle wykorzystywane przez proces automatyczny. Użyj poniższych poleceń, aby odczytać szczegóły raportu i zarejestrować informacje o znalezionych krytycznych lukach w zabezpieczeniach.

export SEVERITY=CRITICAL

gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq ${SEVERITY}; then echo "Failed vulnerability check for ${SEVERITY} level"; else echo "No ${SEVERITY} Vulnerabilities found"; fi

Wynik tego polecenia będzie następujący:

Failed vulnerability check for CRITICAL level

7. Skanowanie w CICD za pomocą Cloud Build

Przyznawanie dostępu kontu usługi Cloud Build

Cloud Build będzie potrzebować uprawnień dostępu do interfejsu API skanowania na żądanie. Udziel dostępu za pomocą tych poleceń.

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/iam.serviceAccountUser"
        
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/ondemandscanning.admin"

Aktualizowanie potoku Cloud Build

To polecenie utworzy w Twoim katalogu plik cloudbuild.yaml, który będzie używany w procesie automatycznym. W tym przykładzie czynności są ograniczone do procesu kompilacji kontenera. W praktyce jednak oprócz kroków dotyczących kontenera należy uwzględnić instrukcje i testy dotyczące konkretnej aplikacji.

Utwórz plik za pomocą tego polecenia.

cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']

#Run a vulnerability scan at _SECURITY level
- id: scan
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
    (gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --location us \
    --format="value(response.scan)") > /workspace/scan_id.txt

#Analyze the result of the scan
- id: severity check
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
      gcloud artifacts docker images list-vulnerabilities \$(cat /workspace/scan_id.txt) \
      --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq CRITICAL; \
      then echo "Failed vulnerability check for CRITICAL level" && exit 1; else echo "No CRITICAL vulnerability found, congrats !" && exit 0; fi

#Retag
- id: "retag"
  name: 'gcr.io/cloud-builders/docker'
  args: ['tag',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']


#pushing to artifact registry
- id: "push"
  name: 'gcr.io/cloud-builders/docker'
  args: ['push',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']

images:
  - us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image
EOF

Uruchamianie potoku CI

Prześlij kompilację do przetworzenia, aby sprawdzić, czy kompilacja ulegnie uszkodzeniu po wykryciu luki w zabezpieczeniach o krytycznym poziomie ważności.

gcloud builds submit

Nie udało się skompilować wersji do sprawdzenia

Przesłana kompilacja nie zostanie zaakceptowana, ponieważ obraz zawiera KRYTYCZNE luki w zabezpieczeniach.

Sprawdź błąd kompilacji na stronie Historia Cloud Build.

Naprawianie luki w zabezpieczeniach

Zaktualizuj plik Dockerfile, aby używać obrazu podstawowego, który nie zawiera krytycznych luk w zabezpieczeniach.

Zastąp Dockerfile, aby używać obrazu Debian 10, za pomocą tego polecenia:

cat > ./Dockerfile << EOF
from python:3.8-slim  

# App
WORKDIR /app
COPY . ./

RUN pip3 install Flask==2.1.0
RUN pip3 install gunicorn==20.1.0

CMD exec gunicorn --bind :\$PORT --workers 1 --threads 8 main:app

EOF

Uruchom proces CI z prawidłowym obrazem

Prześlij kompilację do przetworzenia, aby sprawdzić, czy zakończy się ona powodzeniem, gdy nie zostaną znalezione luki w zabezpieczeniach o krytycznym poziomie ważności.

gcloud builds submit

Sprawdzanie powodzenia kompilacji

Przesłana kompilacja zakończy się powodzeniem, ponieważ zaktualizowany obraz nie zawiera krytycznych luk w zabezpieczeniach.

Sprawdź, czy kompilacja zakończyła się sukcesem na stronie Historia Cloud Build.

Sprawdzanie wyników skanowania

Sprawdź prawidłowy obraz w Artifact Registry.

  1. Otwórz Artifact Registry w Cloud Console.
  2. Kliknij repozytorium skanowania artefaktów, aby wyświetlić jego zawartość.
  3. Kliknij szczegóły obrazu.
  4. Kliknij najnowsze podsumowanie obrazu
  5. Kliknij kartę luk w zabezpieczeniach obrazu.

8. Gratulacje!

Gratulacje! Codelab został ukończony.

Omówione zagadnienia:

  • Tworzenie obrazów za pomocą Cloud Build
  • Artifact Registry na potrzeby kontenerów
  • Automatyczne skanowanie pod kątem luk w zabezpieczeniach
  • Skanowanie na żądanie
  • Skanowanie w CICD za pomocą Cloud Build

Co dalej?

Czyszczenie danych

Aby uniknąć obciążenia konta Google Cloud opłatami za zasoby zużyte w tym samouczku, możesz usunąć projekt zawierający te zasoby lub zachować projekt i usunąć poszczególne zasoby.

Usuwanie projektu

Najprostszym sposobem na uniknięcie płatności jest usunięcie projektu utworzonego w tym samouczku.

Ostatnia aktualizacja: 21.03.2023