
Zgadza się, po premierze na początku maja 2019 roku w Consul można natywnie autoryzować aplikacje i usługi uruchomione w Kubernetes.
W tym podręczniku krok po kroku stworzymy (Proof of concept, PoC — dowód [wykonalności] koncepcji — przyp. red.), demonstrując tę nową funkcję. Oczekuje się, że będziesz mieć podstawową wiedzę o Kubernetes i Hashicorp’s Consul. Chociaż możesz używać dowolnej platformy chmurowej lub lokalnego środowiska, w tym podręczniku będziemy używać Google’s Cloud Platform.
Przegląd
Jeśli przejdziemy do , uzyskamy krótki przegląd jego zastosowań i przypadków użycia, a także szczegóły techniczne i ogólny zarys logiki. Zdecydowanie zalecam zapoznanie się z nią przynajmniej raz, zanim przejdziesz dalej, ponieważ teraz wszystko to wyjaśnię i rozwinę.

Schemat 1: Oficjalny przegląd metody autoryzacji Consul
Przyjrzyjmy się .
Oczywiście, znajdują się tam przydatne informacje, ale brakuje przewodnika, jak tak naprawdę to wszystko wykorzystać. Dlatego, jak każdy rozsądny człowiek, przeszukujesz Internet w poszukiwaniu poradnika. A potem… ponosisz porażkę. Tak bywa. Naprawmy to.
Zanim przejdziemy do tworzenia naszego POC, wróćmy do przeglądu metod autoryzacji Consul (Schemat 1) i wyjaśnijmy go w kontekście Kubernetes.
Architektura
W tym podręczniku stworzymy serwer Consul na oddzielnej maszynie, który będzie współdziałać z klastrem Kubernetes z zainstalowanym klientem Consul. Następnie stworzymy nasze fikcyjne aplikacje w podzie i użyjemy naszego skonfigurowanego sposobu autoryzacji do odczytu z naszego magazynu kluczy/wartości Consul.
Schemat poniżej szczegółowo przedstawia architekturę, którą tworzymy w tym podręczniku, a także logikę metody autoryzacji, która zostanie wyjaśniona później.

Schemat 2: Przegląd metody autoryzacji w Kubernetes
Mała uwaga: Serwer Consul nie musi znajdować się poza klastrem Kubernetes, aby to działało. Tak, może być zarówno w klastrze, jak i poza nim.
A więc, biorąc przeglądowy schemat Consul (Schemat 1) i stosując go do Kubernetes, uzyskujemy powyższy schemat (Schemat 2), a logika będzie następująca:
- Do każdego poda będzie dołączone konto służbowe, zawierające token JWT, wygenerowany i znany Kubernetes. Ten token również jest domyślnie wstawiany do poda.
- Nasza aplikacja lub usługa wewnątrz poda inicjuje polecenie logowania do naszego klienta Consul. W żądaniu logowania podany będzie również nasz token oraz nazwa specjalnie utworzonego metody autoryzacji (typu Kubernetes). Ten krok nr 2 odpowiada krokowi 1 schematu Consul (Schemat 1).
- Nasz klient Consul następnie kieruje to żądanie do naszego serwera Consul.
- MAGIA! Tutaj serwer Consul weryfikuje autentyczność żądania, gromadzi informacje o tożsamości żądania i porównuje je z jakimikolwiek powiązanymi z góry określonymi zasadami. Poniżej przedstawimy inny schemat, aby to zilustrować. Ten krok odpowiada krokom 3, 4 i 5 przeglądowego schematu Consul (Schemat 1).
- Nasz serwer Consul generuje token Consul z uprawnieniami zgodnie z określonymi przez nas zasadami metody autoryzacji (które zdefiniowaliśmy) w odniesieniu do tożsamości żądającego. Następnie wysyła ten token z powrotem. To odpowiada krokowi 6 schematu Consul (Schemat 1).
- Nasz klient Consul przekazuje token żądającej aplikacji lub usłudze.
Nasza aplikacja lub usługa może teraz użyć tego tokena Consul do komunikacji z naszymi danymi Consul, zgodnie z uprawnieniami tokena.
Magia ujawniona!
Dla tych z was, którzy nie zadowalają się jedynie króliczkiem z kapelusza i chcą wiedzieć, jak to działa… pozwólcie mi 'pokazać, jak głęboka nora królika».
Jak już wcześniej wspomniano, nasz 'magiczny' krok (Schemat 2: Krok 4) polega na tym, że serwer Consul weryfikuje autentyczność żądania, gromadzi informacje o żądaniu i porównuje je z jakimikolwiek powiązanymi z góry określonymi zasadami. Ten krok odpowiada krokom 3, 4 i 5 przeglądowego schematu Consul (Schemat 1). Poniżej przedstawiamy schemat (Schemat 3), którego celem jest zobrazowanie, co tak naprawdę się dzieje pod zamknięciem konkretnej metody autoryzacji Kubernetes.

