WiFi no Raspberry Pi

Agora que o Raspberry Pi está com as configurações básicas prontas, (veja o post anterior), o próximo passo é simplificar a conexão dele com a internet.

Quero deixá-lo em um lugar onde não atrapalhe. Quanto menos fios e cabos precisar melhor, portanto WiFi é uma opção melhor do que Ethernet.

Esse Raspberry Pi é bem antigo e não tem WiFi integrado na placa e precisa de um adaptador USB-WiFi.

Mas vamos lá para a configuração. Para quem não sabe, o sistema operacional do Raspberry OS (ou Raspbian) é baseado no Debian Linux e podemos usar muito da documentação deste.

O link abaixo explica como configurar o WiFi no Debian:

https://wiki.debian.org/WiFi/HowToUse#Using_ifupdown

Primeiro precisamos determinar qual é o nome do adaptador WiFi (seja ele integrado na placa ou via USB). Para isso logamos usando SSH e usamos o comando ip a, que lista as interfaces de rede.

$ ip a
> 1: lo: ...
> 2: eth0: ...
> 3: wlan0: ...

A saída do comando tem um tanto a mais de informação do que estou mostrando. Porém podemos identificar "wlan0" como a interface WiFi.

Agora vamos criar um arquivo de configuração para a rede sem fio:

  1. Usamos sudo su para mudar para o usuário root;
  2. Mudamos a máscara de criação de arquivos para 077, que faz com que apenas o dono do arquivo tenha acesso. Isso é importante para evitar os usuários possam ler o arquivo abaixo, que vai conter a senha do WiFi
  3. Criamos o arquivo de configuração usando o comando touch; e
  4. Editamos o arquivo (com o editor nano) adicionando a configuração mostrada em seguida.
$ sudo su
$ uname 077
$ touch /etc/network/interfaces.d/wlan0.conf
$ nano /etc/network/interfaces.d/wlan0.conf

O arquivo de configuração pode ter qualquer nome. Para facilitar coloco o nome da interface que ele configura.

O conteúdo do arquivo de configuração é mostrado abaixo, configurando a interface para ser detectada automaticamente, usar DHCP para obter um endereço de IP e também configura o SSID da rede (nome da rede sem fio) e a sua senha.

# Arquivo: /etc/network/interfaces.d/wlan0.conf mode=0600
allow-hotplug wlan0
iface wlan0 inet dhcp
    wpa-ssid NOME_DA_REDE
    wpa-psk SENHA_DA_REDE

Note que no arquivo de configuração precisamos especificar corretamente o nome da interface de rede duas vezes, "wlan0" no meu caso.

Raspberry Pi modelo B com WiFi

Agora é só reiniciar o Raspberry Pi, desconectar todos os cabos desnecessários e curtir ele através da rede sem fio. Agora, a única coisa que ele precisa é uma tomada.

Revivendo um Raspberry Pi B (modelo antigo)

Tenho um Raspberry Pi antigo, modelo B, e quero fazer ele voltar à vida para rodar testes de projetos multiplataforma.

Gravando o Cartão SD

Entrando no site do Raspberry Pi, encontramos a página de downloads. Optei por escolher a imagem manualmente na página abaixo.

https://www.raspberrypi.com/software/operating-systems/

Como pretendo criar um servidor, não preciso da imagem desktop, podendo utilizar a imagem "lite" (leve), que tem apenas a linha de comando.

Fiz o download da imagem "Raspberry Pi OS Lite (32-bit)", obtendo o arquivo "2022-09-22-raspios-bullseye-armhf-lite.img.xz".

Se você tiver algum modelo mais novo do Raspberry Pi, é possível usar uma imagem "Raspberry Pi OS Lite (64-bit)". Há uma lista dos modelos que suportam o sistema 64-bits.

Para extrair a imagem usamos o comando xz. Isso remove o arquivo compactado .img.xz cria um arquivo descompactado .img.

$ xz -d 2022-09-22-raspios-bullseye-armhf-lite.img.xz

Então, para gravá-la usamos o comando dd, enviando os dados para o cartão SD no caminho /dev/mmcblk0.

$ dd if=2022-09-22-raspios-bullseye-armhf-lite.img of=/dev/mmcblk0

Se tiver dúvidas sobre qual é o seu cartão de memória, o comando ls -lrt /dev/ vai te mostrar uma lista com os dispositivos detectados no sistema, listados do mais velho para o mais novo.

Se quiser também é possível escrever no cartão SD enquanto extrai, sem criar o arquivo descomprimido.

$ xz -dc 2022-09-22-raspios-bullseye-armhf-lite.img.xz | dd of=/dev/mmcblk0

Antes do Primeiro Boot

Habilitando SSH

Para realizar algumas modificações montei a partição de root e de boot do Raspberry Pi.

