Dane uwierzytelniające proxy trafiają do publicznych logów kompilacji częściej, niż się wydaje. Jeden nieostrożny curl -v, jedna zmienna zapisana jawnie, jedno hasło w adresie URL — i Twój login z hasłem leży już w historii pipeline'u, widoczny dla całego zespołu. W tym poradniku pokażemy, jak tego uniknąć.

Wprowadzenie: jak dane uwierzytelniające proxy wyciekają do logów i historii

Wyobraź sobie typową sytuację. Konfigurujesz kompilację, która korzysta z proxy Proxeon, aby uzyskać dostęp do zewnętrznych zasobów. Aby szybko sprawdzić połączenie, wpisujesz hasło bezpośrednio w adresie: http://user:pass@host:port. Kompilacja przechodzi, cieszysz się. A po tygodniu okazuje się, że hasło jest widoczne w logu każdego uruchomienia, w historii powłoki na runnerze, a nawet w szczegółowych danych wyjściowych klienta.

To nie rzadkość, a prawidłowość. Dane uwierzytelniające proxy mają nieprzyjemną cechę: są potrzebne w prawie każdym wywołaniu sieciowym, więc łatwo przedostają się do dziesiątek miejsc jednocześnie.

Co zyskasz na końcu

Po ukończeniu poradnika będziesz mógł skonfigurować CI/CD tak, aby dane uwierzytelniające proxy nie pojawiły się w żadnym logu, ani w historii poleceń, ani w repozytorium. Nauczysz się korzystać z sekretów popularnych systemów, wyłączać niebezpieczne tryby debugowania, bezpiecznie zmieniać hasło bez zatrzymywania kompilacji i sprawdzać to wszystko gotowym skryptem.

Dla kogo jest ten poradnik

Materiał jest przeznaczony dla inżynierów średniego szczebla: DevOps, programistów backendu, automatyków QA. Jeśli potrafisz już uruchomić pipeline i wiesz, czym jest zmienna środowiskowa, będziesz się czuć komfortowo. Zaawansowani czytelnicy znajdą sekcje o rotacji i audycie.

Co musisz wiedzieć wcześniej

Podstawowa konfiguracja zmiennych http_proxy i no_proxy nie jest tutaj powtarzana — poświęcono jej osobny materiał. Zakładamy, że połączenie z proxy już u Ciebie działa, a teraz zadaniem jest bezpieczne przechowywanie danych uwierzytelniających.

Ile czasu to zajmie

Na przeczytanie i zrozumienie zajmie Ci około 40 minut. Na wdrożenie w jednym pipeline od 30 minut do półtorej godziny, w zależności od systemu CI. Rotację i sprawdzanie na wyciek dodasz później; zajmą one po 15–20 minut.

Przygotowanie: co będzie potrzebne

Zanim zaczniesz, zgromadź wszystko, co niezbędne. To zaoszczędzi czas i uchroni przed przerwami w trakcie pracy.

Narzędzia i dostępy

  • Dostęp do Twojego projektu w CI/CD z uprawnieniami do edycji ustawień i sekretów.
  • Aktywna subskrypcja proxy Proxeon z loginem, hasłem, hostem i portem.
  • Lokalna maszyna z zainstalowanym curl, git, a także interpreterami Pythona 3 i Node.js, jeśli planujesz przykłady w tych językach.
  • Edytor tekstu do poprawiania konfiguracji pipeline'u.

Wymagania systemowe

Nie ma specjalnych wymagań. Wszystko działa na Linuxie, macOS i Windowsie. Runnery CI zwykle działają na Linuxie, więc większość przykładów podana jest w składni bash. Dla runnerów Windows różnice zostaną wspomniane osobno.

Co przygotować wcześniej

Zapisz bieżące dane uwierzytelniające proxy w niezawodnym menedżerze haseł. Przydadzą się podczas konfiguracji sekretów. Nie przechowuj ich w zwykłym pliku tekstowym na pulpicie.

Wskazówka: Załóż osobne konto proxy dla CI, jeśli Twój plan Proxeon na to pozwala. Wtedy kompromitacja danych kompilacji nie wpłynie na Twoje osobiste dane i odwrotnie.

Kopia zapasowa konfiguracji

Przed zmianą pipeline'u zrób kopię bieżącego pliku konfiguracyjnego. Po prostu skopiuj .gitlab-ci.yml, plik workflow lub Jenkinsfile do osobnego folderu poza repozytorium.

⚠️ Uwaga: Nigdy nie rób kopii zapasowej, commitując ją do tego samego repozytorium z hasłem w środku. Nawet w tymczasowej gałęzi dane trafią do historii git na zawsze.

Podstawowe pojęcia: terminy prostym językiem

Wyjaśnijmy kluczowe słowa, żeby dalej się nie gubić.

Dane uwierzytelniające proxy

To login i hasło, którymi Twój klient potwierdza prawo do korzystania z proxy Proxeon. Czasami zamiast loginu i hasła stosuje się przypisanie do adresu IP, ale tutaj mówimy o parze login-hasło.

