%
% Chapter: Technische Umsetzung
%

\chapter{Technische Umsetzung}
\section{Berechtigungsverwaltung}
\subsection{Ausarbeitung der Herangehensweise}
Zunächst wurde gebrainstormed, welche Herangehensweisen hier möglich sind.
Ein Artefakt des Brainstormings ist eine Mind-Map, die unter \fullref{app:ideensammlung} zu finden ist.

\subsubsection{Ansatz 1}
Der aus dieser Mindmap, nach individueller Meinung des Autors, vielversprechenste Ansatz ist es,
die \ac{1P}-Restful-API zu verwenden.
Bei diesem Ansatz würden Administratoren*innen und Entwicklern*innen API-Keys für \ac{1P} erhalten.
Entwickler*innen hätten mit ihren Keys bestimmte Leseberechtigungen $r$ und Administratoren*innen
die Berechtigung $r$ zu verändern.

\begin{nicepic}
    \includegraphics[width=0.75\textwidth]{images/dev-stuff-via-api-keys.png}
    \captionof{figure}{Relationsdiagramm: Ansatz 1 | 1Password-API}
    \caption*{Quelle: Eigene Darstellung}
    \label{fig:ansatz-1-mit-api-keys}
\end{nicepic}

Dieser Ansatz wurde zeitnah als unumsetzbar erkannt und verworfen, da \ac{1P} das nachträgliche Verändern
von API-Key-Berechtigungen nicht erlaubt.

\subsubsection{Ansatz 2}
Der nächste Lösungsansatz befasst sich mit einer Abstraktionsebene: Der \ac{MASA}.
Hier ist die grundlegende Idee, dass es eine serverseitige Anwendung gibt, die sich \ac{MASA} nennt.
Diese Anwendung übernimmt die Aufgabe anhand eines hinterlegten \ac{1P}-API-Keys Secrets
aus dem \ac{1P}-Vault des Partnerunternehmens abzufragen und an Entwickler*innen weiterzureichen.
Die \ac{MASA} provisioniert eigene API-Keys an Entwickler*innen und vermerkt serverseitig,
welcher API-Key berechtigt ist, welche \ac{1P}-Einträge abzufragen.
Der API-Key könnte grundlegende Informationen wie zum Beispiel Entwickler*innennamen und Ablaufzeitpunkte des
Keys einbetten. Dieser Ansatz trägt viel Sicherheitsverantwortung, da eine mögliche Ausnutzung einer
Sicherheitslücke der \ac{MASA} direkt in den Firmen-Passwortmanager führen würden.
Um diesem Risikofaktor entgegenzuwirken würde der \ac{1P}-Key der \ac{MASA} verschlüsselt werden und die
\ac{MASA} würde nur einen Teil des Entschlüsselungs-Keys vorrätig halten. Der andere Teil wäre in jedem Entwickler*innen-Key
eingebettet. Dadurch wäre gewährleistet, dass ein*e Angreifer*in, selbst bei sehr weitreichendem Zugriff
in die \ac{MASA}, nicht auf das Innere des Passwortmanagers zugreifen könne, da die \ac{MASA} dazu selbstständig
gar nicht im Stande wäre. Da Entwickler*innen lediglich ein Schlüsselfragment des Verschlüsselungs-Schlüssels
in ihrem Key eingebettet hätten, der einen serverseitigen Schlüssel der \ac{MASA} zum Auslesen benötigt,
bestünde auch keine Gefahr, dass ein*e Entwickler*in anhand seines bzw. ihres Keys ungeschützten Zugang zum Passwortmanager
erhalten würde. Dieser Ansatz erlaubt weitreichende Flexibilität, da sämtliche Logik, die sich mit Berechtigungen
beschäftigt, anwendungsfallspezifisch geplant und umgesetzt wäre.

\begin{nicepic}
    \includegraphics[width=0.75\textwidth]{images/masa-diagram.png}
    \captionof{figure}{Relationsdiagramm: Ansatz 2 | MASA}
    \caption*{Quelle: Eigene Darstellung}
    \label{fig:ansatz-2-mit-masa}
