Kubernetes Secrets i pułapka echo -n

vilya.pl 3 tygodni temu

To jest krótki wpis o tym, dlaczego warto dobrze znać narzędzia, których się używa. Okazuje się, iż choćby te najprostsze mogą czasami zaskoczyć…

Krótki zarys: na testowy klaster Kubernetesa (K8s) trafił mikroserwis, który komunikował się z innymi przez system kolejkowy RabbitMQ. Jednakże zaraz po starcie poda pojawił się komunikat, iż aplikacja nie może połączyć się z serwerem RabbitMQ ze względu na nieprawidłowe dane uwierzytelniające.

W pierwszej kolejności sprawdziłem konfigurację w pliku manifestu K8s (YAML) i zweryfikowałem nazwy zmiennych środowiskowych oraz nazwę sekretu K8s, ale wszystko wyglądało w porządku. Zajrzałem więc do zawartości sekretu, ponieważ w środowisku testowym miałem do niego dostęp.

W celu uproszczenia przyjmijmy, iż sekrety są składowane w domyślnej przestrzeni nazw K8s (default), a nazwa sekretu to my-credentials:

$ kubectl describe secret my-credentials Name: my-credentials Namespace: default Labels: <none> Annotations: <none> Type: Opaque Data ==== password: 12 bytes username: 7 bytes

Polecenia kubectl get secret <SECRET_NAME> oraz kubectl describe secret <SECRET_NAME> nie pokazują domyślnie zawartości, żeby chronić nieuważnego użytkownika przed nieumyślnym ujawnieniem danych wrażliwych (np. w sytuacji, gdy wynik polecenia trafia do ogólnodostępnych logów). Pamiętajmy, iż base64 to jedynie kodowanie tekstu, a nie jego szyfrowanie.

Aby odczytać zawartość, wykonałem:

$ kubectl get secret my-credentials -o jsonpath='{.data}' | jq { "password": "cGFzc3dvcmQxMjMK", "username": "bWllY3p5aw==" } $ echo 'bWllY3p5aw==' | base64 -d mieczyk$ echo 'cGFzc3dvcmQxMjMK' | base64 -d password123

Po odkodowaniu base64 okazało się, iż dane uwierzytelniające są prawidłowe (mieczyk:password123), ale jedna rzecz zwróciła moją uwagę: na standardowym wyjściu, po mieczyk znak zachęty pojawił się w tej samej linii, a po haśle password123 już w nowej linii.

Chyba już wiedziałem, co jest nie tak… Szybka weryfikacja:

$ echo 'password123' | base64 cGFzc3dvcmQxMjMK $ echo -n 'password123' | base64 cGFzc3dvcmQxMjM=

Bingo! Okazało się, iż podczas tworzenia sekretu K8s, hasło zostało podane razem ze znakiem nowej linii, które również zostało zakodowane w base64 i wykorzystane później do próby nawiązania połączenia z RabbitMQ. Poprawne hasło oczywiście nie zawierało białego znaku nowej linii i stąd ten początkowy błąd.

Należy więc pamiętać, iż polecenie echo domyślnie dodaje znak nowej linii, a przełącznik -n temu zapobiega. Tego typu pomyłki mogą zdarzyć się w sytuacji, kiedy próbujemy dodać do sekretu zawartość pliku tekstowego, utworzonego z linii poleceń, na przykład echo 'password' > ./pass.txt.

Scena z filmu Chłopaki nie płaczą (2000).

Jeśli więc chcemy dodać sekret, w którym hasło jest brane z pliku, powinniśmy zrobić to w ten sposób:

$ echo -n 'password123' > ./pass.txt $ kubectl create secret generic my-credentials --from-literal=username=mieczyk --from-file=password=./pass.txt secret/my-credentials created $ kubectl get secret my-credentials -o jsonpath='{.data}' | jq { "password": "cGFzc3dvcmQxMjM=", "username": "bWllY3p5aw==" }

Ewentualnie można jeszcze użyć polecenia printf, które nie dodaje znaku nowej linii w trybie domyślnym:

$ printf %s 'password123' > ./pass.txt
Idź do oryginalnego materiału