To jest krótki wpis o tym, dlaczego warto dobrze znać narzędzia, których się używa. Okazuje się, że nawet 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, że 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, że 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, że 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ę, że 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ę, że 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ć, że 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.

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
