Jaki jest preferowany sposób przechowywania konfiguracji aplikacji?

38

W większości przypadków przechowuję konfigurację aplikacji programistycznych w katalogu głównym projektu, w następujący sposób:

app
|-- config.json

Ale to nie wydaje się być najlepszym podejściem, ponieważ ta konfiguracja ostatecznie jest przechowywana w systemie kontroli wersji - prawdopodobnie skutkując wyciekiem nazw użytkowników, haseł i innych wrażliwych rzeczy.

12 Przewodnik po aplikacji Factor zaleca całkowite usunięcie plików konfiguracyjnych i użycie zmiennych środowiskowych do konfiguracji konfiguracji:

... przechowuje konfigurację w zmiennych środowiskowych. Zmian środowiska Env można łatwo zmieniać między wdrożeniami bez zmiany kodu; w przeciwieństwie do plików konfiguracyjnych, istnieje niewielkie prawdopodobieństwo przypadkowego sprawdzenia ich w repozytorium kodu; i w przeciwieństwie do niestandardowych plików konfiguracyjnych lub innych mechanizmów konfiguracyjnych, takich jak Java System Properties, są one standardem zależnym od języka i systemu operacyjnego.

To brzmi dla mnie naprawdę miło, ale gdzie przechowuje się wspomniane zmienne środowiskowe, bez sprawdzania ich w kontroli źródła? A jakich narzędzi mogę użyć do przekazania tych zmiennych do aplikacji? Może istnieć kilkadziesiąt opcji konfiguracji, a ręczne wpisywanie ich przy każdym uruchomieniu aplikacji nie jest przyjemne - więc muszą być gdzieś przechowywane w jakimś pliku. Wspomniany plik w ten sposób przejdzie w kontrolę źródła i wrócimy do miejsca, w którym zaczęliśmy.

Czy istnieje jakiś powszechnie akceptowany sposób obsługi opcji konfiguracji, który nie wiąże się z ryzykiem przechowywania konfiguracji lokalnej w kontroli źródła?

Rogach
źródło
1
Cóż, git ma przynajmniej coś takiego, .gitignoregdzie mogę zdefiniować pliki lub foldery, których nie należy sprawdzać w kontroli wersji. Jak mówisz, nie widzę, gdzie Vars var powinien naprawdę pomóc, eith masz skrypt, aby je ustawić i powinny być przechowywane razem z projektem lub masz je gdzieś w systemie (katalog domowy lub nawet przy uruchamianiu maszyn skrypty), które wydają się same w sobie powodować wiele problemów, zwłaszcza jeśli konieczna jest duża konfiguracja. W każdym razie podzieliłbym pliki konfiguracyjne, aby poufne informacje trafiły do ​​różnych plików.
thorsten müller
@ thorstenmüller - tylko problem z .gitignore, że konfiguracja bazy / szablonu wciąż musi być przechowywana, co oznacza, że ​​aplikacja musi odczytać dwie konfiguracje - bazową, z domyślnymi opcjami (przechowywanymi w scm) i lokalną, która zastępuje bazę (i nie jest przechowywany w scm). Dzięki env vars wyobrażam sobie, że masowe wdrażanie staje się łatwiejsze - łatwiej jest określić zmienne środowiskowe dla konfiguracji nowej maszyny wirtualnej niż napisać coś w jakimś niestandardowym pliku.
Rogach
Dobre pytanie, po tym jak zacząłem używać do tego celu zwykłego magazynu danych aplikacji, życie stało się łatwiejsze ;-)
Wolf
1
Czy próbowałeś „Redis” redis.io . Jest przeznaczony specjalnie do przechowywania w strukturze klucz-wartość.
Karan
2
@jporcenaluk - Lubię magazyny klucz-wartość, ale dodanie do aplikacji pełnowymiarowego redis tylko do obsługi zarządzania konfiguracją to trochę przesada. Z drugiej strony może nigdy nie pracowałem nad wystarczająco dużymi projektami.
Rogach

Odpowiedzi:

16