Sekret w CI

Sekret — to specjalne przechowywanie wewnątrz systemu CI, do którego wkładasz wrażliwą wartość. System szyfruje ją i podstawia w kompilacji jako zmienną środowiskową, automatycznie ukrywając ją w logach.

Maskowanie

Maskowanie — to sytuacja, gdy CI zastępuje wartość sekretu w wyjściu gwiazdkami. Jeśli hasło przypadkowo się wydrukuje, zamiast niego zobaczysz coś w rodzaju [MASKED]. Nie zawsze działa idealnie, dlatego połączymy kilka zabezpieczeń.

Nagłówek Proxy-Authorization

Kiedy klient uwierzytelnia się na proxy, wysyła nagłówek HTTP Proxy-Authorization z zakodowanymi danymi uwierzytelniającymi. W trybie szczegółowego debugowania wiele klientów drukuje ten nagłówek w całości. Zdekodowanie go jest trywialne, dlatego taki wynik uważa się za wyciek.

Zakres widoczności

Zakres widoczności określa, które kompilacje mają dostęp do sekretu. Prawidłowo ograniczony sekret jest widoczny tylko dla chronionych gałęzi i nie trafia do forków ani pull requestów z zewnątrz.

Wskazówka: Zapamiętaj główną zasadę: sekret powinien istnieć w pamięci procesu dokładnie tak długo, jak jest potrzebny, i nie zostawiać śladów na dysku ani w wyjściu.

Krok 1: Zrozum główną pułapkę — hasło w URL

Cel etapu: nauczyć się rozpoznawać najczęstsze źródło wycieku i zrezygnować z niego na zawsze.

Najczęstszym błędem jest wpisywanie danych uwierzytelniających bezpośrednio w adres proxy: http://user:pass@host:port. To wygodne, więc robi tak prawie każdy początkujący. Problem polega na tym, że taki URL pojawia się w nieoczekiwanych miejscach.

Gdzie dokładnie pojawia się hasło z URL

  1. Lista procesów. Polecenie ps na runnerze pokaże pełny ciąg uruchomienia, łącznie z hasłem. Każdy proces na tej samej maszynie może go odczytać.
  2. Logi samego proxy. Niektóre logi serwerowe rejestrują ciąg połączenia. Jeśli URL zawiera hasło, trafia ono do logu.
  3. Historia poleceń powłoki. Plik .bash_history przechowuje wszystko, co wpisałeś, w tym hasło w URL.
  4. Szczegółowe dane wyjściowe klienta. Przy uruchomieniu z flagą trybu szczegółowego klient drukuje adres docelowy wraz z danymi uwierzytelniającymi.
  5. Logi CI. Jeśli zmienna z URL nie jest oznaczona jako sekret, jest drukowana jawnie na etapie echo lub przy błędzie.

Sprawdź to teraz. Wykonaj na dowolnej maszynie nieszkodliwe polecenie i spójrz na listę procesów.

curl -x http://mojuser:mojehaslo@proxy.proxeon.net:8080 https://przyklad.com & ps aux | grep curl

Zobaczysz swoje hasło jawnie w wyniku ps. To jest właśnie ten wyciek, który eliminujemy.

⚠️ Uwaga: Nawet jeśli kompilacja jest prywatna, do listy procesów runnera może mieć dostęp inny proces, inne zadanie na wspólnym runnerze lub narzędzie do monitorowania. Uznaj hasło w URL za publiczne.

Oczekiwany wynik: rozumiesz pięć miejsc wycieku i nigdy więcej nie będziesz wpisywać hasła w adres proxy.

✅ Sprawdzenie: uruchom testowe polecenie powyżej i upewnij się, że widzisz hasło w wyniku ps. Jeśli widzisz — poprawnie odwzorowałeś problem i jesteś gotowy go rozwiązać.

Krok 2: Właściwy sposób — zmienne środowiskowe i pliki danych uwierzytelniających

Cel etapu: przenieść dane uwierzytelniające z URL do bezpiecznych magazynów — zmiennych środowiskowych i specjalnych plików.

Idea jest prosta. Login i hasło przechowujemy oddzielnie od adresu. Klient czyta je ze środowiska lub z pliku z ograniczonymi uprawnieniami, a nie z linii poleceń. Dzięki temu nie trafiają do listy procesów ani do historii.

Wariant A: zmienne środowiskowe

Wiele klientów potrafi czytać dane uwierzytelniające proxy ze środowiska. Omówimy to na przykładach.

curl przez zmienną środowiskową

Ustaw adres proxy bez danych uwierzytelniających, a login i hasło przekaż osobną flagą, której wartość weź ze zmiennej.

  1. Wyeksportuj zmienną z danymi uwierzytelniającymi do środowiska (w CI zrobi to sekret, lokalnie — bezpieczne źródło).
  2. Przekaż jej wartość przez flagę -U, a nie w URL.
