Jednym z najbardziej frustrujących wyzwań w rozwoju aplikacji jest parytet środowiska. Podczas gdy ostatnie lata pokazały, że narzędzia do wirtualizacji i konteneryzacji, takie jak Vagrant i Docker (oraz własne narzędzie ActiveState State Tool) mogą zapewnić, że systemy operacyjne i zależności, które zasilają infrastrukturę aplikacji są spójne między środowiskami, zewnętrzne zależności są prawie niemożliwe do odtworzenia w środowisku nieprodukcyjnym.

W świecie, w którym zależności od stron trzecich stały się nieodwracalnie splecione z podstawową logiką biznesową prawie każdego projektu oprogramowania, coraz trudniej jest utrzymać spójność między środowiskami programistycznymi, inscenizacyjnymi i produkcyjnymi. Podczas gdy niektóre produkty z self-hosted lookalikes – takie jak Minio do Amazon S3 – łagodzą ból zarządzania wieloma wdrożeniami pojedynczej usługi, nie ułatwiają wyzwania zarządzania konfiguracją w różnych środowiskach.

Gdy produkcja, staging, rozwój, lokalna maszyna Boba i środowisko QE wymagają różnych wdrożeń danej usługi, przekazywanie plików konfiguracyjnych tam i z powrotem lub poleganie na złożonych warunkach w celu określenia, z którym wdrożeniem dane środowisko powinno rozmawiać, staje się coraz bardziej niepraktyczne. Potrzeba elastyczności uwypukla również trudność tych rozwiązań w środowisku o dużej skali. Co jeśli, na przykład, lokalna maszyna Boba musi tymczasowo połączyć się z usługą zarezerwowaną dla środowiska Staging?

Zmienne środowiskowe w Pythonie

Konfiguracja międzyśrodowiskowa jest bolesna, ale na szczęście problemy opisane powyżej stały się na tyle powszechne w ostatnich latach, że zostały już prawie rozwiązane. Dzięki wsparciu społeczności open source i ewangelizacji najlepszych praktyk, takich jak 12 Factor Application, w ostatnich latach nastąpiło przejście od zarządzania konfiguracją aplikacji opartego na plikach do zarządzania konfiguracją opartego na zmiennych środowiskowych.

Dostępne w każdym głównym systemie operacyjnym, zmienne środowiskowe są – tak jak ich nazwa wskazuje – zmiennymi, które są zaimplementowane na poziomie środowiska w celu określenia sposobu, w jaki powinny zachowywać się aplikacje działające pod nim. Mówiąc prościej, są to zmienne niezależne od aplikacji, które są zarządzane poza kontekstem danego procesu. Podstawową zaletą używania zmiennych środowiskowych jest to, że pozwala to programistom zdefiniować, jak aplikacja powinna działać bez zmiany linii kodu.

Na przykład, jeśli lokalna maszyna Boba musi rozmawiać z usługą CDN, która jest zarezerwowana dla środowiska Staging, może on zmienić zmienną środowiskową CDN_URL, aby odzwierciedlić to, co jest zdefiniowane w Staging, bez konieczności dotykania jakiegokolwiek zarządzanego kodu. Co ważniejsze, pozwala to Bobowi definiować mock lub wewnętrzne usługi do użytku z testami jednostkowymi i integracyjnymi, a wszystko to bez konieczności pisania pojedynczej linii dodatkowego kodu.

Definiowanie zmiennych środowiskowych

Podczas gdy akt definiowania zmiennych środowiskowych jest generalnie zależny od systemu operacyjnego, zdecydowana większość języków programowania wyabstrahowała te różnice poprzez użycie pakietów programistycznych, takich jak projekt dotenv Pythona. Na przykład, zamiast definiować API_USER zmienną środowiskową na poziomie OS, lokalnie gitignored .env plik może utrzymywać zmienne środowiskowe w różnych środowiskach dev. Pozwala to programistom wykorzystywać lokalnie zarządzany plik konfiguracyjny do ustawiania zmiennych środowiskowych, a jednocześnie umożliwia konfigurację za pomocą „prawdziwych” zmiennych środowiskowych w środowiskach innych niż deweloperskie.

Jako przykład, oto prosty plik .env, którego programista może używać w swoim lokalnym środowisku:

APP_ENVIRONMENT=localAPP_NAME=localhostQUEUE_DRIVER=syncAPI_USER=bob

Po drugiej stronie, środowisko produkcyjne może definiować swoje zmienne środowiskowe w pliku Dockerfile, z których oba są poprawnymi metodami utrzymywania zmiennych środowiskowych.