\end{nicepic}


\clearpage
Letztendlich entschied sich der Stakeholder gegen die Umsetzung der \ac{MASA}, da dieser Ansatz als zu
aufwändig betrachtet wird und für den durch sie erbrachten Vorteil zu viel Aufwand und Angriffsfläche schaffen würde.

\subsubsection{Ansatz 3}
Der letzte Lösungsansatz befasst sich mit dem Erstellen dedizierter Vaults für jede*n Entwickler*in $d$.
Hierbei existiert eine Python-Toolbox, die anhand einer Yaml-Datei Referenzen auf diese Passwort-Einträge
in $\text{Vault}_d$ legt und von dort entfernt, wenn ein solcher Zugriff laut der Yaml-Datei nicht mehr vorgesehen ist.
Diese Einträge können über feste Eintrags-IDs und über Regex bezogen auf die Eingrags-Titel einem/r Entwickler*in vorgesehen werden.

\begin{nicepic}
    \includegraphics[width=0.75\textwidth]{images/dev-stuff-python.png}
    \captionof{figure}{Relationsdiagramm: Ansatz 3 | Python-Toolbox}
    \caption*{Quelle: Eigene Darstellung}
    \label{fig:ansatz-3-mit-python}
\end{nicepic}

Nach Betrachtung der diversen Ansätze entschied sich der Stakeholder für Ansatz 3, da er ihm kostengünstig und aursreichend erschien.

\subsection{Kodierung}
Um den vom Stakeholder ausgewählten Ansatz 3 wie geplant umzusetzen, wurden zunächst
die Dokumentationen diverser \ac{1P}-Schnittstellen konsultiert. Schnell offenbarte sich eine Alternative
zu API-Keys: Die \ac{1P}-Desktop-Anwendung stellt eine CLI-API bereit.
Die CLI-API der Desktop-Anwendung zu verwenden, würde drei Probleme lösen:
\begin{description}
    \item [Kosten und hedonische Qualität] \hfill \\
        Einen API-Key zu erstellen, zu übermitteln und als Nutzer zu verorten ist kostspielig und umständlich.
        Ein \ac{1P}-Konto haben dem gegenüber viele externe Partner*innen des Partnerunternehmens bereits.
    \item [Authentifizierung und Sicherheit] \hfill \\
        Anstatt einen API-Key unsicher zu speichern und in relevante Programme (=Ansible) zu laden, wird die Authentifizierung zu \ac{1P} ausgelagert.
    \item [Manuelle Einsicht] \hfill \\
        Da über die CLI-Methode der Zugriff auf die Entwickler*innen-Vaults direkt über die \ac{1P}-Desktop-App geschieht, kann diese den Vault-Inhalt auch dem Nutzer in ihrem GUI offenbaren.
    \item [Integrationsaufwand] \hfill \\
        Die Verwendung der \ac{1P}-Restful-API erscheint dem Autor nach ihrer Dokumentation sehr aufwändig und kompliziert. Eine CLI-API zu verwenden würde somit in der Umsetzung Projektressourcen sparen.
\end{description}

So begründet fällt die Wahl der Schnittstelle zu \ac{1P} auf ihre CLI-API.
Um schnelle Softwareentwicklung mit minimalem Overhead zu gewährleisten und um für eine spätere Einbindung in Ansible
bereits in Vorleistung zu treten, fällt die Wahl der Programmiersprache auf Python. Ansible-Module können mit Python geschrieben werden. \cite{bib:ansible-docs-python-module}
Es wurde eine rudimentäre Architektur entworfen, die beschreibt, welche Komponente des Werkzeuges aus welchen kleineren Komponenten besteht.
Am unteren Ende dieses Aggregatbaumes stehen atomare Operationen. Im Kontext dieses Werkzeuges sind atomare Operationen Operationen,
die vom \ac{1P}-CLI ausgeführt werden. Diese Operationen implementiert also \ac{1P} selbst.
Hierbei handelt es sich nur um Lese, Erstell- und Löschvorgänge. Das Erfassen, auf welchen Eintrag welche*r Entwickler*in Zugriff hat,
und auf welche nicht, übernimmt \textit{sync-dev-vault.py}. Die Funktionen der anderen Skripte ergeben sich in Gänze aus ihren Dateinamen.