Być może nie ma na to dobrej odpowiedzi. Wydaje się, że musisz przechowywać te dane w bezpiecznym miejscu, ponieważ pewnego dnia będą one potrzebne do odzyskiwania danych po awarii. Dotyczy to również plików właściwości i skryptów, które ustawiają zmienne środowiskowe.

  • Z kodem źródłowym (w SVN / GIT itp.) Jest naprawdę zły pomysł, ponieważ dane te będą zawierać hasła do produkcyjnej bazy danych i tym podobne.
  • Twoja korporacyjna nocna kopia zapasowa może być wystarczająca, ale jest mało prawdopodobne, aby przechowywać łatwo dostępną historię zmian.
  • Dane muszą być wersjonowane osobno dla używającego oprogramowania. W naszym obecnym systemie zmiana konfiguracji prowadzi do nowej wersji aplikacji i jest to po prostu zły błąd.

Obecnie szukamy rozwiązań tego problemu i skłaniamy się ku repozytorium kodu z ograniczonym dostępem. To repozytorium zawierałoby tylko dane dotyczące współbieżności. Czy inni mają podzielone doświadczenia?

kiwiron
źródło
2
Posiadanie dwóch oddzielnych repozytoriów dla jednego projektu nie wydaje się dobrym pomysłem - nie można przeprowadzać czystych wycofań ani pracować z gałęziami, ponieważ wtedy trzeba będzie manipulować dwoma repozytoriami jednocześnie (np. Inna gałąź wymaga nowej opcji konfiguracji, a kiedy przełącz się do tej nowej gałęzi bez przełączania się w repozytorium konfiguracji, rzeczy psują się w dziwny sposób).
Rogach
2
@Rogach Rozumiem twój punkt widzenia. Istnieją ważne powody, aby zachować pewną konfigurację z kodem, ale jak mówisz w swoim pytaniu, wrażliwe rzeczy muszą iść gdzie indziej. Dwa repozytoria wydają się więc nieuniknione. Nie wspomniałem też, że serwery aplikacji często tutaj pomagają. Źródła danych i zmienne JNDI mogą być konfigurowane przez administratora i nie będą publiczne.
kiwiron
Drugi sklep ma sens. Mogą istnieć inne rodzaje danych, również poufnych, które mogą być przechowywane wraz z konfiguracją (na przykład analizowane dane produkcyjne w celu rozwiązania problemów klientów).
Wolf
1
@Rogach Wydaje się, że przyciągają dużo nienawiści, ale myślę, że podmoduły git poradziłyby sobie z tym dobrze, myślę - gdyby główna była odpowiednio skonfigurowana, a repozytorium o ograniczonym dostępie mogłoby po prostu w niej żyć.
SeldomNeedy
9

Przy badaniu problemów i możliwych rozwiązań pomaga mi metoda spopularyzowana przez Jeffa Atwooda : Gdyby Bóg stworzył sposób przechowywania poufnych informacji konfiguracyjnych, jak by to zrobił?

Cóż, wiedziałby, kto potrzebuje informacji o konfiguracji i przekazuje je tylko tym osobom, a informacje te nigdy nie będą dostępne dla nikogo innego.

Pierwszą część należy już załatwić: Twój system kontroli źródła powinien uwierzytelniać użytkowników. Podejście to zyskuje również ważność zgodnie z 10 w 10 przykazaniach Troy Hunta dotyczących kontroli źródła: „zależności muszą być pod kontrolą źródła”.

Ale jak zabezpieczyć go przed wyciekiem? Cóż, nie trzeba go tam przechowywać w postaci zwykłego tekstu! Użyj szyfrowania. W .NET można wykonać kroki, aby zaszyfrować dane ciągu połączenia w plikach konfiguracyjnych . Musisz znaleźć równoważne metody, aby to zrobić z wybraną przez siebie technologią.

jporcenaluk
źródło
3
Chciałem tylko wyjaśnić - w jaki sposób pomoże konfiguracja szyfrowania? Rozumiem, że będziesz musiał udostępnić to samo hasło odszyfrowywania wszystkim programistom, a to brzmi jak wzywanie problemów.
Rogach,
Jeśli ktoś spoza Twojej firmy uzyska dostęp do Twojego repozytorium, hasła zostaną zaciemnione. Jeśli ktoś skopiuje pliki z projektu na dysk USB i pozostawi gdzieś to samo. Oczywiście będzie to wymagać więcej pracy. Większe bezpieczeństwo zwykle wiąże się z ceną wygody. To rozwiązanie jest trochę niewygodne, dam ci to. Jestem otwarty na lepszy sposób rozwiązania pytania PO!
jporcenaluk
5