$ mount /dev/mmcblk0p2 /mnt
$ mount /dev/mmcblk0p1 /mnt/boot

Na pasta /mnt/boot (/boot do Raspberry Pi) criei um arquivo vazio chamado ssh, que faz o servidor SSH ser habilitado no primeiro boot.

touch /mnt/boot/ssh

Obsoleto: Isso evita ter que acessar o mini computador com tela e teclado só para habilitar o SSH. Assim posso ir direto para o acesso remoto.

Infelizmente, agora é preciso configurar usuário e senha no primeiro boot. Então parece ser obrigatório conectar uma tela e teclado. Deve haver algum jeito de evitar isso.

Agora basta desmontar a partição e iniciar o Raspberry Pi com o cartão SD.

$ umount /dev/mmcblk0p1
$ umount /dev/mmcblk0p2

Raspberry Pi modelo B

Primeiro Boot

As primeiras coisas a fazer são:

  • Escolher o usuário
  • Escolher a senha
  • Identifique o IP no roteador (no meu caso é 192.168.0.101)
  • Instalar chave SSH (opcional)
    $ ssh-copy-id [email protected]
    
  • Fazer o login pelo SSH
    $ ssh [email protected]
    
  • Atualizar
    pi$ sudo apt update
    pi$ sudo apt upgrade
    
  • Reduzir a memória da GPU
    pi$ sudo raspi-config
    
    • 4 Performance Options
      • P2 GPU Memory
        • 8 > OK
    • Finish
  • Reiniciar
    pi$ sudo reboot
    

Ansible: Criptografando Senhas de Usuários

As vezes queremos gerar uma senha fixa para usuários, a qual vamos reutilizar em várias máquinas.

Um exemplo típico é criar usuário administrador, capaz de realizar login com senha. Dessa forma, caso ocorra algum problema com o servidor SSH ou perca a sua chave privada junto com o seu HD, ainda é possível fazer login direto na máquina, por VNC ou por outros meios de acesso remoto.

Porém essa é a senha de administrador de muitos computadores e não queremos colocá-la diretamente em scripts de configuração, como os do Ansible, onde podem ser lidas diretamente.

Podemos, no entanto, criar uma versão encriptada da senha (a mesma usada no arquivo /etc/shadow) e aí sim colocá-la no script.

O código abaixo cria uma senha segura 24 caracteres utilizando pwgen. A opção -s indica que a senha deve ser completamente aleatória.

$ pwgen -s 24 1
> VONga6jUFoXCMQNhDlHgTHQY

Por fim usamos openssl passwd para encriptar a senha gerada Usamos a opção -6 para criptografar a senha com SHA512.

$ openssl passwd -6 'VONga6jUFoXCMQNhDlHgTHQY'
> $6$80Ll7KOwC/XDQVgZ$NwTjYG8cXcMTr9NI1EbtaX7OEAIBq3ULUSJPmpjtk/vUiyB9duYO3aNqmWmBnS.mjgaN37/mo34R8COzNrFBh0

Dessa forma, a preciosa senha está segura, longe de olhos curiosos, e podemos colocá-la no script de criação de usuários.

# Arquivo:  tasks/default-tasks.yml
---
- name: Criar usuário admin com senha
  ansible.builtin.user:
    name: admin
    comment: Usuário Administrador
    password: "$6$80Ll7KOwC/XDQVgZ$NwTjYG8cXcMTr9NI1EbtaX7OEAIBq3ULUSJPmpjtk/vUiyB9duYO3aNqmWmBnS.mjgaN37/mo34R8COzNrFBh0"

Ansible: Testando Playbooks

Ansible é uma excelente ferramenta para automatização de tarefas.

Cria-se uma lista de computadores e instalando neles um servidor SSH e Python 3, é possível automatizar a instalação de programas, alteração de configurações e, o meu favorito, atualização dos computadores.

No maior estilo do TDD (Test Driven Development), muitas vezes, queremos ter certeza que algo está funcionando antes de prosseguir com a execução do playbook.

Exemplos destes casos são:

  • A nova configuração funciona?
  • O usuário realmente pode (não pode) usar usar sudo?
  • Login do usuário root está mesmo desativado?
  • O firewall liberou/bloqueou a porta HTTP?

Podemos criar testes como esses com certa facilidade e inclusive podemos escolher entre a máquina remota ou local para executar os comandos, o que é essencial para alguns testes.

Abaixo mostro dois exemplos, testando as permissões de um usuário do servidor remoto e testando se o computador local pode fazer login como root.

