\item pełna automatyzacja procesu instalowania i konfiguracji systemu operacyjnego na urządzeniach
\item użycie maszyn wirtualnych
\item pozorna ,,bezstanowość'': po zakończeniu pracy w maszynie wirtualnej i jej wyłączeniu, kolejne jej uruchomienie przywróci pierwotny obraz dysku maszyny, bez zmian wprowadzonych przez poprzedniego użytkownika
\item proste tworzenie obrazów maszyn wirtualnych o zmodyfikowanej konfiguracji
\item łatwość użycia: użytkownicy końcowi powinni być w stanie w łatwy sposób obsługiwać maszyny klienckie
\item modularność: możliwość łatwego dodania nowych funkcjonalności
\item użycie rozwiązań, które są Wolnym Oprogramowaniem
\item możliwość wbudowania rozwiązania w już istniejącą architekturę sieciową
\end{itemize}
\paragraph{}
Aby osiągnąć pełną automatyzację procesu instalacji i konfiguracji systemu operacyjnego na urządzeniach wykorzystano
serwer PXE, stworzony z serwera TFTP (tftp-hpa), serwera DHCP (dhcp-isc-server) oraz serwera HTTP (apache2), a także narzędzie
cloud-init do automatycznego przeprowadzenia procesu instalacji systemu operacyjnego nadzorcy oraz narzędzie Ansible, do pełnej
konfiguracji systemu operacyjnego zarządcy.
\paragraph{}
Do implementacji pierwszej części projektu wyszczególnionej powyżej wykorzystano język Python, do zaimplementowania prostego serwera oraz klienta, synchronizujących
obrazy maszyn wirtualnych, QEMU wraz z KVM do uruchamiania samych maszyn oraz system operacyjny nadzorcy Ubuntu Linux w wersji 22.04 LTS.
Całość rozwiązania instalacyjno-konfiguracyjnego zaimplementowano pod kontrolą systemu operacyjnego Ubuntu Linux w
wersji 22.04 LTS na urządzeniu Dell Wyse 5060. Jest to tak zwany ,,cienki klient'', czyli zminiaturyzowana wersja komputera
osobistego o ograniczonej mocy obliczeniowej, której celem było uruchamianie klienta zdalnego pulpitu i umożliwienie w ten sposób
pracy na dużo wydajniejszej maszynie. Maszyny te są obecnie często wykorzystywane przez pasjonatów jako energooszczędne
alternatywy dla komputerów jednopłytkowych (takich jak Raspberry Pi) i służą jako prywatne serwery domowe. Wykorzystany
terminal posiada czterordzeniowy procesor AMD GX-424CC, 8 GB pamięci RAM, dysk SATA SSD 256GB oraz gigabitową kartę sieciową
opartą o chip Realtek RTL8111/8168/8411.
\paragraph{}
Część projektu odpowiedzialna za obsługę systemów zarządców maszyn wirtualnych została także oparta o system operacyjny Ubuntu Linux w wersji 22.04 LTS,
serwer TFTP oraz PXE do serwowania medium instalacyjnego systemu bazowego nadzorców, cloud-init oraz Ansible do automatyzacji instalacji i konfiguracji hostów.
Do obsługi wirtualizacji wykorzystano narzędzie QEMU. Jest to zintegrowany system do emulacji procesorów poprzez tłumaczenie binarne, potrafi także korzystać z technologii KVM do uruchamiania
aplikacji/maszyn wirtualnych z minimalnym narzutem wydajnościowym.\cite{bib:qemu-main} W proponowanym
rozwiązaniu użyto trybu, gdzie QEMU korzysta z KVM, aby zapewnić jak najlepszą wydajność.
%\begin{itemize}
%\item wymagania funkcjonalne i niefunkcjonalne
%\item przypadki użycia (diagramy UML) -- dla prac, w których mają zastosowanie
%\item opis narzędzi, metod eksperymentalnych, metod modelowania itp.
%\item metodyka pracy nad projektowaniem i implementacją -- dla prac, w których ma to zastosowanie
%\end{itemize}
% TODO
\chapter{Specyfikacja zewnętrzna}
\label{ch:specyfikacja-zewnetrzna}
\paragraph{Wymagania sprzętowe - strona kliencka}
Maszyny klienckie, na których uruchomiona ma być aplikacja kliencka i maszyny wirtualne, powinny spełniać następujące wymagania:
\paragraph{QEMU}
QEMU to zintegrowany system do emulacji procesorów poprzez tłumaczenie binarne, potrafi także korzystać z technologii KVM do uruchamiania
aplikacji/maszyn wirtualnych z minimalnym narzutem wydajnościowym. \cite{bib:qemu-main}
\begin{itemize}
\item wymagania funkcjonalne i niefunkcjonalne
\item przypadki użycia (diagramy UML) -- dla prac, w których mają zastosowanie
\item opis narzędzi, metod eksperymentalnych, metod modelowania itp.
\item metodyka pracy nad projektowaniem i implementacją -- dla prac, w których ma to zastosowanie
\item procesor 64-bit, wspierający Intel VT-d, lub AMD-V
\item program uruchomieniowy UEFI
\item co najmniej 4GB pamięci RAM, preferowane 8GB
\item dysk o pojemności co najmniej 250GB
\item płyta główna wspierająca Wake On LAN oraz uruchamianie poprzez PXE
\item karta graficzna o wydajności zbliżonej do Intel HD Graphics 620, na przykład APU z serii AMD Ryzen, Nvidia GT 1030, lub nawet Nvidia GT 730
\item karta sieciowa wspierająca Wake On LAN i prędkości 1 gigabit
\end{itemize}
\paragraph{Wymagania sprzętowe - strona sieciowa}
Sieć, w której ma operować projekt, powinna spełniać poniższe warunki:
% TODO
\chapter{[Właściwy dla kierunku -- np. Specyfikacja zewnętrzna]}
\label{ch:04}
\begin{itemize}
\item warstwa łącza zbudowana w oparciu o sieć Ethernet w klasie co najmniej 5E (osiągającą prędkości 1 gigabita)
\item urządzenia sieciowe pozwalające na transmisję ,,magic packet''
\item preferencyjnie dedykowana podsieć, wyłącznie dla zarządzanych maszyn klienckich
\end{itemize}
\paragraph{Wymagania sprzętowe - strona serwera}
Serwer, na którym uruchomione będą aplikacje serwerów, powinien spełniać następujące wymagania:
\begin{itemize}
\item co najmniej gigabitowa karta sieciowa
\item procesor czterordzeniowy
\item 8GB pamięci RAM, 8GB pamięci SWAP
\item dysk o pojemności co najmniej 250GB
\end{itemize}
\paragraph{Sposób instalacji}
Procedura instalacji serwera zarządcy obrazów i maszyn jest następująca:
\begin{itemize}
\item system operacyjny, na którym uruchamiany jest serwer powinien posiadać zainstalowane następujące pakiety:
\begin{itemize}
\item serwer HTTP Apache2 (apache2 dla Ubuntu)
\item implementację ISC serwera DHCP (dhcp-isc-server dla Ubuntu)
\item serwer TFTP (tftp-hpa dla Ubuntu)
\item interpreter Python w wersji co najmniej 3.9
\end{itemize}
\item po instalacji wymaganych pakietów należy utworzyć wymagane katalogi:
\begin{itemize}
\item\texttt{/ks} - katalog zawierający pliki konfiguracyjne dla narzędzia cloud-init
\item\texttt{/images} - katalog zawierający obraz systemu operacyjnego zarządcy dla maszyn klienckich (Ubuntu Server 22.04 LTS)
\item\texttt{/srv/tftp} - katalog zawierający pliki do uruchomienia instalatora poprzez PXE
\end{itemize}
\item skopiować pliki konfiguracyjne z repozytorium poniżej do odpowiednich katalogów
\item uruchomić instalator klikając enter w oknie wyboru przedstawionym na rys. \ref{fig:boot-screen-pxe}
\item po restarcie wszystkich urządzeń, podmienić adres IP serwera w pliku config.yml i uruchomić skrypty ansible z katalogu \texttt{ansible-scripts} na serwerze:
Po wykonaniu wstępnej konfiguracji, należy zbudować obraz maszyny wirtualnej i zarejestrować go w systemie ich obsługi.
Aby zbudować obraz maszyny wirtualnej, wystarczy stworzyć obraz dysku w formacie qcow2 (np. \texttt{qemu-img create -f qcow2 ubuntu.qcow2 20G}),
a następnie uruchomić maszynę wirtualną z tym obrazem dysku i medium instalacyjnym, zainstalować oraz skonfigurować system operacyjny,
a następnie skopiować utworzony obraz dysku na serwer.
Będąc zalogowanym do powłoki na serwerze, należy umieścić obraz dysku w miejscu, gdzie użytkownik uruchamiający serwer ma dostęp do odczytu i zapisu plików.
Następnie, należy zarejestrować obraz w bazie danych serwera komendą \texttt{python fleetcontrol add\_image}, przykład użycia
przedstawiono na rys. \ref{fig:register-image-command}. Po dodaniu obrazu można zweryfikować, że obraz został prawidłowo zarejestrowany
poprzez komendę \texttt{python fleetcontrol print\_images}. Dla skonfigurowanego serwera dała ona rezultat przedstawiony na rys. \ref{fig:print-images-command}.
Po pierwszym uruchomieniu wszystkie maszyny klienckie powinny same się zarejestrować na serwerze, co można sprawdzić komendą
\texttt{python fleetcontrol print\_clients}. Przykładowy rezultat takiej komendy predstawiono na rys. \ref{fig:print-clients-command}.
Po pomyślnej weryfikacji, można przypisać obrazy do klientów. Odbywa sie to poprzez komendę
\texttt{python fleetcontrol assign\_image} zaprezentowaną na rys. \ref{fig:assign-image-command}.
Konfiguracja serwera odbywa się poprzez edycję pliku \texttt{config.yml}, lub poprzez ustawienie następujących zmiennych środowiskowych
przed uruchomieniem serwera:
\begin{itemize}
\item\texttt{VALHALLA\_SERVER\_NAME} - nazwa serwera
\item\texttt{VALHALLA\_SERVER\_PORT} - port na którym ma nasłuchiwać serwer
\item\texttt{VALHALLA\_SERVER\_HOST} - adres IP hosta, na którym działa serwer (adres karty sieciowej wpiętej do sieci, w której są maszyny klienckie)
\item\texttt{VALHALLA\_SERVER\_PASSWORD} - hasło dostępu do serwera dla klientów
\item\texttt{VALHALLA\_SERVER\_ACCESS\_USERNAME} - nazwa użytkownika dostępowego dla klientów
\item\texttt{VALHALLA\_JWT\_SECRET} - sekretna fraza wykorzystywana do obliczenia tokenu JWT
\item\texttt{VALHALLA\_DATABASE\_FILE} - inny plik bazy danych SQLite3
\item\texttt{VALHALLA\_LOGLEVEL} - poziom logowania dla aplikacji serwera
\end{itemize}
Każde z tych ustawień można ustawić także poprzez plik config.yml, jednak to zmienne środowiskowe mają pierwszeństwo i są
brane pod uwagę preferencyjnie. Po zmianie ustawień serwera należy pamiętać o aktualizacji ustawień klienta. Odbywa się to
poprzez edycję pliku \texttt{config.yml} w katalogu \texttt{ansible\_scripts}.
\caption{Przykładowe wywołanie komendy przypisującej obraz do klienta}
\label{fig:assign-image-command}
\end{figure}
\paragraph{Obsługa - strona klienta}
Maszyna kliencka po uruchomieniu przedstawia ekran wyboru obrazu maszyny wirtualnej do uruchomienia, zaprezentowany na rys. \ref{fig:client-runner-screen}.
Użytkownik wybiera interesujący go obraz korzystając ze strzałek, następnie klawiszem tabulatora wybiera opcję OK i naciska klawisz Enter.
Wtedy cały ekran przejmowany jest przez maszynę wirtualną, która uruchamia się. Po skończonej pracy w maszynie wirtualnej i jej wyłączeniu,
\caption{Ekran wyboru maszyny wirtualnej do uruchomienia}
\label{fig:client-runner-screen}
\end{figure}
\paragraph{Bezpieczeństwo - zarządzanie obrazami}
Każde zapytanie do serwera zarządcy obrazów musi być zautoryzowane. Odbywa sie to poprzez token JWT, który klient wysyła
z każdym zapytaniem do serwera. Proces instalacji systemu bazowego i konfiguracji nie jest jednak chroniony,
jeżeli w sieci znajdują się maszyny, które uruchomią się poprzez PXE, mogą zainstalować podstawową konfigurację systemu.
Nie posiada ona jednak aplikacji klienckiej, ani żadnej konfiguracji, jedynie klucz publiczny SSH, wymagany do wykonania
skryptów Ansible. Jednak o ile złośliwy aktor nie podszyje się pod adres IP dowolnej maszyny do skonfigurowania, nie zostana na takiej maszynie
wykonane skrypty konfigurujące aplikację kliencką oraz nie zostaną przekazane pliki konfiguracyjne.
% Jeśli „Specyfikacja zewnętrzna”:
%\begin{itemize}
%\item wymagania sprzętowe i programowe
%\item sposób instalacji
%\item sposób aktywacji
%\item kategorie użytkowników
%\item sposób obsługi
%\item administracja systemem
%\item kwestie bezpieczeństwa
%\item przykład działania
%\item scenariusze korzystania z systemu (ilustrowane zrzutami z ekranu lub generowanymi dokumentami)
%\end{itemize}
%%%%%%%%%%%%%%%%%%%%%
%% RYSUNEK Z PLIKU
%
@ -910,85 +1118,230 @@ Jeśli „Specyfikacja zewnętrzna”:
\begin{figure}
%\begin{figure}
%\centering
%\begin{tikzpicture}
%\begin{axis}[
% y tick label style={
% /pgf/number format/.cd,
% fixed, % po zakomentowaniu os rzednych jest indeksowana wykladniczo
% fixed zerofill, % 1.0 zamiast 1
% precision=1,
% /tikz/.cd
%},
% x tick label style={
% /pgf/number format/.cd,
% fixed,
% fixed zerofill,
% precision=2,
% /tikz/.cd
%}
% ]
%\addplot [domain=0.0:0.1] {rnd};
%\end{axis}
%\end{tikzpicture}
%\caption{Podpis rysunku po rysunkiem.}
%\label{fig:2}
%\end{figure}
% TODO
\chapter{Specyfikacja wewnętrzna}
\label{ch:specyfikacja-wewnetrzna}
\paragraph{Idea rozwiązania}
Zamysł proponowanego rozwiązania jest dość prosty i opiera się na kilku elementach:
\begin{itemize}
\item serwer przechowuje metadane o obrazach (nazwa, wersja, hash pliku, lokalizacja pliku), same pliki obrazów oraz dane o klientach (nazwa hosta, adres IP, adres MAC, wersja aplikacji klienckiej)
\item dane o obrazach jak i same obrazy są ręcznie dodawane przez administratora
\item klienci sami rejestrują się oraz aktualizują dane o sobie na serwerze
\item klienci pobierają dane o przypisanych do siebie maszynach wirtualnych, pobierają także przypisane obrazy
\item komunikacja odbywa się poprzez protokół HTTP
\item do komunikacji z serwerem wymagana jest autoryzacja poprzez token JWT(JSON Web Token), uzyskiwany poprzez wysłanie loginu oraz hasła w formacie JSON do odpowiedniego punktu końcowego na serwerze
\item po synchronizacji stanu pomiędzy klientem a serwerem, na kliencie uruchamia się okno wyboru obrazu do uruchomienia
\item aplikacja klienta zbiera także podstawowe dane o maszynie: (zainstalowaną pojemność pamięci RAM, liczbę wątków procesora, adres IP oraz MAC karty sieciowej, która ma połączenie z siecią)
\item po wybraniu obrazu, na podstawie danych o maszynie zebranych przez aplikację klienta generowany jest skrypt, uruchamiający program QEMU z zebranymi danymi jako argumentami wywołania
\item oryginalny obraz maszyny wirtualnej jest kopiowany, a następnie uruchamiany jest skrypt włączający maszynę wirtualną
\item po zakończonej pracy i wyłączeniu maszyny wirtualnej, skrypt podmienia modyfikowany obraz dysku maszyny wirtualnej na oryginalny, skopiowany w kroku wcześniej
\item środowisko klienta składa się z bardzo okrojonego środowiska graficznego \texttt{i3}\footnote{\url{https://i3wm.org/}}, które nie pozwala na wyjście z aplikacji klienckiej oraz emulatora terminala rxvt
\item po uruchomieniu maszyny wirtualnej środowisko graficzne promuje jej okno do wypełnienia całego ekranu, jednocześnie przechwytując klawiaturę i myszkę, aby przekierować je do obsługi maszyny wirtualnej
\end{itemize}
\paragraph{Architektura sieciowa rozwiązania}
Proponowana architektura sieciowa dla rozwiązania została zaprezentowana na rys. \ref{fig:prop-network}.
Zakłada ona, że serwer DHCP będzie na tej samej maszynie co serwer TFTP oraz zarządcy obrazów, jednak
możliwe jest rozbicie każdego z tych narzędzi na osobną maszynę dedykowaną. Podobnie, jeżeli zagwarantowana
zostanie poprawna konfiguracja, możliwe jest wykorzystanie dowolnego serwera DHCP, jednak przetestowana została
wyłącznie architektura z serwerem DHCP w implementacji ISC.
\begin{figure}[hb]
\centering
\begin{tikzpicture}
\begin{axis}[
y tick label style={
/pgf/number format/.cd,
fixed, % po zakomentowaniu os rzednych jest indeksowana wykladniczo
\item bcrypt - do tworzenia bezpiecznych ,,hashy'' (wyników funkcji skrótu) haseł
\item Flask - do stworzenia serwera HTTP
\item pyaml - do odczytu i analizy plików o rozszerzeniu YAML
\item PyJWT - do obsługi i tworzenia tokenów JWT
\item prettytable - do formatowania danych w przejrzysty sposób
\item SQLAlchemy - jako ORM do obsługi bazy danych
\item argparse - do parsowania argumentów wywołania programu
\end{itemize}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Pakiet minted wymaga odkomentowania w pliku config/settings.tex %
% importu pakietu minted: \usepackage{minted}%
% i specjalnego kompilowania: %
% pdflatex -shell-escape praca %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\paragraph{}
Program został podzielony na kilka głównych modułów:
\begin{itemize}
\item obsługa bazy danych
\item serwer HTTP, obsługa żądań i odpowiedzi
\item obsługa pliku konfiguracyjnego i zmiennych środowiskowych
\item moduł modeli danych dla bazy danych
\item moduł obsługi autoryzacji poprzez tokeny JWT
\end{itemize}
\paragraph{}
Obsługa bazy danych została zaimplementowana w klasie \texttt{Database}. Jej zadaniem jest zestawienie połączenia z bazą danych
oraz manipulacja wszystkimi modelami wykorzystywanymi w programie. Dodawanie, usuwanie, modyfikacja i pobieranie danych
z bazy danych odbywa się poprzez zaimplementowane metody. Są one wysokopoziomowymi abstrakcjami podstawowych zapytań
SQL:
Krótka wstawka kodu w linii tekstu jest możliwa, np. \lstinline|int a;| (biblioteka \texttt{listings})% lub \mintinline{C++}|int a;| (biblioteka \texttt{minted})
.
Dłuższe fragmenty lepiej jest umieszczać jako rysunek, np. kod na rys \ref{fig:pseudokod:listings}% i rys. \ref{fig:pseudokod:minted}
, a naprawdę długie fragmenty – w załączniku.
\begin{itemize}
\item metody o formacie \texttt{get\_[nazwa\_modelu]\_by\_[nazwa\_atrybutu]} odpowiadają zapytaniom \texttt{SELECT}
\item metody o formacie \texttt{add\_[nazwa\_modelu]} odpowiadają zapytaniom \texttt{INSERT}
\item metody o formacie \texttt{modify\_[nazwa\_modelu]} odpowiadają zapytaniom \texttt{UPDATE}
\item metody o formacie \texttt{delete\_[nazwa\_modelu]} odpowiadają zapytaniom \texttt{DELETE}
\end{itemize}
\paragraph{}
Serwer HTPP został zbudowany w oparciu o bibliotekę Flask. Do obsługi zapytań HTTP stworzono klasę \texttt{Server}, która
zawiera w sobie metody, które obsługują wszystkie punkty końcowe. Autoryzacja dostępu została zaimplementowana przez mechanizm
dekoratorów, a dokładniej przez zaimplementowany dekorator \texttt{require\_auth}. Sprawdza on, czy w nagłówkach zapytania HTTP
klient wysłał odpowiedni token JWT i jeżeli nie był poprawny, zwraca odpowiedni komunikat do klienta. Jeżeli jednak był poprawny,
przekazuje do funkcji obsługującej zapytanie informacje o zautoryzowanym użytkowniku. Przykład użycia tego dekoratora przedstawiono
%% Pakiet minted wymaga odkomentowania w pliku config/settings.tex %
%% importu pakietu minted: \usepackage{minted}%
%% i specjalnego kompilowania: %
%% pdflatex -shell-escape praca %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
% Krótka wstawka kodu w linii tekstu jest możliwa, np. \lstinline|int a;| (biblioteka \texttt{listings})% lub \mintinline{C++}|int a;| (biblioteka \texttt{minted})
% .
% Dłuższe fragmenty lepiej jest umieszczać jako rysunek, np. kod na rys \ref{fig:pseudokod:listings}% i rys. \ref{fig:pseudokod:minted}