\documentclass[11pt,a4paper]{article}
\usepackage[portuguese]{babel}
\usepackage[lining]{ebgaramond}
\usepackage{listings}
\usepackage{booktabs}

\usepackage{style}

\lstdefinestyle{mystyle}{
    basicstyle=\ttfamily\footnotesize,
    breakatwhitespace=false,         
    breaklines=true,                 
    captionpos=b,                    
    keepspaces=true,                 
    numbers=left,                    
    numbersep=5pt,                  
    showspaces=false,                
    showstringspaces=false,
    showtabs=false,                  
    tabsize=2
}

\lstset{style=mystyle}

\setlength{\parindent}{0em}
\setlength{\parskip}{2ex}

\title{Practical Assignment \#2}
\author{
    João Neto -- 2023234004\\[1em]
    Vasco Alves -- 2022228207
}

\begin{document}
\maketitle
\tableofcontents
\newpage

\section{Introdução}

Este projeto tem como âmbito implementar, uma rede virtual privada (VPN) num cenário
de road-warrior, configurar \textit{two-factor authentication} (2FA) com os serviços
OpenVPN e Apache, e gerir certificados X.509 utilizando OCSP.

% NOTE(vasco): Eu acho que basta explicar o cenario e explicar como decidimos 
% implementar 

% Para tal, foi implementado um servidor e um cliente OpenVPN, certificados por uma
% autoridade central (CA) que em si é \textit{self-signed}. Para além disto, foi implementado
% um sistema de autenticação de dois factores através do plugin
% \textit{google-authenticator} para o OpenVPN e para o servidor de Apache.

Decidimos utilizar apenas três máquinas virtuais: o cliente (ou \textit{road warrior}),
a \textit{gateway} que utiliza OpenVPN e um servidor interno com OpenSSL e Apache. 
Isto simplifica a elaboração do projecto, mas por razões de segurança poderia querer
separar a máquina de OpenSSL de outras máquinas destinadas a serviços da rede intera,
pois esta contém o \textit{certificate authority} CA. 

% Ambos o OpenVPN eo  servidor Apache utilizam 2FA,
% recebendo o utilizador, e uma password que é uma concatenação da palavra-passe do utilizador
% e de uma password temporária (TOTP) de 6 dígitos. O servidor de Apache implementa a mesma autenticação.

\begin{tabular}{l l l}

   {\bf Nome} & {\bf Script} & {\bf Rede} \\\toprule
   Road Warrior & VM\_ROAD\_WARRIOR.sh & Rede Externa 193.168.0.0/24 \\
   VPN Gateway & VM\_OPENVPN\_GATEWAY.sh & Router \\
   OpenSSL / Apache & VM\_OPENSSL\_APACHE.sh & Rede Interna 10.60.0.0/24 \\
\end{tabular}

\section{Criação de certificados}

Os certificados utilizados foram auto-certificados por uma autoridade central que "pertence" 
à máquina de OpenSSL. Esta mesma faz a gestão da lista de revogação.

Todas as chaves foram criadas no mesmo computador, com as variáveis que estão
neste código, aspetos importantes para mais tarde serão os parâmetros de CN
que precisam de ser passados mais tarde para aceder ao Apache e ao gateway.
Numa situação normal teríamos uma autoridade de certificação para enviar e
no fundo gerir todos, mas para este cenário podemos inicializar as máquinas
com as chaves, requests e certificados necessários.

O código para gerar os certificados X.509: 

\begin{lstlisting}[language=bash]
cert_ca="/C=PT/ST=Coimbra/L=Coimbra/O=UC/CN=CoimbraVPN"
cert_vpn="/C=PT/ST=Coimbra/L=Coimbra/O=UC/CN=gateway"
cert_user="/C=PT/ST=Coimbra/L=Coimbra/O=UC/CN=warrior"
cert_apache="/C=PT/ST=Coimbra/L=Coimbra/O=UC/CN=apache.coimbra"

openssl genrsa -out "ca.key" 2048
openssl req -x509 -nodes -days 365 -key "ca.key" -out "ca.crt" -subj "$cert_ca"
openssl genrsa -out "vpn.key" 2048
openssl req -new -key "vpn.key" -out "vpn.csr" -subj "$cert_vpn"
openssl ca -batch -in "vpn.csr" -cert "ca.crt" -keyfile "ca.key" -out "vpn.crt" -config cheese.cfg
openssl dhparam -out "dh2048.pem" 2048
openvpn --genkey secret "ta.key"
openssl genrsa -out user.key
openssl req -new -key user.key -out user.csr -subj "$cert_user"
openssl ca -batch -in "user.csr" -cert "ca.crt" -keyfile "ca.key" -out "user.crt" -config cheese.cfg
openssl genrsa -out apache.key
openssl req -new -key apache.key -out apache.csr -subj "$cert_apache" -addext "subjectAltName = IP:10.60.0.1,DNS:apache"
openssl ca -batch -in "apache.csr" -cert "ca.crt" -keyfile "ca.key" -out "apache.crt" -config cheese.cfg
\end{lstlisting}

% Porque é que precisamos de uma chave secreta?
% Criar chave secreta.

\begin{lstlisting}[language=bash]
openssl --genkey secret ta.key
\end{lstlisting}
\section{Configuração geral}
Para configurar as VMs era preciso introduzir os mesmos comandos várias vezes, o que levava muitas vezes a erros de escrita, ou a correr o mesmo comando várias vezes, por isso criamos vários ficheiros .sh para conseguir facilitar o processo. A utilização de ficheiros .sh também vem com outros positivos pois facilita a testagem, e a recriação do cenário rapidamente.

No entanto para os serviços que configuramos, instalar, desativar e dar flush às iptables não foi suficiente, tivemos que criar pastas e sincronizar os relógios de todas as VMs visto que elas estarem ligeiramente atrasadas nunca conseguíamos acertar na password do google-authenticator que utiliza o tempo local para calcular a sua chave.
\begin{lstlisting}[language=bash]
yum install -y epel-release
yum install -y openvpn iptables-services dhcp-client
systemctl stop firewalld
systemctl disable firewalld
systemctl mask firewalld
systemctl enable iptables
iptables -F

CA_DIR="/etc/pki/CA"
mkdir -p "${CA_DIR}/newcerts"
mkdir -p "${CA_DIR}/private"
touch "${CA_DIR}/index.txt"
cp ca/serial "${CA_DIR}/serial"

mkdir -p /etc/openvpn/server
mkdir -p /etc/openvpn/client

# NOTE(vasco): tive problemas com a sincronizacao de tempo
# se nao tiver sincronizado, o TOTP nao funciona
systemctl stop chronyd
ntpdate pool.ntp.org
systemctl start chronyd
\end{lstlisting}

\section{Configuração da \textit{Gateway} VPN}

\subsection{Configurar TOTP}

Foi criado o ficheiro \texttt{totp} com a configuração de autenticação a 
ser utilizada pelo plugin de PAM para o openvpn.

\begin{lstlisting}[language=bash]
plugin /usr/lib64/openvpn/plugins/openvpn-plugin-auth-pam.so totp
\end{lstlisting}

Adicionalmente, devido às restrições de segurança do \textit{systemd},
foi necessário desativar o \texttt{ProtectHome} no serviço do OpenVPN
para que o plugin PAM consiga ler os ficheiros de segredo do Google Authenticator
localizados nas diretorias \textit{home} dos utilizadores.

\begin{lstlisting}[language=bash]
[Service]
ProtectHome=false
\end{lstlisting}

Primeiro, na gateway, entramos como o utilizador desejado e obtemos a chave
do gerador de palavras passes temporárias. Ao inserir a chave no 
\texttt{google authenticator} podemos obter um código QR,  a nossa primeira
chave de 6 dígitos.

\begin{figure}[h]
    \centering
    \includegraphics[width=8em]{google-authenticator}
\end{figure}

\begin{lstlisting}[language=bash]
su john
google-authenticator
\end{lstlisting}

\subsection{Encaminhamento e Firewall}

Para que a gateway funcione como router entre a rede externa e a rede interna,
foi necessário ativar o \textit{IP forwarding} no kernel e configurar as regras
de \textit{iptables} para permitir o tráfego da VPN e realizar o mascaramento
de IP (NAT).

% NOTA(vasco): Não temos regras de DROP a packets
% talvez deviamos mudar isso nao sei

\begin{lstlisting}[language=bash]
# Ativar encaminhamento
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p /etc/sysctl.conf

# Regras de Firewall
iptables -I INPUT 1 -p udp --dport 1194 -j ACCEPT
iptables -I FORWARD 1 -i tun0 -o enp0s9 -j ACCEPT
iptables -I FORWARD 1 -i enp0s9 -o tun0 -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o enp0s8 -j MASQUERADE
\end{lstlisting}

\section{Configuração do Cliente (Road Warrior)}

O cliente encontra-se na rede externa (\texttt{193.136.212.10}) e liga-se à VPN
gateway na porta 1194. Para garantir a segurança, utilizamos autenticação mútua (os certificados X.509)
e um \textit{two factor authentication} (2FA) como palavras-passe temporárias, geradas através do
\textit{Google Authenticator}.

\begin{lstlisting}[language=bash]
client
dev tun
proto udp
remote 193.136.212.1 1194
ca ca.crt
cert user.crt
key user.key
auth-user-pass
cipher AES-256-GCM
auth SHA256
\end{lstlisting}

\section{Servidor Apache e OCSP}

O servidor interno (\texttt{10.60.0.1}) alberga o serviço Apache e o responder OCSP
da autoridade de certificação.

\subsection{Revocation e OCSP}

\begin{enumerate}
    \item Estabelecer a ligação VPN e verificar a conectividade à rede interna.
    \item No diretório da autoridade de certificação (máquina \textit{host}), revogar o certificado do utilizador:
    \begin{lstlisting}[language=bash]
openssl ca -revoke user.crt -config cheese.cfg -keyfile ca.key -cert ca.crt
    \end{lstlisting}
    \item Atualizar o ficheiro \texttt{index.txt} no servidor OCSP e reiniciar o serviço para carregar o novo estado de revogação.
    \item Tentar estabelecer uma nova ligação VPN e verificar que a autenticação falha devido à resposta \texttt{revoked} do responder OCSP.
\end{enumerate}


\section{Conclusão}

% Conclusão!!!
Atingimos o objetivo deste trabalho, conseguimos configurar o VPN tunnel,
o two-factor authentication e conseguimos criar e retirar acesso aos
certificados que emitimos. Utilizar mais maquinas para simular um cenario
maior seria redundante, teriamos que emitir mais certificados mas não iamos
aprender muito mais. 

% Para aprofundar (???)

\end{document}