Wiele osób krytykuje przechowywanie konfiguracji w zwykłych plikach wraz z kodem źródłowym, ale z mojego doświadczenia wynika, że ​​jest to całkiem dobre rozwiązanie:

  • Prosty do wdrożenia w dowolnym języku. W wielu otrzymujesz wsparcie dla złożonych plików konfiguracyjnych od razu po wyjęciu z pudełka. Np. W przypadku Java z Spring Boot, otrzymujesz wsparcie YAML, które może wyrażać dowolną strukturę drzewa, i łatwo jest mieć osobne pliki konfiguracyjne dla różnych środowisk, a także konfigurację bazową, z której mogą dziedziczyć pliki specyficzne dla środowiska.
  • Konfiguracja jest wymagana do uruchomienia oprogramowania, a zmiany w kodzie często wymagają dodania / modyfikacji ustawień konfiguracji, więc naturalne jest zachowanie razem konfiguracji i kodu.
  • Przechowywanie konfiguracji ze źródłem zapewnia wszystkie korzyści związane z kontrolą źródła, takie jak wiedza o tym, kto zmodyfikował to ustawienie i kiedy lub możliwość sprawdzenia konfiguracji podczas regularnego przeglądania kodu.
  • Jeśli nie pracujesz dla CIA, argument bezpieczeństwa wydaje mi się przesadzony. Dlatego hasło do bazy danych jest przechowywane w pliku na komputerze, na którym działa Twoja aplikacja. Cóż, jeśli ktoś uzyska dostęp do komputera z twoją aplikacją, prawdopodobnie masz już poważne kłopoty - może np. Zdjąć aplikację i uruchomić własną aplikację na swoim miejscu na tym samym porcie. W takim scenariuszu dostęp do hasła DB może nie być tak dużym problemem. O ile wszystkie twoje połączenia nie są w pełni zaszyfrowane, mając dostęp do twojego komputera, i tak mogą wąchać wiele interesujących danych z interfejsów sieciowych.
  • Możesz użyć narzędzia takiego jak Hiera, aby mieć tekstowy plik konfiguracyjny, ale nie przechowywać w nim haseł ani innych poufnych danych.

Tak więc w wielu przypadkach konfiguracja tekstowa przechowywana w kontroli źródła wraz z kodem jest dobrym początkiem.

Jeśli jesteś w systemach rozproszonych lub chcesz mieć możliwość zamiany konfiguracji bez konieczności ponownego wdrażania aplikacji, możesz lepiej znaleźć rozwiązanie oparte na serwerze konfiguracji. Spring Cloud obsługuje takie mechanizmy , a konfiguracjami służącymi do obsługi zaplecza może być repozytorium git lub Eureka . Możesz także rzucić własny za pomocą np . Zookeeper . Każde z tych podejść ułatwi zarządzanie spójnymi konfiguracjami na wielu serwerach w celu aktualizacji konfiguracji bez konieczności przebudowywania i ponownego wdrażania oprogramowania. Kosztem tego jest oczywiście nauka serwera konfiguracji i sposobu korzystania z niego z aplikacji, a także innego systemu do wdrażania i obsługi.

Michał Kosmulski
źródło
Ale kod zmienia ręce na kogoś, kto nie ma tajemnic w plikach konfiguracyjnych, będzie prawdziwy bałagan.
Tim Ludwinski,
@TimLudwinski Klucze / sekrety należą do firmy, a nie do indywidualnych deweloperów, dlatego należy je zachować w taki sposób, aby nie zgubiły się, jeśli odejdzie choć jedna osoba. Mogą to być na przykład problemy i utrzymywane przez administratorów / zespół ds. Bezpieczeństwa, dzięki czemu istnieje centralny rejestr.
Michał Kosmulski
5

Walczymy z tym samym problemem, w którym pracuję. Obecnie wszystkie nasze konfiguracje są oparte na plikach i kontrolowane przez źródło za pomocą poszczególnych aplikacji, które ich używają. Prowadzi to do powielania, a programiści mają dostęp do haseł produkcyjnych / qa zamiast do samego programowania.