Pobieranie zmiennych środowiskowych

Niezależnie od sposobu zdefiniowania zmiennych środowiskowych, zawsze można je pobrać w Pythonie za pomocą metody os.getenv():

import os# Get environment variablesUSER = os.getenv('API_USER')

Zauważ, że w przypadku gdy zmienna środowiskowa jest niezdefiniowana, wartość domyślna to None.

Początek pracy z Secrets

Teraz, podczas gdy zmienne środowiskowe są doskonałym rozwiązaniem do zarządzania rozbieżnymi konfiguracjami w różnych środowiskach, nie są one srebrną kulą. W dzisiejszym klimacie rozwoju, bezpieczeństwo musi być najwyższym priorytetem, a wrażliwe dane muszą być przechowywane w bezpieczny sposób.

Niestety, zmienne środowiskowe same w sobie nie są bezpieczne. Chociaż świetnie nadają się do przechowywania danych konfiguracyjnych, sposób w jaki definiujemy bardziej wrażliwe dane, takie jak hasła, klucze API i klucze szyfrowania, powinien wymagać większej ostrożności. To właśnie tutaj do gry wchodzą sekrety. Zaszyfrowane w spoczynku, sekrety powinny być pobierane tylko w pojedynczym uruchomieniu w razie potrzeby, aby zmniejszyć prawdopodobieństwo naruszenia danych. W ten sposób, nawet jeśli twój dostawca hostingu zostanie naruszony, możesz mieć pewność, że twoje poufne sekrety są zamknięte mocno.

Tworzenie &Zarządzanie sekretami za pomocą narzędzia State

Więc, jak tworzymy i zarządzamy sekretami? Chociaż istnieje wiele różnych sposobów na rozwiązanie tego problemu, narzędzie State Tool firmy ActiveState jest doskonałym rozwiązaniem dla języka Python. Podobnie jak virtualenv lub pipenv, State Tool jest interfejsem zarządzania środowiskiem wirtualnym, który zapobiega wzajemnemu zanieczyszczaniu się instalacji i konfiguracji Pythona pomiędzy projektami. To, co odróżnia go od innych narzędzi do zarządzania środowiskiem wirtualnym, to integracja z platformą ActiveState, pozwalająca na stworzenie centralnego interfejsu do zarządzania konfiguracjami środowiska i, tak, sekretami.

Zanim będziemy mogli skorzystać z możliwości State Tool w zakresie zarządzania sekretami, musimy najpierw użyć State Tool do skonfigurowania środowiska wirtualnego w katalogu naszego projektu. Aby to zrobić, najpierw zidentyfikuj projekt ActiveState, z którym będziesz pracował (w tym tutorialu możesz użyć mojego projektu zachflower/envs-vs-secrets-demo, o ile posiadasz darmowe konto ActiveState Platform, lub możesz stworzyć swój własny). Następnie wykonaj polecenie state activate dla danego projektu:

$ state activate zachflower/envs-vs-secrets-demo Where would you like to checkout zachflower/envs-vs-secrets-demo? /home/zach/Projects/miscellaneous/activestate-variables/zachflower/envs-vs-secrets-demoActivating state: zachflower/envs-vs-secrets-demoThe State Tool is currently in beta, we are actively changing and adding features based on developer feedback.Downloading required artifactsDownloading 1 / 1 Installing 0 / 1 0 %You are now in an 'activated state', this will give you a virtual environment to work in that doesn't affect the rest of your system.Your 'activated state' allows you to define scripts, events and constants via the activestate.yaml file at the root of your project directory.To expand your language and/or package selection, or to define client-side encrypted secrets, please visit https://platform.activestate.com/zachflower/envs-vs-secrets-demo.To try out scripts with client-side encrypted secrets we've created a simple script for you in your activestate.yaml, try it out by running 'helloWorld'

Jak widzisz, polecenie activate ustawia środowisko wirtualne tak, jak zostało ono zdefiniowane w Twoim projekcie ActiveState. W przypadku, gdy projekt nie został jeszcze skonfigurowany, zostanie zasiany prosty projekt z domyślnymi parametrami, aby dać ci przykład, jak wszystko powinno być razem. Ta konfiguracja jest przechowywana w pliku o nazwie activestate.yaml w głównym katalogu Twojego projektu.

Plik konfiguracyjny dla Secrets & More

Plik activestate.yaml definiuje runtime deweloperski, pod którym będzie działać Twoja aplikacja. Na przykład, domyślny definiuje prosty skrypt, który wykorzystuje sekret, jak również kilka słuchaczy zdarzeń, którzy wykonują akcje, gdy tylko wystąpi określone zdarzenie:

