migración
BIN
src/assets/images/gatofondo.png
Normal file
After Width: | Height: | Size: 149 KiB |
BIN
src/content/posts/2023-02-15_cortafuegos1/featured.png
Normal file
After Width: | Height: | Size: 407 KiB |
246
src/content/posts/2023-02-15_cortafuegos1/index.md
Normal file
@ -0,0 +1,246 @@
|
||||
---
|
||||
title: "Cortafuegos I: De nodo con iptables"
|
||||
published: 2023-02-15
|
||||
image: "./featured.png"
|
||||
tags: ["Cortafuegos", "iptables"]
|
||||
category: Documentación
|
||||
draft: false
|
||||
---
|
||||
|
||||
Enunciado: [https://fp.josedomingo.org/seguridadgs/u03/ejercicio1.html](https://fp.josedomingo.org/seguridadgs/u03/ejercicio1.html)
|
||||
|
||||
## Preparación
|
||||
|
||||
**Limpiamos las reglas previas**
|
||||
|
||||
```bash
|
||||
iptables -F
|
||||
iptables -t nat -F
|
||||
iptables -Z
|
||||
iptables -t nat -Z
|
||||
```
|
||||
|
||||
**Acceso por SSH**
|
||||
|
||||
Antes de añadir la política por defecto voy a añadir reglas para permitir el acceso por ssh
|
||||
|
||||
```bash
|
||||
iptables -A INPUT -s 172.22.0.0/16 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A OUTPUT -d 172.22.0.0/16 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Estas reglas sirve para acceder desde la misma red, además añado las siguientes para acceder a través de la VPN
|
||||
|
||||
```bash
|
||||
iptables -A INPUT -s 172.29.0.0/16 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A OUTPUT -d 172.29.0.0/16 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Ahora añado las **políticas por defecto**
|
||||
|
||||
```bash
|
||||
iptables -P INPUT DROP
|
||||
iptables -P OUTPUT DROP
|
||||
```
|
||||
|
||||
Ahora pruebo que se han aplicado, por ejemplo, haciendo un ping:
|
||||
|
||||
![ping](https://i.imgur.com/GgWurZe.png)
|
||||
|
||||
**Permitimos tráfico por la interfaz de loopback**
|
||||
|
||||
```bash
|
||||
iptables -A INPUT -i lo -p icmp -j ACCEPT
|
||||
iptables -A OUTPUT -o lo -p icmp -j ACCEPT
|
||||
```
|
||||
|
||||
**Peticiones y respuestas del protocolo ICMP**
|
||||
|
||||
```bash
|
||||
iptables -A INPUT -i ens3 -p icmp --icmp-type echo-reply -j ACCEPT
|
||||
iptables -A OUTPUT -o ens3 -p icmp --icmp-type echo-request -j ACCEPT
|
||||
```
|
||||
|
||||
Pruebo que funciona haciendo un ping
|
||||
|
||||
![ping2](https://i.imgur.com/eTTjjEV.png)
|
||||
|
||||
**Consultas y respuestas DNS**
|
||||
|
||||
```bash
|
||||
iptables -A OUTPUT -o ens3 -p udp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A INPUT -i ens3 -p udp --sport 53 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Pruebo que funciona haciendo una consulta DNS
|
||||
|
||||
![dns](https://i.imgur.com/Ep1vuVz.png)
|
||||
|
||||
**Tráfico HTTP**
|
||||
|
||||
```bash
|
||||
iptables -A OUTPUT -o ens3 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A INPUT -i ens3 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Pruebo que funciona haciendo una consulta HTTP
|
||||
|
||||
![http](https://i.imgur.com/aB17haB.png)
|
||||
|
||||
**Tráfico HTTPS**
|
||||
|
||||
```bash
|
||||
iptables -A OUTPUT -o ens3 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A INPUT -i ens3 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Pruebo que funciona haciendo una consulta HTTPS
|
||||
|
||||
![https](https://i.imgur.com/BzyJeje.png)
|
||||
|
||||
**Tráfico HTTP/HTTPs**
|
||||
|
||||
Los dos puntos anteriores se pueden resumir en una sola regla
|
||||
|
||||
```bash
|
||||
iptables -A OUTPUT -o ens3 -p tcp -m multiport --dports 80,443 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A INPUT -i ens3 -p tcp -m multiport --sports 80,443 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
**Acceso al servidor web**
|
||||
|
||||
```bash
|
||||
iptables -A INPUT -i ens3 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A OUTPUT -o ens3 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Pruebo que funciona haciendo una consulta HTTP desde el exterior
|
||||
|
||||
![web](https://i.imgur.com/1TbKhY2.png)
|
||||
|
||||
## Ejercicios
|
||||
|
||||
### 1. Permite poder hacer conexiones ssh al exterior
|
||||
|
||||
Para esto uso las reglas de ssh citas anteriormente:
|
||||
|
||||
```bash
|
||||
iptables -A INPUT -s 172.22.0.0/16 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A OUTPUT -d 172.22.0.0/16 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Estas reglas sirve para acceder desde la misma red, además añado las siguientes para acceder a través de la VPN
|
||||
|
||||
```bash
|
||||
iptables -A INPUT -s 172.29.0.0/16 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A OUTPUT -d 172.29.0.0/16 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
![ssh1](https://i.imgur.com/8h6tmFh.png)
|
||||
![ssh2](https://i.imgur.com/xhNYful.png)
|
||||
|
||||
### 2. Deniega el acceso a tu servidor web desde una ip concreta
|
||||
|
||||
Como ya he creado en la preparación una regla que permite el acceso al servidor web, para que el bloque funcione tengo que añadir la regla antes, ya que el orden es importante en iptables. Para ello, primero miro la posición de la regla que permite el acceso al servidor web
|
||||
|
||||
```bash
|
||||
iptables -L -n -v --line-numbers
|
||||
```
|
||||
|
||||
![iptables](https://i.imgur.com/VLs4Xd7.png)
|
||||
|
||||
La regla que permite el acceso está en la dirección 8; ahora creo la regla con la ip de mi máqunina:
|
||||
|
||||
```bash
|
||||
iptables -I INPUT 8 -s 172.29.0.42 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j DROP
|
||||
```
|
||||
|
||||
![iptables2](https://i.imgur.com/T361Yz0.png)
|
||||
|
||||
Ahora compruebo que no puedo acceder al servidor web desde mi máquina
|
||||
|
||||
![web](https://i.imgur.com/9xydTG9.png)
|
||||
|
||||
### 3. Permite hacer consultas DNS sólo al servidor 192.168.202.2. Comprueba que no puedes hacer un dig @1.1.1.1
|
||||
|
||||
Primero borro las reglas de DNS que he creado anteriormente
|
||||
|
||||
```bash
|
||||
iptables -D OUTPUT -o ens3 -p udp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -D INPUT -i ens3 -p udp --sport 53 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Y ahora añado las reglas nuevas, permitiendo solo el servidor 192.168.202.2:
|
||||
|
||||
```bash
|
||||
iptables -A OUTPUT -d 192.168.202.2 -p udp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A INPUT -s 192.168.202.2 -p udp --sport 53 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Ahora compruebo que no puedo hacer un `dig@1.1.1.1 www.josedomingo.org`:
|
||||
|
||||
![dns](https://i.imgur.com/May5Dwa.png)
|
||||
|
||||
Y si que puedo usando el dns, `dig@192.168.202.2 www.josedomingo.org`:
|
||||
|
||||
![dns2](https://i.imgur.com/1O9FXoM.png)
|
||||
|
||||
### 4. No permitir el acceso al servidor web de www.josedomingo.org, Tienes que utilizar la ip. ¿Puedes acceder a fp.josedomingo.org?
|
||||
|
||||
Al igual que en el ejercicio 2, primero miro la posición de la regla que permite el acceso al servidor web
|
||||
|
||||
![iptables](https://i.imgur.com/HbcTZPw.png)
|
||||
|
||||
Está en el lugar 5. Ahora creo la regla con la ip de josedomingo.org:
|
||||
|
||||
```bash
|
||||
iptables -I OUTPUT 5 -d 37.187.119.60 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j DROP
|
||||
```
|
||||
|
||||
Compruebo que se ha creado correctamente:
|
||||
|
||||
![iptables2](https://i.imgur.com/Xp4mGZu.png)
|
||||
|
||||
Ahora compruebo que no puedo acceder al servidor web de josedomingo.org
|
||||
|
||||
![web](https://i.imgur.com/POagTDZ.png)
|
||||
|
||||
y si que puedo acceder a portquiz.net:
|
||||
|
||||
![web2](https://i.imgur.com/f0SccEm.png)
|
||||
|
||||
### 5. Permite mandar un correo usando nuestro servidor de correo: babuino-smtp. Para probarlo ejecuta un telnet babuino-smtp.gonzalonazareno.org 25
|
||||
|
||||
Para hacerlo utilizo la ip de babuino:
|
||||
|
||||
```bash
|
||||
iptables -A OUTPUT -d 192.168.203.3 -p tcp --dport 25 -j ACCEPT
|
||||
iptables -A INPUT -s 192.168.203.3 -p tcp --sport 25 -j ACCEPT
|
||||
```
|
||||
|
||||
![smtp](https://i.imgur.com/tBoRNWu.png)
|
||||
|
||||
### 6. Instala un servidor mariadb, y permite los accesos desde la ip de tu cliente. Comprueba que desde otro cliente no se puede acceder
|
||||
|
||||
Instalo MariaDB:
|
||||
|
||||
```bash
|
||||
apt install mariadb-server
|
||||
```
|
||||
|
||||
Configuro el acceso remoto, editando el fichero `/etc/mysql/mariadb.conf.d/50-server.cnf`:
|
||||
|
||||
```bash
|
||||
bind-address = 0.0.0.0
|
||||
```
|
||||
|
||||
Tras eso, reinicio el servicio y añado la regla para permitir el acceso desde mi cliente:
|
||||
|
||||
```bash
|
||||
sudo iptables -A INPUT -s 172.29.0.42 -p tcp --dport 3306 -j ACCEPT
|
||||
sudo iptables -A OUTPUT -d 172.29.0.42 -p tcp --sport 3306 -j ACCEPT
|
||||
```
|
||||
|
||||
Ahora, en la siguiente captura, realizo una conexión con la base de datos desde el cliente, tras eso, desconecto la VPN para dejar de tener la IP que está autorizada, y vuelvo a intentar acceder, pero no puedo:
|
||||
|
||||
![mariadb](https://i.imgur.com/1Z8hCqe.png)
|
BIN
src/content/posts/2023-02-17_cortafuegos2/featured.png
Normal file
After Width: | Height: | Size: 459 KiB |
301
src/content/posts/2023-02-17_cortafuegos2/index.md
Normal file
@ -0,0 +1,301 @@
|
||||
---
|
||||
title: "Cortafuegos II: Perimetral con nftables"
|
||||
published: 2023-02-17
|
||||
image: "./featured.png"
|
||||
tags: ["Cortafuegos", "nftables"]
|
||||
category: Documentación
|
||||
draft: false
|
||||
---
|
||||
|
||||
## Enunciado
|
||||
|
||||
Realiza con nftables el ejercicio de la página [https://fp.josedomingo.org/seguridadgs/u03/perimetral_iptables.html](https://fp.josedomingo.org/seguridadgs/u03/perimetral_iptables.html) documentando las pruebas de funcionamiento realizadas.
|
||||
|
||||
Debes añadir después las reglas necesarias para que se permitan las siguientes operaciones:
|
||||
|
||||
|
||||
|
||||
## Preparación
|
||||
|
||||
El escenario es el siguiente
|
||||
|
||||
![escenario](https://i.imgur.com/ynMPcoB.png)
|
||||
|
||||
Instalo nftables en el cortafuegos
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install nftables
|
||||
```
|
||||
|
||||
Creo las tablas de filter y nat
|
||||
|
||||
```bash
|
||||
sudo nft add table inet filter
|
||||
sudo nft add table inet nat
|
||||
```
|
||||
|
||||
creo las cadenas de filter
|
||||
|
||||
```bash
|
||||
sudo nft add chain inet filter input { type filter hook input priority 0 \; counter \; policy accept \; }
|
||||
sudo nft add chain inet filter output { type filter hook output priority 0 \; counter \; policy accept \; }
|
||||
sudo nft add chain inet filter forward { type filter hook forward priority 0 \; counter \; policy accept \; }
|
||||
```
|
||||
|
||||
creo las cadenas de nat
|
||||
|
||||
```bash
|
||||
sudo nft add chain inet nat prerouting { type nat hook prerouting priority 0 \; }
|
||||
sudo nft add chain inet nat postrouting { type nat hook postrouting priority 100 \; }
|
||||
```
|
||||
|
||||
### SSH al cortafuegos
|
||||
|
||||
Ahora acepto el tráfico ssh entrante al router-fw
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter input ip saddr 172.22.0.0/16 tcp dport 22 ct state new,established counter accept
|
||||
sudo nft add rule inet filter output ip daddr 172.22.0.0/16 tcp sport 22 ct state established counter accept
|
||||
```
|
||||
|
||||
y entrante desde la VPN
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter input ip saddr 172.29.0.0/16 tcp dport 22 ct state new,established counter accept
|
||||
sudo nft add rule inet filter output ip daddr 172.29.0.0/16 tcp sport 22 ct state established counter accept
|
||||
```
|
||||
|
||||
### Política por defecto
|
||||
|
||||
Y pongo la política por defecto a drop:
|
||||
|
||||
```bash
|
||||
sudo nft chain inet filter input { policy drop \; }
|
||||
sudo nft chain inet filter output { policy drop \; }
|
||||
```
|
||||
|
||||
Ahora compruebo que puedo hacer ssh
|
||||
|
||||
![ssh](https://i.imgur.com/T2NL5kC.png)
|
||||
|
||||
![ssh2](https://i.imgur.com/7o6qhGY.png)
|
||||
|
||||
### Activar el bit de forward
|
||||
|
||||
En el cortafuegos, activo el bit de forwarding
|
||||
|
||||
![bitforward](https://i.imgur.com/Ooq3yo9.png)
|
||||
|
||||
### SNAT
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet nat postrouting oifname "ens3" ip saddr 192.168.100.0/24 counter masquerade
|
||||
```
|
||||
|
||||
![snat](https://i.imgur.com/bWXZJ8j.png)
|
||||
|
||||
### SSH desde el cortafuego a la LAN
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter output oifname "ens4" ip daddr 192.168.100.0/24 tcp dport 22 ct state new,established counter accept
|
||||
sudo nft add rule inet filter input iifname "ens4" ip saddr 192.168.100.0/24 tcp sport 22 ct state established counter accept
|
||||
```
|
||||
|
||||
![ssh3](https://i.imgur.com/WRuODxe.png)
|
||||
|
||||
### Tráfico para la interfaz loopback
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter output oifname "lo" counter accept
|
||||
sudo nft add rule inet filter input iifname "lo" counter accept
|
||||
```
|
||||
|
||||
![loopback](https://i.imgur.com/fEVtFCW.png)
|
||||
|
||||
### Peticiones y respuestas protocolo ICMP
|
||||
|
||||
Desde el cortafuegos a internet
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter input iifname "ens3" icmp type echo-request counter accept
|
||||
sudo nft add rule inet filter output oifname "ens3" icmp type echo-reply counter accept
|
||||
```
|
||||
|
||||
Ahora desde mi portátil hago un ping al cortafuegos:
|
||||
|
||||
![icmp](https://i.imgur.com/vO8QNUq.png)
|
||||
|
||||
### Reglas forward
|
||||
|
||||
#### ping desde la LAN
|
||||
|
||||
Desde el cortafuegos a la LAN
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter input iifname "ens4" icmp type echo-reply counter accept
|
||||
sudo nft add rule inet filter output oifname "ens4" icmp type echo-request counter accept
|
||||
```
|
||||
|
||||
![icmp](https://i.imgur.com/oeg8xx6.png)
|
||||
|
||||
#### Consultas y respuestas DNS desde la LAN
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip saddr 192.168.100.0/24 udp dport 53 ct state new,established counter accept
|
||||
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip daddr 192.168.100.0/24 udp sport 53 ct state established counter accept
|
||||
```
|
||||
|
||||
![dns](https://i.imgur.com/vnJEfIP.png)
|
||||
|
||||
#### Permitimos la navegación web desde la LAN
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter output oifname "ens3" ip protocol tcp tcp dport { 80,443 } ct state new,established counter accept
|
||||
sudo nft add rule inet filter input iifname "ens3" ip protocol tcp tcp sport { 80,443 } ct state established counter accept
|
||||
```
|
||||
|
||||
![web](https://i.imgur.com/s4Yw8Cl.png)
|
||||
|
||||
#### Permitimos el acceso a nuestro servidor web de la LAN desde el exterior
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip daddr 192.168.100.0/24 tcp dport 80 ct state new,established counter accept
|
||||
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip saddr 192.168.100.0/24 tcp sport 80 ct state established counter accept
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet nat prerouting iifname "ens3" tcp dport 80 counter dnat ip to 192.168.100.10
|
||||
```
|
||||
|
||||
![web2](https://i.imgur.com/C69ZdJ8.png)
|
||||
|
||||
|
||||
## Reglas del enunciado
|
||||
|
||||
### Permite poder hacer conexiones ssh al exterior desde la máquina cortafuegos
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter output oifname "ens3" tcp dport 22 ct state new,established counter accept
|
||||
sudo nft add rule inet filter input iifname "ens3" tcp sport 22 ct state established counter accept
|
||||
```
|
||||
|
||||
Ahora pruebo accediendo a otra máquina desde el cortafuegos por ssh
|
||||
|
||||
![ssh](https://i.imgur.com/YsoD8Cx.png)
|
||||
|
||||
### Permite hacer consultas DNS desde la máquina cortafuegos sólo al servidor 192.168.202.2. Comprueba que no puedes hacer un dig @1.1.1.1.
|
||||
|
||||
Creo la regla
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter output ip daddr 192.168.202.2 udp dport 53 ct state new,established counter accept
|
||||
sudo nft add rule inet filter input ip saddr 192.168.202.2 udp sport 53 ct state established counter accept
|
||||
```
|
||||
|
||||
Compruebo que no puedo hacer un dig @1.1.1.1 y si uno con @192.168.202.2
|
||||
|
||||
![dns](https://i.imgur.com/XKHU64n.png)
|
||||
|
||||
### Permite que la máquina cortafuegos pueda navegar por internet.
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter output oifname "ens3" ip protocol tcp tcp dport { 80,443 } ct state new,established counter accept
|
||||
sudo nft add rule inet filter input iifname "ens3" ip protocol tcp tcp sport { 80,443 } ct state established counter accept
|
||||
```
|
||||
|
||||
Compruebo que puedo navegar por internet
|
||||
|
||||
![web](https://i.imgur.com/dXNkvJz.png)
|
||||
|
||||
### Los equipos de la red local deben poder tener conexión al exterior.
|
||||
|
||||
Este paso lo realicé en la preparación en el siguiente apartado: [Reglas forward](#reglas-forward)
|
||||
|
||||
### Permitimos el ssh desde el cortafuego a la LAN
|
||||
|
||||
Este paso lo realicé en la preparación en el siguiente apartado: [SSH desde el cortafuego a la LAN](#ssh-desde-el-cortafuego-a-la-lan)
|
||||
|
||||
Pruebo que funciona (usando mi clave privada)
|
||||
|
||||
![ssh2](https://i.imgur.com/JdG9dTH.png)
|
||||
|
||||
### Permitimos hacer ping desde la LAN a la máquina cortafuegos
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter input iifname "ens4" icmp type echo-request counter accept
|
||||
sudo nft add rule inet filter output oifname "ens4" icmp type echo-reply counter accept
|
||||
```
|
||||
|
||||
Compruebo que funciona
|
||||
|
||||
![icmp](https://i.imgur.com/reyRJ34.png)
|
||||
|
||||
### Permite realizar conexiones ssh desde los equipos de la LAN
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip saddr 192.168.100.0/24 tcp dport 22 ct state new,established counter accept
|
||||
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip daddr 192.168.100.0/24 tcp sport 22 ct state established counter accept
|
||||
```
|
||||
|
||||
Ahora, tras copiar mi clave privada a la máquina LAN, accedo a alfa por ssh
|
||||
|
||||
![ssh3](https://i.imgur.com/eZ9IVZf.png)
|
||||
|
||||
### Instala un servidor de correos en la máquina de la LAN. Permite el acceso desde el exterior y desde el cortafuego al servidor de correos. Para probarlo puedes ejecutar un telnet al puerto 25 tcp
|
||||
|
||||
### Permite poder hacer conexiones ssh desde exterior a la LAN
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip daddr 192.168.100.0/24 tcp dport 22 ct state new,established counter accept
|
||||
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip saddr 192.168.100.0/24 tcp sport 22 ct state established counter accept
|
||||
sudo nft add rule inet nat prerouting iifname "ens3" tcp dport 22 counter dnat ip to 192.168.100.10
|
||||
```
|
||||
|
||||
Compruebo que al acceder a la IP del firewall entro en la maquina LAN
|
||||
|
||||
![ssh4](https://i.imgur.com/VzI01Oo.png)
|
||||
|
||||
### Modifica la regla anterior, para que al acceder desde el exterior por ssh tengamos que conectar al puerto 2222, aunque el servidor ssh este configurado para acceder por el puerto 22
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet nat prerouting iifname "ens3" tcp dport 2222 counter dnat ip to 192.168.100.10:22
|
||||
```
|
||||
|
||||
Ahora entro usando el puerto 2222
|
||||
|
||||
![ssh5](https://i.imgur.com/Mm45WLy.png)
|
||||
|
||||
### Permite hacer consultas DNS desde la LAN sólo al servidor 192.168.202.2. Comprueba que no puedes hacer un dig @1.1.1.1
|
||||
|
||||
Como ya tengo una regla para las consultas dns desde la lan,busco los handles que tiene para borrarla
|
||||
|
||||
```bash
|
||||
sudo nft -a list ruleset
|
||||
```
|
||||
|
||||
![dns2](https://i.imgur.com/IH9k9GK.png)
|
||||
|
||||
son el 22 y el 23. Ahora los borro:
|
||||
|
||||
```bash
|
||||
sudo nft delete rule inet filter forward handle 22
|
||||
sudo nft delete rule inet filter forward handle 23
|
||||
```
|
||||
|
||||
Ahora añado las reglas para la LAN
|
||||
|
||||
```bash
|
||||
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip saddr 192.168.100.0/24 ip daddr 192.168.202.2 udp dport 53 ct state new,established counter accept
|
||||
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip saddr 192.168.202.2 ip daddr 192.168.100.0/24 udp sport 53 ct state established counter accept
|
||||
```
|
||||
|
||||
![dns3](https://i.imgur.com/1zmmeCt.png)
|
||||
|
||||
### Permite que los equipos de la LAN puedan navegar por internet.
|
||||
|
||||
Este paso lo realicé en la preparación en el siguiente apartado: [Permite que los equipos de la LAN puedan navegar por internet.](#permite-que-los-equipos-de-la-lan-puedan-navegar-por-internet)
|
||||
|
||||
Compruebo que funciona
|
||||
|
||||
![web2](https://i.imgur.com/wyT7DEF.png )
|
BIN
src/content/posts/2023-02-21_auditoria/featured.png
Normal file
After Width: | Height: | Size: 273 KiB |
340
src/content/posts/2023-02-21_auditoria/index.md
Normal file
@ -0,0 +1,340 @@
|
||||
---
|
||||
title: Administración de Bases de Datos - Auditoria
|
||||
published: 2023-02-21
|
||||
image: "./featured.png"
|
||||
tags: ["Oracle", "Postgres","MongoDB"]
|
||||
category: Documentación
|
||||
draft: false
|
||||
---
|
||||
|
||||
## Activa desde SQL*Plus la auditoría de los intentos de acceso exitosos al sistema. Comprueba su funcionamiento
|
||||
|
||||
Para activar la auditoría y que los datos se almacenen en la base de datos, ejecutamos el siguiente comando:
|
||||
|
||||
```sql
|
||||
ALTER SYSTEM SET audit_trail=db scope=spfile;
|
||||
```
|
||||
|
||||
Para comprobar que se ha activado correctamente, ejecutamos el siguiente comando:
|
||||
|
||||
```sql
|
||||
SELECT name, value FROM v$parameter WHERE name like 'audit_trail';
|
||||
```
|
||||
|
||||
![audit_trail](https://i.imgur.com/juhQKXU.png)
|
||||
|
||||
Para activar la auditoría de los intentos de acceso exitosos al sistema, ejecutamos el siguiente comando:
|
||||
|
||||
```sql
|
||||
AUDIT CREATE SESSION WHENEVER SUCCESSFUL;
|
||||
```
|
||||
|
||||
Ahora, tras acceder a la base de datos con el usuario restaurante (de una práctica anterior), haciendo la siguiente consulta, puedo ver que se ha almacenado la información del acceso:
|
||||
|
||||
```sql
|
||||
SELECT OS_USERNAME, USERNAME, EXTENDED_TIMESTAMP, ACTION_NAME FROM DBA_AUDIT_SESSION;
|
||||
```
|
||||
|
||||
![auditoria](https://i.imgur.com/Y0qJUmC.png)
|
||||
|
||||
|
||||
## Realiza un procedimiento en PL/SQL que te muestre los accesos fallidos junto con el motivo de los mismos, transformando el código de error almacenado en un mensaje de texto comprensible. Contempla todos los motivos posibles para que un acceso sea fallido
|
||||
|
||||
Primero, para vaciar la tabla de auditoría, ejecuto el siguiente comando:
|
||||
|
||||
```sql
|
||||
TRUNCATE table sys.AUD$;
|
||||
```
|
||||
|
||||
Ahora creo una sesión de auditoría para los accesos fallidos:
|
||||
|
||||
```sql
|
||||
AUDIT CREATE SESSION WHENEVER NOT SUCCESSFUL;
|
||||
```
|
||||
|
||||
He obtenido el significado de los códigos de error de la siguiente página: <http://johanlouwers.blogspot.com/2013/01/oracle-database-login-audit.html>
|
||||
|
||||
| Código | Significado |
|
||||
|:-:|---|
|
||||
|00911|El nombre de usuario o la contraseña contiene un carácter no válido|
|
||||
|00988|Falta la contraseña o no es válida|
|
||||
|01004|Inicio de sesión denegado|
|
||||
|01005|Contraseña nula|
|
||||
|01017|Contraseña / usuario no válidos|
|
||||
|01031|Sin privilegios|
|
||||
|01045|El usuario no tiene el privilegio CREATE SESSION|
|
||||
|01918|No existe el user ID|
|
||||
|01920|No existe el rol|
|
||||
|09911|Contraseña incorrecta|
|
||||
|28000|La cuenta está bloqueada|
|
||||
|28001|La contraseña ha caducado|
|
||||
|28002|La contraseña caducará pronto, se debe cambiar ahora|
|
||||
|28003|La contraseña no es lo suficientemente compleja|
|
||||
|28007|La contraseña no se puede reutilizar|
|
||||
|28008|Contraseña antigua no válida|
|
||||
|28009|La conexión a sys se debe realizar desde sysdba o sysoper|
|
||||
|28011|La cuenta va a caducar pronto, se debe cambiar la contraseña|
|
||||
|28221|La contraseña original no ha sido suministrada|
|
||||
|
||||
Ahora, creo el procedimiento en PL/SQL:
|
||||
|
||||
```sql
|
||||
CREATE OR REPLACE PROCEDURE accesosFallidos
|
||||
IS
|
||||
CURSOR c_accesos IS
|
||||
SELECT USERNAME, EXTENDED_TIMESTAMP, ACTION_NAME, RETURNCODE
|
||||
FROM DBA_AUDIT_SESSION
|
||||
WHERE RETURNCODE <> 0;
|
||||
begin
|
||||
for i in c_accesos loop
|
||||
dbms_output.put_line('HORA: ' || i.EXTENDED_TIMESTAMP);
|
||||
dbms_output.put_line(CHR(9)||'-USUARIO: ' || i.USERNAME);
|
||||
case i.RETURNCODE
|
||||
when 00911 then
|
||||
dbms_output.put_line(CHR(9)||'-El nombre de usuario o la contrasena contiene un caracter no valido');
|
||||
when 00988 then
|
||||
dbms_output.put_line(CHR(9)||'-Falta la contrasena o no es valida');
|
||||
when 01004 then
|
||||
dbms_output.put_line(CHR(9)||'-Inicio de sesion denegado');
|
||||
when 01005 then
|
||||
dbms_output.put_line(CHR(9)||'-contrasena nula');
|
||||
when 01017 then
|
||||
dbms_output.put_line(CHR(9)||'-contrasena / usuario no validos');
|
||||
when 01031 then
|
||||
dbms_output.put_line(CHR(9)||'-Sin privilegios');
|
||||
when 01045 then
|
||||
dbms_output.put_line(CHR(9)||'-El usuario no tiene el privilegio CREATE SESSION');
|
||||
when 01918 then
|
||||
dbms_output.put_line(CHR(9)||'-No existe el user ID');
|
||||
when 01920 then
|
||||
dbms_output.put_line(CHR(9)||'-No existe el rol');
|
||||
when 09911 then
|
||||
dbms_output.put_line(CHR(9)||'-contrasena incorrecta');
|
||||
when 28000 then
|
||||
dbms_output.put_line(CHR(9)||'-La cuenta esta bloqueada');
|
||||
when 28001 then
|
||||
dbms_output.put_line(CHR(9)||'-La contrasena ha caducado');
|
||||
when 28002 then
|
||||
dbms_output.put_line(CHR(9)||'-La contrasena caducara pronto, se debe cambiar ahora');
|
||||
when 28003 then
|
||||
dbms_output.put_line(CHR(9)||'-La contrasena no es lo suficientemente compleja');
|
||||
when 28007 then
|
||||
dbms_output.put_line(CHR(9)||'-La contrasena no se puede reutilizar');
|
||||
when 28008 then
|
||||
dbms_output.put_line(CHR(9)||'-contrasena antigua no valida');
|
||||
when 28009 then
|
||||
dbms_output.put_line(CHR(9)||'-La conexión a sys se debe realizar desde sysdba o sysoper');
|
||||
when 28011 then
|
||||
dbms_output.put_line(CHR(9)||'-La cuenta va a caducar pronto, se debe cambiar la contrasena');
|
||||
when 28221 then
|
||||
dbms_output.put_line(CHR(9)||'-La contrasena original no ha sido suministrada');
|
||||
end case;
|
||||
end loop;
|
||||
end;
|
||||
/
|
||||
```
|
||||
|
||||
Compruebo que funciona correctamente:
|
||||
|
||||
![accesosFallidos](https://i.imgur.com/FGHbSQV.png)
|
||||
|
||||
## Activa la auditoría de las operaciones DML realizadas por SCOTT. Comprueba su funcionamiento
|
||||
|
||||
Activo la auditoría de las operaciones DML realizadas por SCOTT:
|
||||
|
||||
```sql
|
||||
AUDIT INSERT TABLE, UPDATE TABLE, DELETE TABLE BY SCOTT BY ACCESS;
|
||||
```
|
||||
|
||||
Ahora inserto un empleado en la tabla emp:
|
||||
|
||||
```sql
|
||||
INSERT INTO emp VALUES (9999, 'Roberto', 'Director', 7839, TO_DATE('21/02/2023', 'DD/MM/YYYY'), 5000, 0, 10);
|
||||
```
|
||||
|
||||
Y se ve reflectado en la tabla de auditoría:
|
||||
|
||||
```sql
|
||||
SELECT USERNAME, OBJ_NAME, ACTION_NAME, EXTENDED_TIMESTAMP FROM DBA_AUDIT_OBJECT;
|
||||
```
|
||||
|
||||
![auditoriaDML](https://i.imgur.com/33VAXWP.png)
|
||||
|
||||
## Realiza una auditoría de grano fino para almacenar información sobre la inserción de empleados con sueldo superior a 2000 en la tabla emp de scott
|
||||
|
||||
La auditoría de grano fino (FGA) es como una versión extendida de la auditoría estándar. Registra los cambios en datos muy concretos a nivel de columna.
|
||||
|
||||
Para realizar la auditoría de grano fino, primero tengo que crear una política de auditoría:
|
||||
|
||||
```sql
|
||||
BEGIN
|
||||
DBMS_FGA.ADD_POLICY (
|
||||
OBJECT_SCHEMA => 'SCOTT',
|
||||
OBJECT_NAME => 'EMP',
|
||||
POLICY_NAME => 'SALARIO_MAYOR_2000',
|
||||
AUDIT_CONDITION => 'SAL < 2000',
|
||||
STATEMENT_TYPES => 'INSERT'
|
||||
);
|
||||
END;
|
||||
/
|
||||
```
|
||||
|
||||
Ahora inserto varios empleados:
|
||||
|
||||
```sql
|
||||
INSERT INTO emp VALUES (2222, 'Bill Gates', 'Director', 7839, TO_DATE('21/02/2023', 'DD/MM/YYYY'), 1000, 0, 10);
|
||||
INSERT INTO emp VALUES (3333, 'Steve Jobs', 'Director', 7839, TO_DATE('21/02/2023', 'DD/MM/YYYY'), 5000, 0, 10);
|
||||
```
|
||||
|
||||
![auditoriaGranoFino](https://i.imgur.com/rqLZNLq.png)
|
||||
|
||||
Y compruebo que aparece en la tabla de auditoría:
|
||||
|
||||
```sql
|
||||
SELECT DB_USER, OBJECT_NAME, SQL_TEXT, EXTENDED_TIMESTAMP FROM DBA_FGA_AUDIT_TRAIL WHERE POLICY_NAME='SALARIO_MAYOR_2000';
|
||||
```
|
||||
|
||||
![auditoriaGranoFino](https://i.imgur.com/EseLG8U.png)
|
||||
|
||||
## Explica la diferencia entre auditar una operación by access o by session ilustrándolo con ejemplos
|
||||
|
||||
Las operaciones by access se auditan por cada acceso a la base de datos, mientras que las operaciones by session se auditan por cada sesión de usuario. Por ejemplo, si un usuario realiza 10 accesos a la base de datos, se auditarán 10 operaciones by access, mientras que si realiza 10 accesos en una misma sesión, se auditarán 1 operación by session.
|
||||
|
||||
La sintaxis es la siguiente:
|
||||
|
||||
```sql
|
||||
AUDIT [operación] [tabla] BY [usuario] BY {ACCESS | SESSION};
|
||||
```
|
||||
|
||||
## Documenta las diferencias entre los valores db y db, extended del parámetro audit_trail de ORACLE. Demuéstralas poniendo un ejemplo de la información sobre una operación concreta recopilada con cada uno de ellos
|
||||
|
||||
Ambos parámetros indican que la auditoría está activada. La diferencia es que el parámetro db guarda la información en la tabla de auditoría, mientras que el parámetro db, extended guarda la información en la tabla de auditoría y en el archivo de alerta.
|
||||
|
||||
Para cambiar el parámetro, utilizo el siguiente comando:
|
||||
|
||||
```sql
|
||||
ALTER SYSTEM SET audit_trail = db, extended SCOPE = SPFILE;
|
||||
```
|
||||
|
||||
Reinicio la base de datos y compruebo que el parámetro se ha cambiado correctamente, con la consulta del ejercicio 1:
|
||||
|
||||
![auditTrail](https://i.imgur.com/sIytDAc.png)
|
||||
|
||||
## Averigua si en Postgres se pueden realizar los cuatro primeros apartados. Si es así, documenta el proceso adecuadamente
|
||||
|
||||
### Ejercicio 1
|
||||
|
||||
En postgres no se puede realizar el ejercicio 1, ya que se registran los inicios de sesión fallidos en el archivo de log, pero no los exitosos.
|
||||
|
||||
### Ejercicio 2
|
||||
|
||||
No se puede realizar un procedimiento ya que los accesos fallidos no está registrado en la base de datos, sino en el archivo de log, sin embargo, en el propio archivo de log, se encuentran explicados con palabras y en español, el objetivo final del procedimiento:
|
||||
|
||||
![accesosFallidos](https://i.imgur.com/n9IuvtS.png)
|
||||
|
||||
### Ejercicio 3
|
||||
|
||||
Para realizar la auditoría voy a usar **Trigger 91plus**, una herramienta creada por la comunidad que permite auditar las operaciones DML en postgres.
|
||||
|
||||
Para instalarla, primero tengo que descargar de github el siguiente fichero
|
||||
|
||||
```bash
|
||||
wget https://raw.githubusercontent.com/2ndQuadrant/audit-trigger/master/audit.sql
|
||||
```
|
||||
|
||||
Y luego lo instalo:
|
||||
|
||||
```sql
|
||||
\i audit.sql
|
||||
```
|
||||
|
||||
![instalacionTrigger](https://i.imgur.com/yYJq9ye.png)
|
||||
|
||||
No puede realizar auditorías de todo lo que realiza un usuario, sino de tablas. Por lo que voy a especificar las tablas del usuario scott que quiero auditar:
|
||||
|
||||
```sql
|
||||
SELECT audit.audit_table('scott.emp');
|
||||
SELECT audit.audit_table('scott.dept');
|
||||
```
|
||||
|
||||
## Averigua si en MySQL se pueden realizar los apartados 1, 3 y 4. Si es así, documenta el proceso adecuadamente
|
||||
|
||||
### Ejercicio 1
|
||||
|
||||
Para obtener los datos de los inicios de sesión, edito el fichero `/etc/mysql/mariadb.conf.d/50-server.cnf`:
|
||||
|
||||
```bash
|
||||
general_log_file = /var/log/mysql/mysql.log
|
||||
general_log = 1
|
||||
log_error = /var/log/mysql/error.log
|
||||
```
|
||||
|
||||
Cambio el propietario del directorio de los logs y reinicio el servicio:
|
||||
|
||||
```bash
|
||||
chown -R mysql:mysql /var/log/mysql
|
||||
systemctl restart mariadb.service
|
||||
```
|
||||
|
||||
Ahora, tras varios inicios de sesión, compruebo el fichero de logs `/var/log/mysql/mysql.log`:
|
||||
|
||||
![mysqlLog](https://i.imgur.com/fpOjaLH.png)
|
||||
|
||||
### Ejercicio 3
|
||||
|
||||
Para realizar la auditoría voy a instalar el plugin `server_audit`:
|
||||
|
||||
```sql
|
||||
INSTALL SONAME 'server_audit';
|
||||
```
|
||||
|
||||
Ahora edito el fichero `/etc/mysql/mariadb.conf.d/50-server.cnf` y reinicio mariadb:
|
||||
|
||||
```bash
|
||||
[server]
|
||||
server_audit_events=CONNECT,QUERY,TABLE
|
||||
server_audit_logging=ON
|
||||
server_audit_incl_users=scott
|
||||
```
|
||||
|
||||
Tras insertar un nuevo empleado, compruebo el fichero de log `/var/lib/mysql/server_audit.log`:
|
||||
|
||||
![mysqlLog](https://i.imgur.com/GAOO4Kz.png)
|
||||
|
||||
## Averigua las posibilidades que ofrece MongoDB para auditar los cambios que va sufriendo un documento. Demuestra su funcionamiento
|
||||
|
||||
Para realizar las auditorías, es necesario instalar la versión Enterprise. La documentación de instalación oficial se encuentra en el siguiente enlace [https://www.mongodb.com/docs/manual/tutorial/install-mongodb-enterprise-on-debian/](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-enterprise-on-debian/). Una vez instalado podemos hacer lo siguiente:
|
||||
|
||||
- Habilitar las auditorías en el syslog desde la consola:
|
||||
|
||||
```bash
|
||||
mongod --dbpath /var/lib/mongodb/ --auditDestination syslog
|
||||
```
|
||||
|
||||
- Habilitar las auditorías en un fichero JSON desde la consola:
|
||||
|
||||
```bash
|
||||
mongod --dbpath /var/lib/mongodb/ --auditDestination file --auditFormat JSON --auditPath /var/lib/mongodb/auditLog.json
|
||||
```
|
||||
|
||||
- Habilitar las auditorías en un fichero BSON desde la consola:
|
||||
|
||||
```bash
|
||||
mongod --dbpath /var/lib/mongodb/ --auditDestination file --auditFormat BSON --auditPath /var/lib/mongodb/auditLog.bson
|
||||
```
|
||||
|
||||
- Habilitar las auditorías en la consola desde la consola:
|
||||
|
||||
```bash
|
||||
mongod --dbpath /var/lib/mongodb/ --auditDestination console
|
||||
```
|
||||
|
||||
He utilizado la salida por consola y preferencia de formato ya que se trata también de un json.
|
||||
|
||||
```bash
|
||||
mongod --dbpath /var/lib/mongodb/ --auditDestination console | jq
|
||||
```
|
||||
|
||||
![mongoAudit](https://i.imgur.com/DNdM1aZ.png)
|
||||
|
||||
##. Averigua si en MongoDB se pueden auditar los accesos a una colección concreta. Demuestra su funcionamiento
|
BIN
src/content/posts/2023-02-22_LDAP_CSV/featured.png
Normal file
After Width: | Height: | Size: 40 KiB |
188
src/content/posts/2023-02-22_LDAP_CSV/index.md
Normal file
@ -0,0 +1,188 @@
|
||||
---
|
||||
title: Poblar un directorio LDAP desde un fichero CSV
|
||||
published: 2023-02-22
|
||||
image: "./featured.png"
|
||||
tags: ["LDAP","OpenStack"]
|
||||
category: Documentación
|
||||
draft: false
|
||||
---
|
||||
|
||||
En alfa creo el siguiente fichero CSV:
|
||||
|
||||
```csv
|
||||
Belen,Nazareth,belennazareth@gmail.com,nazareth,ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC73j7AidXdLgiu5wJw7YgJuvOHyb6U8c04MuQyehYnMknMR8mTnWZr20npVHJ8VHYHDy8RlgbkMMBFgeVCgXJ+Im3A6Efp6HC4yj2SM+73hr1EKCLdRPzCzdtDSUtkqU9k+x2RdF3T6qD6H4Cg/nT8Sg3Qenqds4XORfDWOvntxFja2D0OhZv1MLPUD9pEj+a8D4erfiPx/gKW/Rtu89une+uiwVgK60B5CxnC8XXnXmPO3NhrgyQhVgzQZ658cUbLooxQURVlo1gnOmcqX5h+svUKN1SDbzTyy7HKSk7bbLHEhk7qDh7jSzcf80GLU0li8vXc2to8NpC00EOQ9POPivESz23gMNY8ooDtNU3Ll/xYvhtvXrJNTbuBiuVLzuopMvrQi6LVsQEWmPJzBiJ2qt8JW1KRLcnWRL4AezbxAPXuRYVnYBS3it6L0J4AZjZg63BkIIrfU7GYzrKb+z5mqUgDJhIZ4d5av+OAxPSSzNeVnyWEnWrI0k9kf9qmqhU= nazare@ThousandSunny
|
||||
Antonio,Marchan,antoniomarchan@gmail.com,anthony,ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9kx67eVF+Eh5epqZvQfjOLamYck9lVB9w1e/JO9Nzx7Utxm0ikD4ZCuhANc42RRkbH/2xICo138IpxJtfnbf4ObmaxVpo65lweLw5e8w132v6IXHkCAU5jTdyJS08Gi5I/nEqq/ywEMWJ939zEu0Dfdi/1IDlqBjGPpeomCJCDOkZWHfFyuiHrpgbWniwjRBcQiXjlp7w76/k0K+1Xw5JQz2F/YuTHzEGXqVo7x2T32IprzONXprVd9cn5qItFES5DMHOv62t++3zAOZbLNTs+cFuZmfTkT4YQUoHPkqXCzQmM6hnSAihOQjNKZWy+zSOiTkL22tdd9q4jhUZu4VutNeEFKt4VDlLH1uEV0FCJjb5Fw2gzb62D9sjdsjNa8EZD2IcrjKrIJv83Ca7AyeED5egoFSAMfW1iFIse8pG4olOOv4FyeWtSgjgv9A+URiwkRqFd371lw6Xj0gdEokqO9sBYlcy3gfwT4BZCSlM3AMOjFCMP5kU1Z8uTowg9NM= antonio@debian
|
||||
```
|
||||
|
||||
Creo el siguiente fichero ldif `openssh-lpk.ldif`:
|
||||
|
||||
```ldif
|
||||
dn: cn=openssh-lpk,cn=schema,cn=config
|
||||
objectClass: olcSchemaConfig
|
||||
cn: openssh-lpk
|
||||
olcAttributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey'
|
||||
DESC 'MANDATORY: OpenSSH Public key'
|
||||
EQUALITY octetStringMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
|
||||
olcObjectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
|
||||
DESC 'MANDATORY: OpenSSH LPK objectclass'
|
||||
MAY ( sshPublicKey $ uid )
|
||||
)
|
||||
```
|
||||
|
||||
Ahora, creo un entorno virtual:
|
||||
|
||||
```bash
|
||||
apt install python3-venv -y
|
||||
python3 -m venv entorno_ldap
|
||||
source entorno_ldap/bin/activate
|
||||
pip install ldap3
|
||||
```
|
||||
|
||||
Y el siguiente programa `ldap_csv.py`:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python
|
||||
|
||||
import ldap3
|
||||
from ldap3 import Connection, ALL
|
||||
from getpass import getpass
|
||||
from sys import exit
|
||||
|
||||
### VARIABLES
|
||||
|
||||
# Shell que se le asigna a los usuarios
|
||||
shell = '/bin/bash'
|
||||
|
||||
# Ruta absoluta del directorio que contiene los directorios personales de los usuarios. Terminado en "/"
|
||||
home_dir = '/home/ldap/'
|
||||
|
||||
# El valor inicial para los UID que se asignan al insertar usuarios.
|
||||
uid_number = 500
|
||||
|
||||
# El GID que se le asigna a los usuarios. Si no se manda al anadir el usuario da error.
|
||||
gid = 500
|
||||
|
||||
### VARIABLES
|
||||
|
||||
# Leemos el fichero .csv de los usuarios y guardamos cada linea en una lista.
|
||||
with open('usuarios.csv', 'r') as usuarios:
|
||||
usuarios = usuarios.readlines()
|
||||
|
||||
|
||||
### Parametros para la conexion
|
||||
ldap_ip = 'ldap://alfa.roberto.gonzalonazareno.org:389'
|
||||
dominio_base = 'dc=roberto,dc=gonzalonazareno,dc=org'
|
||||
user_admin = 'admin'
|
||||
contrasena = getpass('Contrasena: ')
|
||||
|
||||
# Intenta realizar la conexion.
|
||||
conn = Connection(ldap_ip, 'cn={},{}'.format(user_admin, dominio_base),contrasena)
|
||||
|
||||
# conn.bind() devuelve "True" si se ha establecido la conexion y "False" en caso contrario.
|
||||
|
||||
# Si no se establece la conexion imprime por pantalla un error de conexion.
|
||||
if not conn.bind():
|
||||
print('No se ha podido conectar con ldap')
|
||||
if conn.result['description'] == 'invalidCredentials':
|
||||
print('Credenciales no validas.')
|
||||
# Termina el script.
|
||||
exit(0)
|
||||
|
||||
# Recorre la lista de usuarios
|
||||
for user in usuarios:
|
||||
# Separa los valores del usuario usando como delimitador ",", y asigna cada valor a la variable correspondiente.
|
||||
user = user.split(',')
|
||||
cn = user[0]
|
||||
sn = user[1]
|
||||
mail = user[2]
|
||||
uid = user[3]
|
||||
ssh = user[4]
|
||||
|
||||
#Anade el usuario.
|
||||
conn.add(
|
||||
'uid={},ou=Personas,{}'.format(uid, dominio_base),
|
||||
object_class =
|
||||
[
|
||||
'inetOrgPerson',
|
||||
'posixAccount',
|
||||
'ldapPublicKey'
|
||||
],
|
||||
attributes =
|
||||
{
|
||||
'cn': cn,
|
||||
'sn': sn,
|
||||
'mail': mail,
|
||||
'uid': uid,
|
||||
'uidNumber': str(uid_number),
|
||||
'gidNumber': str(gid),
|
||||
'homeDirectory': '{}{}'.format(home_dir,uid),
|
||||
'loginShell': shell,
|
||||
'sshPublicKey': str(ssh)
|
||||
})
|
||||
|
||||
if conn.result['description'] == 'entryAlreadyExists':
|
||||
print('El usuario {} ya existe.'.format(uid))
|
||||
|
||||
# Aumenta el contador para asignar un UID diferente a cada usuario (cada vez que ejecutemos el script debemos asegurarnos de ante mano que no existe dicho uid en el directorio ldap, o se solaparian los datos)
|
||||
uid_number += 1
|
||||
|
||||
#Cierra la conexion.
|
||||
conn.unbind()
|
||||
```
|
||||
|
||||
Los ejecuto
|
||||
|
||||
```bash
|
||||
python3 ldap_csv.py
|
||||
```
|
||||
|
||||
Tras eso, podemos realizar un `ldapsearch` para comprobar que se han añadido los usuarios correctamente:
|
||||
|
||||
```bash
|
||||
ldapsearch -x -D "cn=admin,dc=roberto,dc=gonzalonazareno,dc=org" -b "dc=roberto,dc=gonzalonazareno,dc=org" -W
|
||||
```
|
||||
|
||||
![image-2021033016442](https://i.imgur.com/BZDGSdR.png)
|
||||
|
||||
Editamos el fichero `/etc/ldap/ldap.conf`
|
||||
|
||||
```bash
|
||||
BASE dc=roberto,dc=gonzalonazareno,dc=org
|
||||
URI ldap://roberto.antonio.gonzalonazareno.org
|
||||
```
|
||||
|
||||
en el fichero `/etc/pam.d/common-session` añadimos la siguiente linea al final:
|
||||
|
||||
```bash
|
||||
session required pam_mkhomedir.so
|
||||
```
|
||||
|
||||
Ahora creo el siguiente script para encontrar las claves públicas del árbol de LDAP en `/opt/buscarclave.sh` y le damos permiso de ejecución:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
ldapsearch -x -u -LLL -o ldif-wrap=no '(&(objectClass=posixAccount)(uid='"$1"'))' 'sshPublicKey' | sed -n 's/^[ \t]*sshPublicKey::[ \t]*\(.*\)/\1/p' | base64 -d
|
||||
```
|
||||
|
||||
Y le pongo permisos 755:
|
||||
|
||||
```bash
|
||||
chmod 755 /opt/buscarclave.sh
|
||||
```
|
||||
|
||||
Ahora compruebo que funciona:
|
||||
|
||||
![clave](https://i.imgur.com/zz3brvp.png)
|
||||
|
||||
ahora edito el fichero `/etc/ssh/sshd_config` y reinicio el servicio sshd:
|
||||
|
||||
```bash
|
||||
AuthorizedKeysCommand /opt/buscarclave.sh
|
||||
AuthorizedKeysCommandUser nobody
|
||||
```
|
||||
|
||||
Ahora tras eso, Antonio puede conectarse con su usuario:
|
||||
|
||||
![image-2021033016593](https://i.imgur.com/fZ4nDBJ.jpg)
|
BIN
src/content/posts/2023-03-02_cortafuegos3/featured.png
Normal file
After Width: | Height: | Size: 467 KiB |
304
src/content/posts/2023-03-02_cortafuegos3/index.md
Normal file
@ -0,0 +1,304 @@
|
||||
---
|
||||
title: "Cortafuegos III: perimetral sobre escenario"
|
||||
published: 2023-03-02
|
||||
image: "./featured.png"
|
||||
tags: ["Cortafuegos", "iptables"]
|
||||
category: Documentación
|
||||
draft: false
|
||||
---
|
||||
|
||||
El escenario es el siguiente
|
||||
|
||||
![Escenario](https://i.imgur.com/LLToqTl.png)
|
||||
|
||||
Y las interfaces de alfa son las siguientes:
|
||||
|
||||
- ens3: Salida a internet
|
||||
- ens8: DMZ
|
||||
- br-intra: LAN
|
||||
|
||||
## Enunciado
|
||||
|
||||
Sobre el escenario creado en el módulo de servicios con las máquinas Alfa (Router), Bravo (DMZ), Charlie y Delta (LAN) y empleando iptables o nftables, configura un cortafuegos perimetral en la máquina Alfa de forma que el escenario siga funcionando completamente teniendo en cuenta los siguientes puntos:
|
||||
|
||||
## Política por defecto DROP para las cadenas INPUT, FORWARD y OUTPUT.
|
||||
|
||||
Antes de añadir la política por defecto voy a añadir reglas para permitir el acceso por ssh
|
||||
|
||||
```bash
|
||||
iptables -A INPUT -s 172.22.0.0/16 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A OUTPUT -d 172.22.0.0/16 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Estas reglas sirve para acceder desde la misma red, además añado las siguientes para acceder a través de la VPN
|
||||
|
||||
```bash
|
||||
iptables -A INPUT -s 172.29.0.0/16 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A OUTPUT -d 172.29.0.0/16 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Y permito el acceso al resto de máquinas
|
||||
|
||||
```bash
|
||||
iptables -A OUTPUT -d 192.168.0.0/24 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A INPUT -s 192.168.0.0/24 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
|
||||
|
||||
iptables -A OUTPUT -d 172.16.0.0/16 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A INPUT -s 172.16.0.0/16 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
(Este paso lo ejecuto después de crear las reglas ssh)
|
||||
|
||||
```bash
|
||||
iptables -P INPUT DROP
|
||||
iptables -P OUTPUT DROP
|
||||
iptables -P FORWARD DROP
|
||||
```
|
||||
|
||||
## El cortafuego debe cumplir al menos estas reglas:
|
||||
|
||||
### La máquina Alfa tiene un servidor ssh escuchando por el puerto 22, pero al acceder desde el exterior habrá que conectar al puerto 2222.
|
||||
|
||||
|
||||
### Desde Delta y Bravo se debe permitir la conexión ssh por el puerto 22 a la máquina Alfa
|
||||
|
||||
de alfa a charlie/delta
|
||||
|
||||
```bash
|
||||
sudo iptables -A OUTPUT -o br-intra -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
sudo iptables -A INPUT -i br-intra -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Prueba antes y después de crear la regla
|
||||
|
||||
![Escenario](https://i.imgur.com/oiiVuK8.png)
|
||||
|
||||
de alfa a bravo
|
||||
|
||||
```bash
|
||||
sudo iptables -A OUTPUT -o ens8 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
sudo iptables -A INPUT -i ens8 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
![Escenario](https://i.imgur.com/2rAyLZy.png)
|
||||
|
||||
### La máquina Alfa debe tener permitido el tráfico para la interfaz loopback
|
||||
|
||||
```bash
|
||||
iptables -A INPUT -i lo -p icmp -j ACCEPT
|
||||
iptables -A OUTPUT -o lo -p icmp -j ACCEPT
|
||||
```
|
||||
|
||||
Pruebo que funciona, antes y después de aplicar la regla:
|
||||
|
||||
![loopback](https://i.imgur.com/7RfdzSj.png)
|
||||
|
||||
### A la máquina Alfa se le puede hacer ping desde la DMZ, pero desde la LAN se le debe rechazar la conexión (REJECT) y desde el exterior se rechazará de manera silenciosa.
|
||||
|
||||
```bash
|
||||
iptables -A INPUT -s 172.16.0.200/16 -p icmp -m icmp --icmp-type echo-request -j ACCEPT
|
||||
iptables -A OUTPUT -d 172.16.0.200/16 -p icmp -m icmp --icmp-type echo-reply -j ACCEPT
|
||||
```
|
||||
|
||||
Ahora el reject a la LAN
|
||||
|
||||
```bash
|
||||
iptables -A INPUT -s 192.168.1.0/24 -p icmp -m icmp --icmp-type echo-request -j REJECT
|
||||
iptables -A OUTPUT -d 192.168.1.0/24 -p icmp -m icmp --icmp-type echo-reply -j REJECT
|
||||
```
|
||||
|
||||
ping desde bravo:
|
||||
|
||||
![ping desde bravo](https://i.imgur.com/utA5CGz.png)
|
||||
|
||||
ping desde charlie:
|
||||
|
||||
![ping desde charlie](https://i.imgur.com/g6Z7xSD.png)
|
||||
|
||||
### La máquina Alfa puede hacer ping a la LAN, la DMZ y al exterior.
|
||||
|
||||
```bash
|
||||
iptables -A OUTPUT -p icmp -m icmp --icmp-type echo-request -j ACCEPT
|
||||
iptables -A INPUT -p icmp -m icmp --icmp-type echo-reply -j ACCEPT
|
||||
```
|
||||
|
||||
A la LAN:
|
||||
|
||||
![ping a la LAN](https://i.imgur.com/PrsN5x0.png)
|
||||
|
||||
A la DMZ:
|
||||
|
||||
![ping a la DMZ](https://i.imgur.com/PealPbe.png)
|
||||
|
||||
Al exterior:
|
||||
|
||||
![ping al exterior](https://i.imgur.com/e5iIex8.png)
|
||||
|
||||
### Desde la máquina Bravo se puede hacer ping y conexión ssh a las máquinas de la LAN.
|
||||
|
||||
```bash
|
||||
iptables -A FORWARD -s 172.16.0.200/32 -d 192.168.0.0/24 -p icmp -m icmp --icmp-type echo-request -j ACCEPT
|
||||
iptables -A FORWARD -d 172.16.0.200/32 -s 192.168.0.0/24 -p icmp -m icmp --icmp-type echo-reply -j ACCEPT
|
||||
|
||||
iptables -A FORWARD -s 172.16.0.200/32 -d 192.168.0.0/24 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A FORWARD -d 172.16.0.200/32 -s 192.168.0.0/24 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Prueba de ping desde bravo a charlie:
|
||||
|
||||
![ping desde bravo a charlie](https://i.imgur.com/qLycsbI.png)
|
||||
|
||||
Prueba de ssh desde bravo a charlie:
|
||||
|
||||
![ssh desde bravo a charlie](https://i.imgur.com/XZF4qGQ.png)
|
||||
|
||||
### Desde cualquier máquina de la LAN se puede conectar por ssh a la máquina Bravo.
|
||||
|
||||
```bash
|
||||
iptables -A FORWARD -s 192.168.0.0/24 -d 172.16.0.200/32 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A FORWARD -s 172.16.0.200/32 -d 192.168.0.0/24 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Pruebo a acceder desde charlie:
|
||||
|
||||
![ssh desde charlie a bravo](https://i.imgur.com/2rykuVx.png)
|
||||
|
||||
### Configura la máquina Alfa para que las máquinas de LAN y DMZ puedan acceder al exterior
|
||||
|
||||
DMZ a exterior:
|
||||
|
||||
```bash
|
||||
iptables -t nat -A POSTROUTING -s 172.16.0.0/16 -o ens3 -j MASQUERADE
|
||||
iptables -A FORWARD -i ens8 -o ens3 -p icmp -m icmp --icmp-type echo-request -j ACCEPT
|
||||
iptables -A FORWARD -i ens3 -o ens8 -p icmp -m icmp --icmp-type echo-reply -j ACCEPT
|
||||
```
|
||||
|
||||
LAN a exterior:
|
||||
|
||||
```bash
|
||||
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o ens3 -j MASQUERADE
|
||||
iptables -A FORWARD -i br-intra -o ens3 -p icmp -m icmp --icmp-type echo-request -j ACCEPT
|
||||
iptables -A FORWARD -i ens3 -o br-intra -p icmp -m icmp --icmp-type echo-reply -j ACCEPT
|
||||
```
|
||||
|
||||
Prueba de ping desde bravo a google:
|
||||
|
||||
![ping desde bravo a google](https://i.imgur.com/IbX1h7r.png)
|
||||
|
||||
Prueba de ping desde charlie a google:
|
||||
|
||||
![ping desde charlie a google](https://i.imgur.com/g7GKV9E.png)
|
||||
|
||||
### Las máquinas de la LAN pueden hacer ping al exterior y navegar
|
||||
|
||||
El ping lo he configurado en el punto anterior. Ahora la navegación:
|
||||
|
||||
```bash
|
||||
iptables -A FORWARD -i br-intra -o ens3 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A FORWARD -i ens3 -o br-intra -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
|
||||
|
||||
iptables -A FORWARD -i br-intra -o ens3 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A FORWARD -i ens3 -o br-intra -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Prueba de navegación desde charlie (no tengo el comando curl, asi que uso nc):
|
||||
|
||||
![navegación desde charlie](https://i.imgur.com/ZLljVQQ.png)
|
||||
|
||||
### La máquina Bravo puede navegar
|
||||
|
||||
```bash
|
||||
iptables -A FORWARD -i ens8 -o ens3 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A FORWARD -i ens3 -o ens8 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
|
||||
|
||||
iptables -A FORWARD -i ens8 -o ens3 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A FORWARD -i ens3 -o ens8 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Prueba de navegación desde bravo:
|
||||
|
||||
![navegación desde bravo](https://i.imgur.com/qXEvqkP.png)
|
||||
|
||||
### Configura la máquina Alfa para que los servicios web y ftp sean accesibles desde el exterior
|
||||
|
||||
```bash
|
||||
iptables -t nat -A PREROUTING -p tcp -i ens3 --dport 80 -j DNAT --to 172.16.0.200
|
||||
iptables -A FORWARD -i ens3 -o ens8 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A FORWARD -i ens8 -o ens3 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
|
||||
|
||||
iptables -t nat -A PREROUTING -p tcp -i ens3 --dport 21 -j DNAT --to 172.16.0.200
|
||||
iptables -A FORWARD -i ens3 -o ens8 -p tcp --dport 21 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A FORWARD -i ens8 -o ens3 -p tcp --sport 21 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Prueba de navegación desde el exterior (La página es de un taller de Django):
|
||||
|
||||
![navegación desde el exterior](https://i.imgur.com/U2EgQqy.png)
|
||||
|
||||
### El servidor web y el servidor ftp deben ser accesibles desde la LAN y desde el exterior
|
||||
|
||||
```bash
|
||||
iptables -A FORWARD -i br-intra -o ens8 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A FORWARD -i ens8 -o br-intra -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
|
||||
|
||||
iptables -A FORWARD -i br-intra -o ens8 -p tcp --dport 21 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A FORWARD -i ens8 -o br-intra -p tcp --sport 21 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
Prueba de navegación desde charlie, sale un error porque estoy usando el comando nc, pero aun asi se ve que responde rocky con wsgi, que es lo que hay desplegado en bravo:
|
||||
|
||||
![navegación desde charlie](https://i.imgur.com/J9C1mcC.png)
|
||||
|
||||
### El servidor de correos sólo debe ser accesible desde la LAN
|
||||
|
||||
```bash
|
||||
iptables -A FORWARD -i br-intra -o ens8 -p tcp --dport 25 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
iptables -A FORWARD -i ens8 -o br-intra -p tcp --sport 25 -m state --state ESTABLISHED -j ACCEPT
|
||||
```
|
||||
|
||||
### En la máquina Charlie instala un servidor mysql si no lo tiene aún. A este servidor se puede acceder desde la DMZ, pero no desde el exterior.
|
||||
|
||||
### Evita ataques DoS por ICMP Flood, limitando el número de peticiones por segundo desde una misma IP.
|
||||
|
||||
El ping está bloqueado desde el exterior y desde la LAN, por lo que voy a evitar los ataques desde la DMZ, limitando a 1 peticion por segundo(primero hay que borrar la regla anterior):
|
||||
|
||||
```bash
|
||||
iptables -A INPUT -i ens8 -p icmp -m state --state NEW --icmp-type echo-request -m limit --limit 1/s --limit-burst 1 -j ACCEPT
|
||||
```
|
||||
|
||||
![ping desde la DMZ](https://i.imgur.com/L2N9GIc.png)
|
||||
|
||||
En la captura se ve como el 100% de los paquetes han sido rechazados
|
||||
|
||||
### Evita ataques DoS por SYN Flood.
|
||||
|
||||
```bash
|
||||
iptables -t raw -D PREROUTING -p tcp -m tcp --syn -j CT --notrack
|
||||
iptables -D INPUT -p tcp -m tcp -m conntrack --ctstate INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460
|
||||
iptables -D INPUT -m conntrack --ctstate INVALID -j DROP
|
||||
```
|
||||
|
||||
### Evita que realicen escaneos de puertos a Alfa.
|
||||
|
||||
```bash
|
||||
iptables -N antiscan
|
||||
iptables -A antiscan -j DROP
|
||||
```
|
||||
|
||||
## Debemos implementar que el cortafuegos funcione después de un reinicio de la máquina.
|
||||
|
||||
Para hacer la instalación persistente, he utilizado el paquete iptables-persistent
|
||||
|
||||
```bash
|
||||
apt install iptables-persistent
|
||||
```
|
||||
|
||||
Para que funcione, tras crear todas las reglas, ejecuto el siguiente comando:
|
||||
|
||||
```bash
|
||||
sudo iptables-save > /etc/iptables/rules.v4
|
||||
```
|
||||
|
||||
Tras ejecutar eso, las reglas son persistentes. El fichero tiene el siguiente contenido:
|
||||
|
||||
![iptables-save](https://i.imgur.com/KbSN5IX.png)
|
BIN
src/content/posts/2023-03-07_copias_seguridad/featured.png
Normal file
After Width: | Height: | Size: 395 KiB |
400
src/content/posts/2023-03-07_copias_seguridad/index.md
Normal file
@ -0,0 +1,400 @@
|
||||
---
|
||||
title: Sistema de copias de seguridad
|
||||
published: 2023-03-07
|
||||
image: "./featured.png"
|
||||
tags: ["Bacula", "Backup","OpenStack"]
|
||||
category: Documentación
|
||||
draft: false
|
||||
---
|
||||
|
||||
## Enunciado
|
||||
|
||||
Implementar un sistema de copias de seguridad para las instancias del cloud, teniendo en cuenta las siguientes características:
|
||||
|
||||
* Selecciona una aplicación para realizar el proceso: bacula, amanda, shell script con tar, rsync, dar, afio, etc.
|
||||
* Utiliza una de las instancias como servidor de copias de seguridad, añadiéndole un volumen y almacenando localmente las copias de seguridad que consideres adecuadas en él.
|
||||
* El proceso debe realizarse de forma completamente automática
|
||||
* Selecciona qué información es necesaria guardar (listado de paquetes, ficheros de configuración, documentos, datos, etc.)
|
||||
* Realiza semanalmente una copia completa
|
||||
* Realiza diariamente una copia incremental o diferencial (decidir cual es más adecuada)
|
||||
* Implementa una planificación del almacenamiento de copias de seguridad para una ejecución prevista de varios años, detallando qué copias completas se almacenarán de forma permanente y cuales se irán borrando
|
||||
* Selecciona un directorio de datos "críticos" que deberá almacenarse cifrado en la copia de seguridad, bien encargándote de hacer la copia manualmente o incluyendo la contraseña de cifrado en el sistema
|
||||
* Incluye en la copia los datos de las nuevas aplicaciones que se vayan instalando durante el resto del curso
|
||||
* Utiliza una ubicación secundaria para almacenar las copias de seguridad. Solicita acceso o la instalación de las aplicaciones que sean precisas.
|
||||
|
||||
La corrección consistirá tanto en la restauración puntual de un fichero en cualquier fecha como la restauración completa de una de las instancias la última semana de curso.
|
||||
|
||||
---
|
||||
|
||||
El escenario es el siguiente_
|
||||
|
||||
![escenario](https://fp.josedomingo.org/sri2223/4_iaas/img/os.drawio.png)
|
||||
|
||||
| Máquina | IPs | tipo |
|
||||
| :-: | :-: | :-: |
|
||||
| alfa | 172.22.200.218, 172.16.0.1, 192.168.0.1 | Debian |
|
||||
| bravo | 172.16.0.200 | Rocky Linux |
|
||||
| charlie | 192.168.0.2 | Contenedor ubuntu |
|
||||
| delta | 192.168.0.3 | Contenedor ubuntu |
|
||||
|
||||
### Preparaciones previas
|
||||
|
||||
Y he decidido hacer las copias de seguridad desde alfa, ya que tiene conexión directa con las otras instancias. Para ello, voy a utilizar **bacula**, junto con su interfaz web **baculum**, tras ver las características de las distintas herramientas.
|
||||
|
||||
Antes de la instalación, compruebo que en alfa en total se han usado en disco 4.5 GB y en bravo 1.9 GB. Como charlie y delta son contenedores, el espacio ya se ha contado en alfa. Teniendo en cuenta el espacio usado, con un disco de 30 GB debería ser suficiente para guardar las copias de seguridad, tanto incrementales como completas.
|
||||
|
||||
Al disco le he instalado XFS por sus características de tolerancia a fallos, y lo he añadido a `/etc/fstab` para que se monte automáticamente al iniciar el sistema.
|
||||
|
||||
Creo la carpeta `/bacula` en la que va a estar montado permanentemente el disco, y le cambio el propietario y los permisos:
|
||||
|
||||
```bash
|
||||
mkdir -p /bacula
|
||||
chown -R bacula:bacula /bacula/
|
||||
chmod 755 -R /bacula
|
||||
```
|
||||
|
||||
Ahora, añado la siguiente línea al fichero `/etc/fstab`:
|
||||
|
||||
```bash
|
||||
UUID=5f086e6b-6937-460b-93ab-1a65a9e12544 /bacula xfs defaults 0 1
|
||||
```
|
||||
|
||||
## Instalación de bacula
|
||||
|
||||
Primero instalo los paquetes de bacula
|
||||
|
||||
```bash
|
||||
apt install bacula bacula-common-mysql bacula-director-mysql
|
||||
```
|
||||
|
||||
Durante la instalacion de `bacula-director-mysql` pregunta lo siguiente, le doy a yes e introduzco la contraseña de la base de datos.
|
||||
|
||||
![bacula-director-mysql](https://i.imgur.com/R9BRtUi.png)
|
||||
|
||||
Ahora instalo baculum, primero añado los repositorios:
|
||||
|
||||
```bash
|
||||
wget -qO - http://www.bacula.org/downloads/baculum/baculum.pub | apt-key add -
|
||||
echo "deb http://www.bacula.org/downloads/baculum/stable/debian buster main
|
||||
deb-src http://www.bacula.org/downloads/baculum/stable/debian buster main" > /etc/apt/sources.list.d/baculum.list
|
||||
```
|
||||
|
||||
Primero instalo los paquetes de la api
|
||||
|
||||
```bash
|
||||
apt update
|
||||
apt-get install apache2 baculum-common baculum-api baculum-api-apache2
|
||||
a2enmod rewrite
|
||||
a2ensite baculum-api
|
||||
systemctl restart apache2
|
||||
|
||||
```
|
||||
|
||||
Y ahora los paquetes de la interfaz web
|
||||
|
||||
```bash
|
||||
apt-get install baculum-common baculum-web baculum-web-apache2
|
||||
a2enmod rewrite
|
||||
a2ensite baculum-web
|
||||
systemctl restart apache2
|
||||
```
|
||||
|
||||
#### Configuración de la api
|
||||
|
||||
Primero accedo a http://172.22.200.218:9096/ , introduzco el usuario y contraseña por defecto (admin/admin) y configuro la api:
|
||||
|
||||
![configuracion api](https://i.imgur.com/PnRV17i.png)
|
||||
|
||||
Ahora, para permitir el acceso a la consola de bacula, edito el fichero `nano /etc/sudoers.d/baculum-api` y añado las siguiente líneas:
|
||||
|
||||
```bash
|
||||
Defaults:www-data !requiretty
|
||||
www-data ALL = (root) NOPASSWD: /usr/sbin/bconsole
|
||||
www-data ALL = (root) NOPASSWD: /usr/sbin/bdirjson
|
||||
www-data ALL = (root) NOPASSWD: /usr/sbin/bsdjson
|
||||
www-data ALL = (root) NOPASSWD: /usr/sbin/bfdjson
|
||||
www-data ALL = (root) NOPASSWD: /usr/sbin/bbconsjson
|
||||
www-data ALL = (root) NOPASSWD: /usr/bin/systemctl start bacula-dir
|
||||
www-data ALL = (root) NOPASSWD: /usr/bin/systemctl stop bacula-dir
|
||||
www-data ALL = (root) NOPASSWD: /usr/bin/systemctl restart bacula-dir
|
||||
www-data ALL = (root) NOPASSWD: /usr/bin/systemctl start bacula-sd
|
||||
www-data ALL = (root) NOPASSWD: /usr/bin/systemctl stop bacula-sd
|
||||
www-data ALL = (root) NOPASSWD: /usr/bin/systemctl restart bacula-sd
|
||||
www-data ALL = (root) NOPASSWD: /usr/bin/systemctl start bacula-fd
|
||||
www-data ALL = (root) NOPASSWD: /usr/bin/systemctl stop bacula-fd
|
||||
www-data ALL = (root) NOPASSWD: /usr/bin/systemctl restart bacula-fd
|
||||
```
|
||||
|
||||
![sudoers](https://i.imgur.com/H6QUnsE.png)
|
||||
|
||||
![confuracionapi2](https://i.imgur.com/5bNs8rG.png)
|
||||
|
||||
![confuracionapi3](https://i.imgur.com/OygLekr.png)
|
||||
|
||||
![confuracionapi4](https://i.imgur.com/57Vn21e.png)
|
||||
|
||||
Ahora creamos un usuario y una contraseña para la api
|
||||
|
||||
![confuracionapi5](https://i.imgur.com/dKYQjql.png)
|
||||
|
||||
Configuramos, ahora si, baculum en http://172.22.200.218:9095/
|
||||
|
||||
![confbaculum](https://i.imgur.com/mcdrvnm.png)
|
||||
|
||||
y utilizamos las credenciales de la api en la configuración:
|
||||
|
||||
![confbaculum2](https://i.imgur.com/YnQYUAz.png)
|
||||
|
||||
![confbaculum3](https://i.imgur.com/fbTDdCT.png)
|
||||
|
||||
## Configuración del servidor en alfa
|
||||
|
||||
### Selecciona qué información es necesaria guardar
|
||||
|
||||
En todas las instancias voy a guardar el contenido de /home, /etc, /var, /opt, /usr/share (menos los archivos temporales de var). Además de esto, en diferentes instancias voy a guardar lo siguiente:
|
||||
|
||||
| Instancia | Servicios | Localización |
|
||||
| --- | --- | --- |
|
||||
| alfa | bacula | /var/log |
|
||||
| bravo | httpd | /var/www, /etc/httpd |
|
||||
| charlie | dns | /var/chache/bind, /etc/bind |
|
||||
| delta | correo | /etc/postfix |
|
||||
|
||||
Cada día voy a hacer copias incrementales, cada semana se realizará una completa, al igual que cada mes.
|
||||
|
||||
Teniendo en cuenta esto, voy a configurar alfa utilizando los ficheros de configuración (por facilidad respecto a la interfaz web). Primero edito el fichero `/etc/bacula/bacula-dir.conf`, cambiando su contenido por el siguiente (es un fichero en mi github debido a la longitud del mismo):
|
||||
|
||||
[bacula-dir.conf](https://github.com/robertorodriguez98/bacula/blob/main/alfa/bacula-dir.conf)
|
||||
|
||||
compruebo que no hay errores en el fichero de configuración:
|
||||
|
||||
```bash
|
||||
bacula-dir -t -c /etc/bacula/bacula-dir.conf
|
||||
```
|
||||
|
||||
Y tras eso, modifico el fichero `/etc/bacula/bacula-sd.conf`,que contiene la configuración referente a los dispositivos de almacenamiento, cambiando su contenido por el siguiente (es un fichero en mi github debido a la longitud del mismo):
|
||||
|
||||
[bacula-sd.conf](https://github.com/robertorodriguez98/bacula/blob/main/alfa/bacula-sd.conf)
|
||||
|
||||
Al igual que antes, compruebo que no hay errores en el fichero de configuración:
|
||||
|
||||
```bash
|
||||
bacula-sd -t -c /etc/bacula/bacula-sd.conf
|
||||
```
|
||||
|
||||
y reinicio los servicios:
|
||||
|
||||
```bash
|
||||
systemctl restart bacula-sd.service
|
||||
systemctl enable bacula-sd.service
|
||||
systemctl restart bacula-director.service
|
||||
systemctl enable bacula-director.service
|
||||
```
|
||||
|
||||
## Preparación de los clientes
|
||||
|
||||
### Alfa
|
||||
|
||||
Alfa va a ser a la vez cliente y servidor, por lo que voy a instalar el cliente también en alfa:
|
||||
|
||||
```bash
|
||||
apt install bacula-client
|
||||
systemctl enable bacula-fd.service
|
||||
```
|
||||
|
||||
Ahora modifico el fichero `/etc/bacula/bacula-fd.conf`:
|
||||
|
||||
```bash
|
||||
Director {
|
||||
Name = alfa-dir
|
||||
Password = "bacula"
|
||||
}
|
||||
|
||||
Director {
|
||||
Name = alfa-mon
|
||||
Password = "bacula"
|
||||
Monitor = yes
|
||||
}
|
||||
|
||||
FileDaemon { # this is me
|
||||
Name = alfa-fd
|
||||
FDport = 9102 # where we listen for the director
|
||||
WorkingDirectory = /var/lib/bacula
|
||||
Pid Directory = /run/bacula
|
||||
Maximum Concurrent Jobs = 20
|
||||
Plugin Directory = /usr/lib/bacula
|
||||
FDAddress = 10.0.0.247
|
||||
}
|
||||
|
||||
# Send all messages except skipped files back to Director
|
||||
Messages {
|
||||
Name = Standard
|
||||
director = alfa-dir = all, !skipped, !restored
|
||||
}
|
||||
```
|
||||
|
||||
Y reinicio el servicio:
|
||||
|
||||
```bash
|
||||
systemctl restart bacula-fd.service
|
||||
```
|
||||
|
||||
|
||||
### Bravo
|
||||
|
||||
Instalo el cliente
|
||||
|
||||
```bash
|
||||
sudo dnf install bacula-client
|
||||
```
|
||||
|
||||
Y edito el fichero `/etc/bacula/bacula-fd.conf` y añado las siguientes líneas:
|
||||
|
||||
```bash
|
||||
Director {
|
||||
Name = alfa-dir
|
||||
Password = "bacula"
|
||||
}
|
||||
|
||||
Director {
|
||||
Name = alfa-mon
|
||||
Password = "bacula"
|
||||
Monitor = yes
|
||||
}
|
||||
|
||||
FileDaemon {
|
||||
Name = bravo-fd
|
||||
FDport = 9102
|
||||
WorkingDirectory = /var/lib/bacula
|
||||
Pid Directory = /run/bacula
|
||||
Maximum Concurrent Jobs = 20
|
||||
Plugin Directory = /usr/lib/bacula
|
||||
FDAddress = 172.16.0.200
|
||||
}
|
||||
|
||||
Messages {
|
||||
Name = Standard
|
||||
director = alfa-dir = all, !skipped, !restored
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
firewall-cmd --permanent --add-port=22/tcp
|
||||
firewall-cmd --permanent --add-port=80/tcp
|
||||
|
||||
firewall-cmd --permanent --add-port=9101/tcp
|
||||
firewall-cmd --permanent --add-port=9102/tcp
|
||||
firewall-cmd --permanent --add-port=9103/tcp
|
||||
firewall-cmd --reload
|
||||
```
|
||||
|
||||
|
||||
### Charlie y delta
|
||||
|
||||
La configuración en charlie y delta es similar, por eso la pongo junta:
|
||||
|
||||
```bash
|
||||
sudo apt install bacula-client
|
||||
```
|
||||
|
||||
Y edito el fichero `/etc/bacula/bacula-fd.conf`:
|
||||
|
||||
```bash
|
||||
Director {
|
||||
Name = alfa-dir
|
||||
Password = "bacula"
|
||||
}
|
||||
|
||||
Director {
|
||||
Name = alfa-mon
|
||||
Password = "bacula"
|
||||
Monitor = yes
|
||||
}
|
||||
|
||||
FileDaemon { # this is me
|
||||
Name = delta-fd
|
||||
FDport = 9102 # where we listen for the director
|
||||
WorkingDirectory = /var/lib/bacula
|
||||
Pid Directory = /run/bacula
|
||||
Maximum Concurrent Jobs = 20
|
||||
Plugin Directory = /usr/lib/bacula
|
||||
FDAddress = 192.168.0.3
|
||||
}
|
||||
|
||||
# Send all messages except skipped files back to Director
|
||||
Messages {
|
||||
Name = Standard
|
||||
director = alfa-dir = all, !skipped, !restored
|
||||
}
|
||||
```
|
||||
|
||||
Y reinicio el servicio:
|
||||
|
||||
```bash
|
||||
systemctl restart bacula-fd.service
|
||||
```
|
||||
|
||||
Ahora, con todos los cliente configurados, reinicio los servicios de bacula en alfa:
|
||||
|
||||
```bash
|
||||
systemctl restart bacula-fd.service
|
||||
systemctl restart bacula-sd.service
|
||||
systemctl restart bacula-director.service
|
||||
```
|
||||
|
||||
y hago una prueba de conexión usando la consola de bácula y la interfaz web:
|
||||
|
||||
```bash
|
||||
bconsole
|
||||
```
|
||||
|
||||
![bconsole](https://i.imgur.com/PCa4pzo.png)
|
||||
|
||||
|
||||
![web](https://i.imgur.com/EWP7PH0.png)
|
||||
|
||||
## Nodos de almacenamiento
|
||||
|
||||
Ahora voy a crear los nodos de almacenamiento con bconsole
|
||||
|
||||
```bash
|
||||
bconsole
|
||||
```
|
||||
|
||||
![bconsole](https://i.imgur.com/pkpErri.png)
|
||||
|
||||
También se puede hacer desde la interfaz web:
|
||||
|
||||
![web](https://i.imgur.com/DKz9aUK.png)
|
||||
|
||||
Realizo la misma configuración para vol-semanal y vol-mensual.
|
||||
|
||||
Podemos ver que se han creado los volúmenes:
|
||||
|
||||
![web](https://i.imgur.com/WOVsDgp.png)
|
||||
|
||||
## Restauración
|
||||
|
||||
Voy a realizar la restauración por medio de la interfaz web. Para ello utilizo la opción de Perform restore y sigo los siguientes pasos:
|
||||
|
||||
![web](https://i.imgur.com/WpBBp3u.png)
|
||||
|
||||
![web2](https://i.imgur.com/g4kd0Ri.png)
|
||||
|
||||
![web3](https://i.imgur.com/SYrgbek.png)
|
||||
|
||||
![web4](https://i.imgur.com/0Z7Z7Zg.png)
|
||||
|
||||
Selecciono qué quiero copiar y donde:
|
||||
|
||||
![web5](https://i.imgur.com/rgz94GM.png)
|
||||
|
||||
![web6](https://i.imgur.com/DlrJT2c.png)
|
||||
|
||||
y que reemplace los ficheros más antiguos:
|
||||
|
||||
![web7](https://i.imgur.com/Y38EHgZ.png)
|
||||
|
||||
Cuando acabe puedo ver que se ha ejecutado con éxito:
|
||||
|
||||
![web8](https://i.imgur.com/6Gok1iW.png)
|
After Width: | Height: | Size: 148 KiB |
@ -0,0 +1,4 @@
|
||||
[ZoneTransfer]
|
||||
ZoneId=3
|
||||
ReferrerUrl=https://imgur.com/
|
||||
HostUrl=https://i.imgur.com/dGsLI6i.png
|
442
src/content/posts/2023-06-01_despliegue-crossplane-eks/index.md
Normal file
@ -0,0 +1,442 @@
|
||||
---
|
||||
title: Despliegue de EKS usando CrossPlane + ArgoCD
|
||||
published: 2023-06-01
|
||||
image: "./featured.png"
|
||||
tags: ["IaC", "kubernetes","AWS","Crossplane","ArgoCD"]
|
||||
category: Documentación
|
||||
draft: false
|
||||
---
|
||||
|
||||
## Descripción
|
||||
|
||||
El objetivo del proyecto es, utilizando Crossplane, desplegar un clúster de eks y luego sobre éste desplegar una aplicación web estática utilizando para ambos casos como apoyo ArgoCD.
|
||||
|
||||
A pesar de existir una alternativa de IaC como terraform, se ha decidido usar Crossplane ya que permite utilizar los comandos nativos de kubernetes para gestionar todos sus recursos, al ser una extensión del mismo.
|
||||
|
||||
Todos los manifiestos y archivos de configuración se encuentran en el siguiente [repositorio](https://github.com/robertorodriguez98/proyecto-integrado).
|
||||
|
||||
Pincha aquí para ir directamente a la configuración del [**escenario realizado**](#escenario-realizado) o aquí para ir directamente a las [**demos**](#demostraciones).
|
||||
|
||||
También en la página de los proyectos integrados se pueden encontrar la documentación en formato pdf, la presentación, y el vídeo de demostración:
|
||||
|
||||
https://dit.gonzalonazareno.org/gestiona/proyectos/
|
||||
|
||||
---
|
||||
|
||||
## Objetivos que se quieren conseguir
|
||||
|
||||
Los objetivos que se quieren conseguir son los siguientes:
|
||||
* Lograr una mayor **comprensión** de lo que es **Crossplane** y sus posibles aplicaciones.
|
||||
* **Automatización**: La definición de la infraestructura como código y la automatización del proceso de implementación y gestión de la infraestructura permite a los equipos de desarrollo y operaciones centrarse en tareas más importantes y reducir los errores humanos.
|
||||
* **Escalabilidad**: Otra ventaja de Kubernetes es su capacidad de escalar automáticamente, tanto hacia arriba como hacia abajo, en función de las necesidades del sistema. Al utilizar Crossplane para gestionar la infraestructura de AWS, se pueden aprovechar las capacidades de escalabilidad de AWS y de Kubernetes para garantizar que el sistema siempre tenga los recursos necesarios para funcionar correctamente.
|
||||
* **Portabilidad**: Al utilizar Crossplane, se puede asegurar que la infraestructura es portátil y se puede mover fácilmente a otras nubes o proveedores de infraestructura en el futuro. Esto permite a las organizaciones evitar el bloqueo de proveedores y aprovechar las ventajas de diferentes proveedores de nube según sea necesario.
|
||||
* **Costes**: La utilización de una infraestructura basada en la nube puede ser costosa, por lo que es importante asegurarse de que los recursos se utilizan de manera eficiente y se minimizan los costos innecesarios. Al utilizar Crossplane para gestionar la infraestructura de AWS, se puede optimizar el uso de los recursos y evitar pagar por recursos no utilizados.
|
||||
|
||||
### ¿Por qué Crossplane?
|
||||
|
||||
La **principal ventaja** de Crossplane es que, aún existiendo frameworks que permitan desplegar la misma infraestructura, Crossplane traslada esas interacciones a **kubernetes**, utilizando sus comandos propios y sus métodos. Esto quiere decir que, por ejemplo, habiendo desplegado un clúster en AWS, se crean automáticamente los siguientes objetos de kubernetes enlazados a la api de AWS:
|
||||
|
||||
![objetos de kubernetes creados](https://i.imgur.com/A8vDXMj.png)
|
||||
|
||||
Además, utilizando kubectl podemos obtener aún más información acerca de estos objetos, dentro del propio clúster local:
|
||||
|
||||
![cluster local](https://i.imgur.com/hlc1Rae.png)
|
||||
|
||||
En la imagen se puede obtener toda la información referente a el objeto indicado, en este caso un nodegroup, y podemos ver, por ejemplo, el rol de nodo que tiene asignado, la región en la que se encuentra, las subredes disponibles…
|
||||
|
||||
Aparte de eso, las ventajas que tiene frente el principal competidor, terraform, son:
|
||||
* **Ficheros más entendibles (YAML)**: Crossplane utiliza archivos YAML para definir la infraestructura, lo que los hace más fáciles de entender y leer para los desarrolladores que pueden estar más familiarizados con el formato YAML. Terraform, por otro lado, utiliza su propio lenguaje de configuración llamado HCL (HashiCorp Configuration Language), que puede tener una curva de aprendizaje para aquellos que no están familiarizados con él.
|
||||
* **Permite desplegar indistintamente en los proveedores cloud**: Crossplane se enfoca en la gestión de la infraestructura multi-nube, lo que significa que permite a los usuarios definir y gestionar recursos en múltiples proveedores de nube utilizando la misma sintaxis de Kubernetes. Terraform también soporta múltiples proveedores de nube, pero requiere la definición de cada recurso utilizando un proveedor de nube específico.
|
||||
* **Metodología GitOps**: Crossplane está diseñado para trabajar en una metodología GitOps, lo que significa que todas las definiciones de recursos se almacenan en un repositorio Git y los cambios se aplican automáticamente al clúster de Kubernetes utilizando un proceso de integración y entrega continua (CI/CD). Terraform no está diseñado específicamente para trabajar con GitOps, aunque puede integrarse con sistemas de control de versiones como Git para almacenar y gestionar el código de infraestructura.
|
||||
|
||||
## Fundamentos teóricos y conceptos
|
||||
|
||||
### Kubernetes
|
||||
|
||||
Kubernetes o k8s para acortar, es una plataforma de sistema distribuido de código libre para la automatización del despliegue, ajuste de escala y manejo de aplicaciones. Una de las principales ventajas de Kubernetes es que ofrece una plataforma común para el desarrollo y la producción de aplicaciones. Esto significa que los equipos de desarrollo pueden crear aplicaciones en sus equipos y luego trasladarlas sin problemas a un entorno de producción utilizando las mismas herramientas y procesos. Kubernetes proporciona una capa de abstracción entre la infraestructura subyacente y las aplicaciones que se ejecutan en ella, lo que facilita la portabilidad de las aplicaciones entre diferentes plataformas y proveedores de nube. Además, Kubernetes ofrece características de autoreparación, lo que significa que las aplicaciones pueden recuperarse automáticamente de fallos en tiempo de ejecución, sin necesidad de intervención humana.
|
||||
|
||||
#### Plano de control
|
||||
|
||||
El plano de control de Kubernetes es el conjunto de componentes que se encargan de gestionar el estado del clúster y de coordinar todas las operaciones en el mismo. Estos componentes son responsables de tomar decisiones sobre la orquestación y el escalado de los contenedores y aplicaciones en el clúster, y de garantizar que el estado deseado del clúster se mantenga en todo momento.
|
||||
|
||||
### GitOps
|
||||
|
||||
La metodología GitOps es un enfoque para la entrega continua de aplicaciones en la nube que utiliza Git como fuente de verdad para la configuración y la implementación de la infraestructura y las aplicaciones. En la metodología GitOps, todas las definiciones de la infraestructura y las aplicaciones se almacenan en un repositorio Git centralizado. Los cambios en el repositorio Git son automáticamente detectados por una herramienta de despliegue, que se encarga de implementar los cambios en la infraestructura y las aplicaciones.
|
||||
|
||||
La metodología GitOps se basa en los principios de la automatización, la colaboración y la transparencia. En primer lugar, la metodología GitOps
|
||||
|
||||
* **Automatización** de la gestión de la infraestructura y las aplicaciones, lo que permite la implementación continua de cambios en un entorno controlado y seguro.
|
||||
* **Colaboración** entre los miembros del equipo, ya que todos los cambios se realizan en el repositorio Git centralizado, lo que permite a los miembros del equipo trabajar en conjunto de manera más eficiente.
|
||||
* **Transparencia**, ya que todos los cambios y versiones se registran en el repositorio Git centralizado, lo que permite a los miembros del equipo revisar y rastrear el historial de cambios.
|
||||
|
||||
### ArgoCD
|
||||
|
||||
Argo CD es una herramienta de entrega continua (Continuous Delivery) y de operaciones de infraestructura (Infrastructure Operations) que se ejecuta en Kubernetes. Permite la automatización y el control del proceso de implementación y despliegue de aplicaciones en un clúster de Kubernetes.
|
||||
|
||||
![ArgoCD](https://i.imgur.com/893wkC8.png)
|
||||
|
||||
Una de las características más destacadas de Argo CD es su capacidad para automatizar la gestión de versiones y el despliegue de aplicaciones. Permite la definición de flujos de trabajo (workflows) para la implementación de cambios, lo que garantiza que los cambios se realicen de manera controlada y segura. Argo CD también incluye características de seguridad, como el control de acceso basado en roles y la autenticación de usuarios.
|
||||
|
||||
### Infraestructura como código
|
||||
|
||||
Es una práctica que consiste en definir la infraestructura de una aplicación o sistema de forma programática utilizando un lenguaje de programación o una sintaxis específica. En lugar de configurar manualmente servidores, redes y otros recursos de infraestructura, los desarrolladores y los equipos de operaciones pueden definir la infraestructura como código y utilizar herramientas de automatización para gestionar y desplegar la infraestructura en un entorno reproducible y escalable.
|
||||
|
||||
### Crossplane
|
||||
|
||||
Crossplane es una extensión de kubernetes que transforma kubernetes en un **plano de control Universal**. Permite a los usuarios utilizar cualquier API como si fuera nativa de Kubernetes. Esto se logra mediante el uso de los recursos personalizados de Kubernetes (CRD), que permiten a los desarrolladores definir y extender los recursos de Kubernetes con sus propias definiciones. Puede crear y gestionar recursos que no son nativos de Kubernetes, como bases de datos, servicios de almacenamiento en la nube, cuentas de usuario y cualquier otra cosa que una API pueda ofrecer.
|
||||
|
||||
Además, Crossplane es compatible con **múltiples proveedores de nube**, lo que significa que los usuarios pueden utilizar cualquier servicio de cualquier proveedor de nube, incluidos Amazon Web Services, Google Cloud Platform y Microsoft Azure, entre otros. Esto permite a los usuarios crear **aplicaciones que utilizan servicios de varios proveedores de nube** sin tener que preocuparse por la complejidad de gestionar múltiples APIs de nube diferentes.
|
||||
|
||||
![Crossplane](https://i.imgur.com/fJhMKBU.png)
|
||||
|
||||
#### Proveedor
|
||||
|
||||
Un proveedor de Crossplane le permite aprovisionar una **infraestructura en un servicio externo**. se utiliza, entre otras cosas, para la autenticación, la realización de llamadas a API externas y utilizando APIs de kubernetes.
|
||||
|
||||
Para utilizar un proveedor además, es necesaria una configuración. Ésta se realiza por medio del uso de **providerConfig**. Normalmente se utilizan para autenticarse con la API con la que se está comunicando, En este proyecto, se utilizan tanto con las credenciales de **AWS** como con el **clúster de EKS**.
|
||||
|
||||
## Escenario realizado
|
||||
|
||||
El escenario consiste en lo siguiente:
|
||||
* Clúster local de kubernetes, en el que se han instalado las siguientes aplicaciones:
|
||||
* ArgoCD
|
||||
* Crossplane, con los proveedores de AWS y Kubernetes.
|
||||
* Clúster de EKS creado y gestionado por Crossplane, en el que hay 3 nodos.
|
||||
|
||||
![Escenario](https://i.imgur.com/5KqPm1R.png)
|
||||
|
||||
### Instalaciones
|
||||
|
||||
Para la realización del proyecto, se necesita instalar los siguientes recursos:
|
||||
|
||||
#### Clúster local de kubernetes
|
||||
|
||||
Para desplegar un clúster local de k8s, se usará **kind**, ya que el proveedor de aws de crossplane consume muchos recursos, y kind es más liviano. Para su instalación se seguirá la documentación oficial: [Instalación kind](https://kind.sigs.k8s.io/docs/user/quick-start/). Para gestionar el clúster también es necesario kubectl, y la documentación oficial de instalación es la siguiente: [instalación kubectl](https://kubernetes.io/es/docs/tasks/tools/install-kubectl/). Es muy importante partir de un **clúster nuevo** y sin configuraciones previas.
|
||||
|
||||
#### ArgoCD
|
||||
|
||||
Para instalar ArgoCD se ejecutan los siguientes comandos:
|
||||
|
||||
```bash
|
||||
kubectl create namespace argocd
|
||||
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
|
||||
```
|
||||
|
||||
Para acceder a la página de administración, necesito la contraseña inicial. Se obtiene con el siguiente comando; el usuario es admin:
|
||||
|
||||
```bash
|
||||
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d;echo
|
||||
```
|
||||
|
||||
Y para acceder a la página, se realiza el siguiente port-forward:
|
||||
|
||||
```bash
|
||||
kubectl port-forward svc/argocd-server -n argocd 8080:80 --address=0.0.0.0
|
||||
```
|
||||
|
||||
Tras eso ya está configurado ArgoCD.
|
||||
|
||||
#### Crossplane
|
||||
|
||||
Para instalar crossplane utilizamos helm
|
||||
|
||||
```bash
|
||||
helm repo add \
|
||||
crossplane-stable https://charts.crossplane.io/stable
|
||||
helm repo update
|
||||
|
||||
helm install crossplane \
|
||||
crossplane-stable/crossplane \
|
||||
--namespace crossplane-system \
|
||||
--create-namespace
|
||||
```
|
||||
|
||||
### Configuración
|
||||
|
||||
#### AWS
|
||||
|
||||
Es necesaria una cuenta con los permisos de AWS para crear y gestionar los siguientes recursos:
|
||||
* instancias EC2
|
||||
* clúster de EKS
|
||||
* redes VPC
|
||||
* Tokens de acceso a la propia cuenta
|
||||
Una vez se disponga de dicha cuenta, creamos el token en el siguiente apartado:
|
||||
|
||||
credenciales de seguridad > crear clave de acceso > seleccionamos el cuadro y crear clave de acceso > descargar archivo.csv
|
||||
|
||||
#### Proveedores de Crossplane
|
||||
|
||||
##### AWS
|
||||
|
||||
Ahora instalamos la última versión del provider de AWS de crossplane
|
||||
|
||||
```bash
|
||||
cat <<EOF | kubectl apply -f -
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: provider-aws
|
||||
spec:
|
||||
package: xpkg.upbound.io/crossplane-contrib/provider-aws:v0.39.0
|
||||
EOF
|
||||
```
|
||||
|
||||
Tras eso, creamos el fichero **aws-credentials.txt** con las claves generadas en AWS con el siguiente formato:
|
||||
|
||||
```bash
|
||||
[default]
|
||||
aws_access_key_id = <aws_access_key>
|
||||
aws_secret_access_key = <aws_secret_key>
|
||||
```
|
||||
|
||||
Creamos un **secret** de kubernetes con las credenciales
|
||||
|
||||
```bash
|
||||
kubectl create secret \
|
||||
generic aws-creds \
|
||||
-n crossplane-system \
|
||||
--from-file=creds=./aws-credentials.txt
|
||||
```
|
||||
|
||||
Finalmente, se crea un **providerconfig** con el secret que hemos creado
|
||||
|
||||
```bash
|
||||
cat <<EOF | kubectl apply -f -
|
||||
apiVersion: aws.crossplane.io/v1beta1
|
||||
kind: ProviderConfig
|
||||
metadata:
|
||||
name: default
|
||||
spec:
|
||||
credentials:
|
||||
source: Secret
|
||||
secretRef:
|
||||
namespace: crossplane-system
|
||||
name: aws-creds
|
||||
key: creds
|
||||
EOF
|
||||
```
|
||||
|
||||
##### kubernetes
|
||||
|
||||
Instalamos el proveedor con el siguiente comando:
|
||||
|
||||
```bash
|
||||
cat <<EOF | kubectl apply -f -
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: crossplane-provider-kubernetes
|
||||
spec:
|
||||
package: crossplane/provider-kubernetes:main
|
||||
EOF
|
||||
```
|
||||
|
||||
#### Recursos gestionados
|
||||
|
||||
Para desplegar un clúster de aws de forma sencilla, se van a utilizar dos recursos gestionados (managed resources):
|
||||
|
||||
* **eks.yaml**, de tipo composition que contiene parámetros para la creación del clúster, como lo son las redes que se crearán, en qué servidores, qué tipo de máquinas pueden crearse, etc..
|
||||
* **definition.yaml**, de tipo compositeResourceDefinition, contiene los parámetros que se le van a pasar con el manifiesto final, así como los recursos a los que corresponden en composition. También contiene valores por defecto.
|
||||
|
||||
Ambos ficheros se encuentran en el repositorio del proyecto en la carpeta crossplane:
|
||||
https://github.com/robertorodriguez98/proyecto-integrado/tree/main/crossplane
|
||||
|
||||
Para añadirlos, se utiliza kubectl:
|
||||
|
||||
```bash
|
||||
kubectl apply -f eks.yaml && kubectl apply -f definition.yaml
|
||||
```
|
||||
|
||||
#### Ngrok
|
||||
|
||||
Para que ArgoCD esté atento a los commits de github y siga así la metodología GitOps, al tenerlo instalado en un clúster local, es necesario instalar ngrok, exponiendo el puerto 8080:
|
||||
|
||||
```bash
|
||||
curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok
|
||||
```
|
||||
|
||||
Añadimos el token:
|
||||
|
||||
```bash
|
||||
ngrok config add-authtoken [TOKEN]
|
||||
```
|
||||
|
||||
y exponemos el puerto:
|
||||
|
||||
```bash
|
||||
ngrok http https://localhost:8080
|
||||
```
|
||||
|
||||
#### Webhook
|
||||
|
||||
Para que GitHub notifique a ArgoCD en el evento de un push al repositorio, tenemos que añadirlo en la configuración del mismo. Para hacerlo, en el repositorio accedemos al apartado **Settings**; en la barra lateral seleccionamos **Webhooks** y **Add webhook**.
|
||||
|
||||
Dentro de la página, tenemos que rellenar los siguientes campos:
|
||||
* **Payload URL**: la url generada por Ngrok, con la cadena /api/webhook añadida al final.
|
||||
* **Content type**: application/json.
|
||||
* **Event**: Cuando se produce un
|
||||
|
||||
#### Preparación previa a la demo
|
||||
|
||||
Para preparar la demo, iniciaremos la aplicación de argocd **app.yaml** que se encuentra en el repositorio, ésta despliega el siguiente manifiesto:
|
||||
|
||||
```yaml
|
||||
apiVersion: prodready.cluster/v1alpha1
|
||||
kind: ClusterClaim
|
||||
metadata:
|
||||
name: proyecto-eks
|
||||
labels:
|
||||
cluster-owner: robertorm
|
||||
spec:
|
||||
id: proyecto-eks
|
||||
compositionSelector:
|
||||
matchLabels:
|
||||
provider: aws
|
||||
cluster: eks
|
||||
parameters:
|
||||
nodeSize: medium
|
||||
minNodeCount: 3
|
||||
```
|
||||
|
||||
Donde podemos modificar los siguientes parámetros:
|
||||
|
||||
* **name**: Nombre del clúster.
|
||||
* **nodesize**: tipo de máquina que se van a utilizar en los nodos. En el fichero eks.yaml se establecen los siguientes tamaños:
|
||||
* small: t2:micro
|
||||
* medium: t3.micro
|
||||
* large: t3.medium
|
||||
|
||||
Los dos primeros tamaños, entran dentro de la capa gratuita de AWS.
|
||||
* **minNodeCount**: mínimo de nodos que tienen que crearse en el clúster.
|
||||
|
||||
Tras aproximadamente **15 minutos**, el clúster estará creado junto a sus nodos. Si observamos el panel de ArgoCD de la aplicación, podemos ver todos los recursos de AWS que se han desplegado:
|
||||
|
||||
![ArgoCD](https://i.imgur.com/CaTYVUb.png)
|
||||
|
||||
## Demostraciones
|
||||
|
||||
### Modificación del número de nodos
|
||||
|
||||
El escenario final de la demo es el siguiente:
|
||||
|
||||
![Escenario](https://i.imgur.com/5KqPm1R.png)
|
||||
|
||||
Y el flujo de trabajo en el que consiste la primera demo, con el clúster ya desplegado es el siguiente:
|
||||
|
||||
1. Se realiza un commit a **github** con un cambio en el manifiesto **aws-eks.yaml**, concretamente se cambia el número de nodos que va a tener el clúster de EKS.
|
||||
2. **ArgoCD** se da cuenta de que se han realizado cambios en el repositorio, y, aplicando la metodología **gitops**, hace que en los recursos que gestiona se vean reflejados dichos cambios. Compruebo que en el panel de la aplicación se ve reflejado el cambio en el recurso **nodegroup**.
|
||||
3. **Crossplane**, haciendo uso del provider de AWS, se comunica con la API referente a EKS, e indica que el número de nodos ha cambiado.
|
||||
4. Finalmente, en **AWS** se hacen efectivos los cambios, por lo que podemos comprobarlo accediendo a la consola de **EKS** y viendo el nuevo nodo.
|
||||
|
||||
![Demo1](https://i.imgur.com/5Up9qo2.png)
|
||||
|
||||
Tras ello, para demostrar el funcionamiento de Crossplane, y como este asegura que se siga el marco de trabajo **GitOps**, se añade un nodo desde la consola de AWS, mostrando como Crossplane lo detecta y vuelve a dejarlo como está definido en los recursos.
|
||||
|
||||
### Despliegue en el clúster
|
||||
|
||||
Una vez con el clúster, se va a desplegar una aplicación sobre él, utilizando también crossplane. El escenario es el siguiente:
|
||||
|
||||
![Escenario2](https://i.imgur.com/ZqjeuTb.png)
|
||||
|
||||
#### Configuración del proveedor de kubernetes
|
||||
|
||||
Para configurar el proveedor de kubernetes para que tenga acceso al clúster que acabamos de crear, se ejecutan los siguientes comandos; Primero obtenemos el **kubeconfig** y lo guardamos en un fichero:
|
||||
|
||||
```bash
|
||||
kubectl --namespace crossplane-system \
|
||||
get secret proyecto-eks-cluster \
|
||||
--output jsonpath="{.data.kubeconfig}" \
|
||||
| base64 -d >kubeconfig.yaml
|
||||
```
|
||||
|
||||
Enviamos el contenido del fichero a la variable KUBECONFIG:
|
||||
|
||||
```bash
|
||||
KUBECONFIG=$(<kubeconfig.yaml)
|
||||
```
|
||||
|
||||
Usando la variable, creamos un secret que pueda usar el proveedor:
|
||||
|
||||
```bash
|
||||
kubectl -n crossplane-system create secret generic cluster-config --from-literal=kubeconfig="${KUBECONFIG}"
|
||||
```
|
||||
|
||||
Ahora, añadimos la configuración del proveedor usando el secret (el fichero está en la raiz del repositorio). El archivo es: [config-kubernetes.yaml](https://github.com/robertorodriguez98/proyecto-integrado/blob/main/config-kubernetes.yaml):
|
||||
|
||||
```bash
|
||||
kubectl apply -f config-kubernetes.yaml
|
||||
```
|
||||
|
||||
#### Script
|
||||
|
||||
Para facilitar la ejecución de la demo, se ha creado el script [configurar-k8s.sh](https://github.com/robertorodriguez98/proyecto-integrado/blob/main/scripts/configurar-k8s.sh) que aúna los pasos anteriores.
|
||||
|
||||
#### Aplicación de ArgoCD
|
||||
|
||||
Una vez realizados los pasos anteriores, solo queda desplegar la aplicación. Para ello se va a volver a utilizar ArgoCD; en este caso se va a utilizar la aplicación [despliegue-remoto.yaml](https://github.com/robertorodriguez98/proyecto-integrado/blob/main/despliegue-remoto.yaml). Una vez desplegado, se ve así en ArgoCD
|
||||
|
||||
![ArgoCD2](https://i.imgur.com/8RSAr3s.png)
|
||||
|
||||
para obtener la dirección en la que está la aplicación desplegada (gracias al loadbalancer) se utiliza el siguiente comando:
|
||||
|
||||
```bash
|
||||
kubectl describe object loadbalancer-aplicacion-remoto
|
||||
```
|
||||
|
||||
O si queremos la dirección directamente:
|
||||
|
||||
```bash
|
||||
kubectl describe object loadbalancer-aplicacion-remoto | egrep "Hostname"
|
||||
```
|
||||
|
||||
En la captura el comando es "k" ya que tengo un alias para el comando kubectl.
|
||||
|
||||
![hostname](https://i.imgur.com/hnPYe2c.png)
|
||||
|
||||
Finalmente, si accedemos a la dirección podemos visualizar la aplicación desplegada:
|
||||
|
||||
![app](https://i.imgur.com/ak5QzBW.png)
|
||||
|
||||
## Dificultades encontradas
|
||||
|
||||
### Despliegue sobre AWS
|
||||
|
||||
Las principales dificultades que se han encontrado a la hora de desplegar sobre AWS son las siguientes:
|
||||
|
||||
* **Falta de documentación/ejemplos**: Al tratarse de una tecnología relativamente nueva y con una comunidad todavía en crecimiento, no ha sido fácil encontrar ejemplos que aplicaran la api de **AWS** para desplegar específicamente sobre **EKS**.
|
||||
* **Múltiples proveedores**: A la hora de elegir el proveedor en el marketplace, resulta que para Amazon Web Services existen **dos diferentes**, y en la documentación, dependiendo de la versión que se esté consultando, usan uno u otro, teniendo éstos **diferentes métodos y llamadas**.Se ha utilizado finalmente el siguiente, debido a que hay más documentación sobre él: https://marketplace.upbound.io/providers/crossplane-contrib/provider-aws/v0.39.0
|
||||
* **Coste**: El uso de EKS no se encuentra dentro de la **capa gratuita de AWS**, por lo que desplegar un clúster conlleva un gasto económico (aunque no muy alto).
|
||||
|
||||
### Despliegue sobre kubernetes
|
||||
|
||||
Desplegando sobre kubernetes he tenido otras problemáticas. Son las siguientes:
|
||||
|
||||
* **Falta de documentación/ejemplos**: Al ser una extensión de **Crossplane**, los problemas relacionados con la falta de comunidad también se aplican al proveedor de kubernetes.
|
||||
* **Pocas explicaciones**: Existe un repositorio oficial con ejemplos, pero para que estos funcionen sobre un clúster en **AWS** hay que realizar **pasos extra** que no explican.
|
||||
* **Caducidad**: Las credenciales que se utilizan para crear el **secret** de kubernetes que permite la conexión, caducan a los **30 minutos**.
|
||||
|
||||
## Conclusión
|
||||
|
||||
Con la realización del proyecto hemos podido comprender mejor la **infraestructura como código**, así como la implementación de ésta por medio de una nueva tecnología que es **Crossplane**, aplicando este conocimiento a desplegar un clúster de EKS en Amazon Web Services y una aplicación dentro del mismo, haciendo uso de un **entorno con múltiples proveedores**, aprovechando las funcionalidades que este ofrece. Al ser Crossplane una herramienta tan versátil y potente, hay muchas cosas que se pueden hacer que no se han llegado a tocar en el proyecto.
|
||||
|
||||
También, y, a consecuencia del tema del proyecto, hemos aprendido acerca de la metodología **GitOps** y cómo aplicarla utilizando **ArgoCD**, que sirve a la perfección para este propósito gracias al funcionamiento de sus aplicaciones basadas en repositorios de GitHub.
|
||||
|
||||
Finalmente, se ha profundizado en el funcionamiento de **kubernetes**, aprendiendo acerca del plano de control y de las diferentes APIs que gestionan los recursos.
|
||||
|
||||
En conclusión, Crossplane es una herramienta muy **polifacética y útil**, siendo su principal virtud, **trasladar la infraestructura como código al terreno de kubernetes**, haciendo así que sea especialmente atractiva, y, tras un poco de aprendizaje, una herramienta a tener en cuenta de cara a **desplegar infraestructura**.
|
||||
|
||||
## Bibliografía
|
||||
|
||||
* Crossplane on Amazon EKS (canal Containers from the Couch): https://www.youtube.com/live/aWRWKnniqeM?feature=share
|
||||
* Documentación de Crossplane: https://docs.crossplane.io/v1.12/
|
||||
* Proveedores de Crossplane: https://docs.crossplane.io/latest/concepts/providers/
|
||||
* Documentación de la api de los diferentes proveedores:
|
||||
* AWS: https://doc.crds.dev/github.com/crossplane/provider-aws
|
||||
* Helm: https://doc.crds.dev/github.com/crossplane-contrib/provider-helm
|
||||
* K8s: https://doc.crds.dev/github.com/crossplane-contrib/provider-kubernetes
|
||||
* AWS Quickstart: https://docs.crossplane.io/v1.12/getting-started/provider-aws/
|
||||
* Production ready EKS Cluster with Crossplane: https://www.kloia.com/blog/production-ready-eks-cluster-with-crossplane
|
||||
* GitOps model for provisioning and bootstrapping Amazon EKS clusters using Crossplane and Flux: https://aws.amazon.com/es/blogs/containers/gitops-model-for-provisioning-and-bootstrapping-amazon-eks-clusters-using-crossplane-and-flux/
|
||||
* Ejemplos del proveedor de kubernetes: https://github.com/crossplane-contrib/provider-kubernetes
|
||||
|
||||
|