Skip to main content

Usando YubicoLabs




Implementando um servidor YK-KSM e YK-VAL


Vamos ver como implementar um Servidor de Validação OTP Yubico. Existem dois componentes principais em um servidor de validação Yubico OTP, o Key Storage Module (KSM) e o Validation Server (VAL). Ambos são necessários para a validação OTP, e qualquer um deles pode ser replicado para redundância.


Atenção

É importante notar que a Yubico declarou o fim de vida útil para o YubiKey Validation Server (YK-VAL) e o YubiKey Key Storage Module (YK-KSM), como eram conhecidos. No entanto, eles foram movidos para um novo projeto, conhecido como YubicoLabs. Para mais detalhes, consulte o guia de validação OTP autogerenciada da Yubico.


O problema é que o novo projeto YubicoLabs não tem atualizações recentes, sendo 4 anos atrás (meados de 2020) a atualização mais recente para o YK-VAL. Para usar essa projeto é preciso corrigir diversos problemas que serão apresentado no meio do caminho, por sorte, já fiz essa árdua tarefa.


Mas é importante que você tenha isso em mente se deseja usar esse tipo de validação, algo pode quebrar a quaquer momento e só você poderá arrumar, já que as issues do Github não estão sendo respondidas.


A implementação do YK-VAL e YK-KSM pode ser realizada de diferentes formas, dependendo das suas necessidades e da topologia de rede. Podendo ser um único servidor executando tanto o YK-VAL quanto o YK-KSM. Vários servidores, onde um executa o YK-KSM e outro o Validation Server, separadamente. E uma abordagem mais distribuída, com servidores dedicados para cada instância do YK-KSM e do Validation Server, permitindo maior escalabilidade e redundância.



Módulo de Armazenamento de Chaves (YK-KSM)


O YubiKey Key Storage Module (YK-KSM) é um componente desenvolvido pela Yubico que atua como um módulo de armazenamento seguro para chaves AES utilizadas na validação de One-Time Passwords (OTPs) gerados pelas YubiKeys. Sua principal função é armazenar e gerenciar as chaves criptográficas associadas a cada YubiKey, garantindo que apenas servidores de validação autorizados possam acessar essas chaves para verificar a autenticidade dos OTPs.


O YK-KSM ajuda a manter as chaves AES de forma segura, separando-as dos servidores de validação para minimizar riscos em caso de comprometimento de um servidor. Ele recebe OTPs dos servidores de validação, utiliza a chave correspondente para descriptografá-los e retorna os valores dos contadores, permitindo que o servidor de validação determine a validade do OTP.


Opcionalmente, você pode usar um dispositivo USB YubiHSM para manter esses valores secretos seguros, mesmo no caso de um servidor KSM ser comprometido. Devido à maior segurança obtida pelo uso de um YubiHSM, esta é a abordagem recomendada.


Abaixo podemos ver um fluxo de funcionamento simplificado:

  1. OTP enviado diretamente ao KSM
    O cliente (via PAM, configurado para comunicação com o KSM) envia o OTP diretamente ao YK-KSM para processamento.

  2. KSM descriptografa o OTP
    O YK-KSM identifica a chave AES com base no identificador público da YubiKey e descriptografa o OTP, extraindo informações como contadores e timestamp.

  3. Validação interna no KSM
    Dependendo da configuração, o KSM pode realizar validações iniciais básicas, como verificar a integridade dos dados descriptografados.

  4. Encaminhamento ao VAL
    O KSM pode encaminhar os dados descriptografados ao YK-VAL, que realiza validações adicionais, como controle de reutilização do OTP.

  5. Resposta ao Cliente
    O resultado da validação (válido ou inválido) é retornado ao cliente, passando pelo PAM, que autoriza ou rejeita o login com base nessa resposta.


Essa estrutura mantém a função principal do YK-KSM limitada à descriptografia segura, enquanto o YK-VAL gerencia a lógica de validação e a comunicação com o cliente.



Servidor de Validação (YK-VAL)


O YubiKey Validation Server (YK-VAL), desenvolvido pela Yubico, é um componente responsável por validar o uso de OTPs gerados pelas YubiKeys registradas. Enquanto o YK-KSM descriptografa e verifica a autenticidade dos OTPs, ele não rastreia se um OTP já foi usado. Para resolver isso, o YK-VAL mantém um registro dos valores de contador mais recentes associados a cada credencial YubiKey.


Com o YK-VAL é possível garantir que cada OTP seja utilizado apenas uma vez, invalidando OTPs repetidos. Os OTPs com valores de contador mais antigos são rejeitados caso um OTP posterior tenha sido registrado. Isso impede ataques de repetição, pois o YK-VAL reforça que os contadores associados aos OTPs devam sempre aumentar. Dessa forma, o servidor de validação complementa o YK-KSM, garantindo a integridade e a exclusividade no uso de cada OTP.


O serviço de validação de OTP é disponibilizado por meio de uma API de serviço web, sem uma interface HTML baseada em formulários. O protocolo utilizado está documentado em: http://www.yubico.com/developers/api/.


Para garantir redundância, é possível configurar múltiplas instâncias do YubiKey Validation Server, permitindo que os clientes continuem validando OTPs mesmo em caso de falha de um dos servidores. Essa redundância é implementada no YK-VAL através do conceito de sync pool.


O sync pool de uma instância YK-VAL consiste em uma lista de URLs de outros servidores com os quais ele sincroniza os OTPs, dependendo da solicitação do cliente. Por exemplo, em um ambiente com 5 servidores, cada servidor terá os outros 4 listados no seu sync pool. Isso garante que os servidores compartilhem e validem as informações de forma consistente e resiliente.



Pré Requisitos


Para este guia, começamos com uma instalação limpa do Ubuntu Server 22.04 (LTS), vou fazer a configuração por etapas, caso você queira instalar cada componente num servidor distinto. Para que tudo funcione, a Yubikey deve ter suporte a OTP, caso não tenha, não será possível utilizar esse método. Como utilizaremos as versões mais recentes dos softwares da Yubico, vamos adicionar o repositório PPA da Yubico e instalar os pacotes necessários:

# Adicione o repositório da Yubico:
$ sudo add-apt-repository ppa:yubico/stable

# Atualize os repositórios:
$ sudo apt update

# Instale os pacotes necessários para compilar o yubikey-val e yubikey-ksm:
$ sudo apt install -y build-essential help2man libdbi-perl

# Fora do servidor, na minha máquina, vou instalar o yubikey-personalization
# para testar e configurar a Yubikey de maneira simples:
$ sudo apt install -y yubikey-personalization

# Instale o chrony:
$ sudo apt-get install -y chrony

# Agora vamos configurar o chrony, edite o arquivo abaixo:
$ sudo vim /etc/chrony/chrony.conf

## Deixe igual abaixo:
#pool ntp.ubuntu.com iburst maxsources 4
#pool 0.ubuntu.pool.ntp.org iburst maxsources 1
#pool 1.ubuntu.pool.ntp.org iburst maxsources 1
#pool 2.ubuntu.pool.ntp.org iburst maxsources 2
pool pool.ntp.br iburst maxsources 4

# Reinicie o chrony:
$ sudo systemctl restart chrony

Criptografe seu disco

Criptografar o disco do sistema é uma medida altamente recomendada para proteger seus dados. Com a criptografia ativada, o disco só poderá ser acessado mediante a inserção da senha correta, garantindo a segurança mesmo em caso de acesso físico ao equipamento.


Também é recomendado monitorar os acessos ao servidor, lembrando que esse é um serviço que permitirá que você possa logar em outros servidores, é importante fechar todas as brechas que puder.