export PROXY_CREDS="$PROXEON_USER:$PROXEON_PASS"; curl -x http://proxy.proxeon.net:8080 -U "$PROXY_CREDS" https://przyklad.com

Nawet flaga -U ze zmienną jest lepsza niż hasło w URL, ale i tak jest widoczna w ps. Dlatego preferowany jest plik danych uwierzytelniających, o którym poniżej.

Python requests

W Pythonie czytaj dane uwierzytelniające ze środowiska przez os.environ i buduj słownik proxies w pamięci. Nic nie drukuj.

import os, requests; user=os.environ['PROXEON_USER']; pwd=os.environ['PROXEON_PASS']; proxy=f'http://{user}:{pwd}@proxy.proxeon.net:8080'; r=requests.get('https://przyklad.com', proxies={'http':proxy,'https':proxy}); print(r.status_code)

Tutaj hasło pozostaje w zmiennej wewnątrz procesu Pythona i nie trafia do linii poleceń. Najważniejsze, żeby nie logować zmiennej proxy w całości.

Node.js

W Node również bierz dane uwierzytelniające z process.env i twórz agenta proxy w kodzie.

const user=process.env.PROXEON_USER; const pass=process.env.PROXEON_PASS; const proxyUrl=`http://${user}:${pass}@proxy.proxeon.net:8080`; const {HttpsProxyAgent}=require('https-proxy-agent'); const agent=new HttpsProxyAgent(proxyUrl); fetch('https://przyklad.com',{agent}).then(r=>console.log(r.status));

Wskazówka: W każdym języku loguj tylko status odpowiedzi i, jeśli to konieczne, host docelowy. Nigdy nie drukuj całego obiektu z ustawieniami proxy — znajduje się w nim hasło.

Wariant B: plik .netrc

Plik .netrc — to klasyczny sposób przechowywania danych uwierzytelniających oddzielnie od poleceń. curl potrafi go czytać automatycznie.

  1. Utwórz plik .netrc w katalogu domowym runnera w locie, z sekretu CI.
  2. Wpisz linię z maszyną, loginem i hasłem.
  3. Ustaw uprawnienia 600, aby plik czytał tylko właściciel.
  4. Uruchom curl z flagą użycia netrc.
printf 'machine proxy.proxeon.net login %s password %s' "$PROXEON_USER" "$PROXEON_PASS" > ~/.netrc; chmod 600 ~/.netrc; curl --netrc -x http://proxy.proxeon.net:8080 https://przyklad.com

Teraz hasło nie pojawia się ani w linii poleceń, ani na liście procesów. Leży w pliku z uprawnieniami 600, który usuniesz na końcu kompilacji.

⚠️ Uwaga: Uprawnienia 600 są obowiązkowe. Bez nich curl może odmówić czytania pliku, a sam plik stanie się dostępny dla innych użytkowników na maszynie.

Wariant C: konfiguracja curl

curl potrafi czytać flagi z pliku konfiguracyjnego. Umieść tam proxy i dane uwierzytelniające, ustaw uprawnienia 600.

printf 'proxy = http://proxy.proxeon.net:8080\nproxy-user = "%s:%s"\n' "$PROXEON_USER" "$PROXEON_PASS" > ~/.curlrc; chmod 600 ~/.curlrc; curl https://przyklad.com

Przy obecności .curlrc z uprawnieniami 600 dane uwierzytelniające nie są widoczne w procesie i nie zapisują się w historii.

Wariant D: konfiguracja klienta aplikacji

Jeśli masz własną aplikację, która czyta konfigurację, przechowuj dane uwierzytelniające proxy w pliku konfiguracyjnym poza repozytorium. W repozytorium trzymaj tylko szablon z placeholderami, a rzeczywiste wartości podstawiaj na runnerze z sekretów.

Oczekiwany wynik: w żadnym przykładzie hasło nie pojawia się w linii poleceń ani na liście procesów. Żyje albo w zmiennej wewnątrz procesu, albo w pliku z uprawnieniami 600.

✅ Sprawdzenie: uruchom dowolny przykład i równolegle wykonaj ps aux | grep curl. Hasła w wyniku nie powinno być. Jeśli używasz netrc, sprawdź uprawnienia poleceniem ls -l ~/.netrc — powinno być -rw-------.

Krok 3: Sekrety w popularnych systemach CI — GitHub Actions, GitLab CI, Jenkins

Cel etapu: umieścić dane uwierzytelniające proxy w chronionym magazynie swojego systemu CI i podstawiać je bez wycieków.

GitHub Actions

W GitHub sekrety są przechowywane na poziomie repozytorium lub organizacji.

  1. Otwórz repozytorium i przejdź do sekcji ustawień Settings.
  2. Po lewej znajdź pozycję Secrets and variables, a następnie Actions.
  3. Kliknij przycisk New repository secret.
  4. Wpisz nazwę, na przykład PROXEON_USER, i wartość — swój login. Zapisz.
  5. Powtórz dla PROXEON_PASS z hasłem.