\begin{nicepic}
    \includegraphics[width=1\textwidth]{images/config-file.png}
    \captionof{figure}{Struktur der Zugriffs-config.yml}
    \caption*{Quelle: Eigene Darstellung}
    \label{fig:config-file}
\end{nicepic}

\begin{nicepic}
    \includegraphics[width=0.75\textwidth]{images/program-structure.png}
    \captionof{figure}{Diagramm: Programmstruktur Secret-Synchronizer}
    \caption*{Quelle: Eigene Darstellung}
    \label{fig:programmstruktur-secret-synchronizer}
\end{nicepic}

Die Funktionsweise des Programmes ist wie folgt:
\begin{enumerate}
    \item{Wende die Schritte $2..n$ auf alle zu synchronisierenden Entwickler*innen $d \in D$ an.}
    \item{Lösche alle Einträge $e_d \in d$.}
    \item{Kopiere alle vorgesehenen Einträge $e_m \in \text{Master-Vault}$ nach $d$ und ergänze das Feld \enquote{Originale Eintrags-ID} mit dem \ac{UUID} von $e_m$.}
    \item{Erstelle ein ID-Mapping-Objekt von $e_d$ zu $e_m$ in $d$.}
\end{enumerate}


\subsubsection{Performanzprobleme und Optimierung}
Eine Schwierigkeit, die sich im Rahmen der Umsetzung offenbarte, ist, dass das \ac{1P}-CLI sehr langsam ist.
Soll die Liste aller Einträge eines Vaults ausgelesen werden, dauert das nach Erfahrungen des Autors etwa eine Sekunde, da es sich hierbei um \emph{eine} Anfrage handelt.
Diese Listenansicht zeigt jedoch nur begrenzte Informationen der Einträge.
Soll ein bestimmtes Feld eines Eintrages (z.B. \enquote{Originale Eintrags-ID}) in Erfahrug gebracht werden, müssen alle Informationen \textit{eines} Eintrages
abgefragt werden. Hier ist \textit{ein} CLI-API-Aufruf pro Eintrag erforderlich. Sind einem*r Entwickler*in z.B. 30 Einträge zugeordnet, so dauert das Finden eines Eintrages
mit einer bestimmten originalen ID im Durchschnitt $n=30; \frac{n}{2} = 15$ Sekunden. Im langsamsten Fall wären es $n=30$ Sekunden.
Ein Kopiervorgang stellt zwei Aufrufe dar (=\textit{lesen,erstellen}), also dauert das Kopieren von 30 Einträgen $n=30; 2n = 60$ Sekunden.
Das \ac{1P}-CLI kann zwar für Detail-Aufrufe mehrere Eintrags-IDs auf Standard-Input annehmen und bearbeiten, jedoch zeigen Versuche des Autors, dass das nicht die benötigte Zeit pro Eintrag beeinflusst. Das heißt, eine Anfrage für zehn Einträge zu stellen, dauert in etwa zehn mal so lange,
wie zehn Anfragen für jeweils einen Eintrag zu stellen.
\\
\\
In der naiven Herangehensweise, um einen Eintrag einer bestimmten originalen \ac{UUID} zu finden,
wird jeder Eintrag auf dessen originale \ac{UUID} geprüft, bis der passende Eintrag gefunden wurde.
Dieser Lösungsweg hat für \emph{einen} Eintrag eine Zeitkomplexität von $O(n)$.
Eine spätere Ergänzung, um die programmatische Auslesung \emph{eines} Eintrages einer bestimmten originalen \ac{UUID} in $O(1)$ anstatt $O(n)$ zu gewährleisten,
ist die Unterhaltung von Mapping-Objekten in Entwickler*innen-Vaults.
Je Entwickler*innen-Vault wird abschließend zur Synchronisierung ein Mapping-Objekt erstellt.
Diese Mapping-Objekte halten die Informationen vorrätig, welche öffentliche \ac{1P}-\ac{UUID} zu welcher privaten \ac{1P}-\ac{UUID} gehört.
Mit diesen Mapping-Objekten kann ein beliebiger Eintrag anhand einer öffentlichen \ac{UUID}
binnen zwei Anfragen erfasst werden: Anfragen des Mapping-Objektes und Anfragen des privaten Objektes.
Das entspricht einer Zeitkomplexität von $O(2) = O(1)$.
Desweiteren kann \ac{1P} Eintragsdaten lokal zwischenspeichern.
Diese Option lässt sich mit dem Flag \textit{--cache} auf Leseoperationen anwenden
und beschleunigt das Auslesen der angefragten Informationen, soweit diese im Cache existieren.
Auf Unix-ähnlichen Betriebssystemen ist dieses Verhalten
standardmäßig aktiviert. \cite{bib:1password-cli-caching}