# Arquivo: tasks/testes.yml
---
- name: TESTE Verificar se o usuário 'admin' pode usar SUDO sem senha
  # Teste no servidor remoto:
  # - su admin -c "xxx": executa o comando xxx como admin;
  # - whoami: imprime o nome do usuário; e
  # - Esperamos que imprima 'admin' (sem o sudo) e em seguida
  #   imprima 'root' (com sudo).
  ansible.builtin.command: |
    su admin -c "whoami; sudo whoami"
  register: result
  changed_when: false
  failed_when: >
    result.stdout_lines[0] != 'admin'
    or result.stdout_lines[1] != 'root'
  timeout: 5

- name: TESTE Negar login do usuário 'root' port SSH
  # Teste no computador local:
  # - SSH, ativando senha e desativando chave pública;
  # - whoami: um comando qualquer para ser executado; e
  # - Esperamos que a tentativa de login seja negada.
  ansible.builtin.command: >
    ssh -oPasswordAuthentication=yes -oPubkeyAuthentication=no
    -p{{ ansible_port }} root@{{ ansible_host }} whoami
  register: result
  changed_when: false
  failed_when: "'Permission denied (publickey)' not in result.stderr"
  timeout: 5
  # Esta parte final definie que o teste é executado no computador local
  # (que executa o Ansible).
  # Desativamos ansible_become para que use o usuário atual, em vez de
  # usar sudo para se tornar root.
  delegate_to: localhost
  vars:
    ansible_become: false

Ansible: Variáveis Dependentes do Sistema Operacional

Ansible é uma excelente ferramenta para automatização de tarefas.

Cria-se uma lista de computadores e instalando neles um servidor SSH e Python 3, é possível automatizar a instalação de programas, alteração de configurações e, o meu favorito, atualização dos computadores.

No entanto, há coisas que são diferentes de um sistema para outro, por exemplo caminhos de arquivos de configuração e nomes de pacotes.

Para evitar criar várias e várias tarefas que fazem a mesma coisa ajustadas para cada sistema (when: ansible_distribution == ...), enchendo o playbook com código repetido, Ansible permite a importação de arquivos de variáveis com o módulo include_vars, onde podemos escolher dinamicamente o arquivo de variáveis correspondente ao sistema.

Então podemos criar um arquivo para cada um dos sistemas em uso e seguir em frente. Porém isso acaba por se tornar um pesadelo de manutenção: cada nova variável precisa ser adicionada em TODOS os arquivos de variáveis e, ao criar um arquivo de variáveis novo, é preciso atualizar todas as variáveis possíveis.

Uma alternativa interessante seria uma criar estrutura hierárquica, onde definimos valores padrão para todos, em seguida substituímos com os valores para a família, então com os valores para a distribuição e quem sabe até com valores para certas versões.

Padrão          default
                 /   \
Família      Debian  FreeBSD
              / \
Distro  Debian   Ubuntu

Além disso, é importante que a inexistência de algum desses arquivos de especialização não seja um empecilho.

Com um pouco de pesquisa e um pouco de tentativa-e-erro, e com "um pouco" quero dizer interminável, cheguei no código abaixo:

# Arquivo: tasks/default-tasks.yml
---
- name: Carrega variáveis padrão, da família e da distro
  ansible.builtin.include_vars: "{{ item }}"
  with_fileglob:
    - vars/default.yml
    - vars/family_{{ ansible_os_family }}.yml
    - vars/distro_{{ ansible_distribution }}.yml

Usamos include_vars, como de costume, porém junto com with_fileglob. Este geralmente é usado para encontrar vários arquivos usando coringas (wildcards) como vars/*.yml. Mas aqui não usamos coringas, damos direto o nome do arquivo. Se o arquivo não é encontrado ele é ignorado.

Abaixo estão exemplos dos arquivos de variáveis padrão e especializado.

# Arquivo: vars/default.yml
---
doas_config_file: /etc/doas.conf
# Arquivo: vars/family_FreeBSD.yml
---
doas_config_file: /usr/local/etc/doas.conf

Copiando a suas chaves SSH do GitHub ou GitLab

As vezes queremos copiar uma chave pública SSH para um computador.

Esse é um jeito fácil de adicionar a sua própria chave ou de adicionar a chave de alguém para te ajudar com algum problema.

Tendo uma conexão com a internet, é possível fazer o download das chaves públicas SSH de qualquer usuário do GitHub ou GitLab.

Com os comandos abaixo é possível fazer o download da chave adicioná-las nas chaves permitidas para acesso SSH. Basta trocar USUARIO pelo nome do usuário desejado.

  1. Configure a máscara de permissões para 077: leitura e escrita apenas para o usuário dono.
    • umask 077
  2. Crie a pasta ~/.ssh, se ela não existir.
    • mkdir -p ~/.ssh
  3. Faça o download das chaves:
    • GitHub: curl https://github.com/USUARIO.keys >>~/.ssh/authorized_keys
    • GitLab: curl https://gitlab.com/USUARIO.keys >>~/.ssh/authorized_keys

Também podemos usar wget em vez de curl, substituindo curl por wget -O-.