W workflow odwołuj się do sekretów przez kontekst secrets i przekazuj je do kroku jako zmienne środowiskowe.

steps: - name: request env: PROXEON_USER: ${{ secrets.PROXEON_USER }} PROXEON_PASS: ${{ secrets.PROXEON_PASS }} run: printf 'machine proxy.proxeon.net login %s password %s' "$PROXEON_USER" "$PROXEON_PASS" > ~/.netrc; chmod 600 ~/.netrc; curl --netrc -x http://proxy.proxeon.net:8080 https://przyklad.com

GitHub automatycznie maskuje wartości sekretów w logach. Jeśli hasło przypadkowo się wydrukuje, zobaczysz trzy gwiazdki.

⚠️ Uwaga: Sekrety domyślnie nie są dostępne w workflow uruchamianych z forków przez pull_request. Nie zmieniaj tego zachowania na pull_request_target bez absolutnej konieczności — wtedy zewnętrzny kontrybutor będzie mógł uzyskać Twoje dane uwierzytelniające.

GitLab CI

W GitLab sekrety nazywają się zmiennymi CI/CD i są konfigurowane w projekcie.

  1. Otwórz projekt, przejdź do Settings, a następnie CI/CD.
  2. Rozwiń sekcję Variables i kliknij Add variable.
  3. Wpisz klucz PROXEON_USER i wartość.
  4. Zaznacz pole Masked, aby wartość była ukrywana w logach.
  5. Zaznacz pole Protected, aby zmienna była dostępna tylko dla chronionych gałęzi i tagów.
  6. Powtórz dla PROXEON_PASS.

W .gitlab-ci.yml zmienne są dostępne automatycznie jako środowisko.

request: script: - printf 'machine proxy.proxeon.net login %s password %s' "$PROXEON_USER" "$PROXEON_PASS" > ~/.netrc - chmod 600 ~/.netrc - curl --netrc -x http://proxy.proxeon.net:8080 https://przyklad.com

Wskazówka: Flaga Masked w GitLab działa tylko dla wartości spełniających zasady: minimalna długość, bez znaków nowej linii, zestaw znaków zgodny z base64. Jeśli hasło nie jest maskowane, GitLab pokaże ostrzeżenie przy zapisie. W takim przypadku zmień hasło na spełniające wymagania.

Jenkins

W Jenkins dane uwierzytelniające są przechowywane w sekcji Credentials i podstawiane przez wtyczkę Credentials Binding.

  1. Otwórz Manage Jenkins, a następnie Credentials.
  2. Wybierz odpowiedni obszar, na przykład System i Global credentials.
  3. Kliknij Add Credentials.
  4. Wybierz typ Username with password.
  5. Wpisz login i hasło proxy, nadaj czytelny identyfikator, na przykład proxeon-creds.

W Jenkinsfile owiń użycie blokiem withCredentials. Jenkins maskuje wartości w konsoli.

withCredentials([usernamePassword(credentialsId: 'proxeon-creds', usernameVariable: 'PROXEON_USER', passwordVariable: 'PROXEON_PASS')]) { sh 'printf "machine proxy.proxeon.net login %s password %s" "$PROXEON_USER" "$PROXEON_PASS" > ~/.netrc; chmod 600 ~/.netrc; curl --netrc -x http://proxy.proxeon.net:8080 https://przyklad.com' }

⚠️ Uwaga: Jenkins maskuje tylko te wartości, które są ustawione przez Credentials Binding. Jeśli zbudujesz hasło jako ciąg w Groovy i wydrukujesz, maskowanie nie zadziała. Pracuj z danymi uwierzytelniającymi tylko wewnątrz bloku withCredentials i tylko w krokach sh.

Oczekiwany wynik: dane uwierzytelniające leżą w chronionym magazynie Twojego systemu CI, są podstawiane do kompilacji jako środowisko i maskowane w logach.

✅ Sprawdzenie: uruchom kompilację i otwórz log. Upewnij się, że zamiast hasła widoczne są gwiazdki lub znacznik maskowania. Spróbuj celowo wyświetlić zmienną przez echo — system powinien ją ukryć.

Krok 4: Logi — wyłączamy tryby drukujące Proxy-Authorization

Cel etapu: usunąć szczegółowe dane wyjściowe tam, gdzie ujawniają nagłówek autoryzacji, i pozostawić bezpieczny poziom logowania.

Maskowanie CI nie jest panaceum. Jeśli klient drukuje nagłówek Proxy-Authorization w base64, a system nie zna oryginalnego hasła dosłownie, maskowanie może nie zadziałać. Dlatego wyłączamy niebezpieczne tryby u źródła.

curl

Flaga -v, a zwłaszcza --trace, drukują nagłówki, w tym autoryzację proxy. W CI używaj trybu cichego.

  1. Usuń -v, --verbose, --trace i --trace-ascii z poleceń kompilacji.
  2. Do kontroli błędów używaj -sS: cicho, ale pokazując błędy.
  3. Jeśli potrzebujesz debugowania, używaj --trace tylko lokalnie, nigdy w CI.