\subsubsection{Sicherheitsbedenken}
Die Konfigurationsdatei definiert Entwickler*innen-Vaults, über ihre \acp{UUID}. In diesen IDs sieht ein*e Administrator*in keine Vaultnamen. Diese sind nicht sprechend.
Wenn nun aus etwaigen Gründen dort die \ac{UUID} eines Nutzvaults des Partnerunternehmems aufgeführt wäre, würde das
Werkzeug alle sich dort befindlichen Zugänge löschen. Das wäre ein Super-GAU in Form von Datenverlust.

\subsubsection{Sicherheitsvorkehrungen}
Um das zu verhindern, wurde eine Liste mit wichtigen Vault-IDs fest einkodiert. 
Alle Erstell- oder Löschmethoden müssen einen Vault-ID-Parameter erhalten, selbst wenn dieser technisch nicht notwendig ist.
Wenn diese Vault-ID nun in der Liste der fest kodierten Nutzvault-IDs vorkommt, meldet die Methode einen deskriptiven Fehler und beendet die Programmausführung.
Somit ist gewährleistet, dass selbst bei einer fatalen Fehlkonfiguration kein Datenverlust entseht.

\section{Integration in Ansible}
Eine Anfordergung beschreibt, dass \ac{1P}-Einträge von Entwicklern*innen innerhalb von Ansible-Playbooks
dereferenziert und verwendet werden können.

\ac{1P} unterstützt nativ das Ersetzen von \ac{1P}-Referenzen in Dateien durch Secrets.
Diese Technik nennt sich \enquote{\ac{1PSA}}.
Diese Technologie ist jedoch nicht für die hier vorliegende Aufgabenstellung verwertbar, da die dem zugrunde liegende
Berechtigungsverwaltung auf Vault-Basis steht. Entweder hat ein*e Entwickler*in Zugriff auf einen gesamten Vault, oder er*sie hat keinen Zugriff auf den gesamten Vault.
Eine feinere Steuerung ist hier nicht möglich, jedoch für die hier gegebenen Anforderungen nötig. \cite{bib:1password-secrets-automation}
\ac{1PSA} erfasst \acp{UUID} und ist daher mit dem Konzept von Entwickler*innen-Vaults inkompatibel, da
Entwickler*innen hierbei eigene Kopien der originalen Einträge führen, die jeweils eigene \acp{UUID} haben.
Externe Entwickler*innen haben somit keinen Zugriff auf die originalen, öffentlichen \acp{UUID} und die privaten \acp{UUID}, die im Entwickler*innen-Vault
vorhanden sind, gelten jeweils nur für eine*n Entwickler*in. Das erfordert eine maßgeschneiderte, programmatische Lösung:

\begin{nicepic}
    \includegraphics[width=0.75\textwidth]{images/docker-ansible-structure.png}
    \captionof{figure}{Relationsdiagramm: Docker-Ansible-Struktur, um \ac{1P}-Einträge zu dereferenzieren}
    \caption*{Quelle: Eigene Darstellung}
    \label{fig:docker-ansible-structure}
\end{nicepic}

