Jak czytać to kompendium
opcje, nie rankingTo nie jest lista „najlepszych narzędzi”. Każda opcja tutaj działa w produkcji u kogoś dużego. Różnią się tym, co poświęcają: spójność za dostępność, prostotę za elastyczność, wygodę za mniejszą powierzchnię ataku. Twoje zadanie: rozpoznać, który trade-off pasuje do Twojego systemu.
Każda opcja ma ten sam układ: flow (klikalny diagram sekwencji — kto do kogo i po co), box 🔒 Dlaczego to bezpieczne (uwierzytelnienie, autoryzacja, transport, co się dzieje przy awarii) i tabelę trade-offów. Poziomy: L1 podstawy, L2 praktyk, L3 ekspert. Przełącznik głębokości jest w lewym dolnym rogu.
Autoskaler startuje nowego poda o 3:12 w nocy. Po kilku sekundach pod obsługuje ruch, zna adres bazy, ma właściwe limity i loguje się do bazy hasłem, którego nie zna żaden człowiek. Skąd on to wszystko wie — i dlaczego atakujący, który ukradnie obraz kontenera, nie wie nic? Odpowiedź na końcu.
Trzy pytania każdego serwisu
gdzie są inni · jak mam działać · czym się uwierzytelnićMonolit miał jeden plik konfiguracyjny i jedną bazę. 300 mikroserwisów w kilku regionach ma inne życie: instancje rodzą się i umierają co chwilę (autoskaling, deploy, awaria węzła), a każda dostaje nowy adres IP. Plik z listą adresów jest nieaktualny, zanim go zapiszesz.
Dlatego każdy serwis w dużym systemie potrzebuje trzech mechanizmów:
| Pytanie | Mechanizm | Jak często zmienia się odpowiedź |
|---|---|---|
Gdzie jest serwis orders? | Service discovery | Sekundy (instancje się zmieniają) |
| Jaki mam timeout, limit, flagę? | Konfiguracja | Minuty–dni (zmiany ludzi) |
| Jakim hasłem/kluczem/certyfikatem się uwierzytelnić? | Sekrety i tożsamość | Godziny–dni (rotacja), idealnie: krótko żyjące |
▶ Pierwszy dzień
- zapisz 10.0.1.7Ktoś wpisuje adres serwisu B do pliku konfiguracyjnego serwisu A.
- czytaj przy starcieSerwis A czyta plik raz, przy starcie.
- GET /ordersDziała — B rzeczywiście jest pod 10.0.1.7.
💥 Autoskaling w nocy
- węzeł znikaWęzeł z instancją B pada. Orkiestrator uruchamia B gdzie indziej.
- B pod 10.0.9.3Nowa instancja B dostaje nowy adres. Plik o tym nie wie.
- GET /ordersA dalej strzela w stary adres: timeout. Ktoś musi ręcznie zmienić plik i zrestartować A.
- potrzebny rejestrWniosek: adres trzeba odkrywać w chwili wywołania, z miejsca, które śledzi żywe instancje. To jest service discovery.
- Adresy, konfiguracja i sekrety zmieniają się w różnym tempie — dlatego zwykle obsługują je różne systemy.
- Dobre rozwiązanie odpowiada w chwili użycia, a nie w chwili budowania obrazu.
Service discovery
Od DNS, przez rejestry CP i AP, Kubernetes i service mesh, po usługi chmurowe i rozwiązania hyperscalerów.
Dwa wzorce odkrywania, dwa wzorce rejestracji
kto pyta rejestr i kto go aktualizujeKażde narzędzie z tej części to kombinacja dwóch decyzji. Pierwsza: kto pyta rejestr. W client-side discovery klient sam pobiera listę instancji i sam wybiera jedną (load balancing w kliencie). W server-side discovery klient wysyła żądanie do routera lub load balancera, a ten pyta rejestr i przekazuje ruch.
Druga: kto aktualizuje rejestr. W self-registration instancja sama się rejestruje i wysyła heartbeat. W third-party registration robi to zewnętrzny komponent, który obserwuje środowisko (np. orkiestrator). Te nazwy wzorców spopularyzował katalog microservices.io Chrisa Richardsona.
▶ Client-side
- rejestruję sięInstancja (albo platforma za nią) wpisuje swój adres do rejestru.
- lista instancji?Klient pyta rejestr o instancje serwisu i trzyma wynik w cache.
- wybór instancjiKlient sam wybiera instancję (round robin, least requests, strefa). Logika jest w bibliotece lub sidecarze.
- żądanie bezpośrednioRuch idzie prosto do instancji — bez dodatkowego hopu.
▶ Server-side
- rejestracjaInstancja trafia do rejestru (najczęściej robi to platforma: third-party registration).
- żądanie na stały adresKlient zna tylko jeden stabilny adres (DNS load balancera lub wirtualny IP).
- kto żyje?Load balancer zna zdrowe instancje z rejestru lub własnych health checków.
- przekazanieLoad balancer przekazuje żądanie. Klient może być „głupi” i w dowolnym języku.
| Wzorzec | Zyskujesz | Płacisz |
|---|---|---|
| Client-side | brak hopu, sprytny load balancing (strefy, retry) | biblioteka per język albo sidecar; klient musi znać rejestr |
| Server-side | klient prosty, niezależny od języka | dodatkowy hop i komponent do skalowania |
| Self-registration | prosto, instancja wie, kiedy jest gotowa | kod rejestracji w każdym serwisie; martwa instancja nie wyrejestruje się sama |
| Third-party registration | serwisy nic nie wiedzą o rejestrze | potrzebny „registrar” (orkiestrator, agent) |
Sam wzorzec niczego nie zabezpiecza. Rejestr mówi tylko, gdzie jest serwis, a nie, czy to naprawdę on. Dlatego duże systemy łączą discovery z tożsamością: TLS z weryfikacją certyfikatu (najlepiej mTLS), żeby podstawiony wpis w rejestrze nie przekierował ruchu do atakującego. Zapis do rejestru też wymaga autoryzacji — inaczej każdy może „zarejestrować” swój serwer jako payments.
- Pytanie 1: czy decyzję o instancji podejmuje klient, czy pośrednik?
- Pytanie 2: kto pilnuje, żeby rejestr znał tylko żywe instancje?
- Discovery bez weryfikacji tożsamości to zaproszenie do podszycia się.
DNS: najstarszy rejestr świata
uniwersalny, ale z cache, którego nie kontrolujeszNajprostsze discovery: nazwa → adres. Rekord A/AAAA daje adresy IP, a rekord SRV (RFC 2782) daje też port, priorytet i wagę. Każdy język i każda biblioteka HTTP umie DNS — to jego supermoc. Słabość: odpowiedź ma TTL i jest cache'owana po drodze (resolver, system, biblioteka, czasem sama aplikacja), więc po śmierci instancji klienci jeszcze przez chwilę dostają stary adres.
▶ Normalnie
- A? ordersKlient pyta lokalny resolver o
orders.internal. - brak w cacheResolver nie ma odpowiedzi, więc pyta serwer autorytatywny.
- A, B · TTL 30 sSerwer zwraca adresy A i B z TTL. Resolver trzyma je w cache przez TTL.
- połączenieKlient wybiera adres (zwykle pierwszy z listy) i łączy się.
💥 Instancja A pada
- A umieraInstancja A znika. Serwer DNS wkrótce usuwa jej rekord (jeśli ma health check).
- A? ordersResolver ma jeszcze ważną odpowiedź w cache: dalej zwraca A i B.
- timeoutKlient łączy się z martwym A. Do wygaśnięcia TTL część ruchu trafia w próżnię — chyba że klient ma retry na inny adres.
- po TTL tylko BPo wygaśnięciu cache resolver pobiera świeżą odpowiedź. Krótszy TTL skraca okno, ale zwiększa liczbę zapytań.
Klasyczny DNS nie uwierzytelnia odpowiedzi — spoofing i zatrucie cache to znane ataki. W sieci wewnętrznej ryzyko ogranicza się prywatnymi strefami (np. Route 53 private hosted zones, CoreDNS w klastrze) i kontrolą tego, kto może zmieniać rekordy. Właściwa ochrona jest jednak warstwę wyżej: TLS z weryfikacją nazwy w certyfikacie. Nawet jeśli DNS skieruje Cię pod zły adres, serwer atakującego nie pokaże ważnego certyfikatu orders.internal.
Java ma własny cache DNS sterowany właściwością networkaddress.cache.ttl. Gdy jest zainstalowany security manager, domyślnie wyniki są cache'owane na zawsze; bez niego czas zależy od implementacji (w OpenJDK 30 s). Ustaw tę wartość świadomie, jeśli Twoje discovery opiera się na DNS.
- DNS działa wszędzie, ale „wie” o zmianie dopiero po TTL i po wszystkich cache'ach.
SRVniesie port;A— tylko adres.- Prawdziwe zabezpieczenie: TLS i weryfikacja certyfikatu, nie sam DNS.
Rejestry CP: ZooKeeper, etcd, Consul
jedna prawda, uzgodniona przez większośćTe trzy systemy trzymają rejestr w klastrze kilku serwerów, które uzgadniają każdą zmianę przez większość (quorum). ZooKeeper używa protokołu ZAB, a etcd i serwery Consula — Rafta. Skutek w języku CAP: przy podziale sieci strona bez większości nie przyjmie zapisu. Wybierasz spójność kosztem dostępności zapisu.
Kluczowy trik to wpis, który umiera razem z instancją: w ZooKeeperze ephemeral znode (znika, gdy kończy się sesja klienta), w etcd klucz przypięty do lease z TTL (znika, gdy nikt nie odnowi lease), w Consulu wpis z health checkiem wykonywanym przez lokalnego agenta. Klienci nie odpytują rejestru w kółko — zakładają watch i dostają powiadomienie o zmianie.
▶ Rejestracja i śmierć
- grant lease TTL 10 sInstancja uwierzytelnia się (mTLS lub token) i dostaje lease z TTL.
- put klucz + leaseInstancja zapisuje swój adres pod kluczem przypiętym do lease.
- replikacjaLider zatwierdza zapis dopiero, gdy potwierdzi go większość węzłów.
- event PUTKlient z watchem na prefiksie
/services/orders/dostaje nowy adres. - instancja zamarzaInstancja przestaje odnawiać lease (keep-alive).
- event DELETEPo TTL lease wygasa, a klucz znika. Klient dostaje DELETE i usuwa adres z puli.
💥 Podział sieci
- partycjaLider zostaje w mniejszości (np. 1 z 3 węzłów).
- put → błądLider w mniejszości nie zbierze quorum, więc zapis nie przechodzi. Nowa instancja nie zarejestruje się po tej stronie.
- nowy liderWiększość wybiera nowego lidera i dalej przyjmuje zapisy.
- ostatni znany stanKlienci mają w pamięci ostatnią listę. Dobra biblioteka używa jej dalej, zamiast zerować pulę.
| System | Model i API | Kiedy wybierany |
|---|---|---|
| ZooKeeper | drzewo znode'ów, ephemeral/sequential nodes, watch; ZAB | ekosystem Hadoop/Kafka (starsze wersje Kafki), historyczne systemy JVM (np. Finagle ServerSets) |
| etcd | płaski keyspace, lease, watch na prefiks, gRPC; Raft | baza stanu Kubernetesa; własne rejestry, gdy masz już etcd |
| Consul | katalog serwisów, health checki, DNS + HTTP API, KV, mesh; Raft + gossip | wiele platform naraz (VM + Kubernetes + chmury), gotowy interfejs DNS |
Wszystkie trzy wspierają TLS między klientem a serwerem i między węzłami. etcd umie uwierzytelniać klientów certyfikatem i ma RBAC na zakresy kluczy. Consul ma system ACL z tokenami i politykami (kto może rejestrować który serwis, kto może czytać), a ruch gossip może szyfrować współdzielonym kluczem (gossip encryption). ZooKeeper ma ACL na znode'ach i uwierzytelnianie SASL. Bezpieczeństwo awarii: wpis z lease/sesją sam znika, więc martwa instancja nie zostaje w rejestrze na zawsze.
Rejestr CP to krytyczna zależność. Jeśli klient zeruje pulę, gdy nie może połączyć się z rejestrem, awaria rejestru staje się awarią całej firmy. Dobre biblioteki trzymają ostatni znany stan i działają dalej.
🔬 Głębiej: quorum, gossip w Consulu, licencje
Quorum. Klaster z n węzłami potrzebuje większości: ⌊n/2⌋+1. Trzy węzły przeżyją awarię jednego, pięć — dwóch. Dokumentacja Consula zaleca 3 lub 5 serwerów. Parzysta liczba nie zwiększa odporności: cztery węzły też przeżyją awarię tylko jednego.
Consul = Raft + gossip. Tylko serwery Consula uczestniczą w Rafcie. Na każdym węźle działa też agent klienta; agenty tworzą sieć gossip (biblioteka Serf), która wykrywa awarie węzłów bez obciążania serwerów. Health checki uruchamia lokalny agent, więc rejestr skaluje się na tysiące węzłów.
Licencje. W sierpniu 2023 HashiCorp zmienił licencję Consula, Vaulta i Terraforma z MPL 2.0 na Business Source License. W 2025 HashiCorp przejął IBM. Dla części firm to argument za etcd lub forkami (np. OpenBao dla Vaulta).
- CP: przy podziale sieci mniejszość nie przyjmuje zapisów.
- Wpis żyje tak długo jak sesja/lease/health check — martwa instancja znika sama.
- Watch zamiast odpytywania; klient powinien przetrwać niedostępność rejestru.
Rejestr AP: Netflix Eureka
lepiej stara lista niż żadnaNetflix zbudował Eurekę dla AWS z odwrotnym założeniem: przy podziale sieci rejestr ma dalej odpowiadać, nawet jeśli część danych jest nieaktualna. Serwery Eureki replikują się między sobą (peer-to-peer), a klient trzyma lokalną kopię rejestru. Eureka jest dziś popularna głównie w ekosystemie Spring Cloud Netflix.
Domyślne liczby z dokumentacji: klient wysyła heartbeat co 30 s, serwer usuwa instancję po 90 s bez odnowienia, a klient pobiera zmiany rejestru co 30 s. Mechanizm self-preservation: jeśli nagle przestaje przychodzić dużo heartbeatów (poniżej progu, domyślnie 85% oczekiwanych), serwer zakłada problem z siecią, a nie masową śmierć instancji, i przestaje usuwać wpisy.
▶ Normalnie
- registerInstancja rejestruje się w jednym z serwerów (self-registration przez bibliotekę klienta).
- replikacja asyncSerwer przekazuje wpis do pozostałych serwerów. Do zakończenia replikacji serwery mogą widzieć różne stany.
- heartbeat co 30 sInstancja odnawia lease.
- fetch delta co 30 sKlient pobiera zmiany z dowolnego serwera i zapisuje je w lokalnym cache.
- wywołanie z cacheKlient wybiera instancję z lokalnej kopii — nawet gdy Eureka chwilowo nie odpowiada.
💥 Podział sieci
- heartbeaty ginąPołowa heartbeatów nie dociera. Wygląda, jakby połowa floty umarła.
- self-preservationLiczba odnowień spadła poniżej progu, więc serwer wstrzymuje usuwanie wpisów.
- część wpisów martwaKlient może trafić na naprawdę martwą instancję — dlatego potrzebuje timeoutów i retry na inną instancję.
- ale ruch płynieAlternatywa (wyrzucić połowę floty z rejestru) byłaby gorsza: zdrowe instancje straciłyby ruch.
Eureka domyślnie nie wymaga uwierzytelnienia — w Spring Cloud zabezpiecza się ją typowo Spring Security (np. HTTP Basic) i TLS, a dostęp sieciowy ogranicza do sieci prywatnej. Odporność na awarie jest tu ważniejsza niż spójność: lokalny cache klienta oznacza, że awaria całego klastra Eureki nie zatrzymuje ruchu. Ceną jest konieczność obrony przed martwymi wpisami: timeouty, retry, circuit breaker.
| Przy podziale sieci | CP (etcd, ZK, Consul servers) | AP (Eureka) |
|---|---|---|
| Zapis | tylko po stronie większości | wszędzie |
| Odczyt | spójny (lub ostatni znany stan w kliencie) | może być nieaktualny |
| Ryzyko | nowe instancje niewidoczne | ruch do martwych instancji |
- Discovery to dane, które i tak szybko się starzeją — dlatego AP bywa rozsądnym wyborem.
- Self-preservation chroni przed „wyrzuceniem” zdrowej floty przy problemie sieci.
- AP wymaga od klienta timeoutów i retry.
Kubernetes: discovery wbudowane w platformę
Service, EndpointSlice, kube-proxy, CoreDNSW Kubernetesie nie budujesz rejestru — platforma jest rejestrem (third-party registration). Service wybiera pody po etykietach i dostaje stabilny wirtualny adres (ClusterIP) oraz nazwę DNS <service>.<namespace>.svc.cluster.local. Kontroler zapisuje adresy pasujących podów w obiektach EndpointSlice. kube-proxy na każdym węźle zamienia to na reguły jądra (iptables, IPVS lub nftables), które przekierowują ruch z ClusterIP do poda. To server-side discovery bez dodatkowego hopu sieciowego.
▶ Pod staje się gotowy
- pod ReadyKubelet raportuje, że readiness probe przechodzi.
- EndpointSlice += podKontroler dopisuje adres poda (ready) do EndpointSlice serwisu.
- watch EndpointSlicekube-proxy na każdym węźle obserwuje zmiany i aktualizuje reguły jądra.
- DNS → ClusterIPKlient rozwiązuje nazwę serwisu przez CoreDNS i dostaje stały ClusterIP.
- ruch → podReguły jądra na węźle klienta zamieniają ClusterIP na adres jednego z gotowych podów.
💥 Readiness pada
- pod NotReadyReadiness probe przestaje przechodzić (np. pod jest przeciążony).
- endpoint ready=falseKontroler oznacza endpoint jako niegotowy. ClusterIP i DNS się nie zmieniają.
- reguły bez podakube-proxy usuwa poda z puli. Nowe połączenia omijają go; pod nie jest restartowany (to robi liveness).
| Typ | Co daje | Kiedy |
|---|---|---|
| ClusterIP | wirtualny IP + DNS, load balancing w jądrze | domyślnie, ruch wewnątrz klastra |
Headless (clusterIP: None) | DNS zwraca adresy podów bezpośrednio | client-side load balancing, StatefulSety (stała nazwa każdego poda) |
| ExternalName | alias CNAME na nazwę spoza klastra | przejściowe wskazanie zewnętrznej usługi |
| LoadBalancer / Gateway | wejście spoza klastra | ruch od klientów zewnętrznych |
Rejestr aktualizuje tylko control plane: kubelet i kontrolery uwierzytelniają się w API serverze certyfikatami i działają w granicach RBAC. Zwykły pod nie może dopisać się do cudzego serwisu bez uprawnień do zmiany obiektów w API. Ale: domyślnie każdy pod może łączyć się z każdym podem. Ruch ogranicza NetworkPolicy (o ile CNI ją wspiera), a tożsamość i szyfrowanie daje dopiero mTLS (service mesh).
- Kubernetes to third-party registration: o rejestrze decyduje readiness, nie kod aplikacji.
- ClusterIP jest stały; zmienia się tylko lista endpointów za nim.
- Brak tożsamości i szyfrowania między podami „z pudełka” — to dodaje mesh.
Service mesh: discovery + tożsamość w proxy
Envoy, xDS, Istio, LinkerdService mesh przenosi client-side discovery z biblioteki do proxy obok aplikacji. Aplikacja wysyła zwykłe żądanie na orders, a proxy wybiera instancję, robi retry, timeouty i mTLS. Proxy dostaje wiedzę z control plane, który obserwuje rejestr (np. API Kubernetesa). Proxy Envoy powstało w Lyfcie i zostało udostępnione jako open source. Protokół, którym control plane karmi Envoya, to xDS; używa go m.in. Istio (control plane istiod) i gRPC w trybie proxyless. Linkerd ma własne proxy napisane w Ruście.
▶ Normalnie
- watch Service/EndpointSliceControl plane obserwuje serwisy i endpointy.
- CSR + token SAAgent obok proxy A tworzy klucz prywatny i wysyła CSR z poświadczeniami (w Kubernetesie: token konta usługi). istiod weryfikuje poświadczenia i podpisuje krótko żyjący certyfikat z tożsamością SPIFFE.
- xDS: CDS/EDS/LDS/RDSControl plane przesyła strumieniem gRPC klastry, endpointy, listenery i trasy.
- mTLS handshakeProxy A i B wymieniają certyfikaty i sprawdzają nawzajem tożsamość.
- AuthorizationPolicyProxy B sprawdza politykę: czy tożsamość A może wołać tę ścieżkę.
- localhostDopiero teraz żądanie trafia do aplikacji B.
💥 Control plane padł
- istiod niedostępnyControl plane nie działa.
- brak nowych zmianDokumentacja Istio: proxy niepołączone z istiod nie dostaje żadnej nowej konfiguracji. Certyfikaty odnawia agent okresowo u CA (domyślnie istiod), więc długa awaria grozi ich wygaśnięciem.
Mesh daje to, czego brakuje DNS i rejestrom: kryptograficzną tożsamość serwisu. Każde proxy ma krótko żyjący certyfikat X.509 z tożsamością w formacie SPIFFE (w Istio: spiffe://<trust-domain>/ns/<ns>/sa/<service-account>), który jest automatycznie rotowany. Po obu stronach jest mTLS, więc podsłuch i podszycie się wymagają kradzieży klucza. Autoryzacja (kto może wołać kogo) jest w politykach, a nie w adresach IP. Linkerd włącza mTLS między podami w meshu domyślnie. Istio domyślnie działa w trybie PERMISSIVE (przyjmuje mTLS i plaintext) — tryb STRICT trzeba włączyć polityką PeerAuthentication.
| Opcja | Co | Kiedy |
|---|---|---|
| Istio (sidecar) | Envoy przy każdym podzie, bogate L7 | potrzebujesz pełnej kontroli ruchu i polityk |
| Istio ambient | bez sidecarów: ztunnel na węźle (L4, mTLS), waypoint proxy dla L7 | chcesz mTLS taniej, bez wstrzykiwania sidecarów |
| Linkerd | lekkie proxy w Ruście, mTLS domyślnie | prostota i niski narzut ważniejsze niż mnogość funkcji |
| gRPC proxyless (xDS) | biblioteka gRPC sama mówi xDS | flota gRPC, chcesz uniknąć hopu przez proxy |
| Consul service mesh | Envoy + katalog Consula, także poza Kubernetesem | mieszane środowisko VM + K8s |
🔬 Głębiej: typy xDS i dlaczego to standard
xDS to rodzina API: LDS (listenery — na czym proxy słucha), RDS (trasy HTTP), CDS (klastry — grupy upstreamów), EDS (endpointy w klastrze), SDS (sekrety: certyfikaty i klucze). ADS przesyła wszystkie typy jednym strumieniem, co pozwala zachować kolejność aktualizacji. Wersja „delta” wysyła tylko zmiany. Ponieważ API jest otwarte, z xDS korzystają różne control plane'y, a w Google Cloud usługa Cloud Service Mesh (dawniej Traffic Director) karmi xDS zarówno Envoye, jak i proxyless gRPC.
Mesh to nowy krytyczny system z własnym cyklem aktualizacji, narzutem CPU/pamięci na proxy i dodatkową latencją. Duże firmy wdrażają go stopniowo (namespace po namespace) i zaczynają od trybu permissive, żeby nie odciąć ruchu spoza meshu.
- Mesh = client-side discovery w proxy + mTLS + polityki.
- xDS to otwarty protokół control plane → proxy (Envoy, gRPC).
- Awaria control plane zatrzymuje dystrybucję zmian i odnawianie certyfikatów.
Discovery jako usługa chmurowa
AWS Cloud Map, ECS Service Connect, VPC Lattice, GCP, AzureFirmy z ciężarem w jednej chmurze często nie utrzymują własnego rejestru. W AWS Cloud Map to rejestr nazw serwisów: instancje rejestrujesz przez API (robi to np. ECS), a odkrywasz przez DNS (Route 53) lub wywołanie API DiscoverInstances. ECS Service Connect buduje na Cloud Map i dokłada proxy przy każdym zadaniu ECS. VPC Lattice idzie dalej: to zarządzana sieć aplikacyjna między VPC i kontami, z politykami autoryzacji opartymi na IAM. AWS App Mesh (mesh na Envoyu) został wycofany: AWS zakończył jego wsparcie 30 września 2026 r. i wskazuje migrację do ECS Service Connect; dla ruchu między VPC i kontami alternatywą jest VPC Lattice.
▶ Normalnie
- DNS nazwy serwisuA rozwiązuje nazwę DNS serwisu Lattice z sieci VPC powiązanej z siecią serwisów (service network).
- żądanie z SigV4A podpisuje żądanie swoimi tymczasowymi poświadczeniami roli IAM (Signature Version 4).
- ewaluacja politykiLattice sprawdza auth policy: czy ten principal może wywołać tę usługę i ścieżkę.
- routing do celuLattice kieruje żądanie do zdrowego celu (instancja, kontener, Lambda).
💥 Obcy principal
- żądanie bez uprawnieńInny serwis (inna rola) próbuje wołać B.
- denyPolityka nie zezwala na ten principal. Lattice odrzuca żądanie, zanim dotrze do B.
| Usługa | Co | Kiedy |
|---|---|---|
| AWS Cloud Map | rejestr nazw: DNS lub API, opcjonalne health checki | discovery dla ECS/EC2/zasobów poza K8s |
| ECS Service Connect | discovery + proxy dla ECS, metryki, retry | flota w ECS |
| Amazon VPC Lattice | sieć serwisów między VPC/kontami, auth IAM | wiele kont i VPC, różne platformy compute |
| Google Service Directory | rejestr serwisów z DNS i API | discovery w GCP i hybrydowo |
| Google Cloud Service Mesh | zarządzany control plane xDS (Envoy / proxyless gRPC) | mesh bez utrzymywania istiod |
| Azure Container Apps | wbudowane DNS-owe discovery między aplikacjami środowiska | serverless kontenery w Azure |
Zarządzane discovery dziedziczy model IAM chmury: rejestrować i wywoływać może tylko principal z uprawnieniami, a poświadczenia są tymczasowe (role, a nie klucze). W VPC Lattice autoryzacja dzieje się przy każdym żądaniu na podstawie podpisanej tożsamości, a nie adresu IP. Trade-off: tożsamość i polityki są specyficzne dla jednej chmury — przy multi-cloud potrzebujesz warstwy niezależnej (mesh, SPIFFE).
- Chmura oferuje rejestr (Cloud Map, Service Directory) i sieć aplikacyjną (Lattice, Cloud Service Mesh).
- Zysk: brak własnego control plane; koszt: zamknięcie w jednej chmurze.
- App Mesh nie jest już opcją — AWS zakończył jego wsparcie.
Jak robią to hyperscalerzy
Google, Twitter, Airbnb, Lyft — z publicznych źródełNajwięksi zbudowali discovery, zanim istniały gotowe narzędzia. Ich rozwiązania są ciekawe, bo pokazują te same decyzje w skali ekstremalnej. Opisujemy tylko to, co opublikowali sami.
| Firma | Rozwiązanie | Idea |
|---|---|---|
| Borg Name Service (BNS) + Chubby | Borg zapisuje nazwę hosta i port każdego zadania w Chubby (rozproszony serwis blokad z konsensusem Paxos) pod nazwą BNS; Chubby służy jako spójny rejestr nazw (artykuły o Borgu, EuroSys 2015, i o Chubby, OSDI 2006) | |
| Finagle + ServerSets w ZooKeeperze | instancje publikują się w ServerSecie w ZooKeeperze, a klient Finagle odczytuje ten ServerSet (adres zk!host!/ścieżka) | |
| Airbnb | SmartStack (Nerve + Synapse) | Nerve sprawdza zdrowie i rejestruje w ZooKeeperze; Synapse konfiguruje lokalny HAProxy — wczesny „sidecar” |
| Lyft | Envoy | proxy przy każdym serwisie z dynamiczną konfiguracją z control plane — zalążek xDS i dzisiejszych meshy |
| Netflix | Eureka | rejestr AP dla AWS z cache w kliencie (rozdział wyżej) |
Widzisz ewolucję? Biblioteka w kliencie (Finagle, Ribbon) → lokalne proxy konfigurowane z rejestru (SmartStack) → proxy z otwartym protokołem sterowania (Envoy/xDS) → zarządzany control plane. Każdy krok przenosi logikę z kodu aplikacji do infrastruktury, bo w firmie z wieloma językami biblioteka per język staje się kosztem.
- Hyperscalerzy opierali rejestry na systemach z konsensusem (Chubby, ZooKeeper).
- Trend: logika discovery wędruje z biblioteki do proxy i control plane.
Discovery: między czym naprawdę wybierasz
profil systemu → typowy wybór| Profil | Typowy wybór | Główny trade-off |
|---|---|---|
| Wszystko w Kubernetesie | Service + DNS; mesh, gdy potrzebny mTLS/L7 | prostota vs funkcje meshu |
| VM + K8s + kilka chmur | Consul (katalog + DNS + mesh) | jeden rejestr vs kolejny system do utrzymania |
| Jedna chmura, wiele kont | Cloud Map / VPC Lattice, Service Directory | brak utrzymania vs vendor lock-in |
| Flota JVM na Spring Cloud | Eureka lub Consul + biblioteka klienta | dojrzałość w ekosystemie vs biblioteka per język |
| Ekstremalna skala, wiele języków | własny control plane xDS + Envoy / proxyless gRPC | pełna kontrola vs ogromny koszt zespołu |
- Adresy IP w konfiguracji. Umierają przy pierwszym autoskalingu.
- Klient zeruje pulę przy awarii rejestru. Awaria rejestru zamienia się w awarię wszystkiego.
- Długi TTL bez retry. Martwe instancje dostają ruch przez cały TTL.
- Brak readiness probe. Pod dostaje ruch, zanim jest gotowy.
- Zaufanie do adresu zamiast tożsamości. Kto podmieni wpis, przejmie ruch — weryfikuj certyfikat.
Konfiguracja
Od zmiennych środowiskowych, przez ConfigMap i centralne serwery, po dynamiczną konfigurację, feature flags i bezpieczny rollout zmian.
Warstwy konfiguracji i 12-factor
kiedy wartość „zamarza”?Najważniejsze pytanie o każdą wartość konfiguracyjną: kiedy zostaje ustalona. Wartość wkompilowana w obraz zmienisz tylko nowym buildem. Wartość podana przy deployu (zmienna środowiskowa, plik) — nowym deployem lub restartem. Wartość dynamiczna (centralny serwer, feature flag) — w trakcie działania, bez restartu. Im później zamarza, tym szybciej reagujesz, ale tym większe ryzyko, że zła zmiana trafi do produkcji z pominięciem testów i code review.
Manifest The Twelve-Factor App mówi: konfiguracja to wszystko, co różni się między deployami (staging, produkcja), i powinna być w zmiennych środowiskowych, a nie w kodzie. Ten sam obraz idzie wtedy na każde środowisko. To nadal standard dla wartości deploy-time — ale nie dla sekretów (część III) i nie dla wartości, które chcesz zmieniać bez restartu.
▶ Deploy
- obraz + manifestCI publikuje jeden obraz. Manifest środowiska zawiera wartości, np.
DB_POOL_SIZE=20. - start z envOrkiestrator uruchamia proces z ustawionym środowiskiem.
- odczyt przy starcieAplikacja czyta zmienne raz, przy starcie, i waliduje je (fail fast przy złej wartości).
💥 Zmiana w biegu
- nowa wartośćOperator chce zmienić
DB_POOL_SIZEna 40. - proces nie widziŚrodowisko działającego procesu nie zmienia się z zewnątrz.
- rolling restartZmiana wymaga nowego deployu. Zaleta: zmiana przechodzi przez ten sam pipeline co kod.
| Warstwa | Przykład | Zmiana wymaga |
|---|---|---|
| Build-time | stałe w kodzie, plik w obrazie | nowego buildu |
| Deploy-time | env, ConfigMap jako env, plik z wolumenu czytany przy starcie | restartu / deployu |
| Runtime (dynamiczna) | centralny serwer, AppConfig, feature flag | niczego — aplikacja przeładowuje wartość |
Konfiguracja deploy-time jest tak bezpieczna jak pipeline: zmiana przechodzi przez repozytorium, review i ten sam proces wdrożenia co kod, więc masz audyt i rollback (poprzednia wersja manifestu). Zmienne środowiskowe nie są jednak miejscem na sekrety: widzi je każdy proces potomny, narzędzia diagnostyczne i często logi przy awarii.
- Pytaj: kiedy ta wartość zamarza — build, deploy czy runtime?
- 12-factor: jeden obraz, konfiguracja z zewnątrz.
- Dynamiczna zmiana = szybsza reakcja, ale omija pipeline — potrzebuje własnych zabezpieczeń.
Pliki i ConfigMap w Kubernetesie
env czy wolumen — dwie różne semantykiConfigMap przechowuje niesekretną konfigurację jako pary klucz–wartość (do 1 MiB). Pod może ją dostać na dwa sposoby, które zachowują się inaczej przy zmianie. Jako zmienne środowiskowe: wartości są wstrzykiwane przy starcie kontenera i nie aktualizują się same. Jako wolumen: każdy klucz to plik, a kubelet aktualizuje pliki po zmianie ConfigMapy — z opóźnieniem (okres synchronizacji kubeleta plus opóźnienie cache). Wyjątek: plik zamontowany przez subPath nie jest aktualizowany.
▶ Montaż jako wolumen
- kubectl applyOperator zmienia ConfigMapę. RBAC sprawdza, czy może edytować obiekty w tym namespace.
- syncKubelet przy okresowej synchronizacji zauważa nową wersję.
- nowe plikiKubelet aktualizuje pliki w wolumenie. Dokumentacja mówi, że klucze są aktualizowane „ostatecznie” (eventually) — nie natychmiast.
- reloadAplikacja musi sama wykryć zmianę pliku (watch na katalog) i przeładować konfigurację.
💥 ConfigMap jako env
- kubectl applyTa sama zmiana.
- stara wartośćKontener ma środowisko z chwili startu. Pody działają ze starą wartością, aż do restartu.
- rollout restartTypowe rozwiązanie: wymusić rolling update po każdej zmianie ConfigMapy, np. adnotacją z hashem konfiguracji w szablonie poda.
Dostęp do ConfigMap kontroluje RBAC Kubernetesa, a zmiany przechodzą przez API server (audyt). Gdy manifesty są w Git i wdraża je narzędzie GitOps (Argo CD, Flux), każda zmiana ma review i historię. ConfigMapa nie jest szyfrowana i nie jest przeznaczona na sekrety. Opcja immutable: true chroni przed przypadkową zmianą i zmniejsza obciążenie API servera (kubelet nie obserwuje takiej ConfigMapy).
- Env z ConfigMapy = deploy-time. Wolumen = prawie runtime (z opóźnieniem).
subPathnie dostaje aktualizacji.- Najbezpieczniej: konfiguracja w Git + rollout przy zmianie.
Centralny serwer konfiguracji
Spring Cloud Config, Consul KV, etcdGdy masz setki serwisów, chcesz jednego źródła konfiguracji z historią i możliwością zmiany bez deployu. Spring Cloud Config Server udostępnia konfigurację przez HTTP z backendu (najczęściej repozytorium Git, także Vault lub JDBC). Klient pobiera ją przy starcie, a beany oznaczone @RefreshScope przeładowuje po wywołaniu /actuator/refresh. Spring Cloud Bus rozgłasza odświeżenie do wszystkich instancji przez brokera (RabbitMQ lub Kafka). Poza JVM popularny wzorzec to Consul KV (lub etcd) + consul-template, który obserwuje klucze, renderuje plik i może uruchomić komendę przeładowania.
▶ Start i odświeżenie
- pobranie konfiguracjiInstancja pobiera konfigurację swojej aplikacji i profilu (domyślnie przy starcie), uwierzytelniając się w serwerze (np. HTTP Basic lub OAuth2).
- git fetchSerwer czyta pliki z repozytorium (gałąź lub tag = wersja).
- merge zmianyKtoś merguje PR ze zmianą timeoutu. Review i historia są w Git.
- /actuator/busrefreshWebhook z repozytorium (np. przez endpoint
/monitor) albo operator wyzwala odświeżenie na szynie. - refresh na każdej instancjiKażda instancja dostaje zdarzenie odświeżenia: czyści cache
RefreshScopei ponownie wiąże@ConfigurationProperties.
💥 Config Server leży przy starcie
- serwer niedostępnyAwaria serwera konfiguracji.
- start bez konfiguracjiNowa instancja nie dostaje konfiguracji. Z
fail-fastnie wystartuje; bez niego użyje wartości lokalnych. - działające instancje OKUruchomione instancje mają konfigurację w pamięci. Dlatego serwer konfiguracji uruchamia się w kilku replikach, a klient ma retry.
Źródłem prawdy jest Git: każda zmiana ma autora, review i można ją cofnąć revertem. Serwer konfiguracji trzeba zabezpieczyć uwierzytelnieniem i TLS — sam z siebie udostępnia konfigurację każdemu, kto ma dostęp sieciowy. Spring Cloud Config umie trzymać wartości zaszyfrowane (prefiks {cipher}) i odszyfrowywać je po stronie serwera, ale w dużych systemach sekrety zwykle idą do dedykowanego managera (Vault jako backend).
„Odśwież wszystko naraz” to globalny deploy bez canary. Zła wartość trafia do całej floty w sekundy. Duże firmy dzielą rollout konfiguracji na etapy — o tym rozdział „Bezpieczny rollout”.
- Git + serwer konfiguracji = historia, review i zmiana bez deployu.
- Serwer konfiguracji to zależność startowa: replikuj go, a w kliencie miej retry.
- Rozgłoszenie do wszystkich naraz to ryzyko — rób to etapami.
Konfiguracja zarządzana w chmurze
AWS AppConfig, Parameter Store, Azure App ConfigurationChmury oferują gotowe magazyny konfiguracji. AWS Systems Manager Parameter Store to hierarchiczny magazyn parametrów (np. /prod/orders/timeout) z typami String, StringList i SecureString (szyfrowany kluczem KMS). Poziom Standard: do 10 000 parametrów, wartość do 4 KB, bez dodatkowej opłaty; Advanced: wartość do 8 KB i polityki parametrów. AWS AppConfig dodaje to, czego brakuje zwykłemu magazynowi: walidatory (JSON Schema lub funkcja Lambda), strategie wdrożenia (stopniowe udostępnianie) i automatyczny rollback, gdy w trakcie wdrożenia odpali alarm CloudWatch. Azure App Configuration trzyma klucze z etykietami (np. per środowisko), feature flagi, snapshoty i referencje do Key Vault — sekret nie jest kopiowany, aplikacja pobiera go z Key Vault własną tożsamością.
▶ Udane wdrożenie
- nowa wersjaOperator z uprawnieniami IAM tworzy nową wersję konfiguracji.
- walidacjaAppConfig uruchamia walidator. Zła składnia lub wartość spoza zakresu zatrzymuje wdrożenie, zanim cokolwiek się stanie.
- StartDeploymentWdrożenie ze strategią, np. liniowo co kilka minut, z czasem obserwacji (bake time) na końcu.
- GetLatestConfigurationAplikacje (lub AppConfig Agent obok nich) pobierają konfigurację. Każda instancja niezależnie sprawdza stan wdrożenia, więc nowa wersja trafia do rosnącej części klientów.
- alarmy OKAlarmy są zielone przez cały rollout, więc wdrożenie się kończy.
💥 Błędy po zmianie
- część klientów ma nową wersjęRollout jest w toku.
- błędy rosnąOdsetek błędów 5xx przekracza próg alarmu.
- ALARMAppConfig monitoruje alarm przypisany do środowiska.
- rollbackAppConfig automatycznie cofa wdrożenie; klienci wracają do poprzedniej wersji przy kolejnym odpytaniu.
| Usługa | Co | Kiedy |
|---|---|---|
| SSM Parameter Store | prosty magazyn hierarchiczny, typ SecureString | wartości deploy-time, małe sekrety bez rotacji |
| AWS AppConfig | walidacja + stopniowe wdrożenie + rollback na alarm | konfiguracja zmieniana w biegu, feature flagi |
| Azure App Configuration | key-values z etykietami, feature flagi, snapshoty, referencje Key Vault | flota w Azure, .NET/Java z dynamicznym odświeżaniem |
| Google Parameter Manager | parametry z wersjami i referencjami do Secret Manager | flota w GCP |
Odczyt i zapis kontroluje IAM chmury, a aplikacje używają ról zamiast kluczy. Każde wywołanie API trafia do logów audytowych (AWS CloudTrail, Azure Monitor). AppConfig dodaje bezpieczeństwo operacyjne: walidator blokuje złą wartość, a stopniowy rollout z alarmem ogranicza promień rażenia błędu do części floty.
- Magazyn (Parameter Store) ≠ system wdrożeń konfiguracji (AppConfig).
- Walidacja przed wdrożeniem i rollback na alarm to standard dużych firm.
- Referencja do sekretu jest lepsza niż kopia sekretu w konfiguracji.
Dynamiczna konfiguracja i feature flags
Archaius, LaunchDarkly, Unleash, OpenFeatureFeature flag to konfiguracja, która włącza kod dla wybranych użytkowników lub procentu ruchu. Oddziela deploy (kod jest na produkcji) od release (kod jest włączony). Duże platformy flagowe (LaunchDarkly, Unleash) mają wspólny wzorzec: SDK po stronie serwera trzyma reguły w pamięci i ewaluuje flagi lokalnie, bez wywołania sieciowego na każde sprawdzenie. Zmiany dostaje w tle (w LaunchDarkly przez stream). Netflix opublikował bibliotekę Archaius do dynamicznej konfiguracji (Java). OpenFeature standaryzuje API w kodzie, żeby zmiana dostawcy flag nie wymagała przepisania aplikacji.
▶ Włączenie dla 10%
- init z kluczem SDKSDK łączy się z serwisem flag kluczem SDK po stronie serwera i pobiera wszystkie reguły.
- rollout 10%Produkt ustawia flagę
new-checkoutna 10% użytkowników. Zmiana ma autora w logu audytu. - stream: zmiana regułySerwis wysyła nową regułę do SDK.
- żądanie użytkownikaAplikacja pyta SDK o flagę dla użytkownika.
- hash(user) → bucketSDK liczy lokalnie: hash klucza użytkownika daje stały bucket, więc ten sam użytkownik zawsze dostaje ten sam wariant.
💥 Serwis flag niedostępny
- awariaSerwis flag nie odpowiada.
- ostatnie regułySDK ewaluuje na ostatnich znanych regułach z pamięci.
- zimny start → defaultNowa instancja bez połączenia dostaje wartość domyślną z kodu. Wartość domyślna musi być bezpieczna (zwykle: funkcja wyłączona).
Klucz SDK po stronie serwera jest sekretem (pozwala czytać wszystkie reguły), a klucz po stronie klienta daje dostęp tylko do flag oznaczonych jako publiczne. Panel ma role i log audytu: wiesz, kto włączył flagę i kiedy. Bezpieczeństwo awarii daje lokalna ewaluacja i bezpieczna wartość domyślna. Flaga jest też najszybszym „wyłącznikiem awaryjnym” (kill switch) — szybszym niż rollback deployu.
Każda flaga to dodatkowa gałąź w kodzie. Stare, nieusunięte flagi tworzą kombinacje, których nikt nie testował. Ustal właściciela i datę usunięcia dla każdej flagi.
- Flagi oddzielają deploy od release.
- Ewaluacja lokalna: brak latencji i odporność na awarię serwisu flag.
- OpenFeature = przenośne API; dostawca jest wymienny.
Config-as-code na skalę Meta
Configerator, Gatekeeper, ZeusArtykuł „Holistic Configuration Management at Facebook” (SOSP 2015) opisuje, jak Facebook traktuje konfigurację jak kod. Inżynier pisze źródło konfiguracji w Pythonie (z typami w Thrift), kompilator generuje JSON, a walidatory sprawdzają wynik. Zmiana przechodzi code review i trafia do repozytorium Git. Dystrybucję robi Zeus (wersja ZooKeepera rozwijana w Facebooku): przez drzewo obserwatorów do proxy na każdym serwerze, które trzyma konfigurację w lokalnym cache na dysku. Aplikacja czyta konfigurację z lokalnego proxy, a nie z centrali. Na tym zbudowano Gatekeeper (stopniowe włączanie funkcji i eksperymenty), PackageVessel (duże konfiguracje przez dystrybucję peer-to-peer) i MobileConfig.
▶ Zmiana
- źródło + kompilacjaInżynier zmienia źródło konfiguracji. Kompilator generuje JSON, a walidator sprawdza niezmienniki.
- review i commitZmiana przechodzi code review. Git zapisuje autora i historię.
- automatyczny canaryUsługa canary wdraża zmianę na małą grupę serwerów, potem większą, i porównuje metryki z grupą kontrolną.
- dystrybucjaPo udanym canary zmiana idzie przez Zeus i obserwatory do proxy na serwerach.
- odczyt lokalnyAplikacja dostaje nową wartość z lokalnego proxy.
💥 Centrala niedostępna
- proxy bez połączeniaProxy traci kontakt z obserwatorami.
- cache na dyskuAplikacja dalej czyta ostatnią konfigurację z lokalnego cache. Awaria systemu konfiguracji nie zatrzymuje produkcji.
Bezpieczeństwo jest tu głównie operacyjne: kompilacja i walidatory łapią błędy przed commitem, review daje drugą parę oczu, automatyczny canary ogranicza promień rażenia, a lokalny cache na każdym serwerze daje odporność na awarię centrali. Artykuł podaje, że błędy konfiguracji są ważną przyczyną incydentów — stąd tyle warstw ochrony.
- Konfiguracja jak kod: źródło, kompilacja, walidacja, review, canary.
- Odczyt z lokalnego proxy/cache, nie z centrali.
- Flagi (Gatekeeper) to warstwa nad tym samym systemem dystrybucji.
Bezpieczny rollout konfiguracji
konfiguracja to zmiana produkcji — tak samo groźna jak kodKsiążka Google „Site Reliability Engineering” podaje, że około 70% awarii wynika ze zmian w działającym systemie. Zmiana konfiguracji to zmiana. Kilka głośnych awarii zaczęło się od danych konfiguracyjnych wdrożonych wszędzie naraz:
| Incydent | Co się stało | Lekcja |
|---|---|---|
| CrowdStrike, 19.07.2024 | aktualizacja treści (plik kanałowy 291) dla sensora Falcon wywołała awarie Windowsa; Microsoft szacował 8,5 mln urządzeń | aktualizacje treści potrzebują etapowego wdrożenia — CrowdStrike zapowiedział je w swojej analizie |
| Google Cloud, 12.06.2025 | zmiana polityki z pustymi polami replikowała się globalnie; nowy kod w Service Control nie miał flagi ani obsługi błędu i się wywracał | nowa ścieżka kodu za flagą; dane konfiguracyjne propagowane etapami |
▶ Zdrowa zmiana
- schema + testyWalidacja składni, typów i reguł biznesowych. Test, czy kod czytający konfigurację przyjmie nową wartość.
- canaryZmiana trafia do małej części floty. Metryki porównuje się z grupą kontrolną.
- jeden regionPo czasie obserwacji zmiana rozszerza się na jeden region (jedna domena awarii).
- globalnieDopiero na końcu wszystkie regiony.
💥 Zła wartość
- przechodzi walidacjęWartość jest poprawna składniowo, ale wywołuje błąd w nowym kodzie.
- canary chorujeWzrost błędów w grupie canary.
- auto-rollbackSystem cofa zmianę. Ucierpiał tylko 1% floty, a nie wszystkie regiony.
Etapy zamieniają „jedna zła wartość = globalna awaria” w „jedna zła wartość = mały, automatycznie cofnięty incydent”. Do tego: każda zmiana ma autora i review, poprzednia wersja jest zawsze dostępna do rollbacku, a kod czytający konfigurację odrzuca nieprawidłowe wartości i zostaje przy ostatniej dobrej (fail static), zamiast się wywracać.
- Konfiguracja wymaga tego samego co kod: review, testy, canary, rollback.
- Przy błędnej wartości: zostań przy ostatniej dobrej, nie padaj.
- Globalna replikacja w sekundy to cecha i jednocześnie ryzyko.
Konfiguracja: między czym wybierasz
profil → typowy wybór| Potrzeba | Typowy wybór | Trade-off |
|---|---|---|
| Wartości per środowisko, rzadkie zmiany | env / ConfigMap z Git (GitOps) | restart przy zmianie vs pełny audyt i prostota |
| Zmiany bez deployu, jedna chmura | AWS AppConfig, Azure App Configuration | gotowy rollout i rollback vs lock-in |
| Flota Spring/JVM | Spring Cloud Config (Git) + Bus | wygoda w ekosystemie vs globalny refresh |
| Wiele platform | Consul KV + consul-template | uniwersalność vs utrzymanie Consula |
| Włączanie funkcji dla części użytkowników | platforma flag (LaunchDarkly, Unleash) przez OpenFeature | szybki release vs dług flagowy |
| Skala hyperscalera | własny config-as-code (wzór: Configerator) | pełna kontrola vs koszt budowy |
- Globalny push bez canary. Zła wartość trafia wszędzie naraz.
- Brak walidacji. Literówka w JSON wyłącza serwis.
- Konfiguracja tylko w panelu, bez historii. Nikt nie wie, kto i kiedy zmienił timeout.
- Sekrety w ConfigMap lub repozytorium konfiguracji. Konfiguracja nie jest szyfrowana i ma szeroki dostęp.
- Różne obrazy per środowisko. Testujesz inny artefakt niż ten, który wdrażasz.
Sekrety
Gdzie trzymać hasła, klucze i certyfikaty, jak serwis je dostaje, jak je rotować — i jak w ogóle ich nie potrzebować.
Cykl życia sekretu i „secret zero”
każdy sekret kiedyś wycieknie — pytanie, na jak długoSekret to wartość, która daje dostęp: hasło do bazy, klucz API, klucz prywatny TLS, token. Każdy ma cykl życia: utworzenie → przechowanie → dystrybucja → użycie → rotacja → odwołanie. Duże firmy optymalizują dwie liczby: ile osób i systemów widzi sekret i jak długo jest ważny. Sekret ważny godzinę, znany tylko jednemu procesowi, jest wart dla atakującego niewiele.
Problem secret zero: żeby pobrać sekret z managera, serwis musi się uwierzytelnić. Czym? Jeśli kolejnym sekretem, to gdzie ten jest przechowywany? Rozwiązanie w dużych systemach: pierwszym poświadczeniem jest tożsamość nadana przez platformę (token konta usługi Kubernetesa, rola IAM instancji, atestacja węzła), a nie sekret wpisany przez człowieka.
▶ Pierwsze uruchomienie
- tożsamośćPlatforma wydaje serwisowi krótko żyjący, podpisany dowód tożsamości (np. token konta usługi albo poświadczenia roli).
- login dowodemSerwis loguje się do managera tym dowodem. Manager weryfikuje podpis u wystawcy.
- sekret o krótkim TTLManager wydaje sekret zgodnie z polityką dla tej tożsamości.
- użycieSerwis łączy się z bazą.
- rotacjaPrzed wygaśnięciem manager rotuje sekret; serwis pobiera nowy.
💥 Wyciek
- sekret w loguSekret wycieka (np. do logów).
- odwołanieManager odwołuje sekret; krótki TTL i tak ograniczał okno ataku.
Żaden człowiek nie zna sekretu, więc nie może go wkleić do czatu. Pierwszy dowód tożsamości jest podpisany przez platformę i krótko żyjący, więc kradzież daje krótkie okno. Każdy odczyt sekretu jest w logu audytu managera.
- Minimalizuj: liczbę widzów sekretu i czas jego ważności.
- Secret zero rozwiązuje tożsamość platformy, nie kolejny sekret.
- Rotacja i odwołanie muszą być zautomatyzowane.
Kubernetes Secrets: base64 to nie szyfrowanie
wygodne, ale domyślnie odkryteObiekt Secret wygląda jak ConfigMap na sekrety (także do 1 MiB). Wartości są zakodowane w base64 — to kodowanie, nie szyfrowanie. Domyślnie API server zapisuje Secrety w etcd niezaszyfrowane. Dokumentacja Kubernetesa wprost ostrzega: każdy, kto ma dostęp do API z prawem odczytu Secretów lub dostęp do etcd, może je przeczytać; a każdy, kto może utworzyć poda w namespace, może zamontować w nim dowolny Secret z tego namespace. Dlatego produkcja włącza szyfrowanie w spoczynku (EncryptionConfiguration, najlepiej provider kms v2) i ostre RBAC.
▶ Zapis i montaż
- create SecretRBAC sprawdza prawo tworzenia Secretów w namespace.
- szyfrowanie DEKAPI server szyfruje dane lokalnym kluczem danych (DEK).
- DEK zaszyfrowany KEKPlugin KMS szyfruje DEK kluczem z zewnętrznego KMS (KEK nigdy nie opuszcza KMS).
- szyfrogram w etcdW etcd ląduje szyfrogram i zaszyfrowany DEK. Kopia zapasowa etcd sama w sobie nie zdradza sekretu.
- kubelet pobieraKubelet dostaje Secret tylko dla podów na swoim węźle (Node authorizer).
- tmpfsSecret montowany jako wolumen trafia do tmpfs (pamięć), a nie na dysk węzła.
💥 Bez szyfrowania w spoczynku
- base64 w etcdSecret leży w etcd jako czytelne dane.
- wyciek backupuWyciek kopii zapasowej etcd = wyciek wszystkich Secretów klastra.
Trzy warstwy: szyfrowanie w spoczynku z kluczem w zewnętrznym KMS chroni etcd i backupy; RBAC (bez list/watch Secretów dla zwykłych ról, bo dają dostęp do treści) chroni API; Node authorizer sprawia, że kubelet widzi tylko Secrety swoich podów. Bez tych warstw Secret to tylko „ukryta” ConfigMapa.
Prawo create pods w namespace oznacza praktycznie prawo odczytu każdego Secretu tego namespace. Rozdzielaj namespace według granic zaufania.
- base64 ≠ szyfrowanie; domyślnie etcd trzyma Secrety jawnie.
- Produkcja: EncryptionConfiguration z KMS v2 + RBAC.
- Secret w K8s często jest tylko „ostatnią milą” sekretu z zewnętrznego managera.
HashiCorp Vault i OpenBao
sekrety dynamiczne, lease i politykiVault to szeroko stosowany, niezależny od chmury manager sekretów. OpenBao to jego fork zarządzany przez OpenSSF (Linux Foundation). Model: klient loguje się metodą uwierzytelniania (Kubernetes, AWS IAM, JWT/OIDC, AppRole…) i dostaje token z politykami. Polityki są oparte na ścieżkach, a domyślnie wszystko jest zabronione. Najmocniejsza funkcja to sekrety dynamiczne: silnik bazy danych generuje poświadczenia do bazy dynamicznie, na żądanie, z lease (TTL), i odwołuje je po wygaśnięciu lease.
▶ Normalnie
- login: rola + JWTPod wysyła do Vaulta token swojego konta usługi i nazwę roli.
- TokenReviewVault pyta API Kubernetesa, czy token jest ważny, i sprawdza, czy konto usługi i namespace pasują do roli.
- token Vaulta + politykiVault wydaje token z TTL i politykami przypisanymi do roli.
- read database/creds/ordersPod prosi o poświadczenia do bazy.
- CREATE ROLE … VALID UNTILVault tworzy w bazie nowego użytkownika według szablonu SQL z roli.
- user/hasło + lease 1 hPod dostaje unikalne poświadczenia z lease.
💥 Lease wygasa / wyciek
- hasło w loguPoświadczenia wyciekły albo pod zniknął bez odnowienia lease.
- revokePo wygaśnięciu lease (lub ręcznym
vault lease revoke) Vault usuwa użytkownika z bazy. Wyciek dotyczy jednego poda i ma termin ważności.
Brak secret zero: pod loguje się tożsamością nadaną przez Kubernetesa. Polityki domyślnie zabraniają wszystkiego, a każda rola ma minimalny dostęp. Sekrety dynamiczne są unikalne per klient i krótko żyjące, więc wyciek jest lokalny i ma termin ważności. Vault zapisuje żądania w urządzeniach audytu (audit devices), a wrażliwe wartości haszuje (HMAC). Dane w magazynie Vaulta są zaszyfrowane; po restarcie Vault jest zapieczętowany (sealed) i nie odczyta niczego bez odpieczętowania.
🔬 Głębiej: seal/unseal, transit, magazyn
Seal. Klucz główny szyfrujący dane jest chroniony. Domyślnie klucz odpieczętowujący dzieli się algorytmem Shamira na części (np. 5 części, próg 3), które mają różne osoby. W produkcji częściej stosuje się auto-unseal: klucz chroni chmurowy KMS lub HSM, więc restart nie wymaga ludzi.
Transit. Silnik transit to szyfrowanie jako usługa: aplikacja wysyła dane, a dostaje szyfrogram. Klucz domyślnie nie opuszcza Vaulta (eksport trzeba jawnie włączyć przy tworzeniu klucza), więc aplikacja nie zarządza kluczami.
Magazyn. Popularny backend to zintegrowany magazyn (Integrated Storage) oparty na Rafcie — znów quorum. W produkcji HashiCorp zaleca co najmniej 5 węzłów (3 węzły tolerują awarię tylko jednego).
- Auth method zamienia tożsamość platformy na token Vaulta.
- Sekrety dynamiczne: unikalne, z lease, automatycznie odwoływane.
- Vault (BSL) albo OpenBao (open source) — ten sam model.
Chmurowe menedżery sekretów
AWS Secrets Manager, Google Secret Manager, Azure Key VaultFirmy osadzone w jednej chmurze zwykle wybierają jej natywny manager: zero utrzymania, integracja z IAM, KMS i audytem. AWS Secrets Manager szyfruje sekrety kluczem KMS i rotuje je funkcją Lambda (dla RDS i części innych usług jest gotowa, zarządzana rotacja). Wersje mają etykiety AWSCURRENT, AWSPENDING i AWSPREVIOUS. Google Secret Manager trzyma wersje sekretów z IAM na poziomie sekretu; sam nie zmienia wartości — wysyła powiadomienia o rotacji do Pub/Sub, a rotację wykonuje Twój kod. Azure Key Vault trzyma sekrety, klucze i certyfikaty, ma kontrolę dostępu Azure RBAC i soft-delete (domyślnie włączony i nie da się go wyłączyć), a dostęp z aplikacji daje managed identity.
▶ Rotacja według harmonogramu
- createSecretFunkcja generuje nowe hasło i zapisuje je jako wersję z etykietą
AWSPENDING. - setSecretFunkcja ustawia nowe hasło w bazie.
- testSecretFunkcja sprawdza, czy nowe hasło działa.
- finishSecretEtykieta
AWSCURRENTprzechodzi na nową wersję, a stara dostajeAWSPREVIOUS. - GetSecretValue (cache)Aplikacja z rolą IAM pobiera bieżącą wersję, zwykle przez bibliotekę z cache odświeżanym co jakiś czas.
💥 Aplikacja z hasłem w pamięci
- stare hasłoW strategii jednego użytkownika stare hasło przestaje działać po rotacji. Aplikacja z hasłem w pamięci dostaje błędy logowania.
- ponów z nowymRozwiązanie: przy błędzie uwierzytelnienia pobierz sekret ponownie albo użyj strategii naprzemiennych użytkowników (dwa konta, rotowane na zmianę).
| Usługa | Mocne strony | Kiedy |
|---|---|---|
| AWS Secrets Manager | wbudowana rotacja (Lambda / zarządzana), replikacja między regionami, polityki zasobów | flota w AWS, bazy RDS |
| SSM Parameter Store SecureString | tanio, hierarchia ścieżek, typ SecureString | proste sekrety bez rotacji |
| Google Secret Manager | wersje, IAM per sekret, CMEK, powiadomienia o rotacji | flota w GCP |
| Azure Key Vault | sekrety + klucze + certyfikaty, Managed HSM, RBAC | flota w Azure, zarządzanie certyfikatami |
| Vault / OpenBao | sekrety dynamiczne, multi-cloud, PKI, transit | wiele chmur i on-prem, jedna polityka |
Sekret jest zaszyfrowany kluczem z KMS, a dostęp do wartości wymaga uprawnień IAM (i do klucza). Dostęp ma tylko principal z polityką IAM (rola aplikacji, managed identity, konto usługi), a odczyty trafiają do logów audytu (CloudTrail, Cloud Audit Logs — w GCP po włączeniu logów Data Access, Azure Monitor). Rotacja zamyka okno ataku po cichym wycieku. Soft-delete (Key Vault) chroni przed przypadkowym usunięciem.
- Natywny manager = IAM + KMS + audyt bez utrzymania.
- Rotacja AWS: createSecret → setSecret → testSecret → finishSecret.
- Aplikacja musi przeżyć rotację: cache z odświeżaniem i ponowienie przy błędzie logowania.
Jak sekret trafia do serwisu
SDK, sidecar, CSI, operator — gdzie leży jawny tekstManager to połowa sprawy. Druga połowa: jak sekret dociera do procesu i gdzie po drodze jest jawny. Duże firmy wybierają między czterema wzorcami:
| Wzorzec | Jak działa | Jawny tekst w | Kiedy |
|---|---|---|---|
| SDK w aplikacji | aplikacja sama woła API managera | tylko pamięć procesu | maksymalne bezpieczeństwo, kod zna managera |
| Vault Agent Injector | webhook dodaje sidecar, który loguje się i renderuje pliki do /vault/secrets | wolumen w pamięci poda | aplikacja ma czytać plik, bez zmiany kodu |
| Secrets Store CSI Driver | sterownik CSI montuje sekret z managera jako wolumen (dostawcy: AWS, Azure, GCP, Vault) | wolumen poda; opcjonalnie synchronizowany do Secretu K8s | wiele managerów, montaż plików |
| External Secrets Operator | operator synchronizuje sekret z managera do obiektu Secret w K8s | Secret w etcd + pod | aplikacje już używają Secretów K8s |
▶ External Secrets Operator
- odczyt (rola operatora)Operator, według
SecretStoreiExternalSecret, czyta sekret tożsamością przypisaną do SecretStore. - zapis SecretOperator tworzy lub aktualizuje Secret w Kubernetesie.
- env / wolumenPod używa zwykłego Secretu — bez zmian w aplikacji.
- refreshIntervalOperator cyklicznie synchronizuje zmiany (np. po rotacji).
▶ Secrets Store CSI Driver
- start podaKubelet montuje wolumen CSI zdefiniowany przez
SecretProviderClass. - odczyt tożsamością podaDostawca pobiera sekret, zwykle tożsamością (workload identity) tego poda.
- plik w wolumenieSekret trafia jako plik do wolumenu poda. Bez synchronizacji nie powstaje kopia w etcd.
Wszystkie wzorce uwierzytelniają się do managera tożsamością (konto usługi, workload identity), a nie zapisanym hasłem. Różnią się powierzchnią: SDK i CSI bez synchronizacji nie zostawiają kopii w etcd, a ESO zostawia, więc wymaga szyfrowania w spoczynku i RBAC. Pliki w wolumenach z pamięci są lepsze niż zmienne środowiskowe, bo nie dziedziczą ich procesy potomne i nie widać ich w inspekcji kontenera (np. docker inspect pokazuje zmienne środowiskowe).
- Pytaj: ile kopii sekretu powstaje i gdzie są jawne?
- ESO: wygoda (zwykłe Secrety), ale kopia w etcd.
- Plik w tmpfs > zmienna środowiskowa.
Sekrety w GitOps: Sealed Secrets i SOPS
szyfrogram w repozytorium, klucz poza nimW GitOps „wszystko jest w Git”. Sekret w Git jawnie to katastrofa, więc albo trzymasz w Git tylko referencję (ExternalSecret wskazujący sekret w managerze), albo szyfrogram. Sealed Secrets (Bitnami): kontroler w klastrze ma parę kluczy; kubeseal szyfruje sekret kluczem publicznym do obiektu SealedSecret, który można bezpiecznie commitować — odszyfrować go może tylko kontroler. SOPS szyfruje pliki YAML/JSON kluczami z KMS chmury, age lub PGP; Flux ma wbudowaną obsługę odszyfrowania SOPS.
▶ Normalnie
- kubesealDeveloper szyfruje Secret kluczem publicznym kontrolera. Domyślnie szyfrogram jest związany z nazwą i namespace.
- commit SealedSecretDo repozytorium trafia tylko szyfrogram.
- syncNarzędzie GitOps aplikuje SealedSecret do klastra.
- odszyfrowanieKontroler odszyfrowuje kluczem prywatnym i tworzy zwykły Secret.
💥 Kopiowanie do innego namespace
- ten sam szyfrogram, inny namespaceKtoś kopiuje SealedSecret do namespace, do którego nie powinien mieć sekretu.
- odmowaW domyślnym zakresie (strict) odszyfrowanie się nie uda, bo nazwa i namespace są częścią szyfrowania.
W repozytorium jest tylko szyfrogram; klucz prywatny jest w klastrze (Sealed Secrets) lub w KMS (SOPS). Kradzież repozytorium nie zdradza sekretów. Trzeba jednak pamiętać, że historia Git jest wieczna: jeśli klucz kiedyś wycieknie, stare szyfrogramy da się odszyfrować — dlatego po wycieku klucza rotuje się sekrety, nie tylko klucz.
- GitOps: referencja (ESO) albo szyfrogram (Sealed Secrets, SOPS) — nigdy jawny tekst.
- SOPS szyfruje pliki konfiguracyjne kluczami z KMS, age lub PGP.
- Rotacja szyfrogramów w Git jest trudniejsza niż w managerze.
Szyfrowanie kopertowe, KMS i HSM
dlaczego klucz główny nigdy nie wychodzi z sejfuPod spodem każdy manager sekretów korzysta z tego samego wzorca. Szyfrowanie kopertowe: dane szyfrujesz lokalnie kluczem danych (DEK), a sam DEK szyfrujesz kluczem głównym (KEK), który mieszka w KMS lub HSM i nigdy go nie opuszcza. Zapisujesz szyfrogram danych razem z zaszyfrowanym DEK. Do KMS wysyłasz tylko mały DEK, więc dane mogą mieć dowolny rozmiar, a KMS nie staje się wąskim gardłem. AWS KMS chroni klucze w modułach HSM z walidacją FIPS 140-3.
▶ Szyfrowanie
- GenerateDataKeyAplikacja z uprawnieniem IAM do klucza prosi KMS o klucz danych.
- DEK jawny + DEK zaszyfrowanyKMS zwraca DEK w dwóch postaciach.
- AES-GCM lokalnieAplikacja szyfruje dane jawnym DEK i od razu usuwa go z pamięci.
- zapis: szyfrogram + zaszyfrowany DEKZapisywane jest tylko to, co bez KMS jest bezużyteczne.
▶ Odszyfrowanie
- odczytAplikacja czyta szyfrogram i zaszyfrowany DEK.
- Decrypt(DEK)KMS sprawdza IAM i politykę klucza, loguje operację i zwraca jawny DEK.
- odszyfrowanie lokalneAplikacja odszyfrowuje dane.
💥 Kradzież bazy
- dump bazyAtakujący kradnie magazyn: ma szyfrogramy i zaszyfrowane DEK.
- brak dostępu do KMSBez uprawnień do klucza w KMS nie odszyfruje DEK, więc dane są bezużyteczne. Odebranie uprawnień do klucza „wyłącza” dostęp do wszystkich danych naraz.
KEK nie opuszcza HSM, więc nie da się go skopiować. Każde użycie klucza jest autoryzowane (IAM + polityka klucza) i zapisane w audycie. Rotacja KEK nie wymaga ponownego szyfrowania wszystkich danych. Kradzież samych danych bez dostępu do KMS jest bezużyteczna.
- DEK szyfruje dane; KEK w KMS szyfruje DEK.
- Do KMS idzie tylko mały klucz, nie dane.
- Ten wzorzec stoi za KMS v2 w Kubernetesie, Vaultem i chmurowymi managerami.
Tożsamość zamiast sekretu
workload identity i SPIFFE/SPIRENajlepszy sekret to taki, którego nie ma. Trend dużych firm: zamiast długożyjących kluczy dostępu, tożsamość workloadu wymieniana na krótko żyjące poświadczenia. W chmurach: EKS ma IRSA (projektowany token konta usługi + OIDC + sts:AssumeRoleWithWebIdentity) i nowsze EKS Pod Identity; GKE ma Workload Identity Federation for GKE; Azure ma Microsoft Entra Workload ID (federacja tokenu konta usługi). Niezależnie od chmury: SPIFFE (standard tożsamości, projekt CNCF ze statusem graduated) i SPIRE (implementacja) wydają workloadom krótko żyjące dokumenty tożsamości SVID (certyfikat X.509 lub JWT) przez lokalne Workload API.
▶ EKS IRSA
- projektowany token SAKubelet montuje w podzie krótko żyjący token konta usługi z audience dla STS, podpisany przez klaster.
- AssumeRoleWithWebIdentitySDK AWS wysyła token do STS. STS weryfikuje podpis przez dostawcę OIDC klastra i warunki zaufania roli (namespace i konto usługi).
- poświadczenia tymczasoweSTS zwraca poświadczenia roli z terminem wygaśnięcia. SDK odświeża je samo.
- wywołanie APIPod woła np. S3 lub Secrets Manager. Żaden klucz dostępu nie istnieje.
▶ SPIFFE / SPIRE
- atestacja węzłaAgent SPIRE udowadnia serwerowi SPIRE, na jakim węźle działa (np. przez dokument tożsamości instancji chmury).
- Workload API (gniazdo Unix)Proces pyta lokalnego agenta o tożsamość — bez żadnego hasła.
- atestacja workloaduAgent sprawdza, kim jest proces (np. namespace, konto usługi i obraz z kubeleta).
- X.509-SVIDProces dostaje certyfikat z SPIFFE ID, np.
spiffe://acme.com/ns/prod/sa/orders, rotowany automatycznie przed wygaśnięciem. - mTLS / federacjaCertyfikatem robi mTLS z innym serwisem; JWT-SVID może służyć do federacji z chmurą.
Nie ma czego ukraść na długo: poświadczenia żyją minuty–godziny i są rotowane automatycznie. Tożsamość wynika z atestacji (sprawdzonych faktów o węźle i procesie), a nie z posiadania sekretu. Uprawnienia są przypięte do tożsamości (rola IAM, polityka mTLS), więc odebranie dostępu to zmiana polityki, a nie polowanie na kopie klucza.
- Workload identity usuwa długożyjące klucze chmurowe z podów.
- SPIFFE ID + SVID = przenośna tożsamość serwisu (używają jej m.in. Istio).
- Sekret zostaje tylko tam, gdzie system docelowy nie umie federacji (np. stara baza) — i wtedy sekret dynamiczny.
Sekrety: między czym wybierasz
profil → typowy wybór| Profil | Typowy wybór | Trade-off |
|---|---|---|
| Jedna chmura | natywny manager + workload identity (+ CSI lub ESO w K8s) | zero utrzymania vs lock-in |
| Multi-cloud / on-prem | Vault lub OpenBao, auth przez tożsamość platformy | jedna polityka vs utrzymanie krytycznego klastra |
| Bazy z wieloma klientami | sekrety dynamiczne (Vault) lub rotacja managera | unikalne poświadczenia vs obciążenie bazy |
| GitOps | ESO (referencje) albo SOPS / Sealed Secrets | jedno źródło w managerze vs wszystko w Git |
| Ruch serwis–serwis | mTLS z SPIFFE (mesh / SPIRE) zamiast kluczy API | brak sekretów vs złożoność PKI |
Anti-patterny
Galeria błędów, które duże firmy wyeliminowały — zwykle po bolesnym incydencie.
Galeria anti-patternów sekretów
i co zrobić zamiast| Anti-pattern | Dlaczego źle | Zamiast |
|---|---|---|
| Sekret w repozytorium | historia Git jest wieczna; usunięcie commita nie usuwa kopii | skanowanie (push protection), rotacja po wycieku, referencje do managera |
Sekret w obrazie (ENV, ARG, plik) | obraz trafia do rejestrów i cache; warstwy da się odczytać | sekret w runtime; przy buildzie RUN --mount=type=secret |
| Sekret w zmiennej środowiskowej | dziedziczą go procesy potomne, widać go w docker inspect, trafia do zrzutów i logów | plik w tmpfs lub SDK |
| Sekret w logach | logi mają szeroki dostęp i długą retencję | maskowanie w loggerze, typy „Secret” z toString() bez wartości |
| Długożyjący klucz dostępu | wyciek działa miesiącami | workload identity, poświadczenia tymczasowe |
| Jeden sekret dla wszystkich serwisów | wyciek z jednego serwisu = dostęp wszędzie; brak audytu „kto” | sekret per serwis, sekrety dynamiczne |
| Rotacja „kiedyś ręcznie” | nikt jej nie robi, a pierwsza rotacja psuje produkcję | automatyczna rotacja i test, że aplikacja ją przeżywa |
| Secret K8s bez szyfrowania w spoczynku | backup etcd zdradza wszystko | EncryptionConfiguration z KMS v2 |
Serwis w EKS czyta hasło do RDS ze zmiennej środowiskowej ustawionej z Secretu K8s, który ktoś utworzył ręcznie rok temu. Wymień trzy zmiany, które przybliżą go do standardu dużych firm.
Odpowiedź
1) Hasło w AWS Secrets Manager z automatyczną rotacją (lub IAM database authentication dla RDS). 2) Dostarczanie przez Secrets Store CSI Driver lub SDK z workload identity (IRSA / Pod Identity) zamiast zmiennej środowiskowej. 3) Aplikacja odporna na rotację: cache z odświeżaniem i ponowne pobranie sekretu przy błędzie logowania. Jeśli zostaje Secret K8s — szyfrowanie w spoczynku i RBAC.
Egzamin + ściągawka
sprawdź, co zostało w głowieŚciągawka
| Narzędzie / mechanizm | Co robi | Wybierz, gdy |
|---|---|---|
| DNS A/SRV | nazwa → adres (SRV: + port); cache przez TTL | uniwersalność ważniejsza niż szybkość reakcji |
| etcd / ZooKeeper / Consul | rejestr CP: lease/sesja, watch, quorum | potrzebujesz spójnego rejestru i watchy |
| Eureka | rejestr AP, heartbeat, self-preservation | flota Spring Cloud, dostępność ponad spójność |
| K8s Service + EndpointSlice | ClusterIP + DNS, readiness decyduje o ruchu | wszystko w Kubernetesie |
| Istio / Linkerd | proxy przy serwisie + mTLS + polityki dostępu/ruchu | potrzebujesz mTLS i kontroli ruchu między serwisami |
| Cloud Map / VPC Lattice | zarządzany rejestr / sieć serwisów z IAM | jedna chmura, wiele kont |
| ConfigMap (env / wolumen) | env: przy starcie; wolumen: aktualizacja z opóźnieniem | konfiguracja deploy-time, GitOps |
| Spring Cloud Config + Bus | konfiguracja z Git, @RefreshScope, refresh przez szynę | flota Spring/JVM |
| AWS AppConfig | walidator, strategia wdrożenia, rollback na alarm | zmiany w biegu z kontrolą ryzyka |
| OpenFeature + platforma flag | lokalna ewaluacja flag, wymienny dostawca | oddzielenie deployu od release |
| K8s Secret + KMS v2 | szyfrowanie kopertowe w etcd | „ostatnia mila” sekretu w klastrze |
| Vault / OpenBao | auth method, polityki, sekrety dynamiczne, transit | multi-cloud, unikalne poświadczenia |
| Secrets Manager / Secret Manager / Key Vault | natywne IAM + KMS + audyt; rotacja: AWS — Lambda, GCP — powiadomienia Pub/Sub + Twój kod | flota w jednej chmurze |
| ESO / Secrets Store CSI | sync do Secretu / montaż pliku z managera | Kubernetes + zewnętrzny manager |
| Sealed Secrets / SOPS | szyfrogram w Git | GitOps bez zewnętrznego managera |
| IRSA / Pod Identity / Workload Identity / SPIRE | tożsamość workloadu → krótkie poświadczenia | zawsze, gdy cel umie federację |
Wracamy do poda z 3:12. Ruch: Kubernetes dodał go do EndpointSlice, gdy readiness przeszła, a proxy meshu dostały nowy endpoint przez xDS. Konfiguracja: obraz jest ten sam co wszędzie, a wartości przyszły z manifestu w Git (deploy-time) i z systemu konfiguracji z etapowym rolloutem (runtime). Hasło do bazy: pod pokazał tożsamość nadaną przez platformę (token konta usługi), wymienił ją na krótko żyjące poświadczenia (Vault lub chmurowy manager), a mTLS dał mu certyfikat SPIFFE. Atakujący z obrazem kontenera nie ma nic, bo w obrazie nie ma żadnego sekretu, a tożsamości nie da się ukraść z obrazu. Następny krok: sprawdź, który z anti-patternów z części IV jest w Twoim systemie.