curl -sS --netrc -x http://proxy.proxeon.net:8080 https://przyklad.com -o /dev/null -w '%{http_code}'

W ten sposób otrzymasz tylko kod odpowiedzi bez ani jednego nagłówka w wyjściu.

Python requests

Biblioteka requests sama w sobie nie drukuje danych uwierzytelniających, ale włączone logowanie urllib3 na poziomie DEBUG wypisuje nagłówki żądań. Utrzymuj poziom logowania na WARNING lub INFO.

import logging; logging.getLogger('urllib3').setLevel(logging.WARNING)

Wskazówka: Jeśli mimo wszystko potrzebujesz DEBUG do diagnozy, dodaj filtr logowania, który wycina nagłówek Proxy-Authorization z komunikatów. Ale prościej jest diagnozować lokalnie, a w CI trzymać WARNING.

Node.js

W Node unikaj ustawiania zmiennej NODE_DEBUG=http w CI — wypisuje ona nagłówki. Nie drukuj także całego obiektu agent ani obiektu żądania.

  1. Usuń NODE_DEBUG ze środowiska runnera.
  2. W obsłudze błędów drukuj tylko error.message, a nie cały obiekt.
  3. Nie używaj bibliotek loggerów żądań HTTP w produkcyjnej kompilacji.

⚠️ Uwaga: Stos wywołań nieobsłużonego wyjątku również może zawierać URL proxy z danymi uwierzytelniającymi, jeśli zbudowałeś URL z hasłem. To kolejny powód, aby nie umieszczać hasła w URL, a używać netrc lub oddzielnych pól.

Oczekiwany wynik: żadne narzędzie w CI nie drukuje nagłówka autoryzacji ani pełnego URL proxy.

✅ Sprawdzenie: uruchom kompilację i wyszukaj w logu linie Proxy-Authorization, Basic oraz nazwę Twojego użytkownika. Nie powinno być ani jednego dopasowania.

Krok 5: Rotacja hasła proxy bez przestoju kompilacji

Cel etapu: nauczyć się zmieniać hasło tak, aby kompilacje nie spadały, a stare hasło przestało działać.

Hasło proxy należy zmieniać okresowo i obowiązkowo po jakimkolwiek podejrzeniu wycieku. Zadaniem jest zrobić to bez okna przestoju.

Strategia nakładania

Idealny wariant to taki, w którym przez pewien czas działają zarówno stare, jak i nowe hasło. Jeśli Twój plan Proxeon pozwala na utworzenie drugiego konta lub dodatkowego zestawu danych uwierzytelniających, użyj tego.

  1. Utwórz nowe dane uwierzytelniające proxy w panelu Proxeon, nie usuwając starych.
  2. Dodaj nowe wartości do sekretów CI pod tymczasowymi nazwami, na przykład PROXEON_USER_NEW.
  3. Przełącz pipeline na nowe nazwy w osobnej gałęzi i uruchom kompilację.
  4. Upewnij się, że kompilacja przechodzi na nowych danych uwierzytelniających.
  5. Zastąp wartości głównych sekretów PROXEON_USER i PROXEON_PASS nowymi.
  6. Usuń tymczasowe sekrety.
  7. Odwołaj stare dane uwierzytelniające w panelu Proxeon.

W ten sposób w każdej chwili istnieje działający zestaw danych uwierzytelniających i kompilacje nie spadają.

Jeśli nakładanie nie jest dostępne

Gdy dostępna jest tylko jedna para danych uwierzytelniających, działaj w cichym oknie.

  1. Wybierz czas z minimalną aktywnością kompilacji.
  2. Wstrzymaj uruchamianie nowych pipeline'ów na kilka minut.
  3. Zmień hasło w panelu Proxeon.
  4. Natychmiast zaktualizuj wartość sekretu w CI.
  5. Uruchom kompilację testową.
  6. Wznów normalną pracę.

Wskazówka: Sporządź krótki regulamin rotacji i przechowuj go obok opisu pipeline'u. W stresującej sytuacji po wycieku gotowa lista kroków oszczędza nerwy i czas.

⚠️ Uwaga: Po zmianie hasła pamiętaj o usunięciu starego pliku netrc lub curlrc z runnera, jeśli jest buforowany między kompilacjami. W przeciwnym razie klient będzie nadal używać starych danych uwierzytelniających.

Oczekiwany wynik: hasło zostało zmienione, nowe kompilacje działają na nowych danych uwierzytelniających, stare hasło już nie działa.

✅ Sprawdzenie: spróbuj wykonać żądanie ze starym hasłem — powinien zostać zwrócony błąd autoryzacji proxy. Nowa kompilacja przechodzi pomyślnie.

Krok 6: Sprawdzanie na wyciek — gotowy skrypt audytu

Cel etapu: upewnić się, że danych uwierzytelniających nie ma w artefaktach, logach i repozytorium, i zautomatyzować to sprawdzanie.

