Zmienne środowiskowe i wrażliwe dane produkcyjne

Gdy tworzymy aplikację Open Source prędzej czy później stajemy przed poważnym dylematem - które dane możemy w kodzie zostawiać. Pisząc "wrażliwe dane produkcyjne" mam na myśli:

  • host, post, nazwa_użytkownika, hasło do bazy danych na serwerze
  • zmienną secret, której ujawnienie na zewnątrz grozi rychłymi włamaniami i kradzieżą danych
  • dane dostępowe/autoryzacyjne dostępu do zewnętrznych api, np: ClientID i SecretID w przypadku korzystania z api GitHub

Dane takie muszą pozostać zabezpieczone przed użytkownikami, bo nawet jeżeli udostępniamy kod szerszej publiczności nie możemy pozwolić sobie na zostawianie luk w bezpieczeństwie stojącego portalu.

Zdefiniowanie problemu

Rozwiązaniem które promuje RoR jest używanie tzw. zmiennych środowiskowych (enviroment variables). Jest to rozwiązanie bardzo dobre, bo izoluje wszystkie wrażliwe dane od projektu, jednocześnie zachowując elastyczność konfiguracji. Jednak ustawianie zmiennych środowiskowych w niektórych przypadkach może być utrudnione, a wręcz niemożliwe. Dlaczego? Wszystko wynika z hostingu którego używamy. Co prawda obecnie istnieje trend używania zaawansowanych cloudów, które nie ograniczają w żaden krytyczny sposób dostępu do zasobów systemu operacyjnego serwera, jednak nadal istnieją różne rozwiązania.

Kilka sposobów na przekazanie zmiennych środowiskowych do aplikacji:

  • Ustawienie zmiennych środowiskowych w shellu - jeżeli aplikację uruchamia bash jedyne co potrzebujemy zrobić to właśnie dla basha ustawić zmienne środowiskowe. Jednorazowo operację tą można wykonać za pomocą polecenia export, jednak aby zmienne pozostały na stałe na serwerze najczęściej jesteśmy zmuszeni zmienne te wpisać w odpowiednich plikach konfiguracyjnych (omawianie różnych plików konfiguracyjnych dla różnych shellów to obszerne zagadnienie, którego nie będę tutaj omawiać)
  • Przekazanie zmiennych środowiskowych bezpośrednio do aplikacji - jest to metoda dość prymitywna i sprawdzająca się tylko w niektórych przypadkach. Polega ona na definiowaniu zmiennych środowiskowych bezpośrednio podczas uruchamiania aplikacji. Zatem aby ustawić zmienną haslo na wartość password dla serwera rails należy wykonać polecenie haslo=password rails s. Prawda że "proste"? Niestety, przy większej liczbie zmiennych (a zwyczajowo jest ich sporo) metoda ta staje się bardzo brzydka i niewygodna.

Jak to rozwiązujemy u nas?

Sposób rozwiązania tego problemu jest w pewnym sensie "obejściem" problemu i powrotem do pojedynczego pliku konfiguracyjnego. Jednak plik ten działa inaczej niż pliki konfiguracyjne RoR (czyli pliki ruby z rozszerzeniem .rb). Plik o którym piszę to local_env.yml znajdujący się w katalogu config. Jego treść (z fałszywymi danymi oczywiście) dla naszego projektu wygląda tak:

SECRET_KEY_BASE: Q3O8434IRUFSBE847MRQVW7R  
GITHUB_KEY: 93w84mxesvt4iw37fm  
GITHUB_SECRET: 3w4rx8mbw378fvmw39z4fvy7w3f  
API_DISCOURSE: w8374frm98w3f4g938wxfg6m9w3864fgx9wfg6sdfg  

Pliku tego nie ma na GitHubie. Powód jest oczywiście prozaiczny i wynika z w/w założeń. Dlatego jeżeli ktoś chce uruchomić naszą aplikację to musi ten plik utworzyć ręcznie. Brak tego pliku jest oczywiście związany z wpisem w pliku .gitignore o treści /config/local_env.yml.

Jako że plik ten nie jest standardowy dla środowiska rails to jego odwzorowanie na zmienne środowiskowe musimy wykonać sami. Odpowiada za to prosty skrypt umieszczony w pliku application.rb:

config.before_configuration do  
  env_file = File.join(Rails.root, 'config', 'local_env.yml')
  YAML.load(File.open(env_file)).each do |key, value|
    ENV[key.to_s] = value
  end if File.exists?(env_file)
end  

Iteruje on po pliku YAML i wpisuje po kolei wszystkie klucze i wartości do globalnej tablicy ENV. Po wykonaniu tego skryptu możemy w dowolnym miejscu w systemie odwoływać się do tych wartości w banalny sposób, np ENV['SECRET_KEY_BASE'].

Nekromancer

Programista z zawodu i zamiłowania. W fundacji zajmuje się głównie rozwiązaniami backendowymi oraz aplikacjami mobilnymi. Współtwórca portalu apki.org oraz mentor na forum

Jastrzębie-Zdrój http://ownvision.pl/