Die hierfür angedachte Architektur erfordert, dass öffentliche \acp{UUID} in Host-Konfigurationen in Docker-Ansible aufgeführt sind.
Also eine UUID, die für alle Entwickler*innen greifbar ist.

Ab hier wird die Nutzergruppe \enquote{Entwickler*innen} in zwei Untergruppen strukturiert:
\begin{description}
    \item [Interne Entwickler*innen] \hfill \\
        Interne, festangestellte Entwickler*innen haben Vollzugriff auf den \ac{1P} und somit auch Zugriff auf die
        in den Host-Konfigurationen vermerkte, öffentliche \ac{UUID} eines Eintrages.
        Da diese Entwickler*innen keinen Entwickler*innen-Vault haben, müssen sie direkt auf diese notierte, öffentliche \ac{UUID} zugreifen.
\end{description}
\clearpage
\begin{description}
    \item [Externe Entwickler*innen] \hfill \\
        Externe Entwickler*innen verfügen über einen Entwickler*innen-Vault, nicht jedoch über direkten Zugriff auf die vermerkte, öffentliche \ac{UUID}.
        Falls der*die jeweilige Entwickler*in Zugriff auf einen verlinkten Eintrag hat, dann nur auf eine Kopie des Eintrages in dessen*deren jeweiligen Entwickler*innen-Vault.
        Diese Kopie hat eine andere \ac{UUID} als die, die in der Host-Konfiguration steht. Sie ist ja auf technischer Ebene ein anderer Eintrag, nur mit identischem Inhalt.
        Die in den Host-Konfigurationen vermerkten, öffentlichen \acp{UUID} müssen also zunächst in eine private, sich im Entwickler*innen-Vault befindliche, \ac{UUID} übersetzt werden.
\end{description}

Um diese Problemstellung anzugehen, wird ein Ansible Filtermodul entworfen.
Ein Filtermodul dient als
Texttransformator und kann in Ansible verwendet werden.
\\
\\
\texttt{\{\{\ \enquote{hello world} | uppercase \}\}}.\\
\cite{bib:ansible-filter-plugins}
\\
\\
Dieses Beispiel führt das \enquote{uppercase}-Filtermodul an.
Ein Beispiel mit dem im Rahmen dieser Ausarbeitung bereitgestellten Filtermodul würde so aussehen:
\\
\\
\texttt{\{\{ smtp.password | resolve\_1p\_secret \}\}}.

\begin{nicepic}
    \includegraphics[width=1\textwidth]{images/flowchart-resolve-1p-secret.png}
    \captionof{figure}{Flussdiagramm: Businesslogik des 1P-Resolver-Filtermoduls}
    \caption*{Quelle: Eigene Darstellung}
    \label{fig:flowchart-filtermodule-resolve-1p-secret}
\end{nicepic}

\subsection{Akzeptierte Formate}
Das Filtermodul akzeptiert mehrere, verschiedene Eingabeformate und ist rückwärtskompatibil.

\subsubsection*{Kein erkanntes Format}
Wird kein bekanntes Format erkannt, wird der Wert unverändert zurückgegeben. Das ermöglicht Rückwärtskompatibilät,
sodass nach-wie-vor hardgecodede Secrets funktionieren, und nicht versehentlich als \ac{UUID} interpretiert werden.
Das gewährleistet eine flüssigere Migration der Host-Konfigurationen, da somit bestehende Dateien weiterhin valide sind.

\subsubsection*{1P:<...>}
Beginnt der Wert mit \enquote{1P:}, so wird alles Nachfolgende als \ac{UUID} interpretiert.
Es wird versucht, das Feld \enquote{password} aus diesem Eintrag zu dereferenzieren.

\subsubsection*{Objektformat}
Wird ein Yaml-Objekt übergeben, so werden die Keys \enquote{1P\_secret\_uuid} und \enquote{1P\_field\_id} erwartet.
Diese definieren die Werte der Eintrags-\ac{UUID} und der Feld-ID in der ein Secret steht. Das ermöglicht z.B. auch den Benutzernamen (\textit{1P\_field\_id: username}) eines
Eintrages abzufragen, anstelle nur des Passworts. Ist keine Feld-ID gegeben, so wird auf das Standardfeld \enquote{password} zurückgefallen.


