Wstęp do zagadnień bezpieczeństwa na platformie Red Hat Openshift

OpenShift Red Hat

Wstęp do zagadnień bezpieczeństwa na platformie Red Hat Openshift

08/01/2019
Podziel się

Platforma Red Hat OpenShift zyskuje coraz większą popularność jako platforma do zarządzania kontenerami. Z uwagi na fakt, że na tych kontenerach z łatwością osadzane są przeróżne aplikacje, rozwiązanie to naprawdę znalazło uznanie w oczach deweloperów. Nie zawsze jednak praktyki, sprzyjające szybkiemu rozwojowi oprogramowania, ciągną za sobą dbałość o wszystkie aspekty bezpieczeństwa danej implementacji.

Poniżej chciałbym zwrócić uwagę na kilka podstawowych zagadnień bezpieczeństwa, które postaramy się umiejscowić w kontekście konkretnie platformy kontenerowej OpenShift.

Tak naprawdę bardzo liczna grupa zagadnień IT security może zostać zaadresowana przez dosyć fundamentalne pytanie: „Co może mój kontener osadzony na platformie OpenShift?”. Prawdopodobnie w niektórych z nas od razu prowokuje to pytanie o to, do jakich zasobów dyskowych (persistent storage) ma dostęp nasz kontener? Które z nich może modyfikować? Czy akurat ten konkretny kontener może pracować z uprawnieniami roota?

Ostatnie pytanie wydaje się szczególnie interesujące w kontekście potrzeby całkowitego uniknięcia możliwości eksploitacji podatności jakiegoś z mechanizmów platformy OpenShift w taki sposób, aby zyskując kontrolę nad procesem kontenera, który pracuje z uprawnieniami użytkownika uprzywilejowanego, stać się rootem również na maszynie hosta. Jeśli w naszym środowisku nie pozwalamy na uruchamianie kontenerów działających z uprawnieniami użytkownika root, co platforma OpenShift robi za nas domyślnie, wtedy zabezpieczamy się przed tym problemem przynajmniej w pewnym zakresie.

Jeśli jednak naprawdę musimy pojedyncze kontenery uruchomić z użytkownika uprzywilejowanego, to jak zrobić to najbezpieczniej? Wtedy z pomocą przychodzą nam tzw. service accounts. Idealnie należałoby w danym projekcie, jako konkretny użytkownik OpenShift, stworzyć właśnie konto serwisowe. Następnie, za pomocą konta cluster-admin dodać wspomniane konto serwisowe do polityki SCC anyuid:

oc adm policy add-scc-to-user anyuid -z kontoserwisowe (1)

Warto zwrócić uwagę na fakt, że zastosowanie dosyć popularnego rozwiązania:

oc adm policy add-scc-to-user anyuid -z default (2)

sprawi, że wewnątrz konkretnego projektu to wszystkie kontenery będą mogły być uruchamiane jako użytkownik root. Dzięki zastosowaniu (1) tylko konkretny kontener, którego deploymentconfig zostanie zmodyfikowany w sposób nakazujący użycie konkretnego konta serwisowego kontoserwisowe, będzie miał taką możliwość.

W ten sposób znacząco wpłyniemy na kontrolę liczby ‘uprzywilejowanych’ kontenerów, gdyż to ograniczenie dotyczy także możliwości wykonywania pewnych dockerowych dyrektyw jak np. USER, czy najprostsze polecenia chmod, chown wewnątrz pliku Dockerfile. W kwestii samych regół SCC, których nawet powierzchowne omówienie mogłoby spokojnie wystarczyć na niejedną osobną publikację, więcej informacji można znalźć w doskonałym artykule: Understanding Service Accounts and SCCs.

Wracając do naszych początkowych pytań, dotyczących bezpieczeństwa OpenShift, w kontekście samego bezpieczeństwa danych kluczowym wydaje się wybranie odpowiedniej polityki oczyszczania nieużywanych zasobów dyskowych (persistent volumes). Przy użyciu domyślnej polityki Recycle (powoli oznaczana przez Red Hata jako deprecated, zastępowana przez Delete) na danym physical volume w momencie, gdy odpięty zostanie odpowiedni persistent volume claim, dane na tym wolumenie zostaną usunięte. Polityka Retainzachowa te dane.

Przy dalszych rozważaniach, dotyczących persistent wolumenów, naturalną, jednakże równie istotną kwestią jest dobranie odpowiedniego trybu dostępu (access mode) do danego wolumenu.

Idąc dalej w naszych rozważaniach bezpieczeństwa, moglibyśmy zadać pytanie, które jest dosyć uniwersalne do szeregu platform, nie tylko OpenShift: „Kto co może na samej platformie OpenShift?”. Odpowiadając najogólniej – mamy dwa poziomy rozdziału uprawnień do zasobów OpenShift. Pierwszy przyznaje uprawnienia do zasobów na poziomie projektów. Dany użytkownik może być administratorem danego projektu (pełne uprawnienia), mieć prawo edit, a więc do tworzenia i modyfikacji wszystkich obiektów poza tzw. bindings oraz quotami, być ‘zwykłym’ użytkownikiem (basic-user) lub wręcz tylko takim, który dane konfiguracje może jedynie przeglądać (view).

Z podobną granulacją na poziomie przyznanych uprawnień mamy do czynienia w przypadku dostępów, które opisują możliwości danych typów użytkowników w stosunku do całego klastra OpenShift, a nie tylko pojedynczych projektów. Uprawnienia te możemy sprecyzować poprzez wydanie poleceń:

