1. Omówienie
Zmodyfikujesz domyślne kroki wdrażania usługi w Cloud Run, aby zwiększyć bezpieczeństwo, a także dowiesz się, jak bezpiecznie uzyskiwać dostęp do wdrożonej aplikacji. Aplikacja jest „usługą rejestracji partnerów”. aplikacji Cymbal Eats, która jest używana przez firmy współpracujące z Cymbal Eats przy przetwarzaniu zamówień na jedzenie.
Czego się nauczysz
Wprowadź kilka niewielkich zmian w minimalnych domyślnych krokach wdrażania aplikacji w Cloud Run, by znacznie zwiększyć jej bezpieczeństwo. Wykorzystasz istniejącą aplikację i instrukcje wdrażania, a także zmienisz kroki wdrażania, aby zwiększyć bezpieczeństwo wdrożonej aplikacji.
Zobaczysz, jak autoryzować dostęp do aplikacji i wysyłać autoryzowane żądania.
Nie jest to wyczerpujące omówienie zabezpieczeń wdrażania aplikacji, a jedynie zmiany, które możesz wprowadzić we wszystkich przyszłych wdrożeniach aplikacji, które zwiększą ich bezpieczeństwo przy minimalnym nakładzie pracy.
2. Konfiguracja i wymagania
Samodzielne konfigurowanie środowiska
- Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub wykorzystaj już istniejący. Jeśli nie masz jeszcze konta Gmail ani Google Workspace, musisz je utworzyć.
- Nazwa projektu jest wyświetlaną nazwą uczestników tego projektu. To ciąg znaków, który nie jest używany przez interfejsy API Google. W każdej chwili możesz ją zmienić.
- Identyfikator projektu jest unikalny we wszystkich projektach Google Cloud i nie można go zmienić (po jego ustawieniu nie można go zmienić). Cloud Console automatycznie wygeneruje unikalny ciąg znaków. zwykle nieważne, co ona jest. W większości ćwiczeń z programowania konieczne jest odwołanie się do identyfikatora projektu (zwykle nazywa się on
PROJECT_ID
). Jeśli nie podoba Ci się wygenerowany identyfikator, możesz wygenerować kolejny losowy. Możesz też spróbować własnych sił i sprawdzić, czy jest dostępna. Potem nie będzie można go zmienić. Pozostanie ono przez czas trwania projektu. - Dostępna jest trzecia wartość, numer projektu, z którego korzystają niektóre interfejsy API. Więcej informacji o wszystkich 3 wartościach znajdziesz w dokumentacji.
- Następnie musisz włączyć płatności w Cloud Console, aby korzystać z zasobów Cloud/interfejsów API. Ukończenie tego ćwiczenia z programowania nie powinno kosztować zbyt wiele. Aby wyłączyć zasoby, aby nie naliczać opłat po zakończeniu tego samouczka, możesz usunąć utworzone zasoby lub cały projekt. Nowi użytkownicy Google Cloud mogą skorzystać z programu bezpłatnego okresu próbnego o wartości 300 USD.
Aktywowanie Cloud Shell
- W konsoli Cloud kliknij Aktywuj Cloud Shell .
Jeśli dopiero zaczynasz korzystać z Cloud Shell, wyświetli się ekran pośredni (w części strony widocznej po przewinięciu) z opisem tej funkcji. W takim przypadku kliknij Dalej (nie zobaczysz go więcej). Tak wygląda ten jednorazowy ekran:
Uzyskanie dostępu do Cloud Shell i połączenie się z nim powinno zająć tylko kilka chwil.
Ta maszyna wirtualna ma wszystkie potrzebne narzędzia dla programistów. Zawiera stały katalog domowy o pojemności 5 GB i działa w Google Cloud, co znacznie zwiększa wydajność sieci i uwierzytelnianie. Większość czynności z tego ćwiczenia z programowania można wykonać w przeglądarce lub na Chromebooku.
Po nawiązaniu połączenia z Cloud Shell powinno pojawić się informacja, że użytkownik jest już uwierzytelniony i że projekt jest już ustawiony na identyfikator Twojego projektu.
- Uruchom to polecenie w Cloud Shell, aby potwierdzić, że jesteś uwierzytelniony:
gcloud auth list
Dane wyjściowe polecenia
Credentialed Accounts ACTIVE ACCOUNT * <my_account>@<my_domain.com> To set the active account, run: $ gcloud config set account `ACCOUNT`
- Uruchom to polecenie w Cloud Shell, aby sprawdzić, czy polecenie gcloud zna Twój projekt:
gcloud config list project
Dane wyjściowe polecenia
[core] project = <PROJECT_ID>
Jeśli tak nie jest, możesz go ustawić za pomocą tego polecenia:
gcloud config set project <PROJECT_ID>
Dane wyjściowe polecenia
Updated property [core/project].
Konfiguracja środowiska
W tym module będziesz uruchamiać polecenia w wierszu poleceń Cloud Shell. Zwykle możesz skopiować polecenia i wkleić je w niezmienionej formie, ale w niektórych przypadkach trzeba będzie zmienić wartości obiektów zastępczych na prawidłowe.
- Ustaw zmienną środowiskową na identyfikator projektu, aby móc go używać w późniejszych poleceniach:
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export SERVICE_NAME=partner-registration-service
- Włącz interfejs API usługi Cloud Run, który będzie obsługiwać Twoją aplikację, interfejs Firestore API zapewniający miejsce na dane NoSQL, interfejs Cloud Build API, który będzie używany przez polecenie wdrożenia, oraz Artifact Registry, które będą używane do przechowywania kontenera aplikacji podczas kompilacji:
gcloud services enable \
run.googleapis.com \
firestore.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com
- Zainicjuj bazę danych Firestore w trybie natywnym. To polecenie używa interfejsu App Engine API, więc najpierw musisz je włączyć.
Polecenie musi określać region dla App Engine, którego nie będziemy używać, ale musimy utworzyć ze względów historycznych, oraz region dla bazy danych. Dla bazy danych będziemy używać us-central dla App Engine i nam5. nam5 to lokalizacja obejmująca wiele regionów w Stanach Zjednoczonych. Lokalizacje w wielu regionach maksymalizują dostępność i trwałość bazy danych.
gcloud services enable appengine.googleapis.com
gcloud app create --region=us-central
gcloud firestore databases create --region=nam5
- Skopiuj repozytorium przykładowej aplikacji i przejdź do katalogu
git clone https://github.com/GoogleCloudPlatform/cymbal-eats.git
cd cymbal-eats/partner-registration-service
3. Przejrzyj plik README
Otwórz edytor i sprawdź pliki zawierające aplikację. Otwórz plik README.md zawierający czynności niezbędne do wdrożenia tej aplikacji. Niektóre z tych kroków mogą wiązać się z dorozumianymi lub wyraźnymi decyzjami dotyczącymi bezpieczeństwa, które należy wziąć pod uwagę. Zmienisz kilka z tych opcji, aby zwiększyć bezpieczeństwo wdrożonej aplikacji, zgodnie z opisem poniżej:
Krok 3. Uruchom npm install
Warto znać pochodzenie i integralność oprogramowania innych firm wykorzystywanego w aplikacji. Zarządzanie bezpieczeństwem łańcucha dostaw oprogramowania jest istotne przy tworzeniu dowolnego oprogramowania, a nie tylko w przypadku aplikacji wdrażanych w Cloud Run. Ten moduł koncentruje się na wdrożeniu, więc nie dotyczy tego zagadnienia, ale warto zapoznać się z tym tematem oddzielnie.
Kroki 4 i 5. Zmodyfikuj i uruchom polecenie deploy.sh
Te kroki wdrażają aplikację w Cloud Run, pozostawiając większość opcji w wartościach domyślnych. Zmodyfikujesz ten krok, aby zwiększyć bezpieczeństwo wdrożenia na 2 sposoby:
- Nie zezwalaj na nieuwierzytelniony dostęp. Warto pozwolić na wypróbowanie tego rozwiązania podczas eksploracji, ale jest to usługa internetowa przeznaczona dla partnerów komercyjnych i powinna zawsze być uwierzytelniana.
- Określ, że aplikacja musi używać dedykowanego konta usługi dostosowanego tylko z wymaganymi uprawnieniami, a nie konta domyślnego, które prawdopodobnie będzie miało większy dostęp do interfejsów API i zasobów, niż jest to konieczne. Jest to zasada jak najmniejszych uprawnień i stanowi podstawową koncepcję bezpieczeństwa aplikacji.
Kroki 6–11. Twórz przykładowe żądania internetowe, aby zweryfikować prawidłowe działanie
Wdrażanie aplikacji wymaga teraz uwierzytelniania, więc żądania te muszą teraz zawierać potwierdzenie tożsamości zgłaszającego. Zamiast modyfikować te pliki, możesz wysyłać żądania bezpośrednio z wiersza poleceń.
4. Bezpieczne wdrażanie usługi
W skrypcie deploy.sh
zidentyfikowano 2 wymagane zmiany: brak zezwolenia na nieuwierzytelniony dostęp oraz użycie dedykowanego konta usługi z minimalnymi uprawnieniami.
Najpierw utwórz nowe konto usługi, zmodyfikuj skrypt deploy.sh
tak, aby się do niego odwoływał i zablokował nieuwierzytelniony dostęp. Następnie wdróż usługę, uruchamiając zmodyfikowany skrypt. Dopiero wtedy będziemy mogli uruchomić zmodyfikowany skrypt deploy.sh.
Utwórz konto usługi i przyznaj mu potrzebny dostęp do Firestore/Datastore
gcloud iam service-accounts create partner-sa
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:partner-sa@${PROJECT_ID}.iam.gserviceaccount.com" \
--role=roles/datastore.user
Edytuj: deploy.sh
Zmodyfikuj plik deploy.sh
tak, aby nie zezwalać na nieuwierzytelniony dostęp(–no-allow-unauthenticated) oraz określić nowe konto usługi (konto usługi) dla wdrożonej aplikacji. Zmień wartość GOOGLE_PROJECT_ID na identyfikator Twojego projektu.
Spowoduje to usunięcie 2 pierwszych wierszy i zmianę trzech pozostałych, tak jak pokazano poniżej.
gcloud run deploy $SERVICE_NAME \
--source . \
--platform managed \
--region ${REGION} \
--no-allow-unauthenticated \
--project=$PROJECT_ID \
--service-account=partner-sa@${PROJECT_ID}.iam.gserviceaccount.com
Wdrażanie usługi
W wierszu poleceń uruchom skrypt deploy.sh
:
./deploy.sh
Po zakończeniu wdrażania w ostatnim wierszu wyniku polecenia wyświetli się adres URL usługi nowej aplikacji. Zapisz adres URL w zmiennej środowiskowej:
export SERVICE_URL=<URL from last line of command output>
Teraz spróbuj pobrać zamówienie z aplikacji za pomocą narzędzia curl
:
curl -i -X GET $SERVICE_URL/partners
Flaga -i
polecenia curl
informuje, że należy uwzględnić nagłówki odpowiedzi w danych wyjściowych. Pierwszy wiersz danych wyjściowych powinien wyglądać tak:
HTTP/2 403
Aplikacja została wdrożona z opcją blokowania nieuwierzytelnionych żądań. To polecenie curl nie zawiera danych uwierzytelniających, więc jest odrzucane przez Cloud Run. Rzeczywista wdrożona aplikacja nie uruchamia nawet żadnych danych z tego żądania ani nie otrzymuje z niego żadnych danych.
5. Tworzenie uwierzytelnionych żądań
Wdrożona aplikacja jest wywoływana przez wysyłanie żądań internetowych, które teraz muszą być uwierzytelniane, aby umożliwić Cloud Run. Żądania sieciowe są uwierzytelniane przez umieszczenie w formularzu nagłówka Authorization
:
Authorization: Bearer
identity-token
Token tożsamości to krótki, podpisany kryptograficznie zakodowany ciąg znaków wystawiony przez zaufanego dostawcę uwierzytelniania. W takim przypadku wymagany jest ważny token tożsamości wydany przez Google.
Prześlij prośbę jako swoje konto użytkownika
Narzędzie Google Cloud CLI może udostępnić token dla domyślnego uwierzytelnionego użytkownika. Uruchom to polecenie, aby uzyskać token tożsamości dla swojego konta i zapisać go w zmiennej środowiskowej ID_TOKEN:
export ID_TOKEN=$(gcloud auth print-identity-token)
Domyślnie tokeny tożsamości wydane przez Google są ważne przez godzinę. Uruchom następujące polecenie curl, aby wysłać żądanie, które zostało wcześniej odrzucone, ponieważ nie było autoryzowane. To polecenie będzie zawierać niezbędny nagłówek:
curl -i -X GET $SERVICE_URL/partners \
-H "Authorization: Bearer $ID_TOKEN"
Dane wyjściowe polecenia powinny zaczynać się od HTTP/2 200
, co oznacza, że żądanie jest akceptowalne i uznawane. Jeśli odczekasz godzinę i spróbujesz ponownie, to żądanie zakończy się niepowodzeniem, ponieważ token utracił ważność. Treść odpowiedzi znajduje się na końcu danych wyjściowych, po pustym wierszu:
{"status":"success","data":[]}
Nie masz jeszcze żadnych partnerów.
Zarejestruj partnerów przy użyciu przykładowych danych JSON w katalogu za pomocą 2 poleceń curl
:
curl -X POST \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d "@example-partner.json" \
$SERVICE_URL/partner
i
curl -X POST \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d "@example-partner2.json" \
$SERVICE_URL/partner
Powtórz wcześniejsze żądanie GET, by wyświetlić teraz wszystkich zarejestrowanych partnerów:
curl -i -X GET $SERVICE_URL/partners \
-H "Authorization: Bearer $ID_TOKEN"
Powinny pojawić się znacznie więcej danych JSON z informacjami o 2 zarejestrowanych partnerach.
Prześlij prośbę jako nieautoryzowane konto
Uwierzytelnione żądanie wysłane w ostatnim kroku zostało zrealizowane nie tylko dlatego, że zostało uwierzytelnione, ale również dlatego, że uwierzytelniono użytkownika (Twoje konto). Oznacza to, że konto miało uprawnienia do wywoływania aplikacji. Nie wszystkie uwierzytelnione konta umożliwiają taką czynność.
Konto domyślne użyte w poprzednim żądaniu zostało autoryzowane, ponieważ to konto utworzyło projekt zawierający aplikację i domyślnie przyznało jej uprawnienia do wywoływania aplikacji Cloud Run na koncie. W razie potrzeby można je anulować – jest to bardzo przydatne w aplikacji produkcyjnej. Zamiast tego utworzysz nowe konto usługi bez przypisanych do niego uprawnień ani ról i użyjesz go, aby spróbować uzyskać dostęp do wdrożonej aplikacji.
- Utwórz konto usługi o nazwie
tester
.
gcloud iam service-accounts create tester
- Otrzymasz token tożsamości dla tego nowego konta w taki sam sposób jak token tożsamości na koncie domyślnym. Wymaga to jednak, aby konto domyślne miało uprawnienia do odgrywania ról kont usługi. Przyznaj swojemu kontu to uprawnienie.
export USER_EMAIL=$(gcloud config list account --format "value(core.account)")
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="user:$USER_EMAIL" \
--role=roles/iam.serviceAccountTokenCreator
- Teraz uruchom poniższe polecenie, aby zapisać token tożsamości dla tego nowego konta w zmiennej środowiskowej TEST_IDENTITY. Jeśli polecenie wyświetli komunikat o błędzie, odczekaj minutę lub dwie i spróbuj ponownie.
export TEST_TOKEN=$( \
gcloud auth print-identity-token \
--impersonate-service-account \
"tester@$PROJECT_ID.iam.gserviceaccount.com" \
)
- Utwórz uwierzytelnione żądanie internetowe tak jak poprzednio, ale przy użyciu tego tokena tożsamości:
curl -i -X GET $SERVICE_URL/partners \
-H "Authorization: Bearer $TEST_TOKEN"
Dane wyjściowe polecenia będą ponownie rozpoczynać się od HTTP/2 403
, ponieważ żądanie, choć jest uwierzytelnione, nie jest autoryzowane. Nowe konto usługi nie ma uprawnień do wywoływania tej aplikacji.
Autoryzowanie konta
Użytkownik lub konto usługi musi mieć przypisaną w usłudze Cloud Run rolę wywołującego Cloud Run, aby można było wysyłać do niej żądania. Przypisz do konta usługi testera tę rolę za pomocą polecenia:
export REGION=us-central1
gcloud run services add-iam-policy-binding ${SERVICE_NAME} \
--member="serviceAccount:tester@$PROJECT_ID.iam.gserviceaccount.com" \
--role=roles/run.invoker \
--region=${REGION}
Po odczekaniu minut lub dwóch na zaktualizowanie nowej roli powtórz uwierzytelnione żądanie. Zapisz nowy test TEST_TOKEN, jeśli od jego pierwszego zapisu co najmniej godzina minęła.
curl -i -X GET $SERVICE_URL/partners \
-H "Authorization: Bearer $TEST_TOKEN"
Wynik polecenia zaczyna się teraz od HTTP/1.1 200 OK
, a ostatni wiersz zawiera odpowiedź JSON. To żądanie zostało zaakceptowane przez Cloud Run i przetworzone przez aplikację.
6. Uwierzytelnianie programów a uwierzytelnianie użytkowników
Utworzone do tej pory uwierzytelnione żądania używały narzędzia wiersza poleceń curl
. Istnieją inne narzędzia i języki programowania, których można użyć zamiast nich. Jednak uwierzytelnionych żądań Cloud Run nie można wysyłać za pomocą przeglądarki ze zwykłymi stronami internetowymi. Jeśli użytkownik kliknie link lub przycisk, aby przesłać formularz na stronie internetowej, przeglądarka nie doda nagłówka Authorization
wymaganego przez Cloud Run dla żądań uwierzytelnionych.
Wbudowany mechanizm uwierzytelniania Cloud Run jest przeznaczony do użytku przez programy, a nie użytkowników.
Uwaga:
Cloud Run może hostować aplikacje internetowe dla użytkowników, ale tego typu aplikacje muszą zezwalać na żądania nieuwierzytelnione przeglądarek. Jeśli aplikacje wymagają uwierzytelniania użytkownika, muszą obsługiwać to narzędzie, a nie Cloud Run. Możesz to robić w taki sam sposób jak aplikacje internetowe spoza Cloud Run. Nie obejmuje to tego ćwiczenia.
Jak widzisz, do tej pory odpowiedzi na przykładowe żądania były obiektami JSON, a nie stronami internetowymi. Wynika to z faktu, że ta usługa rejestracji partnera jest przeznaczona dla programów, a format JSON jest dla nich wygodny w użyciu. Następnie napisz i uruchomisz program do przetwarzania i wykorzystywania tych danych.
Uwierzytelnione żądania z programu w Pythonie
Program może wysyłać uwierzytelnione żądania do zabezpieczonej aplikacji Cloud Run za pomocą standardowych żądań sieciowych HTTP, ale zawierających nagłówek Authorization
. Jedynym nowym wyzwaniem dla tych programów jest uzyskanie ważnego, ważnego tokena tożsamości do umieszczenia w nagłówku. Ten token zostanie zweryfikowany przez Cloud Run za pomocą usługi Google Cloud Identity and Access Management (IAM), więc token musi zostać wystawiony i podpisany przez urząd rozpoznawany przez uprawnienia. Istnieją biblioteki klienckie w wielu językach, których programy mogą używać do żądania wystawienia takiego tokena. Biblioteka klienta, której użyjemy w tym przykładzie, to Python google.auth
. Istnieje kilka bibliotek Pythona do ogólnych żądań sieciowych; w tym przykładzie wykorzystano popularny moduł requests
.
Pierwszym krokiem jest zainstalowanie 2 bibliotek klienta:
pip install google-auth
pip install requests
Kod Pythona do żądania tokena tożsamości dla użytkownika domyślnego to:
credentials, _ = google.auth.default()
credentials.refresh(google.auth.transport.requests.Request())
identity_token = credentials.id_token
Jeśli na swoim komputerze używasz powłoki poleceń, takiej jak Cloud Shell lub standardowej powłoki terminala, domyślnym użytkownikiem jest ten, który uwierzytelnił się w tej powłoce. W Cloud Shell jest to zwykle użytkownik zalogowany w Google. W innych przypadkach jest to konto, którego użytkownik uwierzytelnił za pomocą gcloud auth login
lub innego polecenia gcloud
. Jeśli użytkownik nigdy się nie logował, nie będzie użytkownika domyślnego, a kod zadziała nie tak.
W przypadku programu wysyłającego żądania do innego programu zwykle nie chcesz używać tożsamości osoby, tylko tożsamości programu wysyłającego prośbę. Właśnie do tego służą konta usługi. Wdrożyłeś usługę Cloud Run za pomocą dedykowanego konta usługi, które zapewnia tożsamość używaną przy wysyłaniu żądań do interfejsu API, takich jak Cloud Firestore. Gdy program działa na platformie Google Cloud, biblioteki klienta automatycznie używają przypisanego do niego konta usługi jako domyślnej tożsamości, więc ten sam kod programu działa w obu sytuacjach.
Kod w Pythonie umożliwiający wysłanie żądania z dodanym nagłówkiem autoryzacji:
auth_header = {"Authorization": "Bearer " + identity_token}
response = requests.get(url, headers=auth_header)
Ten kompletny program w Pythonie wyśle uwierzytelnione żądanie do usługi Cloud Run, aby pobrać wszystkich zarejestrowanych partnerów, a następnie wydrukować ich nazwy i przypisane identyfikatory. Skopiuj i uruchom poniższe polecenie, aby zapisać ten kod w pliku print_partners.py
.
cat > ./print_partners.py << EOF
def print_partners():
import google.auth
import google.auth.transport.requests
import requests
credentials, _ = google.auth.default()
credentials.refresh(google.auth.transport.requests.Request())
identity_token = credentials.id_token
auth_header = {"Authorization": "Bearer " + identity_token}
response = requests.get("${SERVICE_URL}/partners", headers=auth_header)
parsed_response = response.json()
partners = parsed_response["data"]
for partner in partners:
print(f"{partner['partnerId']}: {partner['name']}")
print_partners()
EOF
Uruchomisz ten program poleceniem powłoki. Musisz najpierw uwierzytelnić się jako użytkownik domyślny, aby program mógł korzystać z tych danych. Uruchom to polecenie gcloud auth:
gcloud auth application-default login
Postępuj zgodnie z instrukcjami, aby dokończyć logowanie. Następnie uruchom program z poziomu wiersza poleceń:
python print_partners.py
Dane wyjściowe będą wyglądały mniej więcej tak:
10102: Zippy food delivery
67292: Foodful
Żądanie programu dotarło do usługi Cloud Run, ponieważ zostało uwierzytelnione za pomocą Twojej tożsamości, a Ty jesteś właścicielem tego projektu i dlatego masz uprawnienia do jego domyślnie uruchamiania. Bardziej typowe byłoby, aby ten program działał w ramach tożsamości konta usługi. W przypadku większości usług Google Cloud, takich jak Cloud Run czy App Engine, tożsamością domyślną jest konto usługi, które jest używane zamiast konta osobistego.
7. Gratulacje!
Gratulacje. Udało Ci się ukończyć ćwiczenia z programowania.
Co dalej:
Poznaj inne ćwiczenia z programowania Cymbal Eats:
- Aktywowanie przepływów pracy w Cloud za pomocą Eventarc
- Aktywowanie przetwarzania zdarzeń z Cloud Storage
- Łączenie z Private Cloud SQL z poziomu Cloud Run
- Łączenie z w pełni zarządzanymi bazami danych z Cloud Run
- Bezpieczna aplikacja bezserwerowa z serwerem proxy identyfikującym tożsamość (IAP)
- Aktywowanie zadań Cloud Run za pomocą usługi Cloud Scheduler
- Zabezpieczanie ruchu przychodzącego w Cloud Run
- Łączenie z prywatnym AlloyDB z Autopilota w GKE
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.
Usuwam projekt
Najprostszym sposobem na uniknięcie płatności jest usunięcie projektu utworzonego na potrzeby samouczka.