project: https://platform.activestate.com/zachflower/envs-vs-secrets-demoscripts:# This script uses a secret. Note that you can define your own secrets at# https://platform.activestate.com/zachflower/envs-vs-secrets-demo/scripts - name: helloWorld value: echo ${secrets.user.world}events: # This is the ACTIVATE event, it will run whenever a new virtual environment is created (eg. by running `state activate`) # On Linux and macOS this will be ran as part of your shell's rc file, so you can use it to set up aliases, functions, environment variables, etc. - name: ACTIVATE constraints: os: macos,linux value: | echo "You are now in an 'activated state', this will give you a virtual environment to work in that doesn't affect the rest of your system." echo "" echo "Your 'activated state' allows you to define scripts, events and constants via the activestate.yaml file at the root of your project directory." echo "" echo "To expand your language and/or package selection, or to define client-side encrypted secrets, please visit https://platform.activestate.com/zachflower/envs-vs-secrets-demo." echo "" echo "To try out scripts with client-side encrypted secrets we've created a simple script for you in your activestate.yaml, try it out by running 'helloWorld'"

Pomimo że nie ma tu nic szczególnie przełomowego, potencjalna moc tego pliku powinna być natychmiast oczywista. Na przykład, poniższy skrypt stanowi podstawowy przykład wykorzystania sekretów w pliku konfiguracyjnym:

scripts:# This script uses a secret. Note that you can define your own secrets at# https://platform.activestate.com/zachflower/envs-vs-secrets-demo/scripts - name: helloWorld value: echo ${secrets.user.world}

Gdy polecenie helloWorld zostanie wykonane (w stanie aktywnym), spowoduje ono wyświetlenie wartości sekretu user.world, a w przypadku, gdy sekret nie jest jeszcze zdefiniowany, poprosi o podanie wartości:

$ helloWorldThe action you are taking uses a secret that has not been given a value yet.Name: worldDescription: - (This secret has no description, you can set one via the web dashboard)Scope: user (Only you can access the value) Please enter a value for secret "world": ******

Używanie sekretów

Chociaż przykład jest stosunkowo uproszczony, prawdziwa wartość sekretów pochodzi ze zdarzeń aktywacji. Zamiast pobierać tajną wartość w kontekście skryptu, zmienne środowiskowe mogą być definiowane przy użyciu pobranych sekretów bez narażania tych sekretów poza tym bezpiecznym środowiskiem:

project: https://platform.activestate.com/zachflower/envs-vs-secrets-demo?commitID=5fd1c161-c5a4-480c-8aba-29d8ab361b42events: - name: ACTIVATE constraints: os: macos,linux value: | export WORLD=${secrets.user.world}

Teraz, jeśli sekret user.world jest zdefiniowany, wówczas zmienna środowiskowa WORLD zostanie zdefiniowana i może być pobierana jak każda inna zmienna środowiskowa:

$ echo $WORLDworld!

Jednakże, jeśli nie jest zdefiniowana, wówczas użytkownik zostanie poproszony o jej zdefiniowanie podczas aktywacji środowiska wirtualnego ActiveState:

The action you are taking uses a secret that has not been given a value yet.Name: helloDescription: - (This secret has no description, you can set one via the web dashboard)Scope: user (Only you can access the value) Please enter a value for secret "world": ******

Pretty cool, prawda?

Taking it Further

Zarządzanie konfiguracją w rozwoju aplikacji jest w większości przypadków rozwiązane, ale zarządzanie sekretami jeszcze nie. Liczba projektów, które sprawdziły wrażliwe dane w repozytorium kontroli wersji jest oszałamiająca i jest to coś, co zrobiły nawet bardzo szanowane firmy, ale dzięki zastosowaniu odpowiedniej higieny bezpieczeństwa i produktów takich jak ActiveState’s State Tool, utrzymywanie wrażliwych danych konfiguracyjnych w bezpiecznym stanie staje się łatwiejsze z dnia na dzień.

  • Wypróbuj to sam, tworząc darmowe konto ActiveState Platform i pobierając State Tool, aby uprościć zarządzanie sekretami.
  • Możesz również obejrzeć nasze seminarium internetowe na temat zarządzania współdzielonymi sekretami za pomocą narzędzia State Tool

Powiązane blogi:

Tajemnica zarządzania współdzielonymi sekretami

Deweloperzy mogą szybko i łatwo współdzielić sekrety bez poświęcania bezpieczeństwa

.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.