Schemat 3: Magia ujawniona!
- Jako punkt wyjścia, nasz klient Consul kieruje żądanie logowania do naszego serwera Consul z tokenem konta Kubernetes i konkretną nazwą instancji metody autoryzacji, która została wcześniej utworzona. Ten krok odpowiada krokowi 3 w poprzednim wyjaśnieniu schematu.
- Teraz serwer Consul (lub lider) musi uwierzytelnić otrzymany token. W tym celu skonsultuje się z klastrem Kubernetes (przez klienta Consul) i, przy odpowiednich uprawnieniach, ustalimy, czy token jest autentyczny oraz do kogo należy.
- Następnie zweryfikowane zapytanie wraca do lidera Consul, a na serwerze Consul wykonywane jest wyszukiwanie instancji metody autoryzacji o określonej nazwie z żądania logowania (i typu Kubernetes).
- Lider Consul identyfikuje wskazaną instancję metody autoryzacji (jeśli zostanie znaleziona) i odczytuje zestaw reguł przypisanych do niej. Następnie czyta te reguły i porównuje je z zweryfikowanymi atrybutami tożsamości.
- Tada! Przechodzimy do kroku 5 we wcześniejszym wyjaśnieniu schematu.
Uruchom serwer Consul na zwykłej maszynie wirtualnej.
Od tego momentu głównie będę podawał instrukcje dotyczące tworzenia tego POC, często w punktach, bez wyjaśniających całych zdań. Jak już wcześniej wspomniano, użyję GCP do stworzenia całej infrastruktury, ale możesz stworzyć podobną infrastrukturę w innym miejscu.
- Uruchom maszynę wirtualną (instancję / serwer).

- Utwórz regułę dla zapory sieciowej (grupa zabezpieczeń w AWS):
- Lubię przypisywać tę samą nazwę maszyny do reguły i tagu sieciowego, w tym przypadku to 'skywiz-consul-server-poc'.
- Znajdź adres IP swojego lokalnego komputera i dodaj go do listy dozwolonych adresów IP, abyśmy mogli uzyskać dostęp do interfejsu użytkownika (UI).
- Otwórz port 8500 dla UI. Kliknij Create (Utwórz). Wkrótce ponownie zmienimy tę zaporę [].
- Dodaj regułę dla zapory sieciowej do instancji. Wróć na panel monitorowania VM na serwerze Consul i dodaj 'skywiz-consul-server-poc' w polu tagów sieciowych. Kliknij Save (Zapisz).