\subsection{Übersetzung der UUIDs}
Um die private \ac{UUID} zu ermitteln, die zu der öffentlichen \ac{UUID} gehört, die in der Host-Konfiguration steht,
frägt das Filtermodul den Mapping-Eintrag aus dem jeweiligen Entwickler*innen-Vault an und schlägt die öffentliche \ac{UUID} darin nach.
Die daraus resultierende \ac{UUID} kann von einem*r externen Entwickler*in angefragt werden.

\subsection{Unterscheidung zwischen internen und externen Entwickler*innen}
Ist in der Docker-Ansible-Konfigurationsdatei eine Entwickler*innen-Vault-\ac{UUID} definiert, so wird von einem*r externe*n Entwickler*in ausgegangen.
Ist stattdessen definiert, dass die in den Host-Konfigurationen angegebenen, öffentlichen \acp{UUID} direkt angefragt werden sollen, wird
von einem*r interne*n Entwickler*in ausgegangen. Sind beide Konfigurationen zugleich gegeben, wird ein Inkompatibilitätsfehler erhoben.
Ist ein*e interne*r Entwickler*in angenommen, so wird der Mapping-Schritt übersprungen. Der verbleibende Prozess bleibt unberührt.

\subsection{Kommunikation mit 1Password}
Ist eine \ac{UUID} ermittelt, auf die der*ie Nutzer*in Zugriff hat, wird diese über das \ac{1P}-CLI angefragt.
Dieser Aufruf ist: \textit{op item get <UUID>} mit dem Zusatz \textit{--format json}, um die Ausgabe programmatisch auswerten zu können.

\subsection{Performanz und Benchmarks}
Um diese Konfiguration zu testen, werden in einem Testszenario fünf Werte aus \ac{1P} ausgelesen:
\begin{itemize}
    \item Datenbank-Host
    \item Datenbank-Port
    \item Datenbank-Benutzername
    \item Datenbank-Passwort
    \item Datenbank-Name
\end{itemize}
Diese Einträge abzufragen dauert durch das imperformante \ac{1P}-CLI rund 17 Sekunden.

\subsection{Optimierung}
Es bieten sich zwei Möglichkeiten an, den in \fullref{fig:flowchart-filtermodule-resolve-1p-secret} abgebildeten Prozess zu beschleunigen.
Diese beschäftigen sich damit, zu limitieren, wie oft das \ac{1P}-CLI angefragt wird:

\begin{description}
    \item [Das Mapping-Objekt zwischenspeichern] \hfill \\
        Anstatt das Mapping-Objekt für jedes angefragte Secret erneut abzufragen, könnte es zwischengespeichert werden.
    \item [Ganze Einträge zwischenspeichern] \hfill \\
        Für den Fall, dass ein Eintrag mehrach angefragt wird, könnte ein einmal angefragter Eintrag zwischengespeichert werden.
        Würden mehrere Felder eines Eintrages angefragt werden (z.B. \textit{=Host, Port, Benutzername, Passwort, Name}), so müsste der gesamte Eintrag nur ein mal angefragt werden.
\end{description}

All diese Ansätze erfordern es Daten zwischenzuspeichern. Filtermodule haben allerdings keinen persistenten Arbeitsspeicher über verschiedene Aufrufe hinaus.
E.g. nach jedem angefragten Secret, verliert er seinen internen Zustand.
Daher muss dieses zwischengespeichert in einer Datei stattfinden. Hierfür wird eine Tempdatei über Pythons \textit{tempfile.gettempdir()}-Funktion ermittelt.
Diese Zwischenspeicher beinhalten die vom \ac{1P}-CLI zurückgegebenen Informationen.

\begin{nicepic}
    \includegraphics[width=1\textwidth]{images/flowchart-resolve-1p-secret-with-caching.png}
    \captionof{figure}{Flussdiagramm: Businesslogik des 1P-Resolver-Filtermoduls, mit Zwischenspeicher}
    \caption*{Quelle: Eigene Darstellung}
    \label{fig:flowchart-filtermodule-resolve-1p-secret-with-caching}