Gdzie szukać

  • Artefakty kompilacji: zbudowane pliki, raporty, zrzuty.
  • Logi pipeline'u, w tym stare uruchomienia.
  • Historia repozytorium git.
  • Pamięci podręczne i pliki tymczasowe runnera.

Wyszukiwanie w artefaktach i logach

Pobierz artefakty i logi do lokalnego folderu i wykonaj wyszukiwanie po charakterystycznych markerach: nazwie użytkownika, części hasła, słowie Basic i nagłówku autoryzacji.

grep -RniE 'proxy-authorization|Basic [A-Za-z0-9+/=]{8,}|proxeon.*login|:[^@/]+@proxy' ./artefakty ./logi

Skrypt szuka nagłówka autoryzacji, ciągów base64 po słowie Basic, wzorca loginu w netrc i oznaki hasła w URL przed znakiem małpy. Jakiekolwiek dopasowanie — powód do wyjaśnienia.

Wyszukiwanie w historii git

Hasło mogło trafić do starego commita. Sprawdź całą historię.

git log -p -S 'proxy.proxeon.net' --all | grep -nE ':[^@/]+@proxy|password [^ ]+'

⚠️ Uwaga: Jeśli hasło zostało znalezione w historii git, samo usunięcie pliku nie wystarczy — pozostanie w starych commitach. Konieczne jest przepisanie historii specjalnymi narzędziami i, co ważniejsze, natychmiastowa zmiana hasła. Uznaj takie hasło za skompromitowane.

Automatyzacja w pipeline

Dodaj osobne zadanie, które skanuje zbudowane artefakty przed publikacją i kończy się niepowodzeniem przy wykryciu. Taki bezpiecznik łapie wyciek, zanim wydostanie się na zewnątrz.

leak_check: script: - if grep -RniE 'proxy-authorization|Basic [A-Za-z0-9+/=]{8,}' ./artefakty; then echo 'WYKRYTO WYCIEK'; exit 1; fi

Wskazówka: Dodatkowo podłącz gotowe skanery sekretów na etapie pre-commit lokalnie. Łapią one dane uwierzytelniające jeszcze przed commitem, nie pozwalając im trafić do repozytorium.

Oczekiwany wynik: ręczny audyt i automatyczne zadanie potwierdzają, że danych uwierzytelniających nie ma w żadnym miejscu.

✅ Sprawdzenie: uruchom skrypt audytu — powinien zakończyć się bez dopasowań. Następnie celowo umieść testową linię z markerem Basic w artefakcie i upewnij się, że skrypt ją znajduje i kończy się niepowodzeniem.

Krok 7: Lista kontrolna przed wdrożeniem pipeline'u

Cel etapu: przejść końcową weryfikację przed włączeniem pipeline'u do pracy.

Przejdź przez listę i zaznacz każdy punkt. Jeśli choć jeden nie jest spełniony, nie wdrażaj pipeline'u.

  1. Hasło proxy nigdzie nie jest zapisane w URL w formacie user:pass@host.
  2. Login i hasło są przechowywane tylko w sekretach CI, nie w plikach repozytorium.
  3. Sekrety są oznaczone jako maskowalne i chronione.
  4. Sekrety nie są dostępne dla kompilacji z forków i zewnętrznych pull requestów.
  5. Z poleceń usunięto flagi trybu szczegółowego i śledzenia.
  6. Poziom logowania bibliotek HTTP nie jest DEBUG.
  7. Zmienne debugowania, takie jak NODE_DEBUG, nie występują w środowisku runnera.
  8. Pliki netrc i curlrc są tworzone w locie i mają uprawnienia 600.
  9. Pliki danych uwierzytelniających są usuwane na końcu kompilacji lub leżą w efemerycznym runnerze.
  10. W pipeline jest zadanie sprawdzania na wyciek.
  11. Historia git została sprawdzona i nie zawiera danych uwierzytelniających.
  12. Istnieje regulamin rotacji hasła.

Wskazówka: Zapisz tę listę kontrolną jako szablon i dołączaj ją do każdego nowego pipeline'u, w którym używane jest proxy. Jednolitość zmniejsza liczbę błędów.

✅ Sprawdzenie: wszystkie dwanaście punktów zaznaczonych. Dopiero teraz pipeline jest gotowy do wdrożenia.

Sprawdzenie wyniku: jak się upewnić, że wszystko działa

Zbierzmy końcową weryfikację w jeden scenariusz.

Lista kontrolna działania

  • Kompilacja z powodzeniem korzysta z proxy Proxeon i otrzymuje właściwe odpowiedzi.
  • W logu kompilacji nie ma hasła, loginu, ciągów base64 autoryzacji ani pełnego URL proxy.
  • Na liście procesów runnera podczas żądania hasło nie występuje.
  • Artefakty są czyste, skrypt audytu nie znajduje dopasowań.
  • Sekrety są maskowane nawet przy celowym echo.