- Zainstaluj Consul na maszynie wirtualnej, sprawdź tutaj. Pamiętaj, że potrzebujesz wersji Consul ≥ 1.5 [link]
- Utworzymy pojedynczy węzeł Consul — konfiguracja wygląda następująco.
groupadd --system consul
useradd -s /sbin/nologin --system -g consul consul
mkdir -p /var/lib/consul
chown -R consul:consul /var/lib/consul
chmod -R 775 /var/lib/consul
mkdir /etc/consul.d
chown -R consul:consul /etc/consul.d- Szczegółowy przewodnik dotyczący instalacji Consul i konfiguracji klastra z 3 węzłami znajdziesz tu. .
- Utwórz plik /etc/consul.d/agent.json w następujący sposób []:
### /etc/consul.d/agent.json
{
"acl" : {
"enabled": true,
"default_policy": "deny",
"enable_token_persistence": true
}
}- Uruchom nasz serwer Consul:
consul agent
-server
-ui
-client 0.0.0.0
-data-dir=/var/lib/consul
-bootstrap-expect=1
-config-dir=/etc/consul.d- Powinieneś zobaczyć mnóstwo danych wyjściowych, a w końcu „… update blocked by ACLs”.
- Znajdź zewnętrzny adres IP serwera Consul i otwórz przeglądarkę z tym adresem IP na porcie 8500. Upewnij się, że interfejs użytkownika jest dostępny.
- Spróbuj dodać parę klucz/wartość. Powinien wystąpić błąd. To dlatego, że załadowaliśmy serwer Consul z użyciem ACL i zablokowaliśmy wszelkie reguły.
- Wróć do swojego terminala na serwerze Consul i uruchom proces w tle lub w inny sposób, aby działał, a następnie wprowadź to:
consul acl bootstrap- Znajdź wartość „SecretID” i wróć do interfejsu użytkownika. Na karcie „ACL” wprowadź sekretny identyfikator tokena, który właśnie skopiowałeś. Skopiuj SecretID gdzie indziej, będzie nam potrzebny później.
- Teraz dodaj parę klucz/wartość. Dla tego POC dodamy następujące: klucz: „custom-ns/test_key”, wartość: „Jestem w folderze custom-ns!”
Uruchamianie klastra Kubernetes dla naszej aplikacji z klientem Consul jako Daemonset.
- Utwórz klaster K8s (Kubernetes). Stworzymy go w tej samej strefie co serwer, aby uzyskać szybszy dostęp, dlatego możemy użyć tej samej podsieci do łatwego połączenia z wewnętrznymi adresami IP. Nazwiemy go „skywiz-app-with-consul-client-poc”.

- Jako przypomnienie, oto dobre wskazówki, które znalazłem podczas konfigurowania POC klastra Consul z Consul Connect.
- Będziemy także korzystać z wykresu Helm Hashicorp z rozszerzonym plikiem wartości.
- Zainstaluj i skonfiguruj Helm. Kroki konfiguracyjne:
kubectl create serviceaccount tiller --namespace kube-system
kubectl create clusterrolebinding tiller-admin-binding
--clusterrole=cluster-admin --serviceaccount=kube-system:tiller
. /helm init --service-account=tiller
. /helm update- helm chart:
- Użyj następującego pliku wartości (zauważ, że większość wyłączyłem):
### poc-helm-consul-values.yaml
global:
enabled: false
image: "consul:latest"
# Expose the Consul UI through this LoadBalancer
ui:
enabled: false
# Allow Consul to inject the Connect proxy into Kubernetes containers
connectInject:
enabled: false
# Configure a Consul client on Kubernetes nodes. GRPC listener is required for Connect.
client:
enabled: true
join: ["<PRIVATE_IP_CONSUL_SERVER>"]
extraConfig: |
{
"acl" : {
"enabled": true,
"default_policy": "deny",
"enable_token_persistence": true
}
}
# Minimal Consul configuration. Not suitable for production.
server:
enabled: false
# Sync Kubernetes and Consul services
syncCatalog:
enabled: false- Zastosuj wykres helm:
. /helm install -f poc-helm-consul-values.yaml . /consul-helm - name skywiz-app-with-consul-client-poc- Przy próbie uruchomienia, będą potrzebne uprawnienia dla serwera Consul, więc dodajmy je.
- Zwróć uwagę na „zakres adresów podów” znajdujący się na pulpicie nawigacyjnym klastra i wróć do naszej reguły dla zapory „skywiz-consul-server-poc”.
- Dodaj zakres adresów dla podów do listy adresów IP i otwórz porty 8301 oraz 8300.

- Przejdź do interfejsu użytkownika Consul, a po kilku minutach zobaczysz, że nasz klaster pojawi się na zakładce węzłów.

