% % FH Technikum Wien % !TEX encoding = UTF-8 Unicode % % Erstellung von Master- und Bachelorarbeiten an der FH Technikum Wien mit Hilfe von LaTeX und der Klasse TWBOOK % % Um ein eigenes Dokument zu erstellen, müssen Sie folgendes ergänzen: % 1) Mit \documentclass[..] einstellen % * Master- oder Bachelorarbeit % * Studiengang % * Sprache (english, german, ngerman) % * Zitationsstandard (Harvard, IEEE) (Standard: IEEE) % * Biber oder BibTeX als Literaturbackend (Biber, BibTeX) (Standard: Biber) % 2) Deckblatt, Kurzfassung, etc. ausfüllen % 3) und die Arbeit schreiben (die verwendeten Literaturquellen in Literatur.bib eintragen) % % Getestet mit TeXstudio mit Zeichenkodierung utf-8 (=ansinew/latin1) und TexLive unter Ubuntu % Zu beachten ist, dass die Kodierung der Datei mit der Kodierung des paketes inputenc zusammen passt! % Die Kodierung der Datei twbook.cls MUSS ANSI betragen! % Bei der Verwendung von UTF8 muss nicht nur die Kodierung des Dokuments auf UTF8 gestellt sein, sondern auch die des BibTex-Files! % % Bugreports und Feedback bitte per E-Mail an latex@technikum-wien.at % % Version V2.24 von 2024-12-19 otrebski % \documentclass[BIF,Bachelor,english,IEEE]{twbook}%\documentclass[Bachelor,BMR,ngerman]{twbook} \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc} %% Definieren Sie hier weitere Literaturdatenbanken %\addbibresource{Literaturdatenbank.bib} \usepackage[newfloat]{minted} \usepackage{caption} \newenvironment{code}{\captionsetup{type=listing}}{} \SetupFloatingEnvironment{listing}{name=Source Code} % Die nachfolgenden Pakete stellen sonst nicht benötigte Features zur Verfügung \usepackage{blindtext} % % Einträge für Deckblatt, Kurzfassung, etc. % \title{Hardening Hybrid Infrastructures:\\Security Approaches for Docker Containers and their Host Systems} \author{Benedikt Galbavy} \studentnumber{2210257082} %\author{Titel Vorname Name, Titel\and{}Titel Vorname Name, Titel} %\studentnumber{XXXXXXXXXXXXXXX\and{}XXXXXXXXXXXXXXX} \supervisor{Dipl. Ing. Manuel-Christopher Parg, BSc.} %\supervisor[Begutachter]{Titel Vorname Name, Titel} %\supervisor[Begutachterin]{Titel Vorname Name, Titel} %\secondsupervisor{Titel Vorname Name, Titel} %\secondsupervisor[Begutachter]{Titel Vorname Name, Titel} %\secondsupervisor[Begutachterinnen]{Titel Vorname Name, Titel} \place{Wien} \kurzfassung{\blindtext} \schlagworte{Schlagwort1, Schlagwort2, Schlagwort3, Schlagwort4} \outline{\blindtext} \keywords{Docker, Containerization, Hybrid, Security} %\acknowledgements{\blindtext} \begin{document} \maketitle % % .. und hier beginnt die eigentliche Arbeit. Viel Erfolg beim Verfassen! % \chapter{Containerization} Containerization is more relevant today than ever. Modern software design patterns like microsservices rely heavily on using multiple isolated components---something that would not be possible with traditional hardware-based systems, or at least unfeasibly expensive; this is especially relevant for development and testing environments, which require reproducible and lightweight setups. DevOps pipelines often use containerization to run tasks on demand, ranging from unit tests to artifact building, and are prevalent in many software control systems---for example in the form of GitHub Actions or GitLab CI. Compared to earlier approaches of virtual machines, containers allow running similarly independent systems with less overhead and less start-up delay, primarily due to not simulating the hardware and kernel, but only isolating user space. And these points are only amplified by the wide-spread adoption through major tech companies and cloud platforms, which spent time and money on improving the software and surrounding tooling \cite{finley_2014_amazon}\cite{tozzi_2018_5}, as well as expanding on the original idea through concepts like orchestration of larger, distributed systems \cite{kubernetes_2023_overview}. \section{A Solution to Dependencies} Especially in development, dependencies are a well known problem in non-standard environments; different software requires different versions of the same libraries, often resulting in conflicts. This can be caused by installing the latest version of a given dependency at some point, but not updating it---commonly known as the ``it works on my machine'' problem \cite{pardo_2023_but}\cite{wang_2025_common}. One such scenario of a dependency conflict is python, which often removes functions even in minor versions \cite{a2024_whats}, thus leading to incompatibilities---which are expressed as run-time errors in the case of python specifically, making them harder to detect. Containerization solves that problem by virtualizing encapsulated, standardized environments; Docker is one of the most widely adopted containerization tools \cite{a2025_leading}, and will thus be used as a stand-in for containerization for the purposes of this thesis. There is some functionality specific to docker, which have been highlighted chapter 5; overall these differences are very minor however, and for most purposes alternative tools like Podman fulfill the role equally well. \section{A Duplication of Dependencies} As each container is a separate system, this introduces redundancy, particularly in background services and system-level dependencies rather than application libraries. While Docker does not duplicate the kernel or even the hardware to the same level a full virtual machine does \cite{docker_2023_what}, each container still contains a complete operating system---although it usually does not feature a full desktop environment, but only a minimal user space---especially with minimal distributions like Alpine Linux. Furthermore there is commonly a larger dependency overlap in most modern software[?]: Static elements like glibc and language interpreters mostly contribute to storage redundancy, but have a minimal performance impact. In contrast, service dependencies---including logging daemons, databases, and schedulers---consume CPU time, memory, and I/O resources. Considering similar services are often run on the same machine, such as two web services as shown in Chapter 2.1, these dependencies are often similar or identical. One notable example is databases---which are commonly provided as standalone containers \cite{zhao_2024_simplifying}, instead of being shipped with the image. While this separation can be convenient, this can lead to multiple instances of the same container on one host. \section{A Solution to Duplication} While much research has already explored reducing storage inefficiencies in docker images \cite{skourtis_2019_carving}, a less explored area is the duplication of service dependencies across containers. Many systems run multiple instances of the same service---message queues, databases, caching systems, authentication and redirection proxies, and logging systems are all common examples, despite their potential for centralization. While not all of these services can be reused, identifying the ones that are practical to share offers opportunities for less overhead and tighter integration with the host system. Logging in particular is a promising candidate, as not only is it essential for most systems, but docker already captures container output streams. Instead of routing them to a new container or service, they can be processed centrally on the host, reducing duplication and simplifying management. \section{Sharing Resources---To the Wrong Audience} One of the core premises of containerization is isolation---each container acting independently with limited access to other containers or the host system. The previous sections focused on breaking this isolation for the purposes of resource efficiency. This brings the obvious trade-off of increasing the attack surface. There has been a great deal of research on attacks such as container escapes \cite{putta_2023_enhancing}\cite{yasrab_2018_mitigating}\cite{yasrab_2018_mitigating}, and consequences of such an attack increase dramatically when resources are shared between the containers. While docker networks secure inter-container communication \cite{a2024_networking}\cite{docker}, this does not secure interaction between the container and host system, and does not prevent containers from accessing host resources, especially if they have been deliberately exposed. A prominent example of such an attack is the Log4Shell exploit \cite{zhaojun_2021_cve202144228}---which allowed remote code execution through logging---assuming similar exploits could exist in other logging software, just a single crafted log message could be enough to turn a single compromised container into a wider breach. These risks highlight the importance of considering security implications when services are reused for a hybrid environment---a challenge addressed in the following chapters. \chapter{Constructing a Real World Scenario} Since the focus of this thesis is on identifying improvements and analyzing trade-offs between isolation and efficiency of real world applications, a realistic scenario is required. The constructed environment requires interfaces---HTTP(S), SSH, persistent volumes, background services---similar to those found in a production environment, while still keeping it minimal to ensure accuracy of any implementations. There are countless scenarios that fulfill these criteria, but one of the most common are web services. \section{Use-Case: Small Scale Web Services} In an enterprise context, redundancies can often be planned for and eliminated in advance, but in smaller scale scenarios, be it smaller companies, or even just personal projects, environments often grow organically by adding additional services reactively to changing requirements rather than planning long term---leading to unplanned duplication. Such systems also often use docker compose \cite{kamath_2021_containerize} or similar orchestration tools with convenience focused configurations---containing less moving parts and are easier to update---instead of favoring optimization. However these scenarios also have the highest incentive to stay cost effective. \begin{figure}[!htbp] \centering \includegraphics[width=0.5\linewidth]{img/webservice-use_case.png} \caption{Network diagram of a docker setup with Gitea and Bitwarden}\label{webservice} \end{figure} \subsection{Gitea---A Wide Attack Surface} Gitea serves as an example for any git server. It will be used due to its lightweight design, but is otherwise representative of enterprise grade systems like GitLab. A git server provides a wide attack surface \cite{gitea}\cite{gitlab} due to the mix of different user content through file storage, comments and issues, and CI pipelines, and a mix of interfaces with HTTP(S) access and SSH access---commonly via a user ‘git’. SSH access in particular requires careful configuration \cite{gasser_2014_a}, as the host needs to access an SSH server inside the container, something rarely done otherwise. Gitea requires a database for storing user submissions---which can be an integrated SQLite3 instance, but more commonly is a postgres database container, and it requires a file volume, commonly mounted directly to the host; it furthermore has optional dependencies in code runners for pipelines, and an email server. \subsection{Bitwarden---Increasing the Stakes} Bitwarden, or more accurately vaultwarden---an open source implementation of a bitwarden server---serves a less complex component, but stores highly sensitive data. Unlike Gitea, it only requires a database and optionally an email server, but this raises the question of how big of a security risk is introduced by sharing a core service like a database between two services differing greatly in risk. Vaultwarden in particular provides great value to such an analysis due to its thorough documentation \cite{danigarcia_2025}, allowing purposeful misconfiguration to test different attack vectors. \subsection{NGinX---The Entrypoint} Reverse proxies like NGinX or Traefik are commonly used as an entry point to route incoming requests \cite{wahanani_2021_implementation} to the correct services based on hostname. Compared to Traefik, NGinX also provides a significant amount of additional functionality, however an extended feature set can also introduce unnecessary complexity, increasing the risk of misconfigurations---this has to be analysed in the following chapters. It is also important to point out that oftentimes a firewall is even before the proxy, or integrated into it; examples include iptables rules on the host, or fail2ban integrated with the nginx logs. \subsection{Background Service Redundancy} Additionally to the primary services, there are some background services required, which affect both Gitea and Bitwarden: For TLS/SSL, certificates are required---which are commonly handled by a Let’s Encrypt ``certbot''. The service can either run on the host directly, or in its own container; either way the certificates will need to be exported to the NGinX container---in most cases the certificate service will write to a shared volume. However due to rate limits on issuing certificates, and the rapid testing required for this thesis, automatic certificate management has been eliminated as part of the tested setup. As previously touched upon, most scenarios include some form of log management and processing. Docker already provides prerequisites, and allows configuring log collection to a file or to journald, however the logs still need to be combined, rotated, and sent for further processing, or processed with yet another additional service. It should be noted, that the applications themselves are not the focus of the analysis, but just serve as means to an end; the focus is in the analysis of the dependencies. \section{Use-Case: TBD} Secondary scenario if applicable \chapter{Reproducibility} Since the docker host system will also be tested, it also needs to be reproducible---to achieve that it will be instantiated as a virtual machine. Since the term ‘host’ often has different meanings, especially in a context of containerization, this section will clarify the terms used for the rest of the thesis: The device on which the VM is hosted will henceforth be called VM-host; the host of the Docker containers---the described VM---will be called docker host, docker VM, or just host. To allow reliable reproduction of attacks, these will also be made from a VM, which will be called the client-vm, or just client. If any further services are required, which would normally be external ``on the internet'', a third vm will be used, the ``external-vm''. The VM-host will only ever be used for configuring the VMs, never to test anything. The base configuration can be found in \ref{appendix_base_config}. \section{The Host of the Host} Tools have been selected based on reproducibility and compatibility, but not performance. The resulting stack---Vagrant, VirtualBox, Ansible, Ubuntu---is widely adopted \cite{a2024_vagrant} and well supported, allowing better reuse of existing research, as well as sharing of the test setup. \begin{figure}[!htbp] \centering \includegraphics[width=0.5\linewidth]{img/attack_lab.png} \caption{Relation of the components in the lab setup using a simplified representation of the tested services}\label{lab} \end{figure} \section{Tooling for the VM-Host} To evaluate the effectiveness of base configuration and the implemented measures, a series of controlled attacks are performed from the client VM against the running services in the docker host. At first Ubuntu Desktop was considered as the OS, however as the client VM is not the focus of this thesis and thus does not need to be representative of the real world to the same degree as the docker VM, Kali Linux was determined to be a better option due to the suite of preinstalled tooling for the simulated attacks. The process is split into three phases, mirroring real world scenarios: Reconnaissance: Tools like nmap, netcat and curl are used to discover any open ports, services, and misconfigurations. Exploitation: Metasploit and custom scripts are used to test the effectiveness of known exploits on a specific configuration. Due to the reproducibility of the environment, effectiveness can be measured and compared as a simple pass/fail rate. Post-Exploitation: After gaining access, tools like linpeas and manual inspecting are used to determine access to shared resources. The goal in these tests is not to discover novel exploits, but to simulate real world attack paths and analyse the additional risk introduced by the hybrid architecture. \section{Preparing for Attack} To evaluate the effectiveness of base configuration and the implemented measures, a series of controlled attacks are performed from the client VM against the running services in the docker host. The process is split into three phases, mirroring real world scenarios: Reconnaissance: Tools like nmap, netcat and curl are used to discover any open ports, services, and misconfigurations. Exploitation: Metasploit and custom scripts are used to test the effectiveness of known exploits on a specific configuration. Due to the reproducibility of the environment, effectiveness can be measured and compared as a simple pass/fail rate. Post-Exploitation: After gaining access, tools like linpeas and manual inspecting are used to determine access to shared resources. The goal in these tests is not to discover novel exploits, but to simulate real world attack paths and analyse the additional risk introduced by the hybrid architecture. It should also be noted, that some tested measures only protect against a specific step, or assumes certain prerequisites---some steps will thus be skipped where applicable. \chapter{The Holes in the Wall} This chapter describes the tests against the architecture. Each test starts with the configuration described in \ref{appendix_base_config}, with the corresponding changes as described in \ref{appendix_patches} applied via patch\cite{patch1}. Assuming a complete configuration, the VMs are booted with vagrant\cite{hashicorp_vagrant}. \section{Security analysis---Use-Case: Web Services} \subsection{Base Configuration} The base configuration is a minimal configuration, using default values wherever possible. \subsubsection*{Reconnaissance} \paragraph*{NMap Scan} Fig. 3: Output of \texttt{sudo nmap -sS -p1-65535 192.168.56.10} [In progress note: the log output will be attached in text format instead of as a screenshot in a later draft] While no unexpected ports are open, it does reveal the setup redirecting to Gitea by default, instead of Bitwarden. This is not unexpected, since no other default has been specified. Known services analysis: [TODO: question for next meeting: how to display long outputs?] Fig: 4: Output of \texttt{curl -kL gitea.local.vm} The landing page of Gitea does not directly expose any critical data, however it does list the install version number, which paired with known security vulnerabilities\cite{gitea} can introduce a breach. Fig: 5: Output of \texttt{curl -kL bitwarden.local.vm} Vaultwarden presents a similar issue after allowing the page to execute JavaScript. Exploitation Detailed explanation of all scripts Post-Exploitation Detailed explanation of found consequences \subsection{Outdated versions of services} [TODO: Gitea 1.17.2] \subsection{Firewall on host system} \subsection{Firewall in separate docker container} \subsection{Firewall in NGinX container} \subsection{Separate docker networks} \chapter{Discussion - NAME PENDING} Introduction/Summary \section{Untested configurations} Due to the wide array of possible configurations for any docker setup, is it virtually impossible to cover all in detail. Nonetheless this section will try to highlight some more common configurations, which were left out, and reason on why they were not tested. It is important to note that this list is by no means a complete list in any form. \subsection{Alternatives to docker networks} While it is common to expose specific ports for services---such as 3000 for NODE.js and thus Gitea, or variations on 8080 (8081, 8090, \textellipsis) for HTTP services---this approach is prone to cause port collisions. To avoid this, it is common to use a docker network \cite{a2024_networking} instead, especially as docker compose already defines the name of each service as its hostname. As docker networks are also a common security measure \cite{yasrab_2018_mitigating}, using hostnames not only improves convenience---both, in terms of setup and usage---but also security---thus testing configurations without using docker networks would not provide any meaningful results. \subsection{Hardening of services} The security of both services in the tested setup can be further improved by implementing the suggested hardening measures according to their documentations \cite{}\cite{}---some of which are implemented for other tests---testing security of the services in itself would however go past the scope of this thesis, as the selected services are merely a representation of a possible scenario. \subsection{} % Hier können Sie Ihre KI-Tools dokumentieren. Diese werden automatisch in eine Tabelle integriert. \aitoolentry{My Brain}{Writing the thesis}{``Please write a thesis about [\textellipsis]'' Entire Document} % % Hier beginnen die Verzeichnisse % \clearpage \printbibliography \clearpage % Das Abbildungsverzeichnis \listoffigures \clearpage % Das Tabellenverzeichnis \listoftables \clearpage % Das Verzeichnis über die verwendeten KI-Tools \listaitools \clearpage \phantomsection \addcontentsline{toc}{chapter}{\listacroname} \chapter*{\listacroname} \begin{acronym}[XXXXX] \acro{VM}[VM]{virtual machine} \acro{OS}[OS]{Operating System} \acro{HTTP}[HTTP]{Hypertext Transfer Protocol} \acro{HTTPS}[HTTPS]{Hypertext Transfer Protocol Secure} \acro{SSH}[SSH]{Secure Shell} \acro{TLS}[TLS]{Transport Layer Security} \acro{SSL}[SSL]{Secure Sockets Layer} \acro{CI}[CI]{continuous integration} \end{acronym} % % Hier beginnt der Anhang. % \clearpage \appendix %\chapter{Mermaid Source Code}\label{appendix_mermaid} %\clearpage \chapter{Source Code}\label{appendix_config} \section{Base Configuration}\label{appendix_base_config} \begin{code} \captionof{listing}{Vagrantfile} \label{code:Vagrantfile} \begin{minted}{ruby} Vagrant.configure("2") do |config| BOX_NAME = "ubuntu/jammy64" BOX_VERSION = "20241002.0.0" DESKTOP_BOX_NAME = "kalilinux/rolling" DESKTOP_BOX_VERSION = "2025.1.0" config.vm.define "sandbox" do |sandbox| sandbox.vm.box = BOX_NAME sandbox.vm.box_version = BOX_VERSION sandbox.vm.hostname = "sandbox.vm" sandbox.vm.network "private_network", ip: "192.168.56.10" sandbox.vm.provider "virtualbox" do |v| v.memory = 2048 v.cpus = 2 end sandbox.vm.synced_folder ".", "/vagrant" sandbox.vm.provision "ansible_local" do |ansible| ansible.playbook = "/vagrant/sandbox/playbook.yml" end end config.vm.define "client" do |client| client.vm.box = DESKTOP_BOX_NAME client.vm.box_version = DESKTOP_BOX_VERSION client.vm.hostname = "client.vm" client.vm.network "private_network", ip: "192.168.56.20" client.vm.provider "virtualbox" do |v| v.memory = 4096 v.cpus = 2 end client.vm.synced_folder ".", "/vagrant" client.vm.provision "ansible_local" do |ansible| ansible.playbook = "/vagrant/client/playbook.yml" end end end \end{minted} \end{code} \begin{code} \captionof{listing}{sandbox/docker-compose.yml} \label{code:sandbox:docker} \begin{minted}{yaml} services: vaultwarden: image: vaultwarden/server:latest container_name: vaultwarden restart: unless-stopped networks: - internal environment: DOMAIN: "https://bitwarden.vm.local" DATABASE_URL: "postgres://vaultwarden:vaultwarden@vaultwarden-db/vaultwarden" volumes: - ./vw-data/:/data/ expose: - 80 vaultwarden-db: image: docker.io/library/postgres:latest container_name: vaultwarden-db restart: unless-stopped environment: POSTGRES_DB: vaultwarden POSTGRES_USER: vaultwarden POSTGRES_PASSWORD: vaultwarden volumes: - ./vw-postgres:/var/lib/postgresql/data networks: - internal gitea: image: docker.gitea.com/gitea:latest container_name: gitea environment: - USER_UID=1000 - USER_GID=1000 - GITEA__database__DB_TYPE=postgres - GITEA__database__HOST=gitea-db:5432 - GITEA__database__NAME=gitea - GITEA__database__USER=gitea - GITEA__database__PASSWD=gitea - GITEA__security__INSTALL_LOCK=true restart: unless-stopped networks: - internal volumes: - ./gitea:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro expose: - 3000 - 22 gitea-db: image: docker.io/library/postgres:latest container_name: gitea-db restart: unless-stopped environment: - POSTGRES_USER=gitea - POSTGRES_PASSWORD=gitea - POSTGRES_DB=gitea volumes: - ./postgres:/var/lib/postgresql/data networks: - internal nginx: image: nginx:latest container_name: nginx restart: unless-stopped networks: - internal volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf - ./nginx/certs:/etc/nginx/certs ports: - 80:80 - 443:443 networks: internal: driver: bridge \end{minted} \end{code} \begin{code} \captionof{listing}{sandbox/playbook.yml} \label{code:sandbox:ansible} \begin{minted}{yaml} --- - hosts: all become: true vars: container_count: 1 default_container_name: docker default_container_image: hello-world default_container_command: sleep 1 tasks: - name: Install required system packages apt: pkg: - apt-transport-https - ca-certificates - curl - software-properties-common - virtualenv state: latest update_cache: true - name: Copy nginx conf copy: src: /vagrant/sandbox/nginx.conf dest: /home/vagrant/nginx.conf - name: Copy docker compose copy: src: /vagrant/sandbox/docker-compose.yml dest: /home/vagrant/docker-compose.yml - name: Ensure certs directory exists file: path: /home/vagrant/nginx/certs state: directory mode: '0755' - name: Install mkcert dependencies apt: pkg: - libnss3-tools - ca-certificates state: present update_cache: yes - name: Download mkcert binary get_url: url: https://github.com/FiloSottile/mkcert/releases/latest/download/mkcert-v1.4.4-linux-amd64 dest: /usr/local/bin/mkcert mode: '0755' register: mkcert_download - name: Ensure mkcert CAROOT directory exists file: path: /home/vagrant/.local/share/mkcert state: directory mode: '0755' - name: Initialize mkcert CA command: mkcert -install environment: XDG_DATA_HOME: /home/vagrant/.local/share CAROOT: /home/vagrant/.local/share/mkcert args: creates: /home/vagrant/.local/share/mkcert/rootCA.pem - name: Generate cert for gitea.vm.local command: > mkcert -cert-file /home/vagrant/nginx/certs/gitea.vm.local.pem -key-file /home/vagrant/nginx/certs/gitea.vm.local-key.pem gitea.vm.local args: creates: /home/vagrant/nginx/certs/gitea.vm.local.pem - name: Generate cert for bitwarden.vm.local command: > mkcert -cert-file /home/vagrant/nginx/certs/bitwarden.vm.local.pem -key-file /home/vagrant/nginx/certs/bitwarden.vm.local-key.pem bitwarden.vm.local args: creates: /home/vagrant/nginx/certs/bitwarden.vm.local.pem - name: Ensure export directory exists file: path: /vagrant/shared/ca state: directory mode: '0755' - name: Copy mkcert rootCA.pem to shared directory copy: src: /home/vagrant/.local/share/mkcert/rootCA.pem dest: /vagrant/shared/ca/rootCA.pem remote_src: yes - name: Add Docker GPG apt Key apt_key: url: https://download.docker.com/linux/ubuntu/gpg state: present - name: Add Docker Repository apt_repository: repo: deb https://download.docker.com/linux/ubuntu focal stable state: present - name: Update apt and install docker-ce apt: pkg: - docker-ce - docker-compose-plugin state: latest update_cache: true - name: Add 'vagrant' and 'git' users to docker group user: name: "{{ item }}" groups: docker append: yes loop: - vagrant - git - name: Create git user user: name: git shell: /home/git/docker-shell home: /home/git create_home: yes - name: Deploy docker passthrough shell copy: dest: /home/git/docker-shell content: | #!/bin/sh exec /usr/bin/docker exec -i -u git --env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitea sh "$@" mode: '0755' - name: Update SSH config for git user blockinfile: path: /etc/ssh/sshd_config block: | Match User git AuthorizedKeysCommandUser git AuthorizedKeysCommand /usr/bin/docker exec -i -u git gitea /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k - name: Restart SSH service: name: ssh state: restarted - name: Ensure Docker service is running service: name: docker state: started enabled: true - name: Run docker compose up -d command: docker compose up -d args: chdir: /home/vagrant \end{minted} \end{code} \begin{code} \captionof{listing}{sandbox/nginx.conf} \label{code:sandbox:nginx} \begin{minted}{text} server { listen 443 ssl; server_name gitea.vm.local; ssl_certificate /etc/nginx/certs/gitea.vm.local.pem; ssl_certificate_key /etc/nginx/certs/gitea.vm.local-key.pem; location / { proxy_pass http://gitea:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } server { listen 443 ssl; server_name bitwarden.vm.local; ssl_certificate /etc/nginx/certs/bitwarden.vm.local.pem; ssl_certificate_key /etc/nginx/certs/bitwarden.vm.local-key.pem; location / { proxy_pass http://vaultwarden:80; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } server { listen 80; server_name _; return 301 https://$host$request_uri; } \end{minted} \end{code} \begin{code} \captionof{listing}{client/playbook.yml} \label{code:client:ansible} \begin{minted}{yaml} --- - hosts: all become: true vars: container_count: 1 default_container_name: docker default_container_image: hello-world default_container_command: sleep 1 tasks: # - name: Add Metasploit PPA # apt_repository: # repo: ppa:metasploit-official # state: present # update_cache: yes - name: Install tools apt: pkg: # - metasploit-framework - curl - nmap - libnss3-tools state: present update_cache: yes - name: Add sandbox hostnames to /etc/hosts lineinfile: path: /etc/hosts line: "192.168.56.10 gitea.vm.local bitwarden.vm.local" state: present \end{minted} \end{code} \clearpage \section{Configuration Modifications}\label{appendix_patches} \clearpage \chapter{Test Results}\label{appendix_results} \section{Command Outputs}\label{appendix_logs} \end{document}