Jak przetestować

  1. Uruchom pełny pipeline od początku do końca.
  2. Otwórz log i wykonaj wyszukiwanie po nazwie użytkownika — nie powinno być dopasowań.
  3. Pobierz artefakty i uruchom na nich skrypt audytu.
  4. Sprawdź zadanie sprawdzania na wyciek — powinno przejść na zielono.

Wskaźniki sukcesu

Sukces wygląda tak: kompilacja zielona, żądania przez proxy przechodzą, a wyszukiwanie we wszystkich możliwych miejscach nie znajduje ani jednego fragmentu danych uwierzytelniających. Jeśli tak jest — osiągnąłeś cel poradnika.

Typowe błędy i rozwiązania

Omówmy częste problemy według schematu problem, przyczyna, rozwiązanie.

Problem 1: hasło nadal jest widoczne w logu

Przyczyna: zmienna została utworzona jako zwykła, a nie jako sekret, albo nie jest oznaczona jako maskowalna.

Rozwiązanie: przenieś wartość do sekcji sekretów, włącz maskowanie i sprawdź, czy nazwa zmiennej zgadza się w konfiguracji i w magazynie.

Problem 2: maskowanie nie działa w GitLab

Przyczyna: hasło zawiera znaki lub znaki nowej linii, niedozwolone do maskowania.

Rozwiązanie: zmień hasło na ciąg z liter, cyfr i dozwolonych znaków o wystarczającej długości, spełniający wymagania maskowania.

Problem 3: curl nie czyta netrc

Przyczyna: plik ma nieprawidłowe uprawnienia lub nie znajduje się w katalogu domowym.

Rozwiązanie: ustaw uprawnienia 600 poleceniem chmod i upewnij się, że ścieżka do pliku zgadza się z oczekiwaną, albo wskaż ścieżkę flagą netrc-file.

Problem 4: hasło w śladzie stosu przy błędzie

Przyczyna: URL proxy został zbudowany z danymi uwierzytelniającymi, a klient drukuje go w wyjątku.

Rozwiązanie: przejdź na netrc lub oddzielne pola loginu i hasła, aby URL nie zawierał danych uwierzytelniających, i drukuj tylko komunikat błędu.

Problem 5: stare hasło jest nadal używane po rotacji

Przyczyna: buforowany plik netrc lub curlrc pozostał na runnerze.

Rozwiązanie: usuwaj pliki danych uwierzytelniających na końcu każdej kompilacji i używaj efemerycznych runnerów, gdzie system plików jest czyszczony między uruchomieniami.

Problem 6: sekret wyciekł do forka pull request

Przyczyna: włączony jest tryb, który daje zewnętrznym PR dostęp do sekretów.

Rozwiązanie: wyłącz taki tryb, uruchamiaj kompilacje z sekretami tylko dla zaufanych gałęzi, a sprawdzanie zewnętrznych PR wykonuj bez dostępu do proxy.

Problem 7: hasło znalezione w historii git

Przyczyna: kiedyś dane uwierzytelniające zostały zacommitowane w pliku konfiguracyjnym.

Rozwiązanie: natychmiast zmień hasło, następnie przepisz historię repozytorium, usuwając wrażliwe dane ze wszystkich commitów.

Dodatkowe możliwości: zaawansowana ochrona

Gdy podstawowa ochrona jest skonfigurowana, można ją wzmocnić.

Zewnętrzny menedżer sekretów

Zamiast przechowywać dane uwierzytelniające w samym systemie CI, podłącz zewnętrznego menedżera sekretów. Pipeline otrzymuje dane uwierzytelniające przez krótkotrwały token tylko na czas kompilacji. W ten sposób sekrety nie leżą w ustawieniach projektu na stałe.

Krótkotrwałe tokeny zamiast hasła

Jeśli infrastruktura Proxeon i Twój schemat dostępu to wspierają, preferuj tymczasowe tokeny z ograniczonym czasem życia. Nawet przy wycieku taki token szybko staje się bezużyteczny.

Podział danych uwierzytelniających według środowisk

Używaj różnych danych uwierzytelniających dla kompilacji testowych i produkcyjnych. Kompromitacja danych testowych nie wpłynie na procesy produkcyjne.

Wskazówka: Skonfiguruj powiadomienia o nietypowej aktywności na koncie proxy. Nagły wzrost żądań lub połączenia z nieoczekiwanych źródeł — to sygnał możliwego wycieku, wymagający natychmiastowej rotacji.

Automatyczna rotacja

Zaawansowane zespoły automatyzują rotację według harmonogramu: skrypt tworzy nowe dane uwierzytelniające, aktualizuje sekret i odwołuje stare bez udziału człowieka. Zacznij od ręcznego regulaminu, a automatyzację dodaj, gdy proces będzie dopracowany.

FAQ: częste pytania

Czy mogę po prostu ufać maskowaniu CI i nie zawracać sobie głowy?