Konfiguracja metody autoryzacji poprzez integrację Consul z Kubernetes.
- Wróć do terminala serwera Consul i wyeksportuj token, który wcześniej zapisałeś:
export CONSUL_HTTP_TOKEN=- Będziemy potrzebować informacji z naszego klastra Kubernetes, aby utworzyć instancję metody auth:
- kubernetes-host
kubectl get endpoints | grep kubernetes- kubernetes-service-account-jwt
kubectl get sa -consul-client -o yaml | grep "- name:"
kubectl get secret -o yaml | grep token:- Token jest zakodowany w base64, więc zdekoduj go przy użyciu ulubionego narzędzia []
- kubernetes-ca-cert
kubectl get secret -o yaml | grep ca.crt:- Pobierz certyfikat „ca.crt” (po dekodowaniu z base64) i wpisz go do pliku „ca.crt”.
- Teraz utwórz instancję metody auth, zastępując miejsca na dane wartościami, które właśnie otrzymałeś.
consul acl auth-method create
-type "kubernetes"
-name "auth-method-skywiz-consul-poc"
-description "To jest metoda autoryzacji używająca kubernetes dla klastra skywiz-app-with-consul-client-poc"
-kubernetes-host ""
-kubernetes-ca-cert=@ca.crt
-kubernetes-service-account-
jwt=""- Następnie musimy utworzyć regułę i powiązać ją z nową rolą. W tej części możesz użyć interfejsu użytkownika Consul, ale my użyjemy wiersza poleceń.
- Napisz regułę
### kv-custom-ns-policy.hcl
key_prefix "custom-ns/" {
policy = "write"
}- Zastosuj regułę
consul acl policy create
-name kv-custom-ns-policy
-description "To jest przykładowa polityka dla kv w custom-ns/"
-rules @kv-custom-ns-policy.hcl- Znajdź identyfikator reguły, którą właśnie utworzyłeś, w danych wyjściowych.
- Utwórz rolę z nową regułą.
consul acl role create
-name "custom-ns-role"
-description "To jest przykładowa rola dla przestrzeni nazw custom-ns"
-policy-id- Teraz powiążemy naszą nową rolę z instancją metody auth. Zauważ, że flaga „selector” określa, czy nasza żądanie dostępu otrzyma tę rolę. Sprawdź inne opcje selektora tutaj:
consul acl binding-rule create
-method=auth-method-skywiz-consul-poc
-bind-type=role
-bind-name='custom-ns-role'
-selector='serviceaccount.namespace=="custom-ns"'Konfiguracje na koniec
Prawa dostępu
- Utwórz uprawnienia. Musimy dać Consul pozwolenie na weryfikację i identyfikację poświadczenia tokena konta usługi K8s.
- Zapisz w pliku następujące :
###skywiz-poc-consul-server_rbac.yaml
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: review-tokens
namespace: default
subjects:
- kind: ServiceAccount
name: skywiz-app-with-consul-client-poc-consul-client
namespace: default
roleRef:
kind: ClusterRole
name: system:auth-delegator
apiGroup: rbac.authorization.k8s.io
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: service-account-getter
namespace: default
rules:
- apiGroups: [""]
resources: ["serviceaccounts"]
verbs: ["get"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: get-service-accounts
namespace: default
subjects:
- kind: ServiceAccount
name: skywiz-app-with-consul-client-poc-consul-client
namespace: default
roleRef:
kind: ClusterRole
name: service-account-getter
apiGroup: rbac.authorization.k8s.io- Utwórz uprawnienia
kubectl create -f skywiz-poc-consul-server_rbac.yamlPołączenie z Consul Client
- Jak wspomniano , istnieje kilka opcji połączenia z daemonset, ale przejdziemy do następnego prostego rozwiązania:
- Zastosuj następujący plik [].
### poc-consul-client-ds-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: consul-ds-client
spec:
selector:
app: consul
chart: consul-helm
component: client
hasDNS: "true"
release: skywiz-app-with-consul-client-poc
ports:
- protocol: TCP
port: 80
targetPort: 8500- Następnie zastosuj następującą wbudowaną komendę, aby utworzyć configmap []. Zauważ, że odwołujemy się do nazwy naszego serwisu, zastąp go w razie potrzeby.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
labels:
addonmanager.kubernetes.io/mode: EnsureExists
name: kube-dns
namespace: kube-system
data:
stubDomains: |
{"consul": ["$(kubectl get svc consul-ds-client -o jsonpath='{.spec.clusterIP}')"]}
EOFTestowanie metody autoryzacji
Teraz przyjrzyjmy się magii w akcji!
- Stwórz jeszcze kilka kluczowych folderów z tym samym kluczem na najwyższym poziomie (tzn. /sample_key) i wartością według własnego wyboru. Utwórz odpowiednie polityki i role dla nowych kluczowych ścieżek. Powiązania zrobimy później.

Test użytkownika przestrzeni nazw:
- Stwórzmy naszą własną przestrzeń nazw:
kubectl create namespace custom-ns- Stwórzmy pod w naszej nowej przestrzeni nazw. Napisz konfigurację dla poda.
###poc-ubuntu-custom-ns.yaml
apiVersion: v1
kind: Pod
metadata:
name: poc-ubuntu-custom-ns
namespace: custom-ns
spec:
containers:
- name: poc-ubuntu-custom-ns
image: ubuntu
command: ["/bin/bash", "-ec", "sleep infinity"]
restartPolicy: Never- Utwórz pod:
kubectl create -f poc-ubuntu-custom-ns.yaml- Jak tylko kontener się uruchomi, wejdź tam i zainstaluj curl.
kubectl exec poc-ubuntu-custom-ns -n custom-ns -it /bin/bash
apt-get update && apt-get install curl -y- Teraz wyślemy żądanie logowania do Consul, używając metody autoryzacji, którą wcześniej stworzyliśmy [].
- Aby wyświetlić wprowadzony token z konta usługi:
cat /run/secrets/kubernetes.io/serviceaccount/token- Napisz następujące w pliku wewnątrz kontenera:
### payload.json
{
"AuthMethod": "auth-method-test",
"BearerToken": "<jwt_token>"
}- Login!
curl
--request POST
--data @payload.json
consul-ds-client.default.svc.cluster.local/v1/acl/login- Aby wykonać powyższe kroki w jednej linii (ponieważ wykonamy kilka testów), możemy zrobić to w ten sposób:
echo "{
"AuthMethod": "auth-method-skywiz-consul-poc",
"BearerToken": "$(cat /run/secrets/kubernetes.io/serviceaccount/token)"
}"
| curl
--request POST
--data @-
consul-ds-client.default.svc.cluster.local/v1/acl/login- Działa! Przynajmniej powinno. Teraz weź SecretID i spróbuj uzyskać dostęp do klucza/wartości, do której powinniśmy mieć dostęp.
curl
consul-ds-client.default.svc.cluster.local/v1/kv/custom-ns/test_key --header “X-Consul-Token: ”- Możesz zdekodować „Value” base64 i zobaczyć, że odpowiada wartość w custom-ns/test_key w UI. Jeśli użyłeś tej samej wartości podanej powyżej w tym przewodniku, twoja wartość zakodowana będzie IkknbSBpbiB0aGUgY3VzdG9tLW5zIGZvbGRlciEi.
Test konta użytkownika usługi:
- Utwórz konto użytkownika ServiceAccount przy użyciu następującej komendy [].
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: custom-sa
EOF- Utwórz nowy plik konfiguracyjny dla poda. Zauważ, że dodałem instalację curl dla ułatwienia pracy 🙂
###poc-ubuntu-custom-sa.yaml
apiVersion: v1
kind: Pod
metadata:
name: poc-ubuntu-custom-sa
namespace: default
spec:
serviceAccountName: custom-sa
containers:
- name: poc-ubuntu-custom-sa
image: ubuntu
command: ["/bin/bash","-ec"]
args: ["apt-get update && apt-get install curl -y; sleep infinity"]
restartPolicy: Never- Po tym uruchom powłokę wewnątrz kontenera.
kubectl exec -it poc-ubuntu-custom-sa /bin/bash- Login!
echo "{
"AuthMethod": "auth-method-skywiz-consul-poc",
"BearerToken": "$(cat /run/secrets/kubernetes.io/serviceaccount/token)"
}"
| curl
--request POST
--data @-
consul-ds-client.default.svc.cluster.local/v1/acl/login- Odmowa dostępu. O, zapomnieliśmy dodać nową regułę z odpowiednimi uprawnieniami, zróbmy to teraz.
Powtórz poprzednie kroki:
a) Utwórz identyczną Politykę dla prefiksu „custom-sa/”.
b) Utwórz Rolę i nazwij ją „custom-sa-role”.
c) Przypisz Politykę do Roli.
- Utwórz Rule-Binding (możliwe tylko z cli/api). Zauważ inne wartości flagi selektora.
consul acl binding-rule create
-method=auth-method-skywiz-consul-poc
-bind-type=role
-bind-name='custom-sa-role'
-selector='serviceaccount.name=="custom-sa"'- Powtórz logowanie z kontenera „poc-ubuntu-custom-sa”. Sukces!
- Sprawdźmy nasz dostęp do kluczowej ścieżki custom-sa/.
curl
consul-ds-client.default.svc.cluster.local/v1/kv/custom-sa/test_key --header “X-Consul-Token: ”- Możesz także upewnić się, że ten token nie daje dostępu do kv w „custom-ns/”. Po prostu powtórz powyższe polecenie, zamieniając „custom-sa” na prefiks „custom-ns”.
Odmowa dostępu.
Przykład owerleya:
- Warto zauważyć, że wszystkie powiązania rule-binding będą dodane do tokenu z tymi uprawnieniami.
- Nasz kontener „poc-ubuntu-custom-sa” jest w domyślnej przestrzeni nazw — użyjmy go dla innego rule-binding.
- Powtórz poprzednie kroki:
a) Utwórz identyczną Politykę dla prefiksu klucza „default/”.
b) Utwórz Rolę i nazwij ją “default-ns-role”.
c) Przypisz Politykę do Roli. - Utwórz Rule-Binding (możliwe tylko z cli/api)
consul acl binding-rule create
-method=auth-method-skywiz-consul-poc
-bind-type=role
-bind-name='default-ns-role'
-selector='serviceaccount.namespace=="default"'- Wróć do naszego kontenera „poc-ubuntu-custom-sa” i spróbuj uzyskać dostęp do ścieżki „default/” kv.
- Odmowa dostępu.
Możesz przeglądać przypisane poświadczenia dla każdego tokenu w interfejsie użytkownika w sekcji ACL > Tokens. Jak widać, do naszego aktualnego tokenu przypisana jest tylko jedna „custom-sa-role”. Token, którego obecnie używamy, został wygenerowany, gdy logowaliśmy się, a wówczas istniał tylko jeden rule-binding, który odpowiadał. Musimy się ponownie zalogować i użyć nowego tokenu. - Upewnij się, że możesz czytać zarówno z ścieżek „custom-sa/”, jak i „default/” kv.
Sukces!
To wynika z tego, że nasz „poc-ubuntu-custom-sa” odpowiada powiązaniom reguł „custom-sa” i „default-ns”.
Podsumowanie
Zarządzanie TTL tokenów?
W momencie pisania tego artykułu nie ma zintegrowanego sposobu na określenie TTL dla tokenów generowanych tą metodą autoryzacji. Byłaby to fantastyczna możliwość — zapewnić bezpieczną automatyzację autoryzacji w Consul.
Istnieje możliwość ręcznego utworzenia tokenu z TTL:
Czas wygaśnięcia (Expiration Time) — moment, kiedy ten token zostanie unieważniony. (Opcjonalnie; dodane w Consul 1.5.0)- Dostępne tylko do ręcznego tworzenia / aktualizacji
Mam nadzieję, że wkrótce będziemy mogli kontrolować, jak są generowane tokeny (dla każdej reguły lub metody autoryzacji) i dodawać TTL.
Do tego czasu zaleca się wykorzystanie w swojej logice końcowego punktu wyjścia.
Przeczytaj również inne artykuły na naszym blogu:
Źródło: habr.com
