\begin{tikzpicture}[ font=\footnotesize, >={Stealth[length=2mm]}, box/.style={draw, rounded corners=2pt, align=center, fill=white, inner sep=3pt}, ctr/.style={box, fill=devopsLightBlue, text width=34mm}, vol/.style={box, fill=devopsGray!12, text width=36mm}, ext/.style={box, text width=30mm}, pub/.style={->, thick, devopsBlue}, priv/.style={->, thick, devopsGreen}, adm/.style={->, thick, devopsGray, dashed}, blk/.style={->, thick, devopsRed, densely dotted}, lbl/.style={font=\scriptsize, fill=white, inner sep=1pt} ] % External clients \node[ext] (browser) at (0, 2.55) {Browser / Git client (any source)}; \node[ext] (ip) at (0, 1.5) {Instructor browser\\\texttt{\scriptsize http://100.49.80.94}}; \node[ext] (admin) at (0,-0.8) {Team admin (approved /32 sources)}; \node[ext] (scan) at (0,-2.5) {Any other source}; % EC2 contents \node[vol] (cdata) at (6.6, 4.8) {\textbf{Volume} \texttt{\scriptsize inviscid\_caddy\_data}\\certificates, ACME account}; \node[ctr] (caddy) at (6.6, 2.15) {\textbf{Caddy} \texttt{\scriptsize caddy:2.10.2}\\TLS termination;\\only 80/443 publisher}; \node[ctr] (gitea) at (11.4, 3.0) {\textbf{Gitea} \texttt{\scriptsize 28.1.0}\\\texttt{\scriptsize gitea:3000}}; \node[ctr, text width=40mm] (buttons) at (11.4, 1.3) {\textbf{Color Buttons}\\\texttt{\scriptsize ssw590-group-buttons:3000}}; \node[vol] (gdata) at (16.0, 3.0) {\textbf{Volume} \texttt{\scriptsize inviscid\_gitea\_data}\\repositories, config,\\SQLite \texttt{\scriptsize gitea.db}}; \node[box, text width=34mm] (sshd) at (6.6,-0.8) {\textbf{sshd} (EC2 host), TCP 22}; \begin{scope}[on background layer] \node[draw=devopsGreen, dashed, rounded corners, fill=devopsGreen!5, inner sep=3mm, fit=(caddy)(gitea)(buttons), label={[font=\scriptsize, text=devopsGreen, anchor=north west, yshift=-1pt]south west:Docker network \texttt{inviscid\_services} (private)}] (net) {}; \node[draw=devopsBlue, thick, rounded corners, inner sep=4mm, fit=(net)(sshd)(gdata)(cdata), label={[font=\scriptsize\bfseries, text=devopsBlue]above:EC2 \texttt{ssw590-group-web} (\texttt{us-east-1}) --- Elastic IP 100.49.80.94, no IPv6}] (ec2) {}; \end{scope} % Security group wall \coordinate (sgTop) at (3.25, 5.9); \coordinate (sgBot) at (3.25,-3.0); \draw[line width=2pt, devopsRed] (sgTop) -- (sgBot); \node[font=\scriptsize, text=devopsRed, align=center, anchor=north, fill=white, inner sep=1pt] at ([yshift=-1mm]sgTop) {Security group\\\texttt{ssw590-web-sg}}; % Public flows (allowed by the security group) \draw[pub] (browser.east) -- node[lbl, above, pos=0.72]{443; 80$\to$308} (caddy.west |- browser.east); \draw[pub] (ip.east) -- node[lbl, above, pos=0.72]{80 HTTP} (caddy.west |- ip.east); % Private flows \draw[priv] (caddy.east |- gitea.west) -- node[lbl, above]{\texttt{\scriptsize git.inviscid.dev}} (gitea.west); \draw[priv] (caddy.east |- buttons.west) -- node[lbl, below, pos=0.4]{by IP} (buttons.west); \draw[priv] (caddy.north) -- (cdata.south); \draw[priv] ([yshift=2mm]gitea.east) -- ([yshift=2mm]gdata.west |- gitea.east); % Administrative path \draw[adm] (admin.east) -- node[lbl, above, pos=0.72]{22 SSH} (sshd.west); \draw[adm] (sshd.east) -- node[lbl, below]{SSH tunnel to \texttt{\scriptsize 127.0.0.1:3000}} (13.75,-0.8) |- ([yshift=-3mm]gitea.east); % Blocked \draw[blk] (scan.east) -- node[lbl, above, pos=0.62]{22, 3000, 222, 2019} ([xshift=-1.2mm]sgBot |- scan.east); \node[text=devopsRed, font=\large\bfseries] at (sgBot |- scan.east) {$\times$}; \end{tikzpicture}