Mostly finish writing thesis
This commit is contained in:
parent
2206844a06
commit
766198cfd1
@ -137,3 +137,20 @@
|
|||||||
year={2018},
|
year={2018},
|
||||||
month=sep,
|
month=sep,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@online{CyberArmsRace,
|
||||||
|
title={Inside the secret digital arms race: Facing the threat of a global cyberwar},
|
||||||
|
url={https://www.techrepublic.com/article/inside-the-secret-digital-arms-race/},
|
||||||
|
language={english},
|
||||||
|
author={Steve Ranger},
|
||||||
|
year={2014},
|
||||||
|
}
|
||||||
|
|
||||||
|
@online{MarriottBreach,
|
||||||
|
title={Marriott breach leaves 500 million exposed with passport, card numbers stolen},
|
||||||
|
url={https://arstechnica.com/information-technology/2018/11/marriott-breach-leaves-500-million-exposed-with-passport-card-numbers-stolen/},
|
||||||
|
language={english},
|
||||||
|
author={Megan Geuss},
|
||||||
|
year={2018},
|
||||||
|
month=nov,
|
||||||
|
}
|
||||||
|
@ -77,16 +77,28 @@ than showcasing actual, real-life API messages.
|
|||||||
|
|
||||||
\section{Messages Component}
|
\section{Messages Component}
|
||||||
|
|
||||||
The framework must allow content creators to communicate their \emph{message} to the user.
|
The framework must allow content creators to communicate with the user,
|
||||||
In other words, some way must be provided to ``talk'' to users.
|
and provide some mechanism to enable ``talking'' to them.
|
||||||
This is the responsibility of the \emph{messages} component, which
|
This is the responsibility of the \emph{messages} component, which
|
||||||
provides a chatbox-like element on the frontend.
|
provides a chatbox-like element on the frontend.
|
||||||
The simplest form of communication it accomodates it the insertion of text
|
The simplest form of communication it accomodates it the insertion of text
|
||||||
into the chatbox through API messages.
|
into the chatbox through API messages.
|
||||||
Every message has an optional \emph{originator}, which serves to remind the user
|
This component always expects messages it receives to be in Markdown%
|
||||||
of the purpose of the given message.
|
\footnote{\href{https://daringfireball.net/projects/markdown/}
|
||||||
|
{https://daringfireball.net/projects/markdown/}} format,
|
||||||
|
so that it is possible to nicely format any text that one might want to display.
|
||||||
|
This is especially important when displaying inline code with text around it,
|
||||||
|
so that it is easier to read for the user.
|
||||||
|
Every message has an optional \emph{originator} field, which serves
|
||||||
|
to remind the user of the purpose of the given message.
|
||||||
These messages are also timestamped so that it is easier to navigate through them
|
These messages are also timestamped so that it is easier to navigate through them
|
||||||
and look back older messages from the user.
|
and look back older messages from the user.
|
||||||
|
If no timestamp is present in the API message, then it will be added on
|
||||||
|
the frontend.
|
||||||
|
This is useful, because this will use system time on the user's machine,
|
||||||
|
and as such time zones will not be an issue (whereas if we suggested adding
|
||||||
|
timestamps to the messages on the backend, content creators would have to
|
||||||
|
deal with conversions between time zones).
|
||||||
|
|
||||||
\pic[width=.5\textwidth]{figures/chatbot.png}{The avataobot typing in the messages component}
|
\pic[width=.5\textwidth]{figures/chatbot.png}{The avataobot typing in the messages component}
|
||||||
|
|
||||||
@ -111,6 +123,8 @@ message lengths:
|
|||||||
|
|
||||||
The value 5 comes from the fact that on average english words are 5
|
The value 5 comes from the fact that on average english words are 5
|
||||||
characters long according to some studies.
|
characters long according to some studies.
|
||||||
|
This value could be made configurable in the future, but currently there
|
||||||
|
are no plans to make non-english challenges.
|
||||||
|
|
||||||
\section{IDE Component}\label{idecomponent}
|
\section{IDE Component}\label{idecomponent}
|
||||||
|
|
||||||
@ -168,6 +182,13 @@ the selected file.
|
|||||||
The code making this feature possible is reused several times in the framework
|
The code making this feature possible is reused several times in the framework
|
||||||
for interesting purposes such as monitoring the logs of processes.
|
for interesting purposes such as monitoring the logs of processes.
|
||||||
|
|
||||||
|
It is also worth to mention that integrating such file monitoring into the framework
|
||||||
|
is not quite as simple as described above, because one has to deal with many issues like the
|
||||||
|
semi-undeterministic nature of how a single file modification can sometimes result in
|
||||||
|
several inotify events, or implement rate limiting for the whole thing to avoid
|
||||||
|
saturating the messaging system with file content updates triggered by said events
|
||||||
|
being triggered too frequently.
|
||||||
|
|
||||||
The editor also allows content creators to completely control it using API messages.
|
The editor also allows content creators to completely control it using API messages.
|
||||||
This involves the selecting, reading and writing of files as well as changing the
|
This involves the selecting, reading and writing of files as well as changing the
|
||||||
selected directory.
|
selected directory.
|
||||||
@ -175,6 +196,14 @@ These features allow content creators to ``guide'' a user through code bases
|
|||||||
for example, where in each step of a tutorial a file is opened and explained
|
for example, where in each step of a tutorial a file is opened and explained
|
||||||
through messages sent to the chatbox of the messages component.
|
through messages sent to the chatbox of the messages component.
|
||||||
|
|
||||||
|
Developers have to \emph{explicitly} allow directories one by one to be listed by the
|
||||||
|
editor. This is done to avoid access control issues in case the editor is
|
||||||
|
running with more permissions than the user should have%
|
||||||
|
\footnote{Actually this involves extra caution, such as dealing with
|
||||||
|
symlinks in an allowed directory which could point to other, non-allowed locations}.
|
||||||
|
It is also possible to blacklist file patterns (so that binary files can be
|
||||||
|
excluded for example, as a text editor is not suitable to deal with these).
|
||||||
|
|
||||||
\section{Terminal Component}
|
\section{Terminal Component}
|
||||||
|
|
||||||
This is a full-fledged xterm terminal emulator running right in the user's browser.
|
This is a full-fledged xterm terminal emulator running right in the user's browser.
|
||||||
@ -191,23 +220,27 @@ This small server is responsible for spawning bash sessions and
|
|||||||
unix pseudoterminals (or \code{pty}s) in the \code{solvable} Docker
|
unix pseudoterminals (or \code{pty}s) in the \code{solvable} Docker
|
||||||
container.
|
container.
|
||||||
It is also responsible for connecting the master end of the \code{pty} to the
|
It is also responsible for connecting the master end of the \code{pty} to the
|
||||||
emulator running in your browser and the slave end to the bash session it has
|
emulator running in the browser and the slave end to the bash session it has
|
||||||
spawned.
|
spawned.
|
||||||
This way users are able to work in the shell displayed on the frontend just like
|
This way users are able to work in the shell displayed on the frontend just like
|
||||||
they would on their home machines, which allows for great tutorials
|
they would on their home machines, which allows for great tutorials
|
||||||
explaining topics that involve the usage of a shell.
|
explaining topics that involve the usage of a shell.
|
||||||
Note that this allows coverion an extremely wide variety of topics using TFW: from compiling
|
Note that this allows us to cover an extremely wide variety of topics using TFW:
|
||||||
shared libraries for development, using cryptographic FUSE filesystems
|
from compiling shared libraries for development, to using cryptographic FUSE filesystems
|
||||||
for enhanced privacy%
|
for enhanced privacy%
|
||||||
\footnote{\href{https://github.com/rfjakob/gocryptfs}{https://github.com/rfjakob/gocryptfs}},
|
\footnote{\href{https://github.com/rfjakob/gocryptfs}{https://github.com/rfjakob/gocryptfs}},
|
||||||
to automating cloud infrastructure using Ansible%
|
or automating cloud infrastructure using Ansible%
|
||||||
\footnote{\href{https://www.ansible.com}{https://www.ansible.com}}.
|
\footnote{\href{https://www.ansible.com}{https://www.ansible.com}}.
|
||||||
|
|
||||||
This component exposes several functions through TFW message APIs, such as injecting commands
|
This component exposes several functions through TFW API messages, such as injecting commands
|
||||||
to the terminal, reading command history and registering callbacks that are invoked when
|
to the terminal, reading command history and registering callbacks that are invoked when
|
||||||
certain command are executed by the user.
|
the user executes anything in the terminal.
|
||||||
|
This allows content developers to implement functionality such as advancing the
|
||||||
|
tutorial when a certain command was invoked, or detect common mistakes in using certain
|
||||||
|
tools, such as warning users when they try to use an outdated cipher when
|
||||||
|
encrypting a file using \code{openssl}, or if they generate an RSA key with a small key size.
|
||||||
|
|
||||||
\pic{figures/terminal.png}{The Frontend Terminal of TFW Running top}
|
\pic{figures/terminal.png}{The frontend terminal of TFW running top}
|
||||||
|
|
||||||
The implementation of reading command history is quite an exotic one.
|
The implementation of reading command history is quite an exotic one.
|
||||||
The framework needs to be able to detect if the user has executed any command in the
|
The framework needs to be able to detect if the user has executed any command in the
|
||||||
@ -216,19 +249,23 @@ This is not an easy thing to accomplish without relying on some sort of heavywei
|
|||||||
monitoring solution such as Sysdig%
|
monitoring solution such as Sysdig%
|
||||||
\footnote{\href{https://sysdig.comq}{https://sysdig.com}}.
|
\footnote{\href{https://sysdig.comq}{https://sysdig.com}}.
|
||||||
I deemed most simiar systems a huge overkill to implement this functionality, and their
|
I deemed most simiar systems a huge overkill to implement this functionality, and their
|
||||||
memory footprints are not something we could afford here.
|
memory footprints are not something we could afford here%
|
||||||
|
\footnote{These containers will be spawned on a per-user basis, so we must be as
|
||||||
|
conservative with memory as possible}.
|
||||||
Another way would be to use \code{pam_tty_audit.so} in the PAM%
|
Another way would be to use \code{pam_tty_audit.so} in the PAM%
|
||||||
\footnote{Linux Pluggable Authentication Modules:
|
\footnote{Linux Pluggable Authentication Modules:
|
||||||
\href{http://man7.org/linux/man-pages/man3/pam.3.html}
|
\href{http://man7.org/linux/man-pages/man3/pam.3.html}
|
||||||
{http://man7.org/linux/man-pages/man3/pam.3.html}}
|
{http://man7.org/linux/man-pages/man3/pam.3.html}}
|
||||||
configurations responsible for logins, as this allows for various TTY auditing functions,
|
configurations responsible for logins, as this allows for various TTY auditing functions,
|
||||||
but I have found an ever simpler approach to the problem in the end.
|
but I have found an even simpler approach to solving this problem in the end.
|
||||||
By using the inotify system built into TFW, I can set up the user's environment in
|
It is possible to set up the user's environment in
|
||||||
such a way, that I can enforce and determine the location of the bash \code{HISTFILE}%
|
such a way during the build of the image, that I can enforce and determine the
|
||||||
|
location of the bash \code{HISTFILE}%
|
||||||
\footnote{This environment variable contains the path to the file bash writes command
|
\footnote{This environment variable contains the path to the file bash writes command
|
||||||
history to}
|
history to}
|
||||||
of the user.
|
of the user.
|
||||||
This way I can monitor changes made to this file and read the commands executed
|
By combining this with the inotify system built into TFW,
|
||||||
|
the framework can monitor changes made to this file and read the commands executed
|
||||||
by the user from it.
|
by the user from it.
|
||||||
It is important to keep in mind that the user is able to ``sabotage'' this method%
|
It is important to keep in mind that the user is able to ``sabotage'' this method%
|
||||||
\footnote{By unsetting the \code{HISTFILE} envvar for example},
|
\footnote{By unsetting the \code{HISTFILE} envvar for example},
|
||||||
@ -236,6 +273,18 @@ but that should not be an issue as this is not a feature that is intended to be
|
|||||||
used in competitive environments (and if the users of a tutorial intentionally
|
used in competitive environments (and if the users of a tutorial intentionally
|
||||||
break the system under themselves, well, good for them).
|
break the system under themselves, well, good for them).
|
||||||
|
|
||||||
|
An other advantage of this method is that this can be applied to any interactive
|
||||||
|
application that supports logging commands executed in them in some way or an other.
|
||||||
|
A good example would be GDB%
|
||||||
|
\footnote{\href{https://www.gnu.org/software/gdb/}{https://www.gnu.org/software/gdb/}},
|
||||||
|
which supports an option called \code{set trace-commands on}. This option flushes
|
||||||
|
command history to a file after every executed command.
|
||||||
|
This feature can be combined with the file monitoring capabilities of the framework, and now
|
||||||
|
we can even detect commands executed inside GDB by the user.
|
||||||
|
This is a good example of the flexibility provided by this solution. Feature requests
|
||||||
|
like ``I'd like to create a tutorial about <insert software here>'' are quite common, and
|
||||||
|
supporting them is really easy using this extensible system.
|
||||||
|
|
||||||
\section{Console Component}
|
\section{Console Component}
|
||||||
|
|
||||||
This component is a simple textbox that can be used to display anything to the user,
|
This component is a simple textbox that can be used to display anything to the user,
|
||||||
@ -245,40 +294,55 @@ API through TFW messages to write and read it's contents.
|
|||||||
|
|
||||||
It works great when combined with the process management capabilities of the framework:
|
It works great when combined with the process management capabilities of the framework:
|
||||||
if configured to do so it can display the output of processes like webservers in real time.
|
if configured to do so it can display the output of processes like webservers in real time.
|
||||||
When using this next to the frontend editor of the framework, it allows for a development
|
When using this next to the TFW frontend editor, it allows for a development
|
||||||
experience similar to working in an IDE on your laptop.
|
experience similar to working in an IDE on your laptop.
|
||||||
|
|
||||||
\pic{figures/console_and_editor.png}{The Console Displaying Live Process Logs Next to the TFW Code Editor}
|
Similarly to other developer tools, I chose to display this component inside the terminal
|
||||||
|
window, so that the user can switch between the two in order to conserve space using tabs.
|
||||||
|
It is also possible to configure which one should be displayed by default,
|
||||||
|
as well as switching between them mid-tutorial using API messages.
|
||||||
|
|
||||||
|
\pic{figures/console_and_editor.png}{The console displaying live process logs next to the TFW editor}
|
||||||
|
|
||||||
\section{Process Management}\label{processmanagement}
|
\section{Process Management}\label{processmanagement}
|
||||||
|
|
||||||
The framework includes an event handler capable of managing processes running inside
|
The framework includes an event handler capable of managing processes running inside
|
||||||
the \code{solvable} Docker container.
|
the \code{solvable} Docker container.
|
||||||
It's capabilities include starting, stopping and restarting processes.
|
The capabilities of this componenet include the starting, stopping and restarting of processes,
|
||||||
It is also capable of emitting the standard out or standard error logs of processes
|
as well as emitting the standard out or standard error logs belonging to them, even
|
||||||
(by broadcasting TFW messages).
|
in real-time (by broadcasting TFW messages).
|
||||||
This component can be iteracted with using TFW API messages.
|
This logging feature allows for interesting possiblities such as the handling
|
||||||
|
of live process output, or just requesting the logs belonging to a certain application when
|
||||||
|
some sort of event has occurred (such as on errors).
|
||||||
|
This component also can be interacted with using TFW API messages.
|
||||||
The ``Deploy'' button on the code editor uses this component to restart
|
The ``Deploy'' button on the code editor uses this component to restart
|
||||||
processes.
|
processes, and the console component also uses this event handler to display
|
||||||
|
real-time logs.
|
||||||
|
|
||||||
The Tutorial Framework uses supervisor%
|
The Tutorial Framework uses supervisor%
|
||||||
\footnote{\href{http://supervisord.org}{http://supervisord.org}}
|
\footnote{\href{http://supervisord.org}{http://supervisord.org}}
|
||||||
to run multiple processes inside a Docker container
|
to run multiple processes inside a Docker container
|
||||||
(whereas usually Docker containers run a single process only).
|
(whereas usually Docker containers run a single process only).
|
||||||
This is going to be explained further in a later chapter.
|
This is going to be explained further in Chapter~\ref{usingtfw}.
|
||||||
All this is possible through using the xmlrpc%
|
|
||||||
\footnote{\href{https://docs.python.org/3/library/xmlrpc.html}{https://docs.python.org/3/library/xmlrpc.html}}
|
|
||||||
API exposed by supervisor, which allows the framework to iteract with processes it controls.
|
|
||||||
|
|
||||||
It is also possible to find out what files does a process write logs to.
|
It is also possible to find out what files does a process write logs to.
|
||||||
Combining this with the inotify capabilities of TFW explained
|
Combining this with the inotify capabilities of TFW explained
|
||||||
briefly in~\ref{idecomponent}, it becomes possible to implement live log monitoring
|
briefly in~\ref{idecomponent}, it becomes possible to implement live log monitoring
|
||||||
in the framework.
|
in the framework.
|
||||||
The features involving the use of inotify were among the most difficult ones implement,
|
The features involving the use of inotify were among the most difficult ones implement,
|
||||||
since the sheer number of impossible to debug issues that such
|
since the sheer number of almost impossible to debug issues that such
|
||||||
a complex system could come with.
|
a complex system could come with.
|
||||||
|
|
||||||
I'll briefly explain such a bug, which I've found to be immersely exciting.
|
I'll briefly explain such a bug, which I've found to be immensely exciting.
|
||||||
|
To understand this, it is necessary to signify, that the inotify API supplied by
|
||||||
|
the Linux kernel is not capable
|
||||||
|
of monitoring a single file, it is only able to watch whole directories.
|
||||||
|
I was unaware of this fact before running into this issue, as the Python
|
||||||
|
bindings I was using did not warn me about supplying a filename on top of
|
||||||
|
the directory path, and just stripped down the filename silently%
|
||||||
|
\footnote{In software development it is considered a bad practice to do such things
|
||||||
|
implicitly. It is better to fail loud and clear instead of trying to figure out
|
||||||
|
what the user meant to do.}.
|
||||||
During the initial development of this feature all processes inside the
|
During the initial development of this feature all processes inside the
|
||||||
\code{solvable} Docker container were writing their logs to files
|
\code{solvable} Docker container were writing their logs to files
|
||||||
in the FHS%
|
in the FHS%
|
||||||
@ -291,21 +355,22 @@ This had caused an infinite recursion: when a process would write to \code{/tmp/
|
|||||||
inotify would invoke a process that would also log to that location causing the kernel to
|
inotify would invoke a process that would also log to that location causing the kernel to
|
||||||
emit more inotify events, which in turn would cause more and more new proesses to spawn
|
emit more inotify events, which in turn would cause more and more new proesses to spawn
|
||||||
and write to \code{/tmp/}, causing the whole procedure to repeat again and again.
|
and write to \code{/tmp/}, causing the whole procedure to repeat again and again.
|
||||||
This continued until my machine would start to run out of memory and stat swapping
|
This continued until my machine would start to run out of memory and begin swapping
|
||||||
pages to disk%
|
pages to disk%
|
||||||
\footnote{When a modern operating system runs out of physical RAM, it is going to swap
|
\footnote{When a modern operating system runs out of physical RAM, it is going to swap
|
||||||
virtual memory pages to disk so it can continue to operate --- slowly}
|
virtual memory pages to disk so it can continue to operate --- slowly}
|
||||||
like crazy, causing the whole system to spiral downwards
|
like crazy, causing the whole system to spiral downwards
|
||||||
in a spectacular fashion until the whole thing managed to crash.
|
in a spectacular fashion until the whole thing managed to crash.
|
||||||
It was an event of such chaotic beauty, that I often fondly recall it to this day.
|
It was an event of such rare and chaotic beauty, that I often fondly recall it to this day.
|
||||||
|
After my first encounter with the bug I decided to have lunch instead.
|
||||||
Of course it would take me several hours to identify the exact causes behind this
|
Of course it would take me several hours to identify the exact causes behind this
|
||||||
fascinating phenomenon, but those were \emph{very} fun hours.
|
fascinating phenomenon, but those were \emph{very} fun hours at least.
|
||||||
|
|
||||||
\section{FSM Management}
|
\section{FSM Management}
|
||||||
|
|
||||||
I have already mentioned the event handler called \code{FSMManagingEventHandler},
|
I have already mentioned the event handler called \code{FSMManagingEventHandler},
|
||||||
which is responsible for managing the framework FSM.
|
which is responsible for managing the framework FSM.
|
||||||
For completeness I chose to include it on this chapter as well.
|
For completeness I chose to include it in this chapter as well.
|
||||||
The API it exposes through TFW messages allows client code to attempt stepping the
|
The API it exposes through TFW messages allows client code to attempt stepping the
|
||||||
state machine.
|
state machine.
|
||||||
As previously explained this is something that is considered to be a \emph{privileged}
|
As previously explained this is something that is considered to be a \emph{privileged}
|
||||||
@ -342,26 +407,27 @@ thing work with the Same Origin Policy%
|
|||||||
{https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin\_policy}}
|
{https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin\_policy}}
|
||||||
being in effect?
|
being in effect?
|
||||||
The answer is that developers must use a \emph{relative url}, that is an URL relative
|
The answer is that developers must use a \emph{relative url}, that is an URL relative
|
||||||
to the entry pont of the TFW frontend itself.
|
to the entry point of the TFW frontend itself.
|
||||||
To allow serving several web applications from a single port the framework
|
To allow serving several web applications from a single port the framework
|
||||||
supports optional reverse-proxy configurations through the nginx%
|
supports optional reverse-proxy configurations through the nginx%
|
||||||
\footnote{\href{http://nginx.org}{http://nginx.org}} web server ran by the framework.
|
\footnote{\href{http://nginx.org}{http://nginx.org}} web server ran by the framework.
|
||||||
More on this in a later chapter.
|
More on this in a Chapter~\ref{usingtfw}.
|
||||||
|
|
||||||
\section{Various Frontend Features}
|
\section{Various Frontend Features}
|
||||||
|
|
||||||
The angular frontend of features several different layouts.
|
The Angular frontend of the framework features several different layouts.
|
||||||
These layouts are useful to accomodate different workflows for users,
|
These layouts are useful to accomodate different workflows for users,
|
||||||
such as the previous exampe of editig code and being able to view the
|
such as the previous exampe of editig code and being able to view the
|
||||||
result of said code in real time next to the editor.
|
result of said code in real time next to the editor.
|
||||||
Another example would be editing Ansible playbooks in the file editor,
|
Another example would be editing Ansible playbooks in the file editor,
|
||||||
and then trying to run them in the terminal.
|
and then trying to run them in the terminal.
|
||||||
There are also almost full screen views for each component that makes sense
|
There are also almost full screen views for each component that makes sense
|
||||||
to be used that way.
|
to be used like that, for instance the code editor can be used to conveniently
|
||||||
|
edit larger files this way.
|
||||||
|
|
||||||
The frontend was designed in a way to be fully responsive in windows sizes
|
The frontend was designed in a way to be fully responsive in window sizes
|
||||||
that still keep the whole thing usable (i.e.\ it would not be practial to start
|
that still keep the whole thing usable (i.e.\ it would not be practial to start
|
||||||
solving TFW tutorials on a smart phone, simply because of size limits, so they are
|
solving TFW tutorials on a smart phone, simply because of size limits, so such small screens are
|
||||||
not supported, but the frontend still behaves as expected on small laptops or bigger tablets).
|
not supported, but the frontend still behaves as expected on small laptops or bigger tablets).
|
||||||
This is not an easy thing to impelent and maintain due to the lots of small
|
This is not an easy thing to impelent and maintain due to the lots of small
|
||||||
incompatibilites between browsers given the complexity of the frontend.
|
incompatibilites between browsers given the complexity of the frontend.
|
||||||
@ -381,15 +447,34 @@ The framework frontend is built on grid layout and flexboxes%
|
|||||||
{https://developer.mozilla.org/en-US/docs/Web/CSS/CSS\_Grid\_Layout}},
|
{https://developer.mozilla.org/en-US/docs/Web/CSS/CSS\_Grid\_Layout}},
|
||||||
which gives us the best hopes of being able to maintain it down the line.
|
which gives us the best hopes of being able to maintain it down the line.
|
||||||
It would involve unimaginable horrors to support this multi-layout
|
It would involve unimaginable horrors to support this multi-layout
|
||||||
frontend on older browsers, so browsers without flex and grid
|
frontend on older browsers without flexboxes and grid, so I have
|
||||||
support are not supported by TFW.
|
decided to avoid spending development time on these and make sure that
|
||||||
|
it works like a charm in reasonably modern browsers.
|
||||||
Arguably this is a good thing, as people should keep their browsers up to date to
|
Arguably this is a good thing, as people should keep their browsers up to date to
|
||||||
follow frequent security patches anyway, so let this serve as a reminder to
|
follow frequent security patches anyway, so let this serve as a reminder to
|
||||||
developers looking to get into IT security that the first step is to
|
developers looking to get into IT security that the first step is to
|
||||||
keep your software up to date.
|
keep your software up to date.
|
||||||
|
|
||||||
The frontend of the framework exposes some additional APIs.
|
\pic{figures/tfw_grid.png}{The grid layout of the TFW frontend showcased from developer tools}
|
||||||
These include the changing of layouts, selecting the terminal or console
|
|
||||||
|
There are several additional APIs exposed by the frontend,
|
||||||
|
which include the changing of layouts, selecting the terminal or console
|
||||||
component to be displayed, the possibility of dynamically modifying
|
component to be displayed, the possibility of dynamically modifying
|
||||||
frontend configuration values (such as the frequency of autosaving the files in the editor)
|
frontend configuration values (such as the frequency of autosaving the files in the editor)
|
||||||
and more.
|
and more.
|
||||||
|
|
||||||
|
To accomodate communication with the TFW server, the frontend of the framework
|
||||||
|
comes with some library code which can be used to send and receive TFW messages.
|
||||||
|
This code is mostly WebSockets combined with RxJS%
|
||||||
|
\footnote{\href{https://rxjs-dev.firebaseapp.com}{https://rxjs-dev.firebaseapp.com}},
|
||||||
|
which makes it easier to write completely asynchronous, callback based code.
|
||||||
|
The observables%
|
||||||
|
\footnote{\href{http://reactivex.io/documentation/observable.html}
|
||||||
|
{http://reactivex.io/documentation/observable.html}}
|
||||||
|
provided by RxJS are used all around the TFW frontend, as our library code
|
||||||
|
exposes the operation of receiving data from WebSockets as observables.
|
||||||
|
Client code can subscribe to these observables using callbacks,
|
||||||
|
which will be invoked when the observable emits a new value
|
||||||
|
(i.e.\ when a new message was received on the WebSocket).
|
||||||
|
When using Angular it is generally a good idea to get familiar with reactive programming,
|
||||||
|
because it is very easy to get lost in the callback hell without it.
|
||||||
|
@ -6,25 +6,29 @@ In this chapter I would like to express my gratitude towards great people who ha
|
|||||||
helped me in some way or an other along the way.
|
helped me in some way or an other along the way.
|
||||||
|
|
||||||
First of all I would like to thank Bálint Bokros, my good friend and colleauge for
|
First of all I would like to thank Bálint Bokros, my good friend and colleauge for
|
||||||
his awesome work during the initial phases of development and for always
|
his awesome work regarding TFW and for always
|
||||||
being open to provide useful input.
|
being open to provide useful input.
|
||||||
He has also earned my gratitude by always being there to lift my spirits, be that
|
He has also earned my gratitude by always being there to lift my spirits, be that
|
||||||
with beer or general friendship things.
|
with beer or friendship.
|
||||||
|
|
||||||
I'd also like to thank Gábor Pék and Márk Félegyházi,
|
I'd also like to thank Gábor Pék and Márk Félegyházi,
|
||||||
for letting us make this project possible by always setting reasonable goals,
|
for letting us make this project possible by always setting reasonable goals,
|
||||||
being there to provide feedback and encouraging us along the way.
|
being there to provide feedback and encouraging us along the way.
|
||||||
Gábor Pék also contributed to this in several ways, for which we always will be
|
Gábor has also contributed even more directly, for which I always will be
|
||||||
grateful.
|
grateful: it was mostly due to his visions that we were able to
|
||||||
|
dream this big, something that I've found extremely valuable when looking back.
|
||||||
|
|
||||||
I can't thank my consultant, Levente Buttyán enough for enduring my general
|
I can't thank my consultant, Levente Buttyán enough for enduring my general
|
||||||
inability to deal with deadlines and administration.
|
inability to deal with deadlines and administration.
|
||||||
|
|
||||||
I also appreciate the company my colleagues have provided in the office,
|
I also appreciate the great morale my colleagues and friends provided in the office,
|
||||||
by always being there be that for work or fun. They also have my gratitude
|
by always being there, be that for work or fun. This project couldn't have been realised
|
||||||
for general contributions to the framework, be that with ideas, assistance,
|
sitting in a depressing cube between 200 people hating their jobs. They also have my gratitude
|
||||||
|
for direct contributions to the framework, be that with ideas, assistance,
|
||||||
or actual code.
|
or actual code.
|
||||||
|
|
||||||
Finally I'd like to thank all the developers for using the framework and creating
|
Finally I'd like to thank all the developers for using the framework and creating
|
||||||
great tutorials with it. They always provide useful feedback, bug reports, and
|
great tutorials with it. At the end of the day it feels awesome to know that
|
||||||
|
my work helps other people, and it is content developers who make this possible.
|
||||||
|
They always provide useful feedback, bug reports, and
|
||||||
have great feature requests or even contributions.
|
have great feature requests or even contributions.
|
||||||
|
@ -8,8 +8,10 @@ engineering is on the rise.
|
|||||||
While we are enjoying the comfort that information technology provides us, we often forget
|
While we are enjoying the comfort that information technology provides us, we often forget
|
||||||
about the risks involved in relying so much on software in our everyday lives.
|
about the risks involved in relying so much on software in our everyday lives.
|
||||||
When taking a look on recent events, such as a cyber arms race taking place between leading
|
When taking a look on recent events, such as a cyber arms race taking place between leading
|
||||||
powers, 50 million Facebook accounts being breached
|
powers\cite{CyberArmsRace}, 50 million Facebook accounts being breached
|
||||||
due to the incorrect handling of access tokens\cite{FacebookBreach},
|
due to the incorrect handling of access tokens\cite{FacebookBreach},
|
||||||
|
the very recent Marriott hack where sensitive data on 500 million customers
|
||||||
|
was stolen\cite{MarriottBreach},
|
||||||
or how China is building an Orwellian state of total digital surveillance%
|
or how China is building an Orwellian state of total digital surveillance%
|
||||||
\cite{ChinaSurv}\cite{ChinaCredit},
|
\cite{ChinaSurv}\cite{ChinaCredit},
|
||||||
it becomes clear that security and privacy in the IT sector
|
it becomes clear that security and privacy in the IT sector
|
||||||
|
@ -3,38 +3,39 @@
|
|||||||
In this chapter I am going to evaluate the state of the project and set future goals for
|
In this chapter I am going to evaluate the state of the project and set future goals for
|
||||||
the framework.
|
the framework.
|
||||||
I'll also try and reflect on some of the most important things I have learned during
|
I'll also try and reflect on some of the most important things I have learned during
|
||||||
working on this it, in case I've experienced something that might be useful for
|
working on it, in case I've experienced something that might be useful for
|
||||||
someone else reading this in the future.
|
someone else reading this in the future.
|
||||||
|
|
||||||
\section{Project Evaluation}
|
\section{Project Evaluation}
|
||||||
|
|
||||||
How do we define if a project is a success or not?
|
How do we define if a project is a success or not?
|
||||||
Instead of trying to do so, in this section I am going to express
|
Instead of attempting to do so, in this section I am going to express
|
||||||
my personal feelings and opinions about the Tutorial Framework.
|
my personal feelings and opinions about the Tutorial Framework.
|
||||||
To get unbiased opinions I'd recommend asking someone who hasn't been maintaining
|
To get unbiased opinions I'd recommend asking someone who hasn't been maintaining
|
||||||
this project for so long.
|
this project for so long.
|
||||||
I could promise to be as objective as possible, but I think that it is just better
|
I could promise to be as objective as possible, but I think that it is just better to
|
||||||
to admit that I have a sweet spot for this project.
|
be honest and admit that I have a sweet spot for this project.
|
||||||
|
|
||||||
Currently a total of 63 tutorials based on the framework are running in production,
|
Currently a total of 63 tutorials based on the framework are running in production,
|
||||||
with new ones being released on a weekly basis.
|
with new ones being released on a weekly basis.
|
||||||
These exercises have been solved several hunders of times.
|
These exercises have been solved several hunders of times.
|
||||||
User feedback is getting better and better as the project moves forward.
|
User feedback is getting better and better as the project moves forward.
|
||||||
As a maintainer currently I know about a single unfixed bug in the framework, which
|
As a maintainer, currently I know about a single unfixed bug in the framework, which
|
||||||
is getting reported by users as well.
|
is getting reported by users as well.
|
||||||
There are more, of course, the world is never going to run out of bugs to fix,
|
There are more, of course, the world is never going to run out of bugs to fix,
|
||||||
but I sleep well knowing that things aren't breaking on a constant basis.
|
but at least I sleep well knowing that things aren't breaking on a constant basis.
|
||||||
Considering that this is a one year old project including initial development,
|
Considering that this is a one year old project including initial development,
|
||||||
I'd consider this a solid success.
|
I'd consider this a solid success.
|
||||||
|
|
||||||
We were able to achieve most of the goals we have envisioned on the beginning of
|
We were able to achieve most --- if not all --- of the goals we have envisioned on the
|
||||||
this journey, and considering some of the things we have planned for the future
|
beginning of this journey, and considering some of the things we have planned for the future
|
||||||
we are just getting started.
|
we are just getting started.
|
||||||
|
|
||||||
\section{I Have a Plan!}
|
\section{I Have a Plan!}
|
||||||
|
|
||||||
In this section I'd like to set some goals regarding the future of the framework
|
In this section I'd like to set some goals regarding the future of the framework
|
||||||
apart from implementing new features (new features will always come in as we go).
|
apart from implementing new features, as these will always keep coming in, and we
|
||||||
|
have some great ones planned, that I can promise.
|
||||||
|
|
||||||
First of all I think that we need to put more focus on developing TFW, as currently
|
First of all I think that we need to put more focus on developing TFW, as currently
|
||||||
other projects are often being priorized over it.
|
other projects are often being priorized over it.
|
||||||
@ -52,18 +53,20 @@ To make this better I'd need to consider planning ahead more, so that the newest
|
|||||||
enough to support new features on the roadmap and not get distracted as much by
|
enough to support new features on the roadmap and not get distracted as much by
|
||||||
other features emerging on the horizon.
|
other features emerging on the horizon.
|
||||||
|
|
||||||
An other thing is that I often feel like that there are some things in using the framework
|
An other thing is that I often feel like that there are some things in using TFW
|
||||||
that could be made a lot easier. As a maintainer sometimes I find it hard to
|
that could be made a lot easier. As a maintainer sometimes I find it hard to
|
||||||
tell what these things are, as I know TFW inside out, having written most
|
tell what these things exactly are, as I know the framework inside out, having written most
|
||||||
of the codebase myself.
|
of the codebase myself.
|
||||||
I'd like to set some time aside to create tutorials using the framework myself
|
I'd like to set some time aside to create tutorials using the framework myself,
|
||||||
so I can better narrow these potential difficulities down.
|
so I can better narrow these potential difficulities down.
|
||||||
|
This would require me to be able to take things slow for a few weeks, as this is not
|
||||||
|
something that is possible to do effectively in a rush. In the summer months, maybe?
|
||||||
|
|
||||||
Currently the framework is proprietary software.
|
Currently the framework is proprietary software.
|
||||||
While it is not feasible to go open source today or tomorrow for various reasons,
|
While it is not feasible to go open source today or tomorrow for various reasons,
|
||||||
we all believe that software which is free as in freedom \emph{is} the future.
|
we all believe that software which is free as in freedom \emph{is} the future.
|
||||||
As such, at some point I'd like to open source the whole thing if the circumstances will allow
|
As such, at some point I'd like to open source the whole thing if the circumstances will allow
|
||||||
us to do so.
|
the company to do so.
|
||||||
|
|
||||||
\section{Things That I Have Learned}
|
\section{Things That I Have Learned}
|
||||||
|
|
||||||
@ -78,6 +81,14 @@ as I just simply enjoy admiring quality typography which WYSIWYG%
|
|||||||
I've spent a long time working on and maintaining the Tutorial Framework.
|
I've spent a long time working on and maintaining the Tutorial Framework.
|
||||||
While the list of technical things I've learned is long and exciting, I also feel like
|
While the list of technical things I've learned is long and exciting, I also feel like
|
||||||
I've learned a lot about supporting other developers, project management and communication.
|
I've learned a lot about supporting other developers, project management and communication.
|
||||||
|
An other thing that I've been able to learn is to adopt a more patient mindset while
|
||||||
|
working. Back in the day I used to be nervous because of deadlines and things not
|
||||||
|
working how they were supposed to, but now I know that these things are a part
|
||||||
|
of the job and one must be able to deal with them without getting agitated.
|
||||||
|
Any time I feel like something is not OK, I just try take a step back, relax a bit to
|
||||||
|
blow of steam and approach the issue without acting in haste.
|
||||||
|
I think this is not too related to working as a software engineer, but something
|
||||||
|
that can be applied to anything we do.
|
||||||
|
|
||||||
The most important thing, that I will always remember as a software engineer
|
The most important thing, that I will always remember as a software engineer
|
||||||
and is something that I've learned during this period
|
and is something that I've learned during this period
|
||||||
|
@ -11,10 +11,11 @@ The main points include:
|
|||||||
\item Defining an FSM to describe the flow of the tutorial and implementing proper callbacks
|
\item Defining an FSM to describe the flow of the tutorial and implementing proper callbacks
|
||||||
for this machine, such as ones that display messages to the user
|
for this machine, such as ones that display messages to the user
|
||||||
\item Implementing the required event handlers, which may trigger state transitions in the FSM,
|
\item Implementing the required event handlers, which may trigger state transitions in the FSM,
|
||||||
interact with non-TFW code and do various things that might be needed during an exercise
|
interact with non-TFW code and do various things that might be needed during an exercise,
|
||||||
|
such as compiling code written by the user or runnign unit tests
|
||||||
\item Defining what processes should run inside the container besides the things TFW
|
\item Defining what processes should run inside the container besides the things TFW
|
||||||
starts automatically
|
starts automatically
|
||||||
\item Setting up reverse proxying for any user-facing network applications such as webservers
|
\item Setting up reverse proxying for any user-facing network application such as webservers
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
At first all these tasks can seem quite overwhelming.
|
At first all these tasks can seem quite overwhelming.
|
||||||
Remember that \emph{witchcraft} is what we practice here after all.
|
Remember that \emph{witchcraft} is what we practice here after all.
|
||||||
@ -53,14 +54,18 @@ understanding of how the framework interacts with client code.
|
|||||||
|--...
|
|--...
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
\subsection{Avatao Configuration File}
|
\subsection{Avatao Specific Files}
|
||||||
The \code{config.yml} file is an Avatao challenge configuration file,
|
The \code{config.yml} file is an Avatao challenge configuration file,
|
||||||
which is used describe what kind of Docker containers implement a challenge,
|
which is used describe what kind of Docker containers implement a challenge,
|
||||||
what ports do they expose talking what protocols, define the name of the
|
what ports do they expose talking what protocols, define the name of the
|
||||||
excercise, it's difficulity, and so on.
|
excercise, it's difficulity, and so on.
|
||||||
Every Avatao challenge must provide such a file.
|
Every Avatao challenge must provide such a file.
|
||||||
The Tutorial Framework does not use this file, this is only required to run
|
An other thing that is not even indicated on the structure above is the \code{metadata}
|
||||||
the exercise in production, so it is mostly out of scope for this thesis.
|
directory, which contains the short and long descriptions of challenges in
|
||||||
|
Markdown format.
|
||||||
|
|
||||||
|
The Tutorial Framework does not use these files in any way whatsoever,
|
||||||
|
these are only required to make the tutorial function on the Avatao platform.
|
||||||
|
|
||||||
\subsection{Controller Image}
|
\subsection{Controller Image}
|
||||||
It was previously mentioned that the \code{controller} Docker image is responsible
|
It was previously mentioned that the \code{controller} Docker image is responsible
|
||||||
@ -68,16 +73,16 @@ for the solution checking of challenges (whether the user has completed the exer
|
|||||||
Currently this image is maintained in the test-tutorial-framework repository.
|
Currently this image is maintained in the test-tutorial-framework repository.
|
||||||
It is a really simple Python server which functions as a TFW event handler as well.
|
It is a really simple Python server which functions as a TFW event handler as well.
|
||||||
It subscribes to the FSM update messages
|
It subscribes to the FSM update messages
|
||||||
broadcasted by the \code{FSMManagingEventHandler}, we've previously discussed,
|
broadcasted by the \code{FSMManagingEventHandler}, we have discussed previously,
|
||||||
this way it is capable of keeping track of the state of the tutorial,
|
this way it is capable of keeping track of the state of the tutorial,
|
||||||
which allows it to detect if the final state of the FSM is reached.
|
which allows it to detect if the final state of the FSM is reached.
|
||||||
|
|
||||||
\subsection{Solvable Image}
|
\subsection{Solvable Image}
|
||||||
Currently the Tutorial Framework is maintained in three git repositories:
|
Currently the Tutorial Framework is maintained in three git repositories:
|
||||||
\begin{description}
|
\begin{description}
|
||||||
\item[baseimage-tutorial-framework] Docker baseimage (contains all backend logic)
|
\item[baseimage-tutorial-framework:] Docker baseimage (contains all backend logic)
|
||||||
\item[frontend-tutorial-framework] Angular frontend
|
\item[frontend-tutorial-framework:] Angular frontend
|
||||||
\item[test-tutorial-framework] An example tutorial built using baseimage and frontend
|
\item[test-tutorial-framework:] An example tutorial built using baseimage and frontend
|
||||||
\end{description}
|
\end{description}
|
||||||
Every tutorial based on the framework must use the TFW baseimage as the parent of
|
Every tutorial based on the framework must use the TFW baseimage as the parent of
|
||||||
it's own \code{solvable} image, using the \code{FROM}%
|
it's own \code{solvable} image, using the \code{FROM}%
|
||||||
@ -104,8 +109,11 @@ I am going to discuss these one by one.
|
|||||||
\subsection{Dockerfile}
|
\subsection{Dockerfile}
|
||||||
Since this is a Docker image it must define a \code{Dockerfile}.
|
Since this is a Docker image it must define a \code{Dockerfile}.
|
||||||
This image always uses the baseimage of the framework as a parent image.
|
This image always uses the baseimage of the framework as a parent image.
|
||||||
Besides this developers can use this as a regular \code{Dockerfile} to work with as
|
Besides this developers can use this as a regular \code{Dockerfile} to work with
|
||||||
they see fit to implement their tutorial.
|
in any way they see fit to implement their tutorial.
|
||||||
|
This means that developers looking to create content on Avatao, be that
|
||||||
|
with the Tutorial Framework or without it must be familiar with Docker,
|
||||||
|
as they will have to set everything up to work inside a container.
|
||||||
|
|
||||||
\subsection{Frontend}
|
\subsection{Frontend}
|
||||||
This directory is designed to contain a clone of the frontend repository.
|
This directory is designed to contain a clone of the frontend repository.
|
||||||
@ -116,19 +124,29 @@ setup of the development environment.
|
|||||||
As previously mentioned, the framework uses supervisor to run several processes
|
As previously mentioned, the framework uses supervisor to run several processes
|
||||||
inside a Docker container.
|
inside a Docker container.
|
||||||
Usually Docker containers only run a single process and developers simply start
|
Usually Docker containers only run a single process and developers simply start
|
||||||
more containers instead of processes if required.
|
more containers instead of processes if required (and use tools such as docker-compose%
|
||||||
|
\footnote{\href{https://docs.docker.com/compose/}{https://docs.docker.com/compose/}}
|
||||||
|
or kubernetes%
|
||||||
|
\footnote{\href{https://kubernetes.io}{https://kubernetes.io}}
|
||||||
|
to orchestrate their containers).
|
||||||
This approach is not suitable for TFW, as it would require the framework to orchestrate
|
This approach is not suitable for TFW, as it would require the framework to orchestrate
|
||||||
Docker containers from an other container, which is feasible in theory but
|
Docker containers from inside a container managed by the same Docker daemon, which is
|
||||||
very hard and impractial to do in practice.
|
feasible in theory but very hard and unservicable to do in practice.
|
||||||
|
This would require doing something like mounting the unix domain socket used
|
||||||
|
to manage the Docker daemon inside a running container managed by that daemon,
|
||||||
|
which is a fun thing to
|
||||||
|
play around with in my free time but not something suitable for running in production,
|
||||||
|
not even mentioning the severe security implications of doing something like that.
|
||||||
|
|
||||||
Supervisor is a process control system designed to be able to work with
|
Supervisor is a process control system designed to be able to work with
|
||||||
processes on UNIX-like operating systems.
|
processes on UNIX-like operating systems.
|
||||||
When a tutorial built on TFW is started, the framework starts supervisor with
|
When a tutorial built on TFW is started, a Docker container starts with supervisor running as
|
||||||
PID\footnote{Process ID, on UNIX-like systems the \code{init} program is the first
|
PID\footnote{Process ID, on UNIX-like systems the \code{init} program is the first
|
||||||
process started} 1, which in turn starts all the programs defined
|
process started, and who gets PID 1 traditionally.} 1, which in turn starts all the
|
||||||
in this directory using supervisor configuration files.
|
programs defined in the \code{solvable/supervisor} directory.
|
||||||
For example, a developer would use a file similar to this to run a webserver
|
Content creators can use supervisor configuration files to define these programs.
|
||||||
written in python:
|
For example, a developer would write a file similar to this one and place it into the
|
||||||
|
\code{solvable/supervisor} directory to run a webserver written in Python:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
[program:yourprogram]
|
[program:yourprogram]
|
||||||
user=user
|
user=user
|
||||||
@ -138,35 +156,51 @@ autostart=true
|
|||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
As mentioned earlier in~\ref{processmanagement}, any program that is started this way
|
As mentioned earlier in~\ref{processmanagement}, any program that is started this way
|
||||||
can be managed by the framewok using API messages.
|
can be managed by the framewok using API messages.
|
||||||
|
All this is possible through using the xmlrpc%
|
||||||
|
\footnote{\href{https://docs.python.org/3/library/xmlrpc.html}
|
||||||
|
{https://docs.python.org/3/library/xmlrpc.html}}
|
||||||
|
API exposed by supervisor, which allows the framework to interact with it to control processes.
|
||||||
|
This API is quite flexible and can be used to achieve a number of things which would be
|
||||||
|
clumsy to do without using it (i.e.\ supervisor has a command line utility called
|
||||||
|
\code{supervisorctl} that exposes similar functionality to the xmlrpc bindings,
|
||||||
|
but it is better to communicate with the supervisor daemon directly than to
|
||||||
|
invoke it's command line utility in a separate process when you need something done).
|
||||||
|
|
||||||
\subsection{Nginx}
|
\subsection{Nginx}
|
||||||
For simplicity, exercises based on the framework only expose a single port from the
|
For simplicity, exercises based on the framework only expose a single port from the
|
||||||
\code{solvable} container.
|
\code{solvable} container.
|
||||||
This port is required to serve the frontend of the framework.
|
This port is required to serve the frontend of the framework.
|
||||||
If this is the case, how do we run additional web applications to showcase vulnerabilies
|
If this is the case, how do we run additional web applications to showcase vulnerabilies
|
||||||
on during the tutorial?
|
on during a tutorial?
|
||||||
Since one port can only be bound by one process at a time, we will need to
|
Since one port can only be bound by one process at a time, we will need to
|
||||||
use a reverse-proxy to to bind the port and redirect traffict to other
|
run a reverse-proxy%
|
||||||
webservers binding non-exposed ports.
|
\footnote{\href{https://www.nginx.com/resources/glossary/reverse-proxy-server/}
|
||||||
|
{https://www.nginx.com/resources/glossary/reverse-proxy-server/}} server inside the
|
||||||
|
container to
|
||||||
|
bind the exposed port and redirect traffic to other webservers binding non-exposed ports.
|
||||||
|
|
||||||
To support this, TFW automatically runs an nginx webserver (it uses this nginx
|
To support this, TFW automatically starts an nginx webserver. It uses this nginx
|
||||||
process to serve the framework frontend as well) we can supply additional configurations to.
|
instance to serve the framework frontend as well.
|
||||||
Any configuration files placed into this directory will be interpreted by nginx
|
It is possible to supply additional configurations to this server in a convenient manner:
|
||||||
once the container has started.
|
any configuration files placed into the \code{solvable/nginx} directory will be
|
||||||
|
interpreted by nginx once the container has started.
|
||||||
To set up the reverse-proxying of a webserver running on port 3333,
|
To set up the reverse-proxying of a webserver running on port 3333,
|
||||||
one would write a config file similar to this one:
|
one would write a configuration file similar to this one:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
location /yoururl {
|
location /yoururl {
|
||||||
proxy_pass http://127.0.0.1:3333;
|
proxy_pass http://127.0.0.1:3333;
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
Now the content server by this websever will be available on ``<challenge\_url>/yoururl''.
|
Now the content served by this websever on port 3333
|
||||||
|
will be available on the url \code{<challenge-url>/yoururl} despite that port 3333
|
||||||
|
does not accept connections from outside the container as it is not exposed.
|
||||||
It is very important to understand, that developers
|
It is very important to understand, that developers
|
||||||
have to make sure that their web application \emph{behaves well} behind a reverse proxy.
|
have to make sure that their web application \emph{behaves well} behind a reverse proxy.
|
||||||
What this means is that they are going to be serverd from a ``subdirectory'' of an URL:
|
What this means is that they are going to be served from a ``subdirectory'' of the top
|
||||||
for example ``/register'' will be served under ``/yoururl/register''.
|
level URL\@:
|
||||||
|
for example \code{/register} will be served under \code{/yoururl/register}.
|
||||||
This means that all links in the final HTML must refer to the proxied urls, e.g.\
|
This means that all links in the final HTML must refer to the proxied urls, e.g.\
|
||||||
``/yoururl/register'' and server side redirects must point to the correct hrefs as well.
|
\code{/yoururl/login}, and server side redirects must point to these correct hrefs as well.
|
||||||
Idiomatically this is usually implemented by supplying a \code{BASEURL}
|
Idiomatically this is usually implemented by supplying a \code{BASEURL}
|
||||||
to the application through an environment variable, so that it is able to set
|
to the application through an environment variable, so that it is able to set
|
||||||
itself up correctly.
|
itself up correctly.
|
||||||
@ -181,18 +215,18 @@ Normally when one uses the \code{COPY}%
|
|||||||
command to create a layer%
|
command to create a layer%
|
||||||
\footnote{\href{https://docs.docker.com/storage/storagedriver/}
|
\footnote{\href{https://docs.docker.com/storage/storagedriver/}
|
||||||
{https://docs.docker.com/storage/storagedriver/}} in a Docker image,
|
{https://docs.docker.com/storage/storagedriver/}} in a Docker image,
|
||||||
this action takes place when building that image (i.e.\ in the \emph{build context}
|
this action takes place on building that image (i.e.\ in the \emph{build context}
|
||||||
of that image).
|
of that image).
|
||||||
This is not good for this use case: when building the framework baseimage,
|
This is not good for this use case: when building the framework baseimage,
|
||||||
these configuration files that will be written by content developers do not even
|
these configuration files that will be written by content developers using TFW in
|
||||||
exist.
|
the future do not even exist yet.
|
||||||
How could we copy files into an image layer that will be created in the future?
|
How could we copy files into an image layer that will be created in the future?
|
||||||
|
|
||||||
It is possible to use a command called \code{ONBUILD}%
|
It is possible to use a command called \code{ONBUILD}%
|
||||||
\footnote{\href{https://docs.docker.com/engine/reference/builder/\#onbuild}
|
\footnote{\href{https://docs.docker.com/engine/reference/builder/\#onbuild}
|
||||||
{https://docs.docker.com/engine/reference/builder/\#onbuild}}
|
{https://docs.docker.com/engine/reference/builder/\#onbuild}}
|
||||||
in the Dockerfile of a baseimage to delay another command
|
in the Dockerfile of a baseimage to delay another command
|
||||||
to the point in time when other images will use the baseimage
|
to the point in time where other images will use the baseimage
|
||||||
as a parent with the \code{FROM} command. This makes it possible to execute
|
as a parent with the \code{FROM} command. This makes it possible to execute
|
||||||
commands in the build context of the descendant image.
|
commands in the build context of the descendant image.
|
||||||
This is great, because the config files we need \emph{will} exist in the build
|
This is great, because the config files we need \emph{will} exist in the build
|
||||||
@ -202,6 +236,12 @@ In practice this looks something like this in the baseimage \code{Dockerfile}:
|
|||||||
ONBUILD COPY ${BUILD_CONTEXT}/nginx/ ${TFW_NGINX_COMPONENTS}
|
ONBUILD COPY ${BUILD_CONTEXT}/nginx/ ${TFW_NGINX_COMPONENTS}
|
||||||
ONBUILD COPY ${BUILD_CONTEXT}/supervisor/ ${TFW_SUPERVISORD_COMPONENTS}
|
ONBUILD COPY ${BUILD_CONTEXT}/supervisor/ ${TFW_SUPERVISORD_COMPONENTS}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
It is important to keep in mind however, that the layers created by these
|
||||||
|
\code{ONBUILD} commands will only be available \emph{after} the \code{FROM}
|
||||||
|
command is executed when building the child image \emph{in the future}.
|
||||||
|
This means that if you want to
|
||||||
|
do something with these files in the baseimage build after they have
|
||||||
|
been copied, those things must be done in \code{ONBUILD} commands as well.
|
||||||
|
|
||||||
\subsection{Source Directory}
|
\subsection{Source Directory}
|
||||||
The \code{src} directory usually holds tutorial-specific code, such as
|
The \code{src} directory usually holds tutorial-specific code, such as
|
||||||
@ -210,7 +250,8 @@ served by the exercise and generally anything that won't fit in the other,
|
|||||||
framework-specific directories.
|
framework-specific directories.
|
||||||
The use of this directory is not mandatory, only a good practice, as developers
|
The use of this directory is not mandatory, only a good practice, as developers
|
||||||
are free to implement the non-TFW parts of their exercises as they see fit
|
are free to implement the non-TFW parts of their exercises as they see fit
|
||||||
(the copying of these files into image layers are their resposibility).
|
(the copying of these files into image layers using \code{solvable/Dockerfile}
|
||||||
|
is their resposibility as well).
|
||||||
|
|
||||||
\section{Configuring Built-in Components}
|
\section{Configuring Built-in Components}
|
||||||
|
|
||||||
@ -257,6 +298,21 @@ YAML based state machine implementations also allow the usage of the Jinja2%
|
|||||||
templating language to substitute variables into the YAML file.
|
templating language to substitute variables into the YAML file.
|
||||||
These substitutions are really powerful, as one could even iterate through arrays
|
These substitutions are really powerful, as one could even iterate through arrays
|
||||||
or invoke functions that produce strings to be inserted using this method.
|
or invoke functions that produce strings to be inserted using this method.
|
||||||
|
This is very similar to how Ansible uses%
|
||||||
|
\footnote{\href{https://docs.ansible.com/ansible/2.6/user_guide/playbooks_templating.html}
|
||||||
|
{https://docs.ansible.com/ansible/2.6/user\_guide/playbooks\_templating.html}}
|
||||||
|
Jinja2, and I was certainly inspired by this
|
||||||
|
when coming up with this idea.
|
||||||
|
For example, if we had an FSM with five states, we could use the following
|
||||||
|
Jinja2 code to generate a transition called \code{step_next} between each state
|
||||||
|
in a \code{for} cycle:
|
||||||
|
\begin{lstlisting}
|
||||||
|
{% for i in range(5) %}
|
||||||
|
- trigger: 'step_next'
|
||||||
|
source: '{{i}}'
|
||||||
|
dest: '{{i+1}}'
|
||||||
|
{% endfor %}
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
\subsection{Python based FSM}
|
\subsection{Python based FSM}
|
||||||
Optionally, the same state machine can be implemented like this in Python using
|
Optionally, the same state machine can be implemented like this in Python using
|
||||||
@ -279,7 +335,7 @@ Python as well, it is going to be easier to interface with library code.
|
|||||||
In this section I am going to showcase how implementing event handlers is possible
|
In this section I am going to showcase how implementing event handlers is possible
|
||||||
when using the framework.
|
when using the framework.
|
||||||
I am going to use the Python programming language, but it isn't hard
|
I am going to use the Python programming language, but it isn't hard
|
||||||
to create event handlers in other languages, because the only thing
|
to create event handlers in other languages, as the only thing
|
||||||
they have to be capable of is communicating with the TFW server using
|
they have to be capable of is communicating with the TFW server using
|
||||||
ZeroMQ sockets, as previously discussed.
|
ZeroMQ sockets, as previously discussed.
|
||||||
The library provided by the framework abstracts low level socket logic
|
The library provided by the framework abstracts low level socket logic
|
||||||
@ -305,12 +361,11 @@ abstract method, which is used to, well, handle events.
|
|||||||
To make getting started as smooth as possible I have created
|
To make getting started as smooth as possible I have created
|
||||||
a ``bootstrap'' script which is capable of creating a development envrionment from
|
a ``bootstrap'' script which is capable of creating a development envrionment from
|
||||||
scratch.
|
scratch.
|
||||||
|
|
||||||
This script is distributed as the following bash one-liner:
|
This script is distributed as the following bash one-liner:
|
||||||
\begin{lstlisting}[language=bash]
|
\begin{lstlisting}[language=bash]
|
||||||
bash -c "$(curl -fsSL https://git.io/vxBfj)"
|
bash -c "$(curl -fsSL https://git.io/vxBfj)"
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
This command downloads a script using \code{curl}%
|
This command downloads the script using \code{curl}%
|
||||||
\footnote{\href{https://curl.haxx.se}{https://curl.haxx.se}}, then executes it in bash.
|
\footnote{\href{https://curl.haxx.se}{https://curl.haxx.se}}, then executes it in bash.
|
||||||
In the open source community it is quite common to distribute installers this way%
|
In the open source community it is quite common to distribute installers this way%
|
||||||
\footnote{A good example of this is oh-my-zsh
|
\footnote{A good example of this is oh-my-zsh
|
||||||
@ -340,7 +395,7 @@ then pipes it into a bash interpreter \emph{only if} the checksum
|
|||||||
of the downloaded string matches the one provided, otherwise it displays
|
of the downloaded string matches the one provided, otherwise it displays
|
||||||
an error message.
|
an error message.
|
||||||
Software projects distributing their product as binary installers often
|
Software projects distributing their product as binary installers often
|
||||||
display such checksums on their download pages with the purpose to potentially
|
display such checksums on their download pages with the purpose of potentially
|
||||||
mitigating MITM attacks.
|
mitigating MITM attacks.
|
||||||
|
|
||||||
The bootstrap script clones the three TFW repositories and does several steps
|
The bootstrap script clones the three TFW repositories and does several steps
|
||||||
@ -348,7 +403,7 @@ to create a working environment into a single directory, that is based on
|
|||||||
test-tutorail-framework:
|
test-tutorail-framework:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item It builds the newest version of the TFW baseimage locally
|
\item It builds the newest version of the TFW baseimage locally
|
||||||
\item It pins the version tag in \code{solvable/Dockerfile},
|
\item It pins the version tag of this image in \code{solvable/Dockerfile},
|
||||||
so that this newly-built version will be used by the tutorial
|
so that this newly-built version will be used by the tutorial
|
||||||
\item It places the latest frontend in \code{solvable/frontend} with
|
\item It places the latest frontend in \code{solvable/frontend} with
|
||||||
depencendies installed
|
depencendies installed
|
||||||
@ -376,15 +431,15 @@ Why is this the case?
|
|||||||
|
|
||||||
\subsection{The Frontend Issue}
|
\subsection{The Frontend Issue}
|
||||||
|
|
||||||
To be able to understand this, we will have to gain some understanding of the
|
To be able to understand this, we will have to gain some understanding on how the
|
||||||
build process of Angular projects.
|
build process of Angular projects work.
|
||||||
|
|
||||||
When frontend developers work on Angular projects, they usually use the built-in
|
When frontend developers work on Angular projects, they usually use the built-in
|
||||||
developer tool of the Angular-CLI%
|
developer tool of the Angular-CLI%
|
||||||
\footnote{\href{https://cli.angular.io}{https://cli.angular.io}},
|
\footnote{\href{https://cli.angular.io}{https://cli.angular.io}},
|
||||||
\code{ng serve} to build and serve their application.
|
\code{ng serve} to build and serve their applications.
|
||||||
The advantage of this tool is that it automatically reloads the frontend
|
The advantage of this tool is that it automatically reloads the frontend
|
||||||
when the code on disk is changed, and that it is generally very easy to work with.
|
when the code on the disk is changed, and that it is generally very easy to work with.
|
||||||
On the other hand, a disadvantage is that a \code{node_modules} directory
|
On the other hand, a disadvantage is that a \code{node_modules} directory
|
||||||
containing all the npm%
|
containing all the npm%
|
||||||
\footnote{\href{https://www.npmjs.com}{https://www.npmjs.com}}
|
\footnote{\href{https://www.npmjs.com}{https://www.npmjs.com}}
|
||||||
@ -405,13 +460,14 @@ This is why today frontend builds usually take a lot longer than building anythi
|
|||||||
not involving JavaScript (such as C++, C\# or any other compiled programming language).
|
not involving JavaScript (such as C++, C\# or any other compiled programming language).
|
||||||
|
|
||||||
This mess presents it's own challenges for the Tutorial Framework as well.
|
This mess presents it's own challenges for the Tutorial Framework as well.
|
||||||
Since hundreds of megabytes of dependencies have no place inside Docker containers%
|
Since hundreds of megabytes of npm dependencies have no place inside Docker images%
|
||||||
\footnote{Otherwise it may take tens of seconds just to send the build context to
|
\footnote{Or it may take tens of seconds just to send the build context to
|
||||||
the Docker daemon, which means waiting even before the build began},
|
the Docker daemon, which means waiting even before the build began},
|
||||||
by default the framework will only place the results of a frontend production build
|
by default the framework will only copy the results of a frontend production build
|
||||||
of \code{solvable/frontend} into the image layers.
|
of \code{solvable/frontend} into the image layers.
|
||||||
This slows down the build time of TFW based challenges so much, that instead of like
|
This slows down the build time of TFW based challenges so much, that instead of like
|
||||||
30 seconds, they will often take 5 to 10 minutes.
|
30 seconds, they could often take 5 to 10 minutes depending on what hardware
|
||||||
|
you use.
|
||||||
|
|
||||||
\subsection{The Solution Offered by the Framework}
|
\subsection{The Solution Offered by the Framework}
|
||||||
|
|
||||||
@ -426,7 +482,7 @@ while the \code{tfw.sh} script is capable of starting a development server
|
|||||||
to serve the frontend locally using \code{ng serve} besides starting
|
to serve the frontend locally using \code{ng serve} besides starting
|
||||||
the Docker container without the frontend.
|
the Docker container without the frontend.
|
||||||
If this whole thing wasn't complicated enough, since Docker binds the port
|
If this whole thing wasn't complicated enough, since Docker binds the port
|
||||||
the container is going to use, \code{tfw.sh} has to run this dev server on
|
the container is going to use, \code{tfw.sh} has to run the Angular dev server on
|
||||||
an other port, then use the proxying features of Angular-CLI to forward requests
|
an other port, then use the proxying features of Angular-CLI to forward requests
|
||||||
from this port to the runnign Docker container when requesting resources
|
from this port to the runnign Docker container when requesting resources
|
||||||
other then the entrypoint to the Angular application.
|
other then the entrypoint to the Angular application.
|
||||||
|
BIN
figures/tfw_grid.png
Normal file
BIN
figures/tfw_grid.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 282 KiB |
Loading…
Reference in New Issue
Block a user