To powiedziawszy, myślę, że opracowaliśmy dobre rozwiązanie na przyszłość. Przenosimy nasze pliki konfiguracyjne do osobnego repozytorium git (oznaczonego jako repozytorium konfiguracji). Następnie konfigurujemy serwer spring-cloud-config (java), który po prostu obsługuje pliki z repozytorium konfiguracji na podstawie przekazanych mu profili. Jest to idealne rozwiązanie dla aplikacji Java, które mogą korzystać z klienta i pobierać je podczas uruchamiania. W przypadku naszych aplikacji PHP / innych niż Java usuniemy plik bezpośrednio. (Nieidealny). W przyszłości możemy napisać coś, co pozwoli aplikacji PHP na samodzielne pobieranie konfiguracji i buforowanie ich gdzieś, ale nie jest to wysoki priorytet dla pierwszego uruchomienia. Myślę o tym rozwiązaniu jako o usłudze konfiguracji jako usługi, która nie narusza jednoznacznie rekomendacji 12-czynnikowych aplikacji.

Wierzę, że zookeeper może być używany do tego samego (widziałem konfigurację z kubernetes + zookeeper), więc nie jestem pewien, dlaczego ta odpowiedź uzyskała -1 powyżej.

Spinki do mankietów:

https://spring.io/guides/gs/centralized-configuration/

https://cloud.spring.io/spring-cloud-config/

ssjcory
źródło
3

Zamiast przechowywać całą konfigurację w jednym pliku, przechowuj ją w kilku plikach.

  • Posiadaj katalog konfiguracji . Wszystkie pliki są interpretowane jako pliki konfiguracyjne, z wyjątkiem może README*.
  • Wszystkie nazwy plików są sortowane alfabetycznie, a pliki są ładowane w tej kolejności. Dlatego pliki w takich przypadkach często zaczynają się od cyfry lub dwóch: 01-logging.json. 02-database.jsonitd.
  • Dane ze wszystkich plików są ładowane do tej samej struktury konfiguracji dostępnej dla aplikacji. W ten sposób kilka plików może uzupełniać ustawienia innych, a nawet zastępować je w przewidywalny sposób.
  • Przechowuj tylko w VCS pliki konfiguracyjne z wartościami bezpiecznymi lub wartościami domyślnymi. Dodaj pliki konfiguracyjne z kluczami tajnymi podczas wdrażania lub, jeszcze lepiej, skorzystaj z usługi przechowywania uwierzytelnionych sekretów.

Na najbliższym Linux-ie spójrz na /etc/sudoers.dlub /etc/nginx/conf.d. Pokazuje ten sam wzór.

Zarządzanie sekretami to inna bestia. Możesz nimi zarządzać jako krok ręczny, gdy jesteś mały. Możesz używać rzeczy takich jak Zookeeper. Możesz nawet sprawdzić sekrety w VCS w postaci zaszyfrowanej i odszyfrować je jako krok wdrożenia. Istnieje wiele innych opcji.

(Również opinia: JSON nie jest dobrym formatem pliku konfiguracyjnego, ponieważ nie pozwala na komentarze; komentarze są kluczowe. Formaty TOML, YAML, a nawet INI są lepsze w praktyce.)

9000
źródło
2

Myślę, że twoje opcje są nieco określone przez system operacyjny, w którym wdrażasz

Sugerowałbym, tak, podaj wartości w kontroli źródła. ALE tylko wersje „dev”. Chcesz, aby Twój kod źródłowy się skompilował I działał! nie zawierają dodatkowych tajnych kroków

Proces kompilacji i wdrażania powinien następnie zamienić te wartości na środowisko podczas wdrażania. (ośmiornica ma tego rodzaju model)

Ewan
źródło
0

Zookeeper Apache oferuje wspaniałe opcje przechowywania konfiguracji aplikacji dla systemów rozproszonych. Zmiany dokonane w zookeeper mogą być przechwytywane i przetwarzane przez posiadanie kuratora lub nasłuchującego zookeeper na końcu aplikacji.

Gmoney
źródło
6
Jakie są opcje? jak to działa? Gdzie je przechowuje? Czy jeden jest lepszy od drugiego? Jakie są zalety i wady każdej opcji? Jak to działa w różnych systemach operacyjnych?
3
@Gangz - Byłbym zainteresowany bardziej szczegółową odpowiedzią, nie zniechęcaj się głosami negatywnymi i popraw swoją odpowiedź, aby była pomocna.
Jay Elston,