Instalando o YK-KSM


Agora vamos instalar o YK-KSM (YubiKey Key Storage Module), o métodos de instalação mudou, o suporte a pacotes pré compilados não existe mais, temos que compilar nosso próprio software.

# Defina o nome da nossa maquina:
$ sudo hostnamectl set-hostname ksm-zion.com.br

# Entre no diretório abaixo:
$ cd /usr/src/

# Baixe o pacote:
$ git clone https://github.com/YubicoLabs/yubikey-ksm.git

# Entre dentro do diretório:
$ cd yubikey-ksm

# Agora vamos compilar:
$ sudo make install

# Crie os links simbolicos:
make symlink


Instalando o Servidor Web e PHP


Vamos instalar o Servidor Web e o PHP para que o Web Server possa interagir com o software da Yubico.

# Instale o apache e php:
$ sudo apt install -y apache2 php

# Configurar corretamente o apache:
$ sudo cat << 'EOF' > /etc/apache2/sites-enabled/000-default.conf
<VirtualHost *:80>
ServerName ksm-zion.com.br

ServerAdmin webmaster@localhost
DocumentRoot /var/www

<Directory />
AllowOverride None
Order Deny,Allow
Deny from all
</Directory>

<Directory "/var/www/wsapi">
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ $1.php [L]
</Directory>

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>
EOF

# Carregue o modulo abaixo no apache:
sudo a2enmod php8.1
sudo a2enmod rewrite