\end{nicepic}

\subsubsection{Mapping-Zwischenspeicher}
Wenn das Mapping-Objekt angefragt wird, so wird zunächst geprüft, ob es eine lokal zwischengespeicherte Version gibt.
Falls ja, wird diese geladen und verwendet.
Falls nein, wird es via dem \ac{1P}-CLI angefragt und lokal gespeichert.
Sollte der Mapping-Zwischenspeicher verwendet werden und das gesuchte Objekt nicht darin gefunden werden, so wird dieser Zwischenspeicher gelöscht und das Mapping-Objekt erneut angefragt.
Das deckt folgenden Problemfall ab:

\begin{enumerate}
    \item Zwischenspeicher wird erstellt
    \item Entwickler*in erhält mehr Berechtigungen
    \item Entwickler*in will diese Berechtungen nutzen
    \item Der Zwischenspeicher wird verwendet, spiegelt diese neuen Berechtigungen aber nicht wider
    \item Der Prozess schlägt zu Unrecht fehl
\end{enumerate}

Dieser Prozess würde durch diese Vorkehrung so aussehen:
\begin{enumerate}
    \item Zwischenspeicher wird erstellt
    \item Entwickler*in erhält mehr Berechtigungen
    \item Entwickler*in will diese Berechtungen nutzen
    \item Der Zwischenspeicher wird verwendet, spiegelt diese neuen Berechtigungen aber nicht wider
    \item Das System erneuert den Zwischenspeicher
    \item Der Zwischenspeicher spiegelt nun die neuen Berechtiungen wider
    \item Der Prozess ist erfolgreich
\end{enumerate}

Durch die Implementation des Mapping-Zwischenspeichers, wird die Ausführzeit von 17 Sekunden auf acht Sekunden reduziert.

\subsubsection{Eintrags-Zwischenspeicher}
Wird ein Eintrag von \ac{1P} angefragt, so soll das Filtermodul diessen lokal zwischengespeichern.
Das stellt ein Problem dar, sobald der Eintrag
im Entwickler*innen-Vault manuell verändert wird. Das ist jedoch nicht angedacht.
Die Entwickler*innen sollten keine Schreibberechtigung auf ihren Vault haben.
Werden originale Einträge verändert, werden die Referenzeinträge vom Synchronisierungswerkzeug gelöscht
und neu erstellt. Damit erhalten diese eine neue \ac{UUID} und sind somit im Zwischenspeicher nicht mehr repräsentiert.
Durch das Implementieren des Eintrags-Zwischenspeichers wird die Ausführzeit von acht Sekunden auf zwei Sekunden reduziert.

\begin{table}[!htbp] % !htbp
    \centering
    \begin{tabular}{|l|l|r|}
        \hline
        \textbf{Aktiviertes Caching-Level}   &   \textbf{Ausführzeit (Sekunden)}\\
        \hline
        Ohne Cache                  & 17\\
        \hline
        UUID-Mapping-Cache          &  8\\
        \hline
        Mapping+Item-Cache          &  2\\
        \hline
    \end{tabular}
    \caption{Ausführzeiten des Test-Playbooks mit Testdaten (Fünf Secrets aus einem 1P-Eintrag)}
    \label{tbl:ausführzeiten-versch-caches}
\end{table}

\subsubsection{Sicherheit}
Um zu vermeiden, dass sensible Daten, wie zum Beispiel die Secrets in den Eintrags-Daten des Passwortmanagers im Klartext im Zwischenspeicher, für viele Prozesse lesbar, gespeichert werden,
werden diese in der Schreib- und Lesefunktion mit AES-256 verschlüsselt.
Die Wahl fällt auf AES-256, weil es keine bekannten Angriffe gegen AES-256 gibt, die wesentlich effektiver sind als generische Angriffe gegen Blockchiffren. \cite{bib:BSI-TR-02102-1-2024}