Nie. Maskowanie łapie tylko dokładne dopasowania znanej wartości. Nagłówek w base64 lub częściowy wynik może zostać pominięty. Łącz maskowanie z rezygnacją z hasła w URL i wyłączaniem szczegółowych logów.

Co jest bezpieczniejsze: zmienna środowiskowa czy plik netrc?

Plik netrc z uprawnieniami 600 jest lepszy dla curl, ponieważ wartość nie trafia nawet na listę procesów. Dla kodu w Pythonie i Node wygodniejsze są zmienne środowiskowe, czytane wewnątrz procesu. Oba warianty są bezpieczne przy ostrożnym obchodzeniu się.

Czy należy usuwać plik danych uwierzytelniających po kompilacji?

Tak, jeśli runner jest współdzielony. Na efemerycznych runnerach, gdzie maszyna jest niszczona po kompilacji, jest to mniej krytyczne, ale usuwanie na końcu — dobry nawyk w każdym przypadku.

Co zrobić, jeśli hasło proxy zawiera znaki specjalne?

W netrc i w oddzielnych polach znaki specjalne zwykle nie stanowią problemu. Problemy pojawiają się właśnie przy wstawianiu do URL, gdzie znaki takie jak małpa i dwukropek psują parsowanie. To kolejny argument, aby nie umieszczać hasła w URL.

Czy requests samo w sobie drukuje dane uwierzytelniające?

Domyślnie nie. Wyciek występuje przy włączonym logowaniu DEBUG urllib3 lub przy drukowaniu obiektu ustawień proxy. Utrzymuj logowanie na WARNING i nie drukuj ustawień w całości.

Czy hasło jest widoczne na liście procesów przy użyciu flagi proxy-user?

Tak, flaga w linii poleceń jest widoczna w ps. Dlatego dla curl preferuj netrc lub curlrc, gdzie dane uwierzytelniające nie są przekazywane jako argument.

Jak często zmieniać hasło proxy?

Planową rotację warto przeprowadzać regularnie, na przykład co kwartał, i obowiązkowo natychmiast przy jakimkolwiek podejrzeniu wycieku. Regulamin rotacji z kroku 5 pomoże zrobić to szybko.

Czy mogę przechowywać dane uwierzytelniające w zaszyfrowanym pliku w repozytorium?

Technicznie tak, ale komplikuje to proces i stwarza ryzyko wycieku klucza szyfrowania. Sekrety CI i zewnętrzne menedżery sekretów rozwiązują problem prościej i bezpieczniej. Nie wymyślaj własnego magazynu bez potrzeby.

Co zrobić, jeśli wyciek już nastąpił?

Działaj w kolejności: natychmiast zmień hasło proxy, odwołaj stare dane uwierzytelniające, znajdź wszystkie miejsca wycieku skryptem audytu, w razie potrzeby przepisz historię git i przeanalizuj przyczynę, aby się nie powtórzyła.

Czy te zalecenia dotyczą runnerów Windows?

Tak, zasady są takie same. Różni się składnia: zamiast export użyj sposobu ustawiania zmiennych dla swojej powłoki, a zamiast chmod — konfigurację uprawnień przez właściwości pliku. Logika przechowywania i wyłączania logów jest identyczna.

Zakończenie

Przeszedłeś drogę od niebezpiecznego nawyku wpisywania hasła w URL do pełnej ochrony danych uwierzytelniających proxy w CI/CD. Przypomnijmy, co zostało zrobione.

Nauczyłeś się rozpoznawać pięć miejsc wycieku i zrezygnowałeś z hasła w adresie proxy. Przeniosłeś dane uwierzytelniające do zmiennych środowiskowych i plików netrc, curlrc oraz konfiguracji klienta z uprawnieniami 600. Skonfigurowałeś sekrety w GitHub Actions, GitLab CI i Jenkins z maskowaniem i ograniczeniem zakresu widoczności. Wyłączyłeś szczegółowe logi, które drukują nagłówek autoryzacji, w curl, Python requests i Node. Opanowałeś rotację hasła bez przestoju kompilacji i zebrałeś gotowy skrypt audytu na wyciek. Wreszcie przeszedłeś końcową listę kontrolną przed wdrożeniem.

Co robić dalej. Wdróż listę kontrolną jako obowiązkowy etap przeglądu dla wszystkich pipeline'ów, w których używane jest proxy Proxeon. Dodaj zadanie sprawdzania na wyciek do wszystkich projektów. Stopniowo przechodź do zewnętrznego menedżera sekretów i krótkotrwałych tokenów, gdy podstawowy proces stanie się nawykiem.

Dokąd się rozwijać. Poznaj praktyki zarządzania sekretami w skali organizacji, automatyczną rotację i monitorowanie anomalii na koncie proxy. Bezpieczeństwo danych uwierzytelniających — to nie jednorazowa konfiguracja, ale ciągła dyscyplina inżynierska. Ale teraz masz solidną podstawę, na której możesz budować całą resztę. Powodzenia w bezpiecznych kompilacjach.