oc adm policy <add-role-to-user> lub <add-cluster-role-to-user>

W zależności od tego, jaki jest ‘scope’ przyznawanych przez nas uprawnień, z analogicznymi komendami mamy do czynienia w przypadku potrzeby zabrania danemu użytkownikowi lub grupie wspomnianych uprawnień (remove-role-from-user, remove-cluster-role-from-user).

W celu weryfikacji aktualnego stanu uprawnień wydajemy polecenie (wraz z przykładową odpowiedzią):

[root@rhel-openshift-master ~]# oc get rolebindings
NAME                	ROLE                    USERS           GROUPS                       	
SERVICE ACCOUNTS   SUBJECTS
admin               	/admin              	piotr.stolarek

admin-0             	/admin              	pstolarek 
                                                      	 
edit                	/edit               	testowe1  
                                                      	 
edit-0              	/edit               	testowe2  
                                                     	 
system:deployers    	/system:deployer                                                      	
deployer      	 
system:image-builders   /system:image-builder                                                 	
builder       	 
system:image-pullers	/system:image-puller                 	system:serviceaccounts:test

Wynik tego polecenia w zależności od ustawień konkretnego projektu będzie różnił się zwracaną wartością. Analogiczne polecenie, mające globalną perspektywę całego klastra (oc get clusterrolebindings), będzie natomiast niezależne w kwestii wyniku od aktualnego projektu, w którym jest ono wydawane.

Kolejnym dosyć szerokim zagadnieniem, które w tym momencie dosyć naturalnie pojawiło się w dotychczasowych rozważaniach, jest uwierzytelnianie do samej platformy. Opisane powyżej uprawnienia dla tak zwanych regular users na platformie OpenShift bądź też użytkowników funkcyjnych mogą mieć zastosowanie dopiero w momencie, kiedy określimy źródło uwierzytelniania do platformy (identity provider), które tak naprawdę ‘dostarczy’ nam bazę użytkowników później odzwierciedlonych także na platformie OpenShift. Domyślnie utworzony jest jedynie użytkownik uprzywilejowany ‘system:admin’.

OpenShift nie posiada wewnętrznej bazy użytkowników, natomiast posiada możliwość podłączenia długiej listy wspomnianych providerów. Najbardziej popularną i prawdopodobnie najprościej konfigurowalną opcją jest uwierzytelnianie za pomocą htpasswd. Na potrzeby zastosowań korporacyjnych natomiast najlepiej użyć: LDAPPAssworDIdentityProvider. Poniżej fragment pliku konfiguracyjnego master-config.yaml, dotyczącego tej konfiguracji:

oauthConfig:
assetPublicURL: https:⁄⁄opensourceday.linuxpolska.pl:8443/console/
grantConfig:
method: auto
identityProviders:
- challenge: true
login: true
mappingMethod: claim
name: ldapIPA
provider:
apiVersion: v1
Attributes:
...
bindDN: uid=svc_oseipa,cn=users,cn=accounts,dc=ipa,dc=linuxpolska,dc=pl
BindPassword: ‘opensourceday2018’
...
insecure: false
kind: LDAPPasswordIdentityProvider
url: ldaps://ipa.linuxpolska.pl:636/cn=users,cn=accounts,dc=ipa,dc=linuxpolska,dc=pl?uid?sub?

W powyższym przykładzie jako serwer uwierzytelniania posłużył nam server Red Hat IPA. Komunikacja odbywa się po zabezpieczonym (insecure=false) protokolle ldaps na porcie 636.

Chcąc dopracować naszą konfigurację, administrator powinien rozważyć także ograniczenie możliwości logowania do platformy jedynie przez konkretną grupę w strukturze LDAP w IPA, np. poprzez zastosowanie rozwiązania podobnego do poniższego:

(memberOf=cn=ose_admins,cn=groups,cn=accounts,dc=ipa,dc=linuxpolska,dc=pl).

Przedstawiając kolejne zagadnienia bezpieczeństwa, charakterystyczne dla platformy OpenShift, jako pretekst użyjmy powyższego fragmentu konfiguracji. Już na pierwszy rzut oka hasło dla użytkownika, który może odpytać usługę katalogową o dane identyfikacyjne, jest zaszyte w tym pliku otwartym tekstem. Rozwiązanie to jest co najmniej nieeleganckie, dlatego zmodyfikujemy je tak, aby zastąpić fragment:

BindPassword: ‘opensourceday2018’

poniższym:

bindPassword:
  file: /root/bindPasswordtest.encrypted
  keyFile: /root/bindPasswordtest.key

Odpowiednie pliki klucza oraz właściwy zaszyfrowany plik hasła generujemy komendą:

oc adm ca encrypt –genkey=/root/bindPasswordtest.key –out=/root/bindPasswordtest.encrypted

Dzięki tego typu modyfikacjom w plikach konfiguracyjnych możemy ukryć newralgiczne dane jak np. widoczne powyżej hasło. Generalnie jednak zastosowanie tzw. secretów jest o wiele bogatsze i bardzo sprawdza się w podobnych sytuacjach przy tworzeniu konfiguracji (deploymentconfig) podów, gdzie również chcielibyśmy ukryć niektóre informacje np. nazwę użytkownika, nazwę bazy danych, hasło do bazy danych itp. Przy zastosowaniu tego rozwiązania wymienione przykładowe dane nie pojawią się w postaci niezaszyfrowanej w pliku deploymentconfig podów.

Zobacz również

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

    Skontaktuj się z nami