# Corrija a permissão dos arquivos:
chown www-data. /usr/share/yubikey-ksm/*


Instalando o Banco de dados


Vamos instalar o Mysql para armazenar as chaves criptográficas associadas a cada YubiKey.

# Instale o banco de dados e as bibliotecas necessárias de comunicação entre os componentes:
$ sudo apt install mysql-server php-mysql libdbd-mysql-perl

#
$ sudo mysql_secure_installation

# Crie o banco de dados chamado 'ykksm':
$ echo 'create database ykksm' | sudo mysql

# Agora vamos popular o banco que acabamos de criar com as tabelas necessárias:
$ sudo mysql ykksm < /usr/share/doc/yubikey-ksm/ykksm-db.sql

Agora vamos criar os usuários dentro do Banco de dados e configurar as permissões necessárias.

# Acesse o banco de dados:
$ sudo mysql --silent ykksm

# Crie um usuário dentro do mysql (MySQL 5.7 or MySQL 8 or newer:):
CREATE USER 'ykksmreader'@'localhost' IDENTIFIED BY '8PxMczhNEY9A2PnJuJSPMZCU';

# Crie um usuário dentro do mysql (MySQL 5.7 or MySQL 8 or newer:):
CREATE USER 'ykksmimporter'@'localhost' IDENTIFIED BY 'tkt97N8M_GlBF03tBrymPiQ8';

# Altere o plugin de autenticação para o usuário abaixo, se não dará erro ao importar os dados para o banco:
ALTER USER 'ykksmimporter'@'localhost' IDENTIFIED WITH 'mysql_native_password' BY '{{ settings.ykksmimporter_pass }}';

# De acesso a esse usuário na tabela que criamos:
GRANT SELECT ON ykksm.yubikeys TO 'ykksmreader'@'localhost';

# De acesso a esse usuário na tabela que criamos:
GRANT INSERT ON ykksm.yubikeys TO 'ykksmimporter'@'localhost';

# Recarregue as permissões:
FLUSH PRIVILEGES;


Logs


Vamos configurar o sistema de Logs para o KSM.

# Crie a configuração de logs para o KSM:
$ cat << 'EOF' > /etc/rsyslog.d/ykksm.conf
local0.* -/var/log/ykksm.log
EOF


# Crie o arquivo de configuração para rotação de logs:
$ cat << 'EOF' > /etc/logrotate.d/ykksm
/var/log/ykksm.log {
weekly
missingok
rotate 9999
notifempty
postrotate
invoke-rc.d rsyslog reload > /dev/null
endscript
}
EOF


# Corrija as permissões do arquivo de log:
$ sudo chmod 644 /var/log/ykksm.log
$ sudo chown syslog:adm /var/log/ykksm.log


## Agora vamos impedir que os logs fiquem duplicados, estando no arquivo syslog e no arquivo configurado acima.

# Edite o arquivo padrão de configuração do rsyslog:
$ sudo vim /etc/rsyslog.d/50-default.conf

## Encontre a linha abaixo:
*.*;auth,authpriv.none -/var/log/syslog

## Altere para excluir local0:
*.*;auth,authpriv.none,local0.none -/var/log/syslog


# Reinicie o serviço Rsyslog para aplicar as mudanças:
$ sudo systemctl restart rsyslog


# Agora vamos corrigir o script para gerar logs na facility local0:
$ sudo vim +38 /usr/share/yubikey-ksm/ykksm-decrypt.php

## Encontre a linha abaixo:
openlog("ykksm", LOG_PID, $logfacility)

## Altere para:
openlog("ykksm", LOG_PID, LOG_LOCAL0)


Interface de descriptografia de OTP


Vamos instalar a interface para descriptografar os OTPs, ela também é implementada usando um script PHP. Para instalar ela no local padrão, use o comando abaixo.

sudo make -f /usr/share/doc/yubikey-ksm/ykksm.mk symlink


Configuração YK-KSM


Agora vamos configurar o script ykksm-config.php para que o sistema saiba como acessar os dados no banco de dados necessários para a validação das chaves das YubiKeys. Um arquivo de exemplo pode ser encontrado em /etc/yubico/ksm/ykksm-config.php. No entanto, vou sobrescrevê-lo, pois já sei que a configuração abaixo funciona.

# para que nao fique dando erro no apache por nao ter o arquivo, vamos corrijir:
cat << 'EOF' > /etc/yubico/ksm/ykksm-config.php
<?php

$dbuser='ykksmreader';
$dbpass='SENHA-DE-ykksmreader';
$basepath='';
$dbname='ykksm';
$dbserver='';
$dbport='';
$dbtype='mysql';

$db_dsn = "mysql:dbname=ykksm;host=127.0.0.1";
$db_username = $dbuser;
$db_password = $dbpass;
$db_options = array();
$logfacility = LOG_AUTH;
?>
EOF


Resolvendo os problemas


Agora vamos corrigir todos os problemas nos scripts que o YK-KSM utiliza. Esses problemas ocorrem devido à compatibilidade com versões antigas do PHP. O objetivo é atualizar o código para garantir que funcione corretamente em versões mais recentes do PHP, eliminando erros de sintaxe e funções obsoletas.



Correção de sintaxe

O script ykksm-utils.php contém sintaxe e práticas que não são mais compatíveis com versões recentes do PHP, exigindo atualizações para evitar erros. Um exemplo disso é o uso de chaves {} como em $var{$indice}. Essa sintaxe era usada para acessar um indice dentro de um array e foi depreciada e removidos em versões modernas do PHP.


Abaixo deixo a função yubi_hex2bin corrigida com sua versão antiga comentada logo abaixo dela:


sudo vim +31 /usr/share/yubikey-ksm/ykksm-utils.php
function yubi_hex2bin($h)
{
if (!is_string($h)) return null;
$r = '';
for ($a = 0; $a < strlen($h); $a += 2) {
$r .= chr(hexdec($h[$a] . $h[$a + 1]));
}
return $r;
}

//function yubi_hex2bin($h)
//{
// if (!is_string($h)) return null;
// $r='';
// for ($a=0; $a<strlen($h); $a+=2) {
// $r.=chr(hexdec($h{$a}.$h{($a+1)}));
// }
// return $r;
//}


Função mcrypt Depreciada

A função mcrypt_module_open() faz uso da extensão mcrypt, que foi removida a partir do PHP 7.2. A extensão mcrypt não é mais recomendada e deve ser substituída pela extensão openssl, que fornece funcionalidades criptográficas mais modernas e seguras. Abaixo deixo o novo código seguido do original comentado logo abaixo do novo. A primeira linha possui um comentário, é o link de onde eu peguei esse código.


sudo vim +56 /usr/share/yubikey-ksm/ykksm-utils.php
// https://github.com/Yubico/yubikey-ksm/issues/24
function aes128ecb_decrypt($key, $ciphertext) {
// Se OpenSSL estiver disponível e suportar aes-128-ecb, usa openssl
if (extension_loaded('openssl') && function_exists('openssl_decrypt') && in_array('aes-128-ecb', openssl_get_cipher_methods())) {
$result = openssl_decrypt(yubi_hex2bin($ciphertext), 'aes-128-ecb', yubi_hex2bin($key), OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
if ($result !== false) {
// Converte o resultado para hexadecimal
return bin2hex($result);
} else {
echo "Erro na descriptografia com OpenSSL.\n";
return '';
}
} else {
// Bloco legado com mcrypt
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'ecb', '');
$iv = yubi_hex2bin('00000000000000000000000000000000');
mcrypt_generic_init($td, yubi_hex2bin($key), $iv);
$result = bin2hex(mdecrypt_generic($td, yubi_hex2bin($ciphertext)));
mcrypt_generic_deinit($td);
return $result;
}
}

//function aes128ecb_decrypt($key,$in)
//{
// $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'ecb', '');
// $iv = yubi_hex2bin('00000000000000000000000000000000');
// mcrypt_generic_init($td, yubi_hex2bin($key), $iv);
// $result = bin2hex(mdecrypt_generic($td, yubi_hex2bin($in)));
// mcrypt_generic_deinit($td);

// return $result;
//}


Corrigir include_path dos scripts

Os scripts PHP podem utilizar um path personalizado configurado diretamente no arquivo php.ini. No entanto, em alguns casos, essa configuração isolada pode não ser suficiente. Nessas situações, é necessário definir o path personalizado diretamente no código do script, garantindo que ele seja reconhecido corretamente durante a execução.

# Para corrigir um problema de import, faça:
$ sudo vim /usr/share/yubikey-ksm/ykksm-decrypt.php
ini_set('include_path', '/etc/yubico/ksm:/usr/share/yubikey-ksm');

require_once 'ykksm-config.php';
require_once 'ykksm-utils.php';


Testes final da instalação do YK-KSM


Agora vamos testar nossa instalação do YK-KSM. Nesse primeiro teste o resultado deve ser um erro, já que não temos chave alguma cadastrada ainda, vamos apenas avaliar se o sistema está funcionando.

$ curl -ks 'http://localhost/wsapi/decrypt.php?otp=dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh'
ERR Unknown yubikey

Você precisará importar chaves para o banco de dados para que a função decrypt faça algo útil.



Gerar chave KSM


O sistema responsável por importar os dados da YubiKey para o banco de dados exige que o arquivo esteja criptografado. Por isso, para realizar a importação, é necessário criar uma chave GPG específica para essa finalidade. Essa chave deve ser do tipo DSA e Elgamal, garantindo não apenas a capacidade de criptografar o arquivo, mas também de assiná-lo.


Abaixo está um exemplo de como gerar uma chave GPG. No final do processo, foi gerada uma chave com o ID F5B0DE41885070DA.

gpg --full-generate-key

gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

gpg: directory '/root/.gnupg' created
gpg: keybox '/root/.gnupg/pubring.kbx' created
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(14) Existing key from card
Your selection? 2
DSA keys may be between 1024 and 3072 bits long.
What keysize do you want? (2048)
Requested keysize is 2048 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: YK-KSM Import Key
Email address:
Comment:
You selected this USER-ID:
"YK-KSM Import Key"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: WARNING: some OpenPGP programs can't handle a DSA key with this digest size
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key F5B0DE41885070DA marked as ultimately trusted
gpg: directory '/root/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/5852D8BF775645EA403A0A9EF5B0DE41885070DA.rev'
public and secret key created and signed.

pub dsa2048 2024-11-13 [SC]
5852D8BF775645EA403A0A9EF5B0DE41885070DA
uid YK-KSM Import Key
sub elg2048 2024-11-13 [E]

Certifique-se de salvar e proteger a chave privada, pois ela será necessária tanto para criptografar quanto para descriptografar os arquivos.


danger

Apagar isso antes de publicar.

Password do gpg: 'UGPXIoLcUGED6bqWUGuxMccN'



Gerar Chaves Yubikey


Para criar chaves AES para suas YubiKeys gerenciadas pelo YK-KSM, utilizamos a ferramenta ykksm-gen-keys. Como uma boa prática de segurança, nunca armazene suas chaves de criptografia (das Yubikeys) em texto plano. Normalmente, a saída da ferramenta é direcionada diretamente ao GnuPG para ser criptografada, mas, neste exemplo, o processo será dividido em duas etapas para maior clareza.


# Gere as chaves AES, no exemplo, vamos gerar 5 chaves:
$ sudo ykksm-gen-keys --urandom 1 5 > ~/keys.txt


# Agora vamos assinar e criptografar o arquivo com as chaves:
$ sudo gpg -a --encrypt -r F5B0DE41885070DA -s -o ~/keys.asc ~/keys.txt
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u


# Apague o arquivo de texto simples de modo seguro:
$ sudo shred -u ~/keys.txt


# Podemos ver qe o arquivo está criptografado:
$ sudo cat ~/keys.asc
-----BEGIN PGP MESSAGE-----

hQMOA78enPRdXt3QEAv/dt5BxsAHTSFNl3PljnZJFM3lPtplogATCft8NCuH9Uv7
npd78HH2HmC2U/hBWuhkI5iaTdOvrUtjLlLU741gUDxdgEm78eNEbyqdtS4B54/6
ZQ/+kb730H9htdwMjLacyv9rojyqCJEWvABBuHmHhDjCIAcyxRwA58C7TEnh96MZ
2+vaA+djpaOzLOv5niDfSX+Fy5YKjKcqZkHjmG++xu+hsKv/hCtDNZumgwLBFI1r
pLibR7POg19woFG9TS5S7RV5R2paRGrD90eeKKBVm6EYUHV6/coa+0accBFL7bii
CCag1wl5Qfqd8yjUka9d3HZBe70cgo9HO3/LGzY322ldQLtD0o/W9z4lDfKuCXX0
L77f8z8JR56swTTEXDufw60DVLV9gjyAgrZ7hgQv/qy5q4NDBuAcgpDMxkNXA+jm
Kjj2YfVjCx2DxO65XjIJqgo/X3mNxqMin4QXHCsFbGbY/yZdEEJkGD7fpMxlYU0r
KIXj+LCGxLtgzBqyutLUDACMYhC6hLCNhLLW/U0oeMV76HYWmq7JmiNd3+KmveKP
z2RXco4uDdIfeEEa3vZlnZr448L432BIk3wvFu4tMa/NE2upeObomLkh+L2LSzMs
sO2WqgiZUD72EVORxR6pxACYOlLti9XCv9SUJVIabno/lPM/uo7KHfmzAOc2DXig
U2hmf9EnkoAmRvV0ynd42VQHT4vyiNRqDA9rafFOWqrsfnwaUImqSrO+7p98OUDk
XZn1OeJODHpsiMZWdBjlCuBBPRirJ314vw2LU89w5CeGrrlOZ0IfHTT/TcAJKuUU
wWaQWwctFMnLoHW6cuVdgWRRNJ8f+uz1rmTcQ4pdlbxn5Xbgpa3rB/sflPhGecOg
LtWrmoKmXCJIav4aPyA6tXJGNvWYNHCTzmINIOsSPYapSJFXoVDfEWTnH4eyWK7f
QhBxcnQmZBffmKhmibMakbRfGA6H90w9RQ26XBAjhzYTBmtO2Jg7OHJjrzvsIZbv
wEbDLiHzNKIZRdIzwWDFnTjSwL8B4enI5npsHYbFMXQdy7m2XCgGcMO03dNBPMV8
mlD4zXVLbxv2//zlWsYipgPaF+9OU6/lV3xcHL6/TveA3cUXC6jvOhigs+RFvZfC
V4aq4UmQGUcYLUys1+EwEgI8vTeEXnDrsZnqde3GeI9nXiUy3R6C4GqzuxhgJBNs
UP990G5VJGr5z2diHhKyekz4OMXrtz5WWgJomIoO32yRTWGasDw/0qNnwuRuw7Rl
t0+ePsSEx1mLqOdauE0/Cvu1fzrFulUGY8UMM1E1LstMZAB3F552xDWRPj3eT2YN
CHW9UsmhoqjmAp2uVvmRK3gMaCnVAsowSJWgbhxkhhZO7ULRzaMZEc3w+kRBpkSH
JMThaYoQiHTELfjIY6ZvEKgQfXv3dZ20AbY48D3z7tYF2zlMMdnvrJPLrlXSp2sc
7UgszGhlZxX3UHv9+xAiYUj1/ljpqXgDtrt9ewwHNbFtj0mUU33XTyzJYRW9lbMV
JufhAKsbh1krdpv5pymNuAwIbg==
=FoNH
-----END PGP MESSAGE-----


# Para exibir as chaves direto do arquivo criptografado, pode usar o comando abaixo:
$ sudo gpg < ~/keys.asc
gpg: WARNING: no command supplied. Trying to guess what you mean ...
gpg: encrypted with 2048-bit ELG key, ID 4813C89974AD07B2, created 2024-11-13
"YK-KSM Import Key"
# ykksm 1
# serialnr,identity,internaluid,aeskey,lockpw,created,accessed[,progflags]
1,cccccccccccb,517ee34e09aa,cb8d22ed5decbdb8da62d3819516cdce,a7f4650a8d50,2024-11-13T20:21:45,
2,cccccccccccd,4c6456c147c6,a83eee58d91d9dbbd09a2bd22c35710e,d7d7353b7ad5,2024-11-13T20:21:45,
3,ccccccccccce,108887fe8d0d,0b90eaf29c43cb4e11580c6959c6a84b,7ea6868bc573,2024-11-13T20:21:45,
4,cccccccccccf,939975044b65,4adb5424af5ac81bc2f5b2d08fb538d8,5827b73a625b,2024-11-13T20:21:45,
5,cccccccccccg,b5e274f67c39,707d144e8b9d1ef8b23d7f0662b79fff,2198a1f7749a,2024-11-13T20:21:45,
# the end
gpg: Signature made Wed 13 Nov 2024 08:22:25 PM UTC
gpg: using DSA key 5852D8BF775645EA403A0A9EF5B0DE41885070DA
gpg: Good signature from "YK-KSM Import Key" [ultimate]

Observe que a opção --urandom fará com que a ferramenta use /dev/urandom em vez de /dev/random, o que acelera o processo, mas é considerado por alguns como tendo segurança mais fraca.


indice das chaves

Ao criar chaves para as YubiKeys usando o comando ykksm-gen-keys --urandom 1 5, cinco chaves serão geradas com índices de 1 a 5. No entanto, é importante lembrar que, ao gerar mais chaves no futuro, não se deve reutilizar os mesmos índices (1 a 5). Isso resultará em um conflito, pois o índice de chave é armazenado no banco de dados como um identificador exclusivo e não pode ser duplicado.


Para evitar esse problema, ao gerar novas chaves, sempre inicie do próximo índice disponível. Por exemplo, se o intervalo de índices atual vai de 1 a 5, para gerar mais 3 chaves, o comando correto seria ykksm-gen-keys --urandom 6 8.


Para identificar o último índice utilizado no banco de dados, você pode usar o comando ykksm-export. Esse comando exibe todas as entradas armazenadas no banco, incluindo os índices das chaves geradas.



Importando as chaves Yubikey para o Banco de Dados


Para importar chaves para o banco de dados do YK-KSM, use a ferramenta ykksm-import. Ela lê os dados da entrada padrão e os insere no banco. Caso ocorra um erro, a execução é interrompida, podendo resultar em um banco em estado intermediário. Certifique-se de que os dados estão corretos antes de iniciar a importação.

# Vamos importar as chaves criadas no paso anterior usando o comando completo:
$ sudo ykksm-import --verbose --database 'DBI:mysql:dbname=ykksm;host=127.0.0.1' --db-user ykksmimporter --db-passwd 'SENHA' < ~/keys.asc
Verification output:
gpg: WARNING: no command supplied. Trying to guess what you mean ...
[GNUPG:] ENC_TO 4813C89974AD07B2 16 0
[GNUPG:] KEY_CONSIDERED 5852D8BF775645EA403A0A9EF5B0DE41885070DA 0
[GNUPG:] KEY_CONSIDERED 5852D8BF775645EA403A0A9EF5B0DE41885070DA 0
[GNUPG:] DECRYPTION_KEY A9F0D2262C5FC37E971BD70D4813C89974AD07B2 5852D8BF775645EA403A0A9EF5B0DE41885070DA u
[GNUPG:] KEY_CONSIDERED 5852D8BF775645EA403A0A9EF5B0DE41885070DA 0
gpg: encrypted with 2048-bit ELG key, ID 4813C89974AD07B2, created 2024-11-13
"YK-KSM Import Key"
[GNUPG:] BEGIN_DECRYPTION
[GNUPG:] DECRYPTION_INFO 2 9 0
[GNUPG:] PLAINTEXT 62 1731529345 keys.txt
[GNUPG:] PLAINTEXT_LENGTH 570
[GNUPG:] NEWSIG
gpg: Signature made Wed 13 Nov 2024 08:22:25 PM UTC
gpg: using DSA key 5852D8BF775645EA403A0A9EF5B0DE41885070DA
[GNUPG:] KEY_CONSIDERED 5852D8BF775645EA403A0A9EF5B0DE41885070DA 0
[GNUPG:] SIG_ID 4LyJLlII9Tq6dDNih4pSiMTNy80 2024-11-13 1731529345
[GNUPG:] KEY_CONSIDERED 5852D8BF775645EA403A0A9EF5B0DE41885070DA 0
[GNUPG:] GOODSIG F5B0DE41885070DA YK-KSM Import Key
gpg: Good signature from "YK-KSM Import Key" [ultimate]
[GNUPG:] VALIDSIG 5852D8BF775645EA403A0A9EF5B0DE41885070DA 2024-11-13 1731529345 0 4 0 17 10 00 5852D8BF775645EA403A0A9EF5B0DE41885070DA
[GNUPG:] KEY_CONSIDERED 5852D8BF775645EA403A0A9EF5B0DE41885070DA 0
[GNUPG:] TRUST_ULTIMATE 0 pgp
[GNUPG:] VERIFICATION_COMPLIANCE_MODE 23
[GNUPG:] DECRYPTION_OKAY
[GNUPG:] GOODMDC
[GNUPG:] END_DECRYPTION
encrypted to: 4813C89974AD07B2
signed by: 59BB191D
line: 1,cccccccccccb,517ee34e09aa,cb8d22ed5decbdb8da62d3819516cdce,a7f4650a8d50,2024-11-13T20:21:45,
serialnr 1 publicname cccccccccccb internalname 517ee34e09aa aeskey cb8d22ed5decbdb8da62d3819516cdce lockcode a7f4650a8d50 created 2024-11-13T20:21:45 accessed eol
line: 2,cccccccccccd,4c6456c147c6,a83eee58d91d9dbbd09a2bd22c35710e,d7d7353b7ad5,2024-11-13T20:21:45,
serialnr 2 publicname cccccccccccd internalname 4c6456c147c6 aeskey a83eee58d91d9dbbd09a2bd22c35710e lockcode d7d7353b7ad5 created 2024-11-13T20:21:45 accessed eol
line: 3,ccccccccccce,108887fe8d0d,0b90eaf29c43cb4e11580c6959c6a84b,7ea6868bc573,2024-11-13T20:21:45,
serialnr 3 publicname ccccccccccce internalname 108887fe8d0d aeskey 0b90eaf29c43cb4e11580c6959c6a84b lockcode 7ea6868bc573 created 2024-11-13T20:21:45 accessed eol
line: 4,cccccccccccf,939975044b65,4adb5424af5ac81bc2f5b2d08fb538d8,5827b73a625b,2024-11-13T20:21:45,
serialnr 4 publicname cccccccccccf internalname 939975044b65 aeskey 4adb5424af5ac81bc2f5b2d08fb538d8 lockcode 5827b73a625b created 2024-11-13T20:21:45 accessed eol
line: 5,cccccccccccg,b5e274f67c39,707d144e8b9d1ef8b23d7f0662b79fff,2198a1f7749a,2024-11-13T20:21:45,
serialnr 5 publicname cccccccccccg internalname b5e274f67c39 aeskey 707d144e8b9d1ef8b23d7f0662b79fff lockcode 2198a1f7749a created 2024-11-13T20:21:45 accessed eol

Ao importar grandes conjuntos de dados, é recomendável evitar a opção --verbose para reduzir o excesso de informações.


Para aumentar a segurança durante as importações, é recomendável configurar um arquivo para armazenar as credenciais do banco de dados. Isso evita a necessidade de passá-las diretamente na linha de comando, reduzindo o risco de exposição. Crie o arquivo de configuração abaixo:

/etc/yubico/ksm/config-db.cfg
# Configuração do banco de dados para o YK-KSM
$dbuser = 'ykksmimporter';
$dbpass = 'SENHA';
$dbname = 'ykksm';
$dbserver = 'localhost';
$dbport = '3306';
$dbtype = 'mysql';

Após criar o arquivo, ajuste as permissões para garantir que apenas o usuário autorizado possa acessá-lo:

$ sudo chmod 600 /etc/yubico/ksm/config-db.cfg

Para executar agora, basta usar o comando abaixo:

$ sudo ykksm-import --verbose < ~/keys.asc 


Para testar a importação, você pode tentar descriptografar um OTP (inválido) para uma das chaves AES também inválida, da seguinte forma:

$ curl -ks 'http://localhost/wsapi/decrypt.php?otp=cccccccccccdvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv'
ERR Corrupt OTP

Podemos ver se realmente foram importadas no banco:

$ echo "select * from yubikeys;" | sudo mysql -u root ykksm
1 cccccccccccb 2024-11-17T20:22:21 ffbfe18e9f4b 50201d5ef969b7357592829a8b9c7813 dcb7e06077a6 885070DA 1 1
2 cccccccccccd 2024-11-17T20:22:21 9c40b3ad8454 ece2f50ae9d0c00cc85021bcb587b206 757b0a705451 885070DA 1 1
3 ccccccccccce 2024-11-17T20:22:21 b6d87939aa99 33bcb8f9ea48539a10c470d37e18916e e0791e51a975 885070DA 1 1
4 cccccccccccf 2024-11-17T20:22:21 223d5494c035 b2e2f1a3890aae84333f653b09e94d74 f8706fd76222 885070DA 1 1
5 cccccccccccg 2024-11-17T20:22:21 2af04d4c7aa5 c2926d9711614a82c936e0d741491cbb dcd8718b7222 885070DA 1 1

O publicname é o Public ID da chave.
O internalname é o Private ID da chave.
O aeskey é o Secre Key da chave.


Agora vamos testar com uma chave que está no banco:

# Primeiro configure a Yubikey (Slot 1) com os seguintes parâmetros de chave (vou usar a numero 1):
$ ykman otp yubiotp --public-id cccccccccccb --private-id ffbfe18e9f4b --key 50201d5ef969b7357592829a8b9c7813 1
Upload credential to YubiCloud? [y/N]: n
Program a YubiOTP credential in slot 2? [y/N]: y

# Agora toque na Yubikey para gerar o OTP, no meu caso coloquei no slot 1:
cccccccccccbtfdkuvrvkccrtcdighibebchucrknhcb

# Com o OTP em mãos, vamos testar:
$ curl -ks 'http://localhost/wsapi/decrypt.php?otp=cccccccccccbtfdkuvrvkccrtcdighibebchucrknhcb'
OK counter=0001 low=fb7c high=d7 use=00

Nosso serivdor YK-KSM está bem configurado.



Hardening


Vamos efetuar algumas configurações para tornar o sistema mais protegido. Vamos começar criando o arquivo harden.ini que têm como objetivo ajustar a segurança e o comportamento do PHP.

vim /etc/php/8.1/mods-available/harden.ini
display_errors = Off
log_errors = On

A primeira linha desativa a exibição de erros no navegador ou na saída padrão. Já a segunda linha ativa o registro de erros no arquivo de log configurado no PHP. Para aplicar essa configuração faça:

# Ative a configuração acima:
$ sudo phpenmod harden

# Reinicie o Apache:
$ sudo systemctl restart apache2

# Veja se deu certo:
$ php -i | grep -E "display_errors|log_errors"

Configure um firewall local para restringir o acesso ao serviço do YK-KSM, permitindo comunicação apenas com os servidores que realmente precisam acessá-lo. Isso aumenta a segurança, limitando a exposição do serviço na rede.

# Instale o iptables-persistent:
$ sudo apt install iptables-persistent -y

# Agora configure essas regras básicas:
cat << 'EOF' > /etc/iptables/rules.v4
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 4 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 12 -j ACCEPT
-A INPUT -p udp -m udp -m multiport --dports 33433:33690 -j ACCEPT
-A INPUT -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[iptables denied]: "
COMMIT
EOF

Lembrando você deve liberar a porta do SSH para não ficar preso do lado de fora do servidor e ainda deve liberar as portas 80 e 443.



Instalação do YK-VAL


Primeiro, você deve baixar e instalar a versão mais recente do YK-VAL:

# Entre no diretório abaixo:
$ cd /usr/src/

# Baixe o pacote:
$ sudo git clone https://github.com/YubicoLabs/yubikey-val.git

# Entre dentro do diretório:
$ cd yubikey-val

# Agora vamos compilar:
$ sudo make install

Dependendo da sua distribuição, o grupo do Apache (ou do servidor HTTP) pode ser diferente de www-data, usado no Debian e Ubuntu. No Red Hat, Fedora ou CentOS o grupo é apache, e no SUSE é www.

$ sudo make install wwwgroup=www-data


Web Server e PHP


Devemos instalar o Web Server e PHP, como ja instalamos nessa maquina e vamos usar a mesma para VAL e KSM, não precisa, mas vou deixar o comando de ambos os tipos para facilitar.

# Para instalar o VAL num servidor separado:
$ sudo apt install -y apache2 php php-curl php-pear

# Quando já temos Web Server e PHP:
$ sudo apt install -y php-curl php-pear


Banco de dados


Para o mysql é a mesma coisa, já instalamos tudo, mas caso precise instalar do zero:

# Para instalar o VAL num servidor separado:
$ sudo apt install -y mysql-server php-mysql

# Rode o script inicial do mysql:
$ sudo mysql_secure_installation

# O processo abaixo deve ser realizado tanto para servidores VAL separados quanto para no mesmo servidor do KSM:
$ echo 'create database ykval' | mysql

# Vamos popular o banco com as tabelas necessárias:
$ mysql ykval < /usr/share/doc/yubikey-val/ykval-db.sql

Crie o Banco de dados e o usuário específico para o YK-VAL:

sudo mysql --silent ykval

# Crie um usuário dentro do mysql (MySQL 5.7 or MySQL 8 or newer:):
CREATE USER 'ykval_verifier'@'localhost' IDENTIFIED BY '8PxMczhNEY9A_2PnJuJSPMZCU';

# De as permissões abaixo para o usuario criado:
GRANT SELECT,INSERT,UPDATE(modified, yk_counter, yk_low, yk_high, yk_use, nonce) ON ykval.yubikeys TO 'ykval_verifier'@'localhost';
GRANT SELECT,INSERT,UPDATE(id, secret, active) ON ykval.clients TO 'ykval_verifier'@'localhost';
GRANT SELECT,INSERT,UPDATE,DELETE ON ykval.queue TO 'ykval_verifier'@'localhost';
FLUSH PRIVILEGES;
exit


Configurar a Verificação de Interface OTP


A interface de verificação OTP é implementada com um script PHP, que pode ser configurado em qualquer URL. Entretanto, recomendamos hospedá-lo em: http://$servername/wsapi/verify. Para simplificar o processo, use links simbólicos que apontam para os arquivos do YK-VAL. Siga as etapas abaixo:

# O comando abaixo cria automaticamente os links simbólicos necessários:
$ sudo make symlink
install -d /var/www/wsapi/2.0
ln -sf /usr/share/yubikey-val/ykval-verify.php /var/www/wsapi/2.0/verify.php
ln -sf /usr/share/yubikey-val/ykval-sync.php /var/www/wsapi/2.0/sync.php
ln -sf /usr/share/yubikey-val/ykval-resync.php /var/www/wsapi/2.0/resync.php
ln -sf 2.0/verify.php /var/www/wsapi/verify.php

Após criar os links simbólicos, edite o arquivo ykval-verify.php para incluir o caminho correto das dependências. Abra o arquivo com seu editor preferido, como vim:

# Edite o arquivo abaixo:
$ sudo vim /usr/share/yubikey-val/ykval-verify.php

# Insira as seguintes configurações no início do arquivo para ajustar os caminhos:
ini_set('include_path', '/etc/yubico/val:/usr/src/yubikey-val');

# Deve ficar acima dos requires abaixo:
require_once 'ykval-common.php';
require_once 'ykval-config.php';
require_once 'ykval-synclib.php';
require_once 'ykval-log-verify.php';

# Agora ajuste as permissões dos scripts:
$ sudo chown www-data. /usr/share/yubikey-val/ykval-{common,synclib,log-verify}.php


Configurando o Caminho de Inclusão para o Daemon de Fila


Para que o daemon de fila funcione corretamente com os arquivos de configuração do YK-VAL, é necessário criar um arquivo que defina o caminho de inclusão apropriado. Para isso, use o comando abaixo:

$ cat << 'EOF' > /etc/default/ykval-queue
DAEMON_ARGS="/etc/yubico/val:/usr/share/yubikey-val"
EOF

O argumento DAEMON_ARGS define os diretórios onde estão localizados os arquivos de configuração e as bibliotecas necessárias para o daemon.



Configurando o YK-VAL


Para configurar o YK-VAL, é necessário criar e ajustar o arquivo ykval-config.php, que define as configurações essenciais, incluindo conexões ao banco de dados e detalhes de sincronização.

# Comece editando o arquivo abaixo:
$ sudo vim /etc/yubico/val/ykval-config.php

Normalmente, só será preciso modificar o DSN (YKVAL_DB_DSN), as senhas do banco de dados (YKVAL_DB_PW), as listas do sync pool caso tenha mais de um servidor de validação (YKVAL_SYNC_POOL e YKVAL_ALLOWED_SYNC_POOL), e as URLs do YK-KSM dentro da função otp2ksmurls. Abaixo você pode ver exemplo usando uma configuração para o MySQL:

/etc/yubico/val/ykval-config.php
# Modifique a senha:
$dbpass = '8PxMczhNEY9A_2PnJuJSPMZCU';

# Para Mysql:
$baseParams['__YKVAL_DB_DSN__'] = "mysql:dbname=ykval;host=127.0.0.1";

# Para melhorar o desempenho do banco de dados, você pode usar conexões persistentes,
# evitando que cada requisição necessite de uma nova conexão.
# Para habilitar isso, modifique `YKVAL_DB_OPTIONS` da seguinte forma:
$baseParams['__YKVAL_DB_OPTIONS__'] = array(PDO::ATTR_PERSISTENT => true);

Se estiver executando um servidor KSM deparado (ou não), ainda existem alguns ajustes que podem ser feitos:

    return array(
// "https://ykksm1.example.com/wsapi/decrypt?otp=$otp",
// "https://ykksm2.example.com/wsapi/decrypt?otp=$otp",
"http://127.0.0.1:80/wsapi/decrypt?otp=$otp",
"http://127.0.0.1:8002/wsapi/decrypt?otp=$otp",
);

As opções acima indicam o servidor KSM, comente a conexão via porta 8002 ou 80, se for no mesmo servidor. Se for outro servidor, ajuste o endereço IP.

Após criar o arquivo, ajuste as permissões para garantir que apenas o usuário autorizado possa acessá-lo:

$ sudo chmod 640 /etc/yubico/val/ykval-config.php

$ sudo chown root.www-data /etc/yubico/val/ykval-config.php

Se você estiver operando com vários servidores de validação no ambiente, é altamente recomendado adicionar os hosts usados no pool de sincronização (YKVAL_SYNC_POOL) diretamente no arquivo /etc/hosts de cada servidor. Isso ajuda a evitar atrasos que podem ocorrer devido a consultas DNS durante o processo de sincronização entre os servidores.

$ cat << 'EOF' >> /etc/hosts
127.0.0.1 api.example.com
192.168.10.15 api1.example.com
EOF


Configurando o Web Server


Configure o Apache para hospedar a interface HTTP do YK-VAL seguindo os passos abaixo:

# Crie uma configuração para o acesso ao ykval no servidor web:
$ cat << 'EOF' > /etc/apache2/sites-available/ykval.conf
<VirtualHost *:80>
ServerName api.example.com
ServerAdmin support@example.com

DocumentRoot /var/www/

<Directory "/var/www/wsapi">
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ $1.php [L]
</Directory>

<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>

<Directory /var/www/>
Options FollowSymLinks
AllowOverride All
Order allow,deny
allow from all
</Directory>

ErrorLog /var/log/apache2/ykval-error.log
LogLevel warn

CustomLog /var/log/apache2/ykval-access.log "%h %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\""
ServerSignature On

</VirtualHost>
EOF

# Ative a configuração do site criado com o comando abaixo:
$ sudo a2ensite ykval

# Certifique-se de que o módulo 'rewrite' está habilitado:
$ sudo a2enmod rewrite

# Certifique-se de que o módulo 'php' está habilitado:
$ sudo a2enmod php8.1

# Recarregue o servidor Apache para aplicar as alterações:
$ sudo systemctl restart apache2

Uso de TLS

Embora o uso de HTTPS não seja obrigatório, recomendamos fortemente configurá-lo para maior segurança. Instale uma pilha TLS no Apache, como mod_ssl ou mod_gnutls, e configure um certificado TLS usando ferramentas como certtool ou certbot. Escolha o método que melhor se adapta ao seu ambiente e siga as instruções de configuração padrão para Apache com suporte a TLS.

Logs


A interface PHP do YK-VAL utiliza o syslog para registrar as requisições recebidas, assim como o YK-KSM, usando a facility LOG_LOCAL0. Lembre-se que o YK-KSM também usa a mesma facility para armazenar os logs em um arquivo separado. Caso estejam no mesmo servidor, altere a facility, se for servidor diferentes, pode deixar na mesma.

# Crie o arquivo de configuração abaixo:
$ cat << 'EOF' > /etc/rsyslog.d/ykval.conf
local0.* -/var/log/ykval.log
EOF


# Crie o arquivo de configuração para rotação de logs:
$ cat << 'EOF' > /etc/logrotate.d/ykval
/var/log/ykval.log {
weekly
dateext
compress
missingok
rotate 9999
notifempty
postrotate
invoke-rc.d rsyslog reload > /dev/null
endscript
}
EOF


# Corrija as permissões do arquivo de log:
$ touch /var/log/ykval.log
$ sudo chmod 644 /var/log/ykval.log
$ sudo chown syslog:adm /var/log/ykval.log


## Agora vamos impedir que os logs fiquem duplicados, estando no arquivo syslog e no arquivo configurado acima.

# Edite o arquivo padrão de configuração do rsyslog:
$ sudo vim /etc/rsyslog.d/50-default.conf

## Encontre a linha abaixo:
*.*;auth,authpriv.none -/var/log/syslog

## Altere para excluir local0:
*.*;auth,authpriv.none,local0.none -/var/log/syslog


# Reinicie o serviço Rsyslog para aplicar as mudanças:
$ sudo systemctl restart rsyslog


Iniciar Daemon de Sincronização


Ao usar o yubikey-val em um sync pool, o daemon ykval-queue deve estar em execução para garantir a sincronização dos dados entre os servidores do pool. Embora você possa iniciá-lo manualmente com:

$ sudo ykval-queue

A prática recomendada é automatizar sua execução em segundo plano, garantindo que ele seja iniciado automaticamente e gerenciado de forma confiável. A configuração exata depende do sistema operacional. Nos sistemas modernos, geralmente é melhor configurar o ykval-queue como um serviço, utilizando ferramentas como systemd ou scripts de inicialização padrão. Isso assegura que o daemon será iniciado no boot e reiniciado automaticamente caso falhe.



Sincronizar dados de um servidor existente (opcional)

Ao adicionar um novo servidor a um pool de sincronização, é possível importar os dados de contador de YubiKeys de um servidor existente. Primeiro, no servidor existente, edite o arquivo de configuração /etc/yubico/val/ykval-config.php e adicione o endereço IP do novo servidor às seguintes configurações:

  • YKRESYNC_IPS
    Adicione o IP do novo servidor para permitir a sincronização completa.

  • YKVAL_ALLOWED_SYNC_POOL
    Adicione o IP do novo servidor para autorizar a comunicação no pool de sincronização.


Depois de liberar a comunicação entre os servidores, siga os passos abaixo para iniciar a sincronização:

# Iniciar a Sincronização completa:
$ sudo ykval-synchronize http://<IP ou nome do host do servidor existente>/wsapi/2.0/resync all

Resolvendo os problemas


Agora vamos corrigir todos os problemas nos scripts que o YK-KSM utiliza. Esses problemas ocorrem devido à compatibilidade com versões antigas do PHP. O objetivo é atualizar o código para garantir que funcione corretamente em versões mais recentes do PHP, eliminando erros de sintaxe e funções obsoletas.



Correção de sintaxe

Vamos corrigir uma função depreciada no script ykval-log.php. Basicamente, a nova função adiciona suporte para tratar instâncias de CurlHandle. Essa melhoria resolve possíveis problemas de registro de informações quando a variável $value no array $extra é uma instância de CurlHandle, o que pode causar erros ou gerar mensagens ilegíveis nos logs.

/usr/src/yubikey-val/ykval-log.php
//    public function log ($priority, $message, $extra = NULL)
// {
// $prefix = '';
// foreach ($this->fields as $val)
// $prefix .= "[$val] ";
//
// $suffix = '';
// if (is_array($extra)) {
// foreach($extra as $key => $value) {
// if (is_array($value)) {
// $value = implode(':', $value);
// }
// $suffix .= " $key=$value ";
// }
// }
//
// $message = $prefix . $message . $suffix;
//
// $message = implode(':', array(
// $this->log_levels[$priority],
// $this->name,
// $message
// ));
//
// syslog($priority, $message);
// }

public function log ($priority, $message, $extra = NULL)
{
$prefix = '';
foreach ($this->fields as $val)
$prefix .= "[$val] ";

$suffix = '';
if (is_array($extra)) {
foreach($extra as $key => $value) {
if (is_array($value)) {
$value = implode(':', $value);
} elseif ($value instanceof CurlHandle) {
// Converte o CurlHandle para uma string legível
$value = json_encode(curl_getinfo($value));
}
$suffix .= " $key=$value ";
}
}

$message = $prefix . $message . $suffix;

$message = implode(':', array(
$this->log_levels[$priority],
$this->name,
$message
));

syslog($priority, $message);
}

Agora faça um reboot!



Validando a configuração do YK-VAL


Agora já podemos validar o nosso serviço fazendo um teste de solicitação para a URL do servidor. Por exemplo:

# Faça um teste para o servidor:
$ curl 'http://localhost/wsapi/2.0/verify.php?id=1&nonce=asdmalksdmlkasmdlkasmdlakmsdaasklmdlak&otp=dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh'
h=z2qq4VPHOCmCiDqlCRRlVpS0E28=
t=2024-11-13T21:48:34Z0741
status=NO_SUCH_CLIENT

Naturalmente, você precisará importar as chaves dos clientes no banco de dados para que a função de verificação funcione corretamente.



Criando a chave de API dos clientes


Para que um cliente possa autenticar um OTP de YubiKey com o serviço de validação, é necessário um ID de cliente e uma chave secreta correspondente (a chave secreta é usada apenas para verificações autenticadas). Para criar um novo cliente no banco de dados com uma chave secreta gerada automaticamente, o comando ykval-gen-clients pode ser utilizado.

# Crie chave de clientes, vamos criar 5 chaves:
$ sudo ykval-gen-clients --urandom 5
1,fMdDnda/Sh/Jb+UA0FCR1P/0sds=
2,jdmtvMdZbLiaQKW+krMdIy37mCQ=
3,2yQrl7byjVE7uxZ5XxogHtL2VFs=
4,D9u8hy3EtXTprcQnHVZS8KAI6yA=
5,376kW15yFZ6Bfs2OCoYP9fvJ7x8=

# É possível ver as chaves no banco com o comando abaixo:
$ echo "select * from clients;" | sudo mysql -u root ykval
id active created secret email notes otp
1 1 1731534608 fMdDnda/Sh/Jb+UA0FCR1P/0sds=
2 1 1731534608 jdmtvMdZbLiaQKW+krMdIy37mCQ=
3 1 1731534608 2yQrl7byjVE7uxZ5XxogHtL2VFs=
4 1 1731534608 D9u8hy3EtXTprcQnHVZS8KAI6yA=
5 1 1731534608 376kW15yFZ6Bfs2OCoYP9fvJ7x8=

## Também podemos exportar os clientes, uma forma de ver os dados:
$ sudo ykval-export-clients

Antes de começarmos os testes, instale a ferramenta libykclient-dev. Depois vamos poder executar comandos de teste:

# Instale a ferramenta mencionada:
$ sudo apt install libykclient-dev

# Faça um teste usando a chave configurada no KSM, a API com indice 1 deve ser a chave com indice 1 no KSM:
$ ykclient --url "http://127.0.0.1/wsapi/2.0/verify.php?id=%d&otp=%s" --apikey +nzbRHG3/zZUEHuLBSPahBL0XS8= 1 --debug cccccccccccbclfcfhlbrgtrhflncibduilclkfjvrhc
Input:
validation URL: http://127.0.0.1/wsapi/2.0/verify.php?id=%d&otp=%s
client id: 1
token: cccccccccccbclfcfhlbrgtrhflncibduilclkfjvrhc
api key: +nzbRHG3/zZUEHuLBSPahBL0XS8=
Response from: http://127.0.0.1/wsapi/2.0/verify.php?id=1&nonce=thicumwynokidejqrinrcafaneqtxtxt&otp=cccccccccccbclfcfhlbrgtrhflncibduilclkfjvrhc&h=sIgO6ycNgVZZ1BZ3tQDzQ5x8wmw%3D
Verification output (0): Success
otp: cccccccccccbclfcfhlbrgtrhflncibduilclkfjvrhc
nonce: thicumwynokidejqrinrcafaneqtxtxt
t: 2024-11-17T22:13:07Z0409
timestamp: (null)
sessioncounter: (null)
sessionuse: (null)
sl: 0
status: OK


# Tente novamente com o mesmo OTP, vera um erro:
$ ykclient --url "http://127.0.0.1/wsapi/2.0/verify.php?id=%d&otp=%s" --apikey +nzbRHG3/zZUEHuLBSPahBL0XS8= 1 --debug cccccccccccbclfcfhlbrgtrhflncibduilclkfjvrhc
Input:
validation URL: http://127.0.0.1/wsapi/2.0/verify.php?id=%d&otp=%s
client id: 1
token: cccccccccccbclfcfhlbrgtrhflncibduilclkfjvrhc
api key: +nzbRHG3/zZUEHuLBSPahBL0XS8=
Response from: http://127.0.0.1/wsapi/2.0/verify.php?id=1&nonce=mrbyzydtdgupusjxqmnuumseagzjfkft&otp=cccccccccccbclfcfhlbrgtrhflncibduilclkfjvrhc&h=BYYkqHuJpGDPe6wSLMlfyxsJTTg%3D
Verification output (2): Yubikey OTP was replayed (REPLAYED_OTP)
otp: cccccccccccbclfcfhlbrgtrhflncibduilclkfjvrhc
nonce: mrbyzydtdgupusjxqmnuumseagzjfkft
t: 2024-11-17T22:17:35Z0273
timestamp: (null)
sessioncounter: (null)
sessionuse: (null)
sl: (null)
status: REPLAYED_OTP


Habilitando HTTPS


Habilite o módulo mod_ssl, ele já vem instalado e só necessário habilitar.

user@val:~$ sudo a2enmod ssl
Enabling module ssl.
Run '/etc/init.d/apache2 restart' to activate new configuration!

Agora vamos configurar o apache para incluir as chaves de TLS:

user@val:~$ sudo sh -c 'cat > /etc/apache2/sites-available/ykval-ssl.conf'
<VirtualHost *:443>
ServerName api.example.com
ServerAdmin support@example.com

SSLEngine on
SSLCertificateFile /etc/ssl/private/api.example.com-chain.pem
SSLCertificateChainFile /etc/ssl/private/api.example.com-chain.pem
SSLCertificateKeyFile /etc/ssl/private/api.example.com-key.pem

DocumentRoot /var/www/
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/www/>
Options FollowSymLinks
AllowOverride All
Order allow,deny
allow from all
</Directory>

ErrorLog /var/log/apache2/ykval-ssl-error.log
LogLevel warn

CustomLog /var/log/apache2/ykval-ssl-access.log "%h %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\""
ServerSignature On

</VirtualHost>

Agora vamos habilitar os últimos módulos e reiniciar o apache2:

# Habilite o módulo de reescrita:
user@val:~$ sudo a2enmod rewrite
Enabling module rewrite.
Run '/etc/init.d/apache2 restart' to activate new configuration!

# Desative o site padrão do apache:
user@val:~$ sudo a2dissite default
Site default disabled.
Run '/etc/init.d/apache2 reload' to activate new configuration!

# Habilite os dois sites 'ykval' e 'ykval-ssl':
user@val:~$ sudo a2ensite ykval ykval-ssl
Enabling site ykval.
Enabling site ykval-ssl.
Run '/etc/init.d/apache2 reload' to activate new configuration!

# Reinicie o serviço do apache2:
user@val:~$ sudo systemctl restart apache2


Habilitando Revogação de chave


Habilita o revoke https://github.com/YubicoLabs/yubikey-val/blob/master/doc/Revocation_Service.adoc



Fontes


https://www.yubico.com/

https://support.yubico.com/hc/en-us/articles/360016649099-Ubuntu-Linux-Login-Guide-U2F

https://developers.yubico.com/python-pyhsm/YubiKey_KSM.html

https://www.yubico.com/products/software-development-toolkits-sdks/

https://www.yubico.com/products/hardware-security-module/

https://developers.yubico.com/pam-u2f/

https://developers.yubico.com/yubico-pam/YubiKey_and_SSH_via_PAM.html

https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html

https://www.linode.com/docs/guides/how-to-use-yubikey-for-two-factor-ssh-authentication/

https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html

https://developers.yubico.com/OTP/Guides/Self-hosted_OTP_validation.html

https://www.yubico.com/products/yubicloud/

https://support.yubico.com/hc/en-us/articles/360021227000-YK-VAL-YK-KSM-and-YubiHSM-1-End-of-Life

https://developers.yubico.com/pam-u2f/

https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html

http://www.freedesktop.org/wiki/Software/pkg-config

https://github.com/json-c/json-c/wiki

https://support.yubico.com/support/solutions/articles/15000006449-using-your-u2f-yubikey-with-linux

https://github.com/Yubico/libu2f-host/blob/master/70-u2f.rules

https://developers.yubico.com/yubico-pam/

https://developers.yubico.com/yubico-pam/Releases/

https://support.yubico.com/support/solutions/articles/15000011356-ubuntu-linux-login-guide-u2f#2_Installing_the_Required_Software

https://github.com/YubicoLabs/yubikey-ksm/blob/master/doc/Installation.adoc

https://github.com/YubicoLabs/yubikey-val/blob/master/doc/Installation.adoc

https://github.com/YubicoLabs/yubikey-ksm/blob/master/doc/Generate_KSM_Key.adoc

https://github.com/YubicoLabs/yubikey-ksm/blob/master/doc/Generate_Keys.adoc

https://github.com/YubicoLabs/yubikey-ksm/blob/master/doc/Import_Keys_To_KSM.adoc

https://developers.yubico.com/PIV/Introduction/Certificate_slots.html

https://developers.yubico.com/OTP/OTPs_Explained.html

https://developers.yubico.com/WebAuthn/