Il servizio AWS Key Management Service, spesso abbreviato con la sigla KMS, è studiato per gestire le fasi entyption di oggetti e della gestione delle chiavi di sicurezza usate in fase di cifratura e decifratura. Essendo un servizio unico e centralizzato garantisce la sicurezza ed è studiato per lavorare con tutti gli altri servizi e a tutte le applicazioni AWS. Visto che si tratta di un argomento molto importante e delicato, si rimanda alla guida ufficiale e alla pagina ufficiale per i dettagli, questo vuole essere solo un riassunto dei comandi principali per poter usare questo servizio. Si rimanda alla documentazione ufficiale anche per i dettagli sulla rotazione delle chiavi e la gestione delle policy di accesso, temi molto importanti che è fondamentale conoscere per garantire la sicurezza nel Cloud, è fondamentale anche ricordare che il servizio presenta dei costi d’uso: per ogni chiave c’è un costo di manutenzione mensile e sono previsti dei costi in base alle richieste di operazioni eseguite. Per usare questo servizio bisogna aver presente la differenza tra chiavi simmetriche e asimmetteriche e bisogna conoscere bene la differenza tra i tipi di chiave: owned (SSE), managed oppure custom.

La procedura di creazione di una chiave da console è molto semplice, richiede queste informazioni:

  • tipo: simmetrico o asimmetrico
  • uso: semplice o hMAC
  • origine: KMS, CloudHSM oppure esterna
  • region: semplice o multi AZ
  • nome, descrizione e tags
  • regole IAM di amministratore e l’elenco degli utenti abilitati all’uso delle chiavi

Con la CLI è possibile gestire il servizio KMS con un gruppo di comandi dedicato, i principali comandi sono:

  • la lista di tutte le chiavi:
    $ aws kms list-keys
  • il dettaglio di una chiave:
    $ aws kms describe-key --key-id <key_id>
  • la chiave pubblica di una chiave di tipo asimmetrico:
    $ aws kms get-public-key --key-id <key_id>
  • comando per la cifratura di un file:
    $ aws kms encrypt --key-id <key_id> --plaintext fileb://in.txt --output text
    $ aws kms encrypt --key-id <key_id> --plaintext fileb://in.txt --output text --encryption-algorithm RSAES_OAEP_SHA_256 --query CiphertextBlob | base64 --decode > out.txt
  • comando la la decifratura di un file:
    $ aws kms decrypt --key-id <key_id> --ciphertext-blob fileb://out.txt --encryption-algorithm RSAES_OAEP_SHA_256 --output text --query Plaintext | base64 --decode
  • comando per creare una chive, per questo comando specifico si rimanda alla documentazione ufficiale per tutti i dettagli, un semplice esempio:
    $ aws kms create-key --key-spec RSA_4096 --key-usage ENCRYPT_DECRYPT

Anche la libreria SDK mette a disposizione molte funzioni per la gestione delle chiavi gestite con il servizio KMS, i principali sono:

def get_keys(profile_name):
  boto3.setup_default_session(profile_name=profile_name)
  kms = boto3.client('kms')
  response = kms.list_keys( Limit=100, )#Marker='string'
  if 'Keys' in response:
    return response['Keys']
  return []
def get_key_detail(profile_name,key_id):
  boto3.setup_default_session(profile_name=profile_name)
  kms = boto3.client('kms')
  response = kms.describe_key(KeyId=key_id)
  if 'KeyMetadata' in response:
    return response['KeyMetadata']
  return {}
def get_keys_detail(profile_name):
  l=[]
  lista=get_keys(profile_name)
  for k in lista:
    l.append ( get_key_detail(profile_name,k['KeyId']) )
  return l
def get_public_key(profile_name,key_id):
  boto3.setup_default_session(profile_name=profile_name)
  kms = boto3.client('kms')
  response = kms.get_public_key(KeyId=key_id)
  return response
def entrypt_file(profile_name,key_id,source_file_path,dest_file_path,algoritm):
  boto3.setup_default_session(profile_name=profile_name)
  kms = boto3.client('kms')
  with open(source_file_path, 'rb') as infile :
    with open(dest_file_path, 'wb') as outfile :
      while True:
        chunk = infile.read(1000)
        if not chunk :
          break
        resp = kms.encrypt(KeyId=key_id, Plaintext=chunk,EncryptionAlgorithm=algoritm)['CiphertextBlob']
        outfile.write(resp)
def decrypt_file(profile_name,key_id,source_file_path,dest_file_path,algoritm):
  boto3.setup_default_session(profile_name=profile_name)
  kms = boto3.client('kms')
  with open(source_file_path, 'rb') as infile :
    with open(dest_file_path, 'wb') as outfile :
      while True:
        chunk = infile.read(1000)
        if not chunk :
          break
        resp = kms.decrypt(KeyId=key_id,CiphertextBlob=chunk,EncryptionAlgorithm=algoritm)['Plaintext']
        outfile.write(resp)
  return None

Con CloudFormation non solo è possibile gestire la creazione delle chiavi ma è possibile anche gestire il modo in cui queste sono usate nelle risorse, questo servizi infatti può essere usato assieme ad altri per cifrare cose che devono esserlo, come per esempio le password di un database o la chiave di accesso di un server SFTP. La sintassi CloudFormation per creare chiavi è molto semplice e necessita solo della lista dei permessi, inoltre è possibile creare da template degli alias da usare come referenze nel codice delle applicazioni:

RdsKey:
  Type: AWS::KMS::Key
  Properties:
    KeyPolicy:
      Version: 2012-10-17
      Id: key-rds
      Statement:
      - Sid: Enable IAM User Permissions
        Effect: Allow
        Principal:
          AWS: !Join
          - ''
          - - 'arn:aws:iam::'
            - !Ref 'AWS::AccountId'
            - ':root'
        Action: 'kms:*'
        Resource: '*'
RdsAlias:
  Type: AWS::KMS::Alias
  Properties:
  AliasName: alias/rds
  TargetKeyId:
    Ref: RdsKey
Outputs:
  RdsAlias:
    Description: 'RDS KMS Encryption Key Alias'
    Value:
      Ref: 'RdsAlias'

Le chiavi possono essere usate per impostare la cifrature di un sistema, per esempio nel caso di database RDS:

MySQLDatabase:
  Type: 'AWS::RDS::DBInstance'
  Properties:
    Engine: MySQL
    DBName: "RDS"
    StorageEncrypted: true
    KmsKeyId: !Ref rdsKey
    MasterUsername: 'dbuser'
    MasterUserPassword: 'Passw0rd!'
    DBInstanceClass: db.t2.small
    AllocatedStorage: 5
    DBSubnetGroupName: !Ref RDSDBSubnetGroup
    VPCSecurityGroups:
      - Ref: RDSSecurityGroup

Il servizio KMS si integra perfettamente anche con Secret Manager, infatti con KMS è possibile gestire il sistema di cifratura delle password salvate,si rimanda alla documentazione ufficiale.

Il recupero dei valori segreti è possibile sempre grazie alle librerie SDK, per esempio in python con la libreria Boto3:

import json
import boto3
import json
secrets = boto3.client("secretsmanager")
rds = json.dumps(secrets.get_secret_value(SecretId="prod/app/Database")['SecretString'])
print(rds)
Pubblicato il 02/03/2024 nella categoria AWS

In questo articolo sono elencati la maggior parte dei comandi per GNU Linux e per le distribuzioni Debian, l’elenco è incompleto e non descrive tutti i parametri di ogni comando, per maggiori dettagli riguardo ad un singolo comando si rimanda ai siti ufficiali oppure è possibile visualizzare tutti i parametri oppure è possibile usare il comando MAN, per esempio la lista dei parametri può essere visualizzata con il comando:

$ man ls

Si rimanda alla documentazione ufficiale del comando man per ogni dettaglio e i parametri e funzionalità.


Gestione di files e directories:

cd dir entrare nella sottodirectory dir della cartella corrente
cd /home entrare nella directory /home
cd .. risalire di un livello
cd ../.. risalire di due livelli
cd ~ vai alla home directory dell’utente corrente
cd - vai alla directory precedente
pwd visualizzare il path della directory di lavoro
ls visualizzare file e directory
ls -F visualizzare file e directory separandoli
ls -l visualizzare i dettagli di file e directory
ls -a visualizzare anche i file nascosti
ls *a* visualizzare file e cartelle il cui nome contiene il carattere a
ls -lSr |more visualizzare la dimensione dei file ordinandoli per dimensione
tree visualizzare file e directory in un albero a partire da root
mkdir dir1 creare la directory dir1
mkdir dir1 dir2 creare due directory contemporaneamente
mkdir -p /tmp/dir1/dir2 creare un’albero di directory
rm -f file1 eliminare il file file1
rmdir dir1 eliminare la directory dir1
rm -rf dir1 eliminare ricorsivamente la directory dir1 e sul contenuto
mv dir1 new_dir rinominare/muovere una directory o file
cp file1 file2 copiare un file da file1 a file2
cp dir/* . copiare tutti i file di una directory dentro la directory di lavoro corrente
cp -a /tmp/dir1 . copiare una directory dentro la directory di lavoro corrente
cp -a dir1 dir2 copiare una directory
ln -s file1 lnk1 creare un link simbolico al file(o directory) file1 chiamato lnk1
ln file1 lnk1 creare un link fisico al file(o directory) file1 chiamato lnk1
find / -name file1 cercare un file partendo dalla radice /
find / -user user1 cercare tutti i file appartenenti all’utente user1
find /usr/bin -type f -atime +100 cercare tutti i file non utilizzati negli ultimi 100 giorni
find /usr/bin -type f -mtime -10 cercare tutti i file creati o modificati entro 10 giorni
locate \*.ps cercare tutti i file con una determinata estensione

Manipolazione dei file:

cat file1 visualizzare il contenuto di un file partendo dalla prima riga
tac file1 visualizzare il contenuto di un file partendo dall’ultima riga
more file1 visualizzare il contenuto di un file lungo
less file1 visualizza il file permettendo di scorrere il file sia in avanti che indietro
head -2 file1 visualizzare le prime due righe di un file
tail -2 file1 visualizzare le ultime due righe di un file
tail -f /var/log/messages visualizzare in tempo reale ciò che viene aggiunto ad un file
dos2unix filedos.txt fileunix.txt convertire un file di testo MSDOS in formato UNIX
unix2dos fileunix.txt filedos.txt convertire un file di testo UNIX in formato MSDOS
recode HTML page.txt page.html convertire un file di testo in formato html
cat file1 \textbar comando > result.txt elaborare il testo di un file e scrivere il risultato su un nuovo file
cat file1 \textbar comando >> result.txt elaborare il testo di un file ed appendere su un file esistente
grep Aug /dir/file cercare la parola Aug all’interno del file
grep ^Aug /dir/file cercare le parole che cominciano con Aug del file
grep [0-9] /dir/file selezionare tutte le righe che contengono numeri
grep Aug -R /var/log/* estendere la ricerca della stringa Aug dentro la directory /var/log
sed 's/stringa1/stringa2/g' file.txt rimpiazzare stringa1 con stringa2 nel file
echo 'abcd' | tr '[:lower:]' '[:upper:]' convertire da minuscolo in maiuscolo
sed -e '1d' result.txt elimina la prima riga dal file example.txt
sed -n '/stringa1/p' visualizza solo righe che contengono stringa1
sed -e 's/ *$//' example.txt rimuovi i caratteri vuoti alla fine di ogni riga
sed -e 's/stringa1//g' example.txt cancella solo la parola stringa1 da tutte le righe
sed -n '1,5p;5q' example.txt stampare a video dalla riga 1 alla 5
sed -n '5p;5q' example.txt stampare a video la riga numero 5
sed -e 's/00*/0/g' example.txt sostituire più zeri con un solo zero
cat -n file1 numerare le righe di un file
cat example.txt | awk 'NR%2==1' rimuove tutte le righe pari da example.txt
echo a b c | awk '{print $1}' stampare a video la prima colonna di una riga
echo a b c | awk '{print $1, $3}' stampare la prima e la terza colonna di una riga
paste file1 file2 fondere il contenuto di due file per colonne
paste  -d  '+' file1 file2 fondere il contenuto di due file per colonne con il delimitatore +
sort file1 file2 ordinare i contenuti di due file
sort file1 file2 | uniq ordinare omettendo le linee ripetute
sort file1 file2 | uniq -u ordinare stampando solo le line univoche
sort file1 file2 | uniq -d ordinare stampando solo le line duplicate
comm -1 file1 file2 comparare i contenuti di due file sopprimendo le righe univoche del file1
comm -2 file1 file2 comparare i contenuti di due file sopprimendo le righe univoche del file2
comm -3 file1 file2 comparare i contenuti di due file sopprimendo le righe che appaiono su entrambi i file

Gestione del sistema e processi:

shutdown -h now arresto del sistema
init 0 arresto del sistema
telinit 0 arresto del sistema
shutdown -h ore:minuti arresto programmato del sistema
shutdown -c cancellare un arresto programmato del sistema
shutdown -r now riavvio del sistema
reboot riavvio del sistema
logout per abbandonare la sessione
top visualizza i processi di sistema che utilizzano più cpu
ps -eafw visualizza i processi di sistema
ps -e -o pid,args --forest visualizza i processi sistema in maniera gerarchica
pstree mostra un albero dei processi sistema
kill -9 IDProcesso forzare la chiusura del processo e terminarlo
kill -1 IDProcesso forzare il processo a ricaricare la configurazione
lsof -p $$ visualizza la lista dei file aperti dai processi
lsof /home/user1 la lista dei file aperti in una determinato path di sistema
strace -c ls >/dev/null mostra le chiamate di sistema fatte e ricevute da un processo
strace -f -e open ls >/dev/null visualizza le chiamate alle librerie
watch -n1 'cat /proc/interrupts' mostra gli interrupts in tempo reale
last reboot mostra lo storico dei reboot
lsmod visualizza i mooduli del kernel caricati
free -m visualizza lo status della ram in megabyte
smartctl -A /dev/hda monitorare l’affidabilità di un hard-disk mediante SMART
smartctl -i /dev/hda verificare se SMART è attivo su un hard-disk
tail /var/log/dmesg visualizzare gli eventi inerenti al processo di boot del kernel
tail /var/log/messages visualizzare gli eventi di sistema

Informazioni sul sistema:

arch mostra l’architettura della macchina
uname -m mostra l’architettura della macchina
uname -r mostra la versione del kernel in uso
dmidecode -q mostra componenti hardware di sistema – (SMBIOS/DMI)
hdparm -i /dev/hda mostra le info e le caratteristiche di un hard-disk
hdparm -tT /dev/sda eseguire un test di lettura su un hard-disk
cat /proc/cpuinfo visualizzare informazioni sulla cpu
cat /proc/interrupts visualizzare gli interrupts
cat /proc/meminfo verificare la memoria in uso
cat /proc/swaps visualizzare i filesystem(s) swap
cat /proc/version visualizzare la versione del kernel
cat /proc/net/dev visualizzare gli adattori di rete
cat /proc/mounts visualizzare i filesystem(s) montati
lspci -tv visualizzare le periferiche pci
lsusb -tv visualizzare le periferiche usb
date visualizzare la data di sistema
cal 2008 visualizzare il calendario dell’anno 2008
date 041217002007.00 impostare data e ora –  MeseGiornoOreMinutiAnno.Secondi
clock -w salvare definitivamente le modifiche della data sul BIOS

Mount e gestione dischi:

mount /dev/hda2 /mnt/hda2 montare il disco hda2 nella directory /mnt/hda2
umount /dev/hda2 smontare il disco hda2 (prima uscire da /mnt/hda2)
fuser -km /mnt/hda2 forzare umount quando il device è occupato
mount /dev/fd0 /mnt/floppy montare un floppy-disk
mount /dev/cdrom /media/cdrom montare un cdrom/dvdrom
mount -o loop file.iso /media/cdrom montare un file ISO9660 o Immagine iso
mount -t vfat /dev/hda5 /mnt/hda5 montare un filesystem windows FAT32
mount /dev/sda1 /mnt/usbdisk montare una pendrive usb o flash
df -h visualizzare l’elenco delle partizioni montate
du -sh dir1 conoscere lo spazio su disco occupato dalla directory dir1
du -sk * | sort -rn visualizzare la dimensione dei file ordinanti per dimensione
badblocks  -v  /dev/hda1 verifica bad blocks sul disco hda1
fsck /dev/hda1 ripara e verifica l’integrità del filesystem linux sul disco hda1
fsck.ext2 /dev/hda1 ripara e verifica l’integrità del filesystem ext2 sul disco hda1
e2fsck /dev/hda1 ripara e verifica l’integrità del filesystem ext2 sul disco hda1
mkfs /dev/hda1 creare un filesystem di tipo linux sulla partizione hda1
mke2fs /dev/hda1 creare il filesystem di tipo linux ext2 sulla partizione hda1
mke2fs -j /dev/hda1 creare il filesystem di tipo linux ext3 sulla partizione hda1
mkfs -t vfat 32 -F /dev/hda1 creare un filesystem di tipo FAT32
fdformat  -n /dev/fd0 formattare un floppy disk
mkswap /dev/hda3 creare un filesystem di tipo swap
swapon /dev/hda3 attivare una nuova partizione di swap
swapon /dev/hda2 /dev/hdb3 attivare due partizioni di swap
mkisofs /dev/cdrom > cd.iso creare l’immagine iso di un cdrom sull’hard-disk
mkisofs /dev/cdrom | gzip > cd_iso.gz creare l’immagine iso compressa di un cdrom
mkisofs -J -allow-leading-dots -R -V LabelCD -iso-level 4 -o ./cd.iso data_cd creare l’immagine iso di una directory da masterizzare
cdrecord -v dev=/dev/cdrom cd.iso masterizzare un immagine iso
gzip -dc cd\_iso.gz | cdrecord dev=/dev/cdrom masterizzare un immagine iso compressa
mount -o loop cd.iso /mnt/iso montare un’immagine iso
cd-paranoia -B rippare le traccie audio da un cd in file wav
cd-paranoia -- '-3' rippare le prime tre traccie audio da un cd
cdrecord --scanbus scansionare il bus per identificare il canale scsi

Gestione utenti e gruppi:

groupadd nomegruppo creare un nuovo gruppo
groupdel nomegruppo eliminare un gruppo
groupmod -n nuovogruppo vecchiogruppo rinominare un gruppo
useradd -c "Nome Cognome" -g admin  -d /home/user1 -s /bin/bash user1 creare un nuovo utente appartenente al gruppo admin
useradd user1 creare un nuovo utente
userdel -r user1 eliminare un utente (-r elimina la home directory)
usermod -c "User FTP" -g system -d /ftp/user1 -s /bin/nologin user1 modificare gli attributi utente
passwd modificare la password
passwd user1 modificare la password di un utente(solo da root)
chage -E 2005-12-31 user1 impostare la scadenza password per un utente
chsh --list-shells mostra gli utenti loggati da remoto
who -a mostra gli utenti loggati in maniera dettagliata

Gestione permessi sui files:

ls -lh visualizzare i permessi
chmod ugo+rwx directory1 impostare i permessi di lettura(r), scrittura(w) ed accesso(x) per gli utenti proprietario(u), gruppo(g) e altri(o)
chmod go-rwx directory1 rimuovere i permessi di lettura(r), scrittura(w) ed accesso(x) per gli utenti gruppo(g) e altri(o)
chown user1 file1 modificare il proprietario di un file
chown -R user1 directory1 modificare l’utente proprietario di una directory e tutti i file e directory contenuti al suo interno
chgrp group1 file1 modificare il gruppo di appartenenza di un file
chown user1:group1 file1 modificare utente e gruppo proprietario di un file
find / -perm -u+s visualizzare tutti i file presenti sul sistema con SUID impostato
chmod u+s /bin/file1 impostare il bit SUID su un file binario l’utente che esegue quel file ottienegli stessi privilegi del proprietario
chmod u-s /bin/file1 disattivare il bit SUID su un file binario
chmod g+s /home/public impostare il bit SGID su una directory simile a SUID ma impostato sulla directory
chmod g-s /home/public disattivare il bit SGID su una directory
chmod o+t /home/public impostare il bit STIKY su una directory consente la cancellazione dei file solo ai legittimi proprietari
chmod o-t /home/public disattivare il bit STIKY su una directory
chattr +a file1 consente su un file l’apertura in scrittura solo in modalità append
chattr +c file1 consente che un file venga compresso dal kernel automaticamente
chattr +d file1 fa in modo che il programma Dump ignori il file durante un backup
chattr +i file1 rende un file immutabile, ovvero non potr\`{a} essere eliminato, alterato, rinominato o linkato
chattr +s file1 consente ad un file di essere cancellato in maniera sicura, azzerandone i blocchi sul disco
chattr +S  file1 fa in modo che se un file viene modificato i cambiamenti vengano scritti in maniera sincrona sul disco come con sync
chattr +u file1 permette di recuperare il contenuto di un file anche se questo viene cancellato
lsattr visualizzare gli attributi speciali

Gestione archivi e file compressi:

bunzip2 file1.bz2 decomprimere il file denominato file1.bz2
bzip2 file1 comprimere il file denominato file1
gunzip file1.gz decomprimere il file denominato file1.gz
gzip file1 comprimere il file denominato file1
gzip -9 file1 comprimere con la massima compressione
rar a file1.rar testfile creare un archivio rar chiamato file1.rar
rar a file1.rar file1 file2 dir1 comprimere in rar simultaneamente file1, file2 e dir1
rar x file1.rar comprimere un archivio rar
unrar x file1.rar decomprimere un archivio rar
tar -cvf archive.tar file1 creare un archivio tar non compresso
tar -cvf archive.tar file1 file2 dir1 creare un archivio contenente file1, file2 e dir1
tar -tf archive.tar visualizzare il contenuto di un archivio
tar -xvf archive.tar estrarre un archivio tar
tar -xvf archive.tar -C /tmp estrarre un archivio tar dentro /tmp
tar -cvfj archive.tar.bz2 dir1 creare un archivio tar compresso in bzip2
tar -xvfj archive.tar.bz2 decomprimere un archivio tar compresso in bzip2
tar -cvfz archive.tar.gz dir1 creare un archivio tar compresso in gzip
tar -xvfz archive.tar.gz decomprimere un archivio tar compresso in gzip
zip file1.zip file1 creare un archivio compresso in zip
zip -r file1.zip file1 file2 dir1 zippare più file e directory contemporaneamente
unzip file1.zip decomprimere un archivio zip

Gestione pacchetti Debian:

dpkg -i pacchetto.deb installare/aggiornare un pacchetto deb
dpkg -r nomepacchetto rimuovere un pacchetto deb dal sistema
dpkg -l visualizzare tutti i pacchetti deb installati sul sistema
dpkg -l | grep httpd visualizzare tutti i pacchetti col nome httpd
dpkg -s nomepacchetto ottenere informazioni su un determinato pacchetto installato
dpkg -L nomepacchetto la lista dei file forniti da un pacchetto installato
dpkg --contents pacchetto.deb la lista dei file forniti da un pacchetto non installato
apt-get install nomepacchetto installare/aggiornare un pacchetto deb
apt-cdrom install nomepacchetto installare/aggiornare un pacchetto deb da cdrom
apt-get update aggiorna la lista dei pacchetti(non installati)
apt-get upgrade aggiorna tutti pacchetti deb installati
apt-get remove nomepacchetto rimuovere un pacchetto deb dal sistema
apt-get check verifica la corretta risoluzione delle dipendenze
apt-get clean ripulire la cache dai pacchetti scaricati
apt-cache search nomepacchetto ritorna la lista dei pacchetti con la stringa

Gestione backup:

dump -0aj -f /tmp/home0.bak /home backup full della directory /home
dump -1aj -f /tmp/home0.bak /home backup incrementale della directory /home
restore -if /tmp/home0.bak ripristino di un backup in maniera interattiva
rsync -rogpav --delete /home /tmp  rsync -rogpav -e ssh --delete sincronizzazione tra directory rsync via ssh tunnel

Principali comandi di rete:

ifconfig eth0 visualizza configurazione di una scheda di rete ethernet
ifup eth0 attiva interfaccia eth0
ifdown eth0 disattiva interfaccia eth0
ifconfig eth0 192.168.1.1

netmask 255.255.255.0

configura ip address
ifconfig eth0 promisc configura eth0 in modalità promiscua
dhclient eth0 active interface eth0 in dhcp mode
route -n visualizza tabella di routing
route add -net 0/0 gw IPGateway configura default gateway
route add -net 192.168.0.0

netmask 255.255.0.0 gw 192.168.1.1

configura route statica
route del 0/0 gw IPgateway rimuovi route statica
ip link show mostra status link di tutte le interfaccie
mii-tool eth0 mostra status link dell’interfaccia ‘eth0’
ethtool eth0 mostra statistiche scheda di rete ‘eth0’
netstat -tup tutte le connessioni di rete attive e rispettivi PID
netstat -tupl tutti servizi di rete sul sistema e rispettivi PID
tcpdump tcp port 80 visualizza tutto il traffico http
iwlist scan visualizza le reti wireless
iwconfig eth1 visualizza configurazione di una scheda rete wireless
hostname mostra l’hostname del sistema
host www.example.com risoluzione hostname in ip address e viceversa
nslookup www.example.com risoluzione hostname in ip address e viceversa
whois www.example.com lookup sul database Whois
nbtscan ipaddr risoluzione nome netbios
nmblookup -A ipaddr risoluzione nome netbios
smbclient -L ipaddr/hostname visualizza le condivisioni remote di un host windows
smbget -Rr smb://ipaddr/share come wget permette di scaricare file da un host windows via smb
mount -t smbfs -o username=user,password=pass 

//WinClient/share /mnt/share

montare una condivisione di rete windows
Pubblicato il 02/03/2024 nella categoria Debian

Come visto nel precedente articolo e come descritto nella documentazione ufficiale, un tema WordPress è formato da tre files base ma questi sono sufficienti solo a creare una prima pagina, per attivare tutte le funzionalità del framework come gli articoli e le pagine, un tema ha bisogno files specifici per la visualizzazione e la gestione dei componenti. In questo articolo è necessario l’utilizzo del linguaggio PHP per lo sviluppo di componenti necessari: il framework mette a disposizione diverse funzionalità descritte nella documentazione ufficiale, il programmatore del tema deve implementare una serie di files base che devono rispettare una gerarchia prefissata:

I files principali obbligatori ed indispensabili per il funzionamento di un tema sono:

  • footer.php
  • functions.php
  • header.php
  • index.php
  • page.php
  • screenshot.png
  • sidebar.php
  • single.php
  • style.css

La lista completa dei files Php previsti dal framework è disponibile nel sito ufficiale, nella prima parte di questa guida sono stati introdotti il foglio di stile Css e allo screenshot parte dei files obbligatori, gli altri files vengono descritti in questa serie di articoli che presenterà un esempio di costruzione di un tema semplice con alcuni casi d’uso specifici.


Il primo file da gestire è il file index.php il quale descrive il funzionamento della pagina principale del sito, di default è sempre la prima pagina può anche essere l’unica presente. Un esempio funzionante può essere trovato nella documentazione ufficiale che presenta un esempi di codice:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="<?php bloginfo( 'charset' ); ?>">
    <title><?php wp_title( '|', true, 'right' ); ?></title>
    <link rel="stylesheet" href="<?php echo esc_url( get_stylesheet_uri() ); ?>" type="text/css" />
    <?php wp_head(); ?>
  </head>
  <body>
    <?php get_header(); ?>
    <h1><?php bloginfo( 'name' ); ?></h1>
    <h2><?php bloginfo( 'description' ); ?></h2>
    <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
      <h3><?php the_title(); ?></h3>
      <?php the_content(); ?>
      <?php wp_link_pages(); ?>
      <?php edit_post_link(); ?>
    <?php endwhile; ?>
    <?php if ( get_next_posts_link() ) {
      next_posts_link();
    } ?>
    <?php if ( get_previous_posts_link() ) {
       previous_posts_link();
    } ?>
    <?php else: ?>
      <p>No posts found. :(</p>
    <?php endif; ?>
    <?php get_sidebar(); ?>
    <?php get_footer(); ?>
  </body>
</html>

Da questo primo esempio di codice si può notare subito la presenta di alcune chiamate a metodi php messi a diposizione del framework di WordPress, i principali sono:

  • wp_title: metodo per il recupero dell’informazione del titolo del sito
  • get_stylesheet_uri: metodo il recupero dell’url “assoluto” del foglio stile style.css
  • wp_head: metodo per il recupero e la stampa del tag head definito dal tema
  • bloginfo: metodo per il recupero delle informazioni del sito come il nome e la descrizione
  • have_posts: metodo per la verifica della presenza di post da visualizzare
  • the_post e the_content: metodi per il recupero delle informazioni dei post, questi metodo vengono richiamati all’interno di un ciclo chiamato loop, verranno approfonditi in un articolo dedicato
  • edit_post_link: metodo per il recupero e la visualizzazione del link che punta da un articolo alla sua pagina amministrativa, ovviamente non viene visualizzato nulla se non è eseguita la login amministrativa
  • get_next_posts_link e get_previous_posts_link: metodo per il recupero e la visualizzaione dei link verso altri post rispetto a quelli visualizzati
  • get_header, get_sidebar e get_footer: metodi per la visualizzazione dei componenti header, sidebar e footer del tema, anche questi saranno approfonditi in un articolo dedicato

Si rimanda sempre alla documentazione ufficiale per maggiori dettagli.

Pubblicato il 02/03/2024 nella categoria Wordpress

Il servizio SQS di AWS permette di creare code di dati, il nome deriva dall’inglese Simple Queue System. In Infromatica per coda si intende una struttura dati costituita come raccolta di entità gestite in una sequenza che può essere modificata aggiungendo entità a un estremo e rimuovendole dall’altro estremo, si rimanda alla pagina wiki per maggiori dettagli sui vari tipi di code e il loro funzionamento.

Su AWS il servizio SQS ha determinate caratteristiche che lo distinguono da sistemi simili, le principali caratteristiche sono:

  • è di tipo Serverless quindi risulta completamente gestito
  • non ha un limite di scrittura/lettura (throughput) e non ha limiti di numero di entità gestite
  • il limite massimo di retenzione di una entità è di 4 giorni come default che può essere modificato fino a 14 giorni massimo
  • ogni entità ha un limite massimo di 256 Kb
  • è possibile avere entità duplicate e possono essere ordinate, di default infatti le code non sono di tipo FIFO ma può essere attivata come opzione avanzata
  • i servizi che scrivono nella coda sono detti Producer
  • i servizi che leggono dalla coda sono Consumer ed è loro compito eliminare l’elemento letto
  • è possibile gestire la scalabilità dei Consumer tramite AutoScaling grazie ad allarmi di CloudWatch
  • è possibile gestire la sicurezza tramite sistema di entryption con KMS (client side) ed è possibile definire regole di acesso (access policy) trmiate il servizio IAM
  • il servizio prevede molti parametri e configurazioni avanziate per la gestione di un DLQ (dead letter queue), un DQ (delay queue) e il polling (long polling)

Il costo del servizio è calcolato in base all’uso con un milione di richieste al mese gratuite, si rimanda al sito ufficiale per tutti i dettagli sul servizio.


La CLI mette a disposizione una serie di comandi per la gestione delle code SQS, i principali comandi sono:

  • lista delle code:
    aws sqs list-queues
    aws sqs list-queues --queue-name-prefix "rahul"
  • creazione di una nuova coda:
    aws sqs create-queue --queue-name sqs-formaz-with-tag --tags "env"="formazione" --attributes DelaySeconds=10
  • gestione delle entità nella coda:
    aws sqs get-queue-attributes --queue-url https://sqs.us-east-1.amazonaws.com/<aws-account-number>/sqs-formaz-with-tag --attribute-names All
    
    aws sqs send-message --queue-url https://sqs.us-east-1.amazonaws.com/<aws-account-number>/sqs-formaz-with-tag --message-body "Test message to my-sqs-using-cli sqs"
    
    aws sqs receive-message --queue-url https://sqs.us-east-1.amazonaws.com/<aws-account-number>/sqs-formaz-with-tag
    
    aws sqs purge-queue --queue-url https://sqs.us-east-1.amazonaws.com/<aws-account-number>/sqs-formaz-with-tag
  • eliminazione di una coda:
    aws sqs delete-queue --queue-url https://sqs.us-east-1.amazonaws.com/<aws-account-number>/sqs-formaz-with-tag

La libreria SDK mette a disposizione una serie di funzioni per la gestione delle code SQS, nel sito ufficiale possono essere trovati esempi dei principali linguaggi di programmazione come Java , Javascript e Python tramite la libreria boto3, i metodi principali sono:

def get_sns_list(profile_name):
  boto3.setup_default_session(profile_name=profile_name)
  sqs_client = boto3.client("sqs") #, region_name=AWS_REGION
  topics_iter = sqs_client.list_queues(
    MaxResults=100
  )
  if 'QueueUrls' in topics_iter :
    return topics_iter['QueueUrls']
  return []
def create_queue(profile_name, queue_name,delay_seconds,visiblity_timeout):
  boto3.setup_default_session(profile_name=profile_name)
  sqs_client = boto3.client("sqs") #, region_name=AWS_REGION
  response = sqs_client.create_queue(QueueName=queue_name,Attributes={
    'DelaySeconds': str(delay_seconds),
    'VisibilityTimeout': str(visiblity_timeout)
     # 'FifoQueue': 'true'
  })
  return response
def delete_queue(profile_name, queue_name):
  boto3.setup_default_session(profile_name=profile_name)
  sqs_client = boto3.client("sqs") #, region_name=AWS_REGION
  response = sqs_client.delete_queue(QueueUrl=queue_name)
  return response
def get_queue(profile_name, queue_url):
  boto3.setup_default_session(profile_name=profile_name)
  sqs_client = boto3.client("sqs") #, region_name=AWS_REGION
  response = sqs_client.get_queue_attributes( QueueUrl=queue_url, AttributeNames=['All'])
  if 'Attributes' in response:
    return response['Attributes']
  return {}
def send_queue_message(profile_name,queue_url,msg_attributes,msg_body):
  boto3.setup_default_session(profile_name=profile_name)
  sqs_client = boto3.client("sqs") #, region_name=AWS_REGION
  response = sqs_client.send_message(QueueUrl=queue_url,
    MessageAttributes=msg_attributes,
    MessageBody=msg_body)
  return response
def receive_queue_messages(profile_name,queue_url):
  boto3.setup_default_session(profile_name=profile_name)
  sqs_client = boto3.client("sqs") #, region_name=AWS_REGION
  response = sqs_client.receive_message(QueueUrl=queue_url,MaxNumberOfMessages=10)
  if 'Messages' in response:
    return response['Messages']
  return []
def delete_queue_message(profile_name,queue_url, receipt_handle):
  boto3.setup_default_session(profile_name=profile_name)
  sqs_client = boto3.client("sqs") #, region_name=AWS_REGION
  response = sqs_client.delete_message(QueueUrl=queue_url,ReceiptHandle=receipt_handle)
  return response

Con CloudFormation è possibile gestire le risorse di SQS con il tipo specifico

SqsQueue:
  Type: AWS::SQS::Queue
  Properties:
    QueueName: !Ref QueueName
    VisibilityTimeout: 180
    Tags:
    -
      Key: StackId
      Value: !Ref AWS::StackId

Inoltre bisogna ricordarsi che, in presenza di producer/consumer, è sempre necessario gestire le regole di accesso tramite la definizione di una regola IAM, per esempio:

SqsQueueLambdaConsumer:
  Type: AWS::Serverless::Function
  Properties:
    CodeUri: lambda
    Handler: consumer.entrypoint
    Runtime: python3.8
    MemorySize: 1280
    Timeout: 900
    Role: !GetAtt SqsQueueLambdaIamRole.Arn
SqsQueueLambdaIamRole:
  Type: 'AWS::IAM::Role'
  Properties:
    AssumeRolePolicyDocument:
    Version: 2012-10-17
    Statement:
    - Effect: Allow
      Principal:
      Service:
      - lambda.amazonaws.com
      Action:
      - 'sts:AssumeRole'
    Path: /
      Policies:
      - PolicyName: root
        PolicyDocument:
          Version: 2012-10-17
          Statement:
          - Effect: Allow
            Action:
            - sqs:GetQueueUrl 
            - sqs:SendMessage
            - sqs:ReceiveMessage
            - sqs:DeleteMessage
            Resource:
            - !GetAtt SqsQueue.Arn

L’esempio completo di coda SQS con un funzioni Lambda producer/consumer è disponibile nel solito repository:

https://github.com/alnao/AWSCloudFormationExamples/tree/master/Esempio18sqs
Pubblicato il 24/02/2024 nella categoria AWS

Una delle evoluzioni principali dalla versione 8 di Java è stata l’introduzioni delle “Lambda Function” dette anche “Java Lambda Expression” che permettono di scrivere del codice senza dovergli dare un nome (metodo o classe), le possibili sintassi di questa tecnica prevedono 3 tipi sinonimi a seconda del numero di parametri e del numero di istruzioni nel blocco:

parameter -> expression
(parameter1, parameter2) -> expression
(parameter1, parameter2) -> { code block }

Il caso più semplice e più usato è l’uso delle lambda function per definire l’iterazione di una lista:

import java.util.ArrayList;
public class Main {
  public static void main(String[] args) {
    ArrayList<Integer> numbers = new ArrayList<Integer>();
    numbers.add(5);
    numbers.add(9);
    numbers.add(8);
    numbers.add(1);
    numbers.forEach( (n) -> { System.out.println(n); } );
  }
}

Ma allo stesso modo è possibile definire un oggetto “codice”:

import java.util.function.Consumer;
...
Consumer<Integer> method = (n) -> { System.out.println(n); };
numbers.forEach( method );

Si rimanda alla documentazione ufficiale, il quick start presentato dal sito ufficiale e alla pagina w3c per maggiori dettagli.


L’uso di questa tecnica è usato in moltissimi casi specifici, si elencano alcuni esempi dove il codice classi può essere sostituito con questa tecnica:

  • definizione del comportamento di un bottone:
    bottone.setOnAction(
      event -> System.out.println("Click done")
    );
  • filtri con ciclo for:
    public List<Persona> getMaschi(iscritti){
      List<Persona> persone = new ArrayList<Persona>();
      for (Persona p:iscritti)
        if (isMaschio(p))
          persone.add(p);
      return persone;
    }
  • filtri con metodo:
    Predicate<Persona> allMaschi = p -> p.getSesso().equals("M");
    public List<Persona> getIscrittiFiltratiPer(Predicate<Persona> pred){
      List<Persona> persone = new ArrayList<Persona>();
      for (Persona p:iscritti)
        if (pred.test(p))
          persone.add(p);
      return persone;
    }
    ms.getIscrittiFiltratiPer(allMaschi);
  • logiche annidate sulle liste con filter e map:
    lista.stream()
    .filter( p -> p.getGender() == Person.Sex.MALE) //filtrare elementi di una lista
    .map(p -> p.getEmailAddress()) //funzione map per modificare un elemento
    .forEach(email -> System.out.println(email));
  • definizione di interfacce funzionali:
    package java.awt.event;
    import java.util.EventListener;
    public interface ActionListener extends EventListener {
      public void actionPerformed(ActionEvent e);
    }
  • runnable block:
    public class RunnableTest {
      public static void main(String[] args) {
        System.out.println("=== RunnableTest ===");
        Runnable r1 = new Runnable(){// Anonymous Runnable
        
        @Override
        public void run(){
          System.out.println("Hello world old style!");
        }
      };
      // Lambda Runnable
      Runnable r2 = () -> System.out.println("Hello world with Lambda!");
        r1.run();
        r2.run(); 
      }
    }

La tecnica delle Lambda Function è stata introdotta per semplificare la vita dei programmatori, assieme alla tecnica delle classi innestate, questa tecnica è molto utile e usata tuttavia spesso rende il codice molto meno leggibile e l’utilizzo deve sempre essere pensato, si rimanda alla pagina ufficiale che consiglia quando usare e quando non usare queste tecniche.

Una nota obbligatoria è il nome di queste funzioni: “Lambda Function” e “Lambda Expression” sono nomi usati anche da altre tecnologie, come le lambda function di AWS, per questo motivo è sempre consigliato usare il nome con il linguaggio di programmazione “Java Lambda Function” per evitare fraintendimenti, poi ovviamente è possibile usare “Java Lambda Function” per definire delle “AWS Lambda Function” ma questa è una sega mentale di noi programmatori che lavorano con Java in Cloud.

Pubblicato il 24/02/2024 nella categoria Java & Spring Boot

Le trasformazioni e le transazioni sono delle tecniche introdotte con la terza versione di CSS che permettono di creare dinamicità in un pagine che risultano statici. Queste tecniche sono state studiate per poter permettere la definizione di animazioni senza l’ausilio di alcun linguaggio di scripting e senza conoscenze evolute di programmazione.

Secondo lo standard esistono tre tipi di tecniche che possono applicate:

  • trasformazioni: permette di modificare l’aspetto grafico lasciando invariata la sua posizione e le dimensioni originali
  • transazioni: permette di modificare l’aspetto grafico modificando anche posizione e/o le dimensioni
  • animazioni: permette di creare trasformazioni e transazioni che variano nel tempo con dei frame-set temporali

Le trasformazioni permettono di modificare l’aspetto di un elemento, il caso d’uso più semplice è quello di modificare l’aspetto di un testo rendendolo maiuscolo:

p.uppercase {
  text-transform: uppercase;
}

Ma il linguaggio CSS prevede una proprietà specifica “transform” che permette di ruotare, deformare e scalare elementi indicando il valore di rapporto di rotazione o dimensionamento:

div.a {
  transform: rotate(20deg);
}
div.b {
  transform: skewY(20deg);
}
div.c {
  transform: scaleY(1.5);
}

Inoltre è previsto una ulteriore proprietà che permette di definire il comportamento della trasformazione indicando se si tratta di un tipo piatto, 3d o natuale.

transform-style: flat|preserve-3d|initial|inherit;

Da notare che quasi tutti i broweser accettano questo tipo di trasformazione ma a volte si comportano in maniera diversa infatti sono usate le stesse unità di misura, si rimanda alla documentazione ufficiale per tutti i dettagli di questa proprietà


Le transazioni sono una evoluzioni delle trasformazioni in quanto permettono anche di definire modifica alle posizioni e alle dimensioni degli oggetti, la sintassi prevista è:

transition: property duration timing-function delay|initial|inherit;

per esempio volendo modififare in maniera dinamica la larghezza di un elemento al passaggio del mouse di definiscono due classi:

div.trans {
  width: 100px;
  transition: width 2s;
}
  div.trans:hover {
  width: 300px;
}

Un altro esempio molto usato è la transazione grafica di un input al momento del focus sull’elemento: evidenziare un elemento input quando l’utente lo seleziona:

input[type="text"] {
  width: 100px;
  -webkit-transition: width .35s ease-in-out;
  transition: width .35s ease-in-out;
}
input[type="text"]:focus {
  width: 250px;
}

Anche in questo caso è consigliato consultare la documentazione ufficiale per tutti i dettagli.


Le animazioni son un tema sempre molto scottante in quando abbelliscono molto un sito ma lo rendono anche molto pensate ed è sempre difficile trovare un equilibrio. Il linguaggio permette di definire transazioni di elementi con la proprietà che definisce il comportamento principale:

animation: name duration timing-function delay iteration-count direction fill-mode play-state;

che ha molti valori necessari nella definizione:

  • animation-name: specifica il nome dei keyframe
  • animation-duration: specifica quanti secondi deve durare la animazione
  • animation-timing-function: specifica la velocità di esecuzione
  • animation-delay: specifica quando delay/ritardo deve esserci
  • animation-iteration-count: specifica quante volte la animazione deve essere eseguita
  • animation-direction: specifica la direzione
  • animation-fill-mode: specifica il comportamento dell’elemento prima e dopo l’animazione
  • animation-play-state: specifica se l’animazione è attiva o meno

L’esempio più semplice è muovere un elmento in maniera continua definendo la sua animazione i keyframe di inizio e partenza:

div.anima {
  animation: mymove 5s infinite;
}
@keyframes mymove {
  from {left: 0px;}
  to {left: 200px;}
}

Anche in questo si rimanda sempre alla documentazione ufficiale per tutti i dettagli, questa tecnica permette di creare casi d’uso più complesso come il carosello dei loghi disponibile in questo sito (in alto a destra) realizzabile combinando le animazioni con piccolo Javascript:

div.logo {
  width: 100px;
  height: 100px;
  background: red;
  position: relative;
  animation: fading 10s infinite;
}
@keyframes fading{
  0%{opacity:0}
  50%{opacity:1}
  100%{opacity:0}
}

Una cosa interssante e molto usata è usare la tecnica delle animazioni per creare effetti che creano ombre e sfondi al testo, per esempio per creare un effetto Neon colorato ad un titolo:

.glow {
  font-size: 80px;
  color: #fff;
  text-align: center;
  animation: glow 1s ease-in-out infinite alternate;
}
@-webkit-keyframes glow {
  from {
    text-shadow: 0 0 10px #fff, 0 0 20px #fff, 0 0 30px #e60073, 0 0 40px #e60073, 0 0 50px #e60073, 0 0 60px #e60073, 0 0 70px #e60073;
  }
  to {
    text-shadow: 0 0 20px #fff, 0 0 30px #ff4da6, 0 0 40px #ff4da6, 0 0 50px #ff4da6, 0 0 60px #ff4da6, 0 0 70px #ff4da6, 0 0 80px #ff4da6;
  }
}

Anche in questo caso si rimanda alla documentazione ufficiale per tutti i dettagli.

Pubblicato il 24/02/2024 nella categoria Css3 & Bootstrap

Il servizio AWS Config è stato studiato per permettere ai customer di valutare, registrare e monitorare tutte le modifiche alle configurazioni delle risorse per semplificare la gestione del Cloud. Da notare che come servizio non permette di modificare le configurazione ma è studiato solo per essere uno strumento di monitoraggio con un registro unificato per tutte le risorse del Cloud. Bisogna sempre ricordare che per risorsa AWS si intende qualsiasi entità in AWS e comprende qualsiasi tipo di entità creata, l’elenco completo di tutti i tipi di risorse è disponibile nella documentazione ufficiale:

Da console web è possibile attivare il servizio con una procedura chiamata 1-click, inoltre è possibile definire regole usando quelle definite di default (Managed) e personalizzate (Custom), si rimanda sempre alla documentazione ufficiale per tutti i dettagli.

La documentazione ufficiale descrive molto bene il funzionamento del sistema e presenta diversi esempi di utilizzo con casi d’uso reali , per esempio è possibile contare il numero di istanze EC2 attive aggregando il dato per tipo con una semplice query:

SELECT configuration.instanceType, COUNT(*)
 WHERE resourceType = 'AWS::EC2::Instance'
 GROUP BY configuration.instanceType

La CLI mette a disposizione una serie di comandi per la gestione del servizio. Per evitare problemi con doppi nomi, è stato creato il tipo config-service per far riferimento ai comandi del servizio AWS Config per evitare fraintendimenti con il comando configuration utilizzato per definire i profili della AWS CLI. I principali comandi di questo servizio sono

  • – recupero dello stato dei sistemi di registro di AWS Config
    aws configservice describe-delivery-channels
    aws configservice describe-configuration-recorders
    aws configservice describe-configuration-recorder-status
  • elenco di tutte le regole
    aws configservice describe-config-rules 
    aws configservice describe-config-rules | grep ConfigRuleName
  • creazione ed eliminazione di una regola
    aws configservice put-config-rule --generate-cli-skeleton > putConfi gRule.json
    aws configservice put-config-rule --cli-input-json file://putConfigRule.json
    aws configservice delete-config-rule --config-rule-name ConfigRuleName
  • elenco di tutte le regole compliance
    aws configservice describe-compliance-by-config-rule
    aws configservice describe-compliance-by-resource --resource-type AWS::EC2::Instance
    aws configservice get-compliance-details-by-resource --resource-type AWS::EC2::Instance --resource-id i-nnnnnnnn
  • lista delle risorse
    aws configservice list-discovered-resources
    aws configservice list-discovered-resources --resource-type "AWS::EC2::Instance"
    aws configservice list-discovered-resources --resource-type "AWS::CloudFormation::Stack"
  • storico di eventi di una risorsa
    aws configservice get-resource-config-history --resource-type AWS::EC2::Instance --resource-id i-0117ee5195da9794b

Oltre alla documentazione ufficiale, è consigliata anche la lettura di un libro disponibile nel sito ufficiale che descrive in maniera dettagliata tutti i comandi


Anche la libreria SDK mette a disposizione i metodi per gestire il servizio da codice: la libreria boto3 mette a disposizione metodi per i servizio config, i principali metodi messi a disposizione sono:

def resources_list(profile_name,resource_type):
  boto3.setup_default_session(profile_name=profile_name)
  config = boto3.client('config')
  lista = config.list_discovered_resources(
    resourceType=resource_type
    #limit=100,
    #nextToken='string'
  )
  if 'resourceIdentifiers' in lista:
    return lista['resourceIdentifiers']
  return [] 
def resource_detail(profile_name, resource_type, resource_id):
  boto3.setup_default_session(profile_name=profile_name)
  config = boto3.client('config')
  lista = config.get_resource_config_history(
    resourceType=resource_type,
    resourceId=resource_id,
    limit=100,
    #nextToken='string'
  )
  if 'configurationItems' in lista:
    return lista['configurationItems']
  return []

Per la gestione di AWS Config in CloudFormation sono previsti tutti i tipi di risorse, si rimanda alla documentazione ufficiale per tutti i dettagli. Nell’esempio proposto in AwsLabs viene definita la regola per la registrazione degli evento sui volumi delle EC2:

ConfigRecorder:
  Type: AWS::Config::ConfigurationRecorder
  Properties:
    Name: default
    RecordingGroup:
    ResourceTypes: ['AWS::EC2::Volume']
    RoleARN: !GetAtt [ConfigRole, Arn]
  DeliveryChannel:
    Condition: CreateDeliveryChannel
    Type: AWS::Config::DeliveryChannel
    Properties:
      ConfigSnapshotDeliveryProperties:
        DeliveryFrequency: Six_Hours
      S3BucketName: !Ref 'ConfigBucket'
      SnsTopicARN: !Ref 'ConfigTopic'
  ConfigRuleForVolumeTags:
    Type: AWS::Config::ConfigRule
    Properties:
      InputParameters:
        tag1Key: CostCenter
      Scope:
        ComplianceResourceTypes: ['AWS::EC2::Volume']
      Source:
        Owner: AWS
        SourceIdentifier: REQUIRED_TAGS
    DependsOn: ConfigRecorder

Per ulteriori informazioni ed esempi si rimanda al repository ufficiale di AwsLabs.

Pubblicato il 17/02/2024 nella categoria AWS

Nei progetti Angular i Moduli sono gruppi di componenti di una applicazione, il raggruppamento permette di gestire le importazioni di altri moduli e la gestione del comportamento i unico punto dichiarativo dove vengono elencati i componenti, altri moduli importati e i providers (come gli interceptor), per esempio nella applicazioni presentate in altri articoli è stato creato un modulo di default dalla procedura guidata di creazione dei progetti:

@NgModule({
  declarations: [
    AppComponent,
    FilmsListComponent,
    FilmDetailComponent,
    LoginComponent,
  ],
  imports: [
    BrowserModule, 
    ReactiveFormsModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [{
    provide: HTTP_INTERCEPTORS, 
    useClass: AuthInterceptorServiceService,
    multi: true
  }],
  bootstrap: [AppComponent],
  schemas: [CUSTOM_ELEMENTS_SCHEMA,NO_ERRORS_SCHEMA]
}) export class AppModule { }

in questo caso tutti i componenti non devono importare i moduli dichiarati nella sezione imports e quindi risulta molto più snello e semplice.

Tuttavia nei progetti di grandi dimensioni questa tecnica presenta alcune limitazioni: la sezione dichiarativa può diventare molto grande e complessa, inoltre tutti i moduli usati nella applicazione risultano condivisi tra tutti i componenti anche quelli che non li usano. Per risolvere questo problema esisono due strade: dichiarare diversi moduli separando i componenti e gli import a seconda delle necessità rendendo molto snello il codice ma anche in questo caso si richiesta il disordine causato dal proliferare di classi di questo tipo.

La tecnica alternativa più usata è l’uso dei componenti con la caratteristica standalone, questa permette di definire componenti che importano in autonomia i moduli senza dover dichiarare l’elenco dei moduli nella classe generica. Per creare componenti di questo tipo si può usare la sintassi

ng g c component_name --standalone

Un semplice esempio mostra come la sintassi implementa questa tecnica:

@Component({
  standalone: true, 
  selector: 'photo-gallery',
  // an existing module is imported directly into a standalone component
  imports: [MatButtonModule],
  template: `
...
  <button mat-button>Next Page</button>
`,
})
export class PhotoGalleryComponent {
  // logic
}

In questo semplice esempio presentato nella documentazione ufficiale  è possibile vedere come aggiungendo la proprietà standalone si può aggiungere una sezione imports specifica nella dichiarazione delle annotation del componente. Sempre nel sito ufficiale esiste anche una pagina specifica dedicata alla migrazione da componenti modulari a componenti standalone.

Pubblicato il 17/02/2024 nella categoria Angular & Ionic

Il servizio SNS è studiato appositamente per gestire sistemi di notifiche dove una o più sorgenti abbiano la necessità di inviare notifiche ad uno o più destinatari, questo servizio non è da confondere con il servizio di code SQS che si occupa solo di smistamento di dati e non di notifiche con code come le FIFO. Esistono due tipi di notifiche: A2A e A2P:

  • A2S permette di notificare in maniera asincrona notifiche push anche molti-a-molti come Kinesis, Lambda e API Gateway
  • A2P consente l’invio di messaggi tramite SMS, notiche push ad aplicazioni e/o tramite e-mail.

I casi d’uso più usati sono invio da e per applicazioni per smartphone di messaggi, invio di SMS a clienti, invio di notifiche mail da una applicazione o da altri servizi AWS, procedure AWS Step Function che inviano notifiche nei flusso operativo.

Come ogni servizio AWS prevede un costo calcolato in base ad una tariffa ad uso, si rimanda alla documentazione ufficiale per maggiori dettagli riguardo alle tariffe e tutte le caratteristiche del servizio.


La CLI mette a disposizione una serie di comandi per il controllo del servizio SNS, si rimanda alla documentazione ufficiale. I principali comandi sono:

  • creazione di un topic
    aws sns create-topic --name ProvaAlbertoCLI
  • lista dei topic
    aws sns list-topics
  • lista delle sottoscrizioni
    aws sns list-subscriptions
  • creazione di una sottoscrizione
    aws sns subscribe --topic-arn arn:aws:sns:eu-west-1:xx:ProvaAlbertoCLI --protocol email --notification-endpoint test@email.com
  • pubblicazione di un contenuto in un topic
    aws sns publish --topic-arn arn:aws:sns:eu-west-1:xx:ProvaAlbertoCLI --message "Hello World!"
  • eliminazione di un topic
    aws sns delete-topic --topic-arn arn:aws:sns:eu-west-1:xxx:ProvaAlbertoCLI

Si rimanda sempre alla pagina specifica dove sono elencati tutti i comandi e i parametri previsti.


La libreria SDK mette a disposizione una serie di metodi per la gestione dei topic SNS, per tutti i dettagli si rimanda alla documentazione ufficiale, i principali metodi sono:

def get_sns_list(profile_name):
  boto3.setup_default_session(profile_name=profile_name)
  sns_client = boto3.client('sns')
  topics_iter = sns_client.list_topics()
  if 'Topics' in topics_iter :
    return topics_iter['Topics']
  return []
def create_topic(profile_name, topic_name):
  boto3.setup_default_session(profile_name=profile_name)
  sns_client = boto3.client('sns')
  topic = sns_client.create_topic(Name=topic_name)
  return topic
def delete_topic(profile_name, topic_arn):
  boto3.setup_default_session(profile_name=profile_name)
  sns_client = boto3.client('sns')
  topic = sns_client.delete_topic(TopicArn=topic_arn)
  return topic
def subscribe_topic(profile_name, topic_arn,email):
  boto3.setup_default_session(profile_name=profile_name)
  sns = boto3.client('sns')
  sns_resource = boto3.resource('sns')
  topics_iter = sns.list_topics()
  if 'Topics' in topics_iter :
    for element in topics_iter['Topics']:
      if topic_arn==element['TopicArn']:
        topic_arn = element['TopicArn']
        topic = sns_resource.Topic(arn=topic_arn)
        subscription = topic.subscribe(Protocol='email', Endpoint=email, ReturnSubscriptionArn=True)
        return subscription
  return {}
def get_subscriptions(profile_name,topic_arn):
  boto3.setup_default_session(profile_name=profile_name)
  sns_client = boto3.client('sns')
  subscriptions = sns_client.list_subscriptions()
  if 'Subscriptions' in subscriptions:
    list=[]
    for el in subscriptions['Subscriptions']:
      if topic_arn == el['TopicArn']:
        list.append(el)
      return list
  return []
def publish(profile_name,topic_arn,post):
  boto3.setup_default_session(profile_name=profile_name)
  #sns_client = boto3.client('sns')
  sns_resource = boto3.resource('sns')
  topic = sns_resource.Topic(arn=topic_arn)
  result = topic.publish(Message=post)
  return result

Il servizio CloudFormation permette la definizione e la gestione di SNS, si rimanda alla documentazione ufficiale per tutti i dettagli e la descrizione di tutte le proprietà. Il tipo base permette di definire un sistema di notifiche con poche proprietà:

GenericSnsTopic:
  Type: AWS::SNS::Topic
  Properties:
    DisplayName: uploadGenericSns
    TopicName: uploadGenericSns

Inoltre in un template è possibile anche impostare le sottoscrizioni con una risorsa specifica:

AlarmTopic:
  Type: AWS::SNS::Topic
  Properties:
    DisplayName: uploadGenericSns
    TopicName: uploadGenericSns
    Subscription:
    - Protocol: email
      Endpoint: !Ref NotificationEmail
  NotificationEmail:
    Type: AWS::SNS::Subscription
    Properties:
      Endpoint: example@mail.com
      Protocol: email
      TopicArn: !GetAtt AlarmTopic.Arn

Per tutti i dettagli si rimanda alla documentazione ufficiale, si possono trovare alcuni esempi nel solito repository:

https://github.com/alnao/AWSCloudFormationExamples/tree/master/Esempio13lambdaApplicationS3Utils
Pubblicato il 10/02/2024 nella categoria AWS

Questo articolo vuole essere un riassunto il più possibile completo e chiaro riguardo ai comandi di GNU Liunx e le varie possibilità di utilizzo della shell.

La shell bash mette a disposizione una serie di scorciatoie che è possibile usare da riga di comando:

  • tasto TAB espande il nome di un file o di un comando
  • !! ri-esegue l’ultimo comando eseguito
  • !n riesegue l’ennesimo comando presente nella storia, dove ‘n’ e’ il numero del comando da rieseguire
  • !stringa riesegue l’ultimo comando che inizia con i caratteri specificati in stringa
  • !stringa:p visualizza l’ultimo comando che inizia con i caratteri specificati in stringa
  • !?comando? ricerca il comando specificato tra punti interrogativi
  • history visualizza l’elenco di tutti i comandi eseguiti
  • CTRL-U cancella tutta la riga dalla posizione del cursore all’inizio della riga
  • CTRL-K cancella tutta la riga dalla posizione del cursore alla fine della riga
  • CTRL-W cancella una parola dalla posizione del cursore all’inizio della riga
  • ALT-D cancella una parola dalla posizione del cursore alla fine della riga
  • CTRL-A sposta il cursore all’inizio della riga
  • CTRL-E sposta il cursore alla fine della riga
  • ALT-F sposta il cursore alla fine della parola successiva (F sta per forward)
  • CTRL-B sposta il cursore all’inizio della parola precedente (B sta per backward)
  • CTRL-T inverte gli ultimi due caratteri a sinistra del cursore (T sta per transpose)
  • ALT-T inverte le ultime due parole a sinistra del cursore
  • ALT-U trasforma in maiuscolo la parola su cui si trova il cursore (U sta per uppercase)
  • ALT-L trasforma in minuscolo la parola su cui si trova il cursore (L sta per lowercase)

Nei sistemi basati su GNU Linux, tutte le shell hanno un path base spesso detto semplicemente path utilizzato per abbreviare i comandi ed evitare all’utente di dover inserire il path base ogni volta che esegue un comando; per esempio il comando cp, utilizzato per copiare files o cartelle, si trova quasi sempre nella cartella /bin/ e, per evitare che l’utente inserisca il path ogni volta, viene impostato nel path base la cartella bin così la shell cerca i comandi inseriti dall’utente anche in quella cartella. In poche parole il path base è l’elenco delle cartelle dove la shell deve cercare un comando inserito dall’utente, questo elenco è modificabile e personalizzabile: un utente può aggiungere e togliere cartelle da questo elenco visto che questo valore è salvato in una variabile d’ambiente chiamata

$PATH

e il cui contenuto può essere visualizzato con il comando:

$ echo $PATH

e si visualizza l’elenco delle cartelle in sequenza con il separatore due-punti, per esempio:

/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

Se si vuole aggiungere all’elenco una cartella basta lanciare il comando

$ export PATH=$PATH:/cartella/da/aggiungere

ma eseguendo questo comando la modifica sarebbe solo temporanea fino al successivo riavvio del sistema, per rendere definitiva la modifica al path base bisogna modificare il file

~/.bashrc

aggiungendo lo stesso comando, in questo modo verrà eseguito ad ogni login dell’utente.


Gli alias sono dei comandi personalizzati che la shell bash permette di creare a piacimento dell’utente, questo può essere una chiamata ad un comando standard GNU Linux o ad un comando eseguibile (come uno script sh). Un semplice esempio è creare un nuovo alias che cancella i file di una determinata cartella basta lanciare il comando:

alias cancella="rm -fr /mnt/Dati/toDel/*"

poi nella bash basta lanciare il comando cancella per eseguire l’alias che eseguirà il comando indicato. La definizione di alias viene però persa al riavvio del sistema e/o alla log-out dell’utente, per rendere permanente un comando occorre modificare il file:

~/.baschrc

che si trova dentro la cartella home dell’utente (~), quindi capite che ogni utente può avere i propri alias compreso l’utente root, si può aggiungere in questo file una riga per ogni alias (meglio alla fine del file), per esempio (se non esistono già) si possono aggiungere queste righe:

alias ls='ls --color=auto'
alias cancella="rm -fr /tmp/* "

dopo aver salvato il file, basterà che scriviate sul terminale il nuovo alias affinché venga eseguito il comando, si può utilizzare questa semplice procedura potete crearvi tutti i comandi che vi servono, comprese alias che richiamino script sh oppure programmi eseguibili non standard della shell bash.


Esistono dei comandi specifici per ogni esigenza: se è essere necessario rinominare un gruppo di file dentro una cartella specifica, per farlo è possibile con uno semplice script per la shell Bash per evitare di dover ripetere l’operazione per ogni file, per esempio per modificare l’estensione di tutti i file si può usare

$ for i in *.from; do mv $i $(basename $i .from).to; done

oppure scrivere lo script

for file in *.from; do
mv $file ${file%.from}.to
done

In alternativa allo script in bash, esiste un comando molto più veloce e sicuro, mmv (Multiple Move) che serve a spostare o copiare file multipli e che possano essere raggruppati con un carattere jolly, questa azione viene effettuata in modo sicuro, ovvero non ci sono cancellazioni di file inaspettate dovute a collisioni dei nomi dei file di destinazione con nomi di file già esistenti, inoltre non ci sono problemi nel caso in cui i nomi dei file contengano spazi. Un esempio di utilizzo è:

$ mmv 'aaa*bbb?' 'pinco#1pallino#2'

e con questo comando vengono rinominati tutti i file contenenti le stringe “aaa” e “bbb” e terminanti con un carattere e verrà dato il nome “pinco” + ciò che trova l’asterisco + “pallino” + ciò che trova il punto di domanda. Un esempio più semplice:

$ mmv '*.ps' '#1.eps'

per rinominare tutti i file da .ps a .eps, per maggiori informazioni e una guida completa potete vedere il comando man di mmv. Il metodo più semplice rimangono i programmi di gestione file del desktop che tutti quanti usano mmv ma basta un semplice click per eseguire il comando, è possibile provare in Dolphin, Konqueror, Total Commander o qualsiasi altro filemanager presente nel sistema Debian.


Durante l’installazione al passo Copia del sistema base e impostazioni finali è stato installato nel proprio sistema il sistema Grub, questo è il componente della piattaforma GNU Linux che avvia il sistema operativo all’accensione del sistema: dopo l’accensione infatti compare con una schermata che permette di avviare il sistema GNU Linux in diverse modalità ed eventualmente sistemi operativi diversi se sono installate diverse versioni del KernelLinux o altri sistemi operativi, un utente non esperto deve evitare di eseguire modifiche lasciando i valori di default ma un utente più esperto potrà avviare il sistema ottimizzato a seconda delle proprie esigenze.

New grub theme for debian 12! So hyped for debian 12 "bookworm"! : r/debian

Questo pacchetto è importante perché permette di installare più sistemi operativi nello stesso sistema e poi scegliere quale avviare al momento dell’accensione (chiamata appunto boot del sistema oppure bootloader), in tutti gli altri sistemi operativi (come MS Windows e MacOX) questo componente non è presente per questo un utente non abituato a Grub non riesce a capirne l’utilità, è persino possibile installare più versioni di Debian o diverse distribuzioni nel sistema e poi gestirne l’avvio di sistemi operativi con Grub. Per gli utenti Debian di oggi, Grub viene installato durante la fase di installazione del sistema base e viene auto-configurato quindi l’utente non deve inserire nessuna configurazione: l’auto-configurazione rileva la presenza di altri sistemi operativi e li inserisce nell’elenco di quelli che Grub può avviare, ovviamente se il sistema operativo è stato installato dopo l’installazione di Grub bisogna rilanciarne la configurazione.

Il menù di avvio viene regolato dal file

/boot/grub/grub.cfg

ma non bisogna MAI modificarlo a mano visto che ci sono una serie di comandi che permettono di modificare le configurazioni, come per esempio lo sfondo e il carattere usato infatti di default viene usato uno sfondo semplice e un tema base. Per maggiori dettagli sulla configurazione del bootloader vi rimando al sito ufficiale oppure ad una guida italiana. Il problema principale di Grub è che, se si cambiano i componenti del sistema come gli HardDisk, può succedere che rimanga disallineato rispetto all’effettiva architettura del sistema, per ripristinare il bootloader bisogna seguire una guida molto chiara dove sono spiegati tutti i passi per il ripristino e la riattivazione, in particolare il comando

# grub-install --root-directory=/mnt /dev/sdX

ripristina la versione di Grub2 nel sistema, ovviamente i parametri mnt e sdX devono essere modificati con la configurazione del sistema.


La gestione del cestino viene gestita dai vari Desktop (GNOME, KDE o XFCE), e come per altri sistemi, anche in Debian il cestino in realtà è una semplice cartella particolare dove vengono parcheggiati temporaneamente i file in attesa di una cancellazione definitiva, in realtà il Kernel di GNU Linux non gestisce nativamente il cestino, infatti se un utente usa i comandi:

$ rm
$ rmdir

la cancellazione di file o delle cartelle è definitiva e il file non viene spostato in nessun cestino temporaneo quindi bisogna sempre prestare attenzione quando si usano questi comandi. Bisogna sempre tenere conto che il cestino dei Desktop può lasciare della sporcizia nei sistemi, cioè il cestino potrebbe non essere svuotato oppure capita che alcuni desktop non eseguano la cancellazione definitiva ma postano i file in un altra cartella nascosta nonostante il lancio della funzione di svuota il cestino, questa sporcizia può essere lasciata in una cartella specifica che potete trovare al path:

/home/nomeutente/.local/share/Trash/file/

che dovrebbe essere controllata e svuotata periodicamente con il comando

$ rm -rf ~/.local/share/Trash/files/*

per esempio è possibile inserire questo comandi nello script rc.local per svuotare il cestino (in maniera definitiva) ad ogni avvio del sistema. Se avete dei dischi montati con il comando mount, i vari desktop manager e i programmi di gestione dei file come Dolphin creano delle directory Trash (cestino) all’interno dei volumi montati, per esempio

/mnt/Dati/.Trash-1000/files

e anche in questo caso basta pulire queste cartelle a mano oppure semplicemente svuotare il cestino dal desktop.


Il comando sudo consente agli utenti senza privilegi di amministratore, di eseguire i comandi come super-utente senza dover effettuare la login come super-utente e senza conoscere la password dell’utente amministratore, in alcune distribuzioni derivate da Debian come Knoppix o Ubuntu questo comando è impostato di default perché non viene usato l’utente root mentre per chi usa Debian o altre distribuzioni GNU Linux questo comando è sconsigliato ma è possibile configurare il comando sudo, di default questo comando non viene installato durante la fase di installazione del sistema base e per averlo a disposizione basta installare il pacchetto sudo, con il comando:

# apt-get install sudo

per poi lanciare il comando

# visudo

e inserire alla fine del file la riga

nomeutente ALL=(ALL:ALL) ALL

dove ovviamente nomeutente è l’username dell’utente da abilitare per questo comando, questo comando va a scrivere un file sudoers che contiene le impostazioni del comando. Ogni volta che viene lanciato il comando sudo viene chiesta una password, che non è la password dell’utente root, ma è la password dell’utente, l’uso di sudo in Debian può diventare utile per chi vuole scrivere script (in sh per esempio) utilizzando comandi che solo il super-utente può lanciare, un esempio classico è la modifica veloce del file fstab, usando invece un semplice script in sh la cosa si fa molto più veloce e interessante, infatti basta creare un file, dandogli estensione sh (solo per comodità perché come sempre visto le estensioni non sono significative) e scrivere al suo interno le righe:

#!/bin/sh
sudo kwrite /etc/fstab

purtroppo questo non funziona al meglio perché richiede la password dell’utente che lancia lo script, per risolvere il problema dell’inserimento della password basta inserire il comando echo che simula la digitazione di caratteri nel sistema:

#!/bin/sh
echo password | sudo -S kwrite /etc/fstab

e lo script digiterà automaticamente la password al posto dell’utente, in questo modo si ha a disposizione uno script per eseguire il comando sudo che digita automaticamente la password. Se la installazione del sistema Debian viene avviata dalla versione live, il comando sudo viene installato di default e non viene impostata la password dell’utenza root, per impostarla basta lanciare il comando:

$ sudo passwd root <nuovapassword>

questo perché in quasi tutte le live il comando sudo viene usato al posto dell’utenza root e questo viene ereditato nelle installazioni che vengono avviate da sistemi live.

Pubblicato il 10/02/2024 nella categoria Debian

Per creare un tema da zero partendo da un foglio bianco bisogna prima di tutto conoscere i linguaggi per la costruzione di pagine web, come HTML e CSS, inoltre è indispensabile conoscere anche il linguaggio script PHP: questo è il linguaggio con cui è scritto WordPress, senza queste conoscenze è impossibile iniziare a costruire un proprio tema e conviene cercare i temi già esistenti sullo “store” di WordPress. Un altro dettaglio da non trascurare è sono necessari i permessi di scrittura nel web-server per poter caricare e modificare i file dall’ambiente di sviluppo al server, senza questi permessi non sarà possibile proseguire. Questi articoli sono divisi in più step visto che la costruzione di un tema è sequenza di elementi da sviluppare. Per ogni dubbio si rimanda alla guida ufficiale disponibile al sito ufficiale.

Sviluppando un tema bisogna tener presente che iii tutti iii i temi di wordpress rispettano uno schema ben preciso: http://www.graphical.it/wp-content/uploads/2010/12/SCHEMA.jpg

Nello schema sono presentati gli elementi di un sito Worpdress: una testata, una coda, un contenuto centrale affiancato da una eventuale barra (destra o sinistra). Tutti i componenti del tema dovranno trovarsi in una cartella dedicata che dovrà essere posizionata nella cartella

/wp-content/themes/<nometema>

nel webserver che espone il sito. All’interno devono sempre essere spresenti almeno tre files:

  • index.php: file PHP principale del tema
  • style.css: file degli stili in formato css
  • functions.php: file PHP dove è possibile definire funzioni che modificano il comportamento del tema usando le funzionalità del framework WordPress.

Le prime righe del file CSS devono obbligatoriamente essere le informazioni riguardanti il tema, come standard è previsto un commento dove sono indicate le informazioni:

/*
Theme name: Primo alnao.it
Theme url: https://www.alnao.it
Description: Tema sviluppato da AlNao come primo esempio
Version: 1.0
Author: <a href="https://www.alnao.it" title="AlNao.it">AlNao.it</a>
Author url: https://www.alnao.it
Tags: first, clean, minimal
*/

Quando questi files vengono depositati all’interno di un sito WordPress nella cartella specifica themes, automaticamente nel menù Apparences alla voce Themes (rispettivamente Aspetto e Temi in italiano), sarà possibile trovare il tema elencato nella lista dei temi disponibili ma sarà assente la immagine di esempio (miniatura) ma saranno presenti le varie informazioni indicate nel file CSS come nome dell’autore e la breve descrizione del tema. Per configurare la miniatura è sufficiete creare un file immagine screenshot.png di esempio contenga la immagine di esempio del vostro tema e/o il logo, aggiungendola nella cartella del tema comparirà come miniatura nell’elenco dei temi.

Per maggior informazioni si rimanda alla documentazione ufficiale: infatti esiste un sito dedicato ai programmatori developer.wordpress.org che sviluppano temi e componenti per WordPress. In questa serie di articoli saranno descritti i principali passi per lo sviluppo di un tema, in altri articoli saranno descritti i passi per lo sviluppo di plugin e widget che necessitano di un conoscenze maggiori rispetto a quelle necessarie per lo sviluppo di un tema, si consiglia di saltare questa sezione se non si conoscono le basi di programmazione PHP.

Pubblicato il 10/02/2024 nella categoria Wordpress

Il tema della sicurezza non deve mai essere sottovalutato, in particolare quando si lavora in un Cloud AWS è indispensabile prestare attenzione alle regole di accesso alle istanze Ec2 per evitare che qualcuno di non autorizzato acceda alle istanze e faccia danni o rubi informazioni. In particolare, in AWS, per Security Group si intende il sotto-servizio per la definizione delle regole di accesso alle macchine Ec2: di default tutte le interfacce di rete sono bloccate sia in ingresso sia in uscita ma grazie ai Security Group (spesso indicati con la sigla SG) è possibile abilitare porte di rete in ingresso e in uscita. Si rimanda sempre alla documentazione ufficiale per tutti i dettagli riguardo a questo servizio. Il servizio era inizialmente studiato solo per le istanze E22 ma oggi è usato per gestire le regole di rete anche di altri servizi come RDS e ALB, si tuttavia il SG è un sottoservizio del servio Ec2. Purtroppo spesso in lingua italiana il nome di questo servizio viene tradotto con gruppo di sicurezza, questa traduzione spesso può creare confusione quindi è consigliato usare sempre la lingua inglese per evitare fraintendimenti.

Le regole definite con SG sono di due tipi: in ingresso (incoming) e in uscita (outgoing), tipicamente si autorizza tutto il traffico in uscite mentre è importate limitare le regole in ingresso solo ai protocolli, alle porte e agli IP indispensabili. Si rimanda alla documentazione ufficiale per maggior informazioni riguardo alla procedura guidata via web.


La CLI mette a disposizione una serie di comandi per la gestione dei SecurityGroup, si rimanda alla documentazione ufficiale e alla guida per tutti i dettagli. I principali comandi sono:

  • elenco delle regole e il dettaglio di uno specifico
    aws ec2 describe-security-groups 
    aws ec2 describe-security-groups --group-ids sg-903004f8
  • creazione di un nuovo security group
    aws ec2 create-security-group --group-name my-sg --description "My security group" --vpc-id vpc-xxxx
  • aggiunta, rimozione emodifica di una regola all’interno del security group
    aws ec2 authorize-security-group-ingress --group-id sg-903004f8 --protocol tcp --port 3389 --cidr x.x.x.x/x
    aws ec2 authorize-security-group-ingress --group-id sg-903004f8 --protocol tcp --port 22 --cidr x.x.x.x/x
    aws ec2 modify-security-group-rules ...
    aws ec2 revoke-security-group-ingress ..
  • modifica di una reola con tutti i dettagli
    aws ec2 modify-security-group-rules --group-id sg-1234567890abcdef0 --security-group-rules SecurityGroupRuleId=sgr-abcdef01234567890,SecurityGroupRule='{Description=test,IpProtocol=-1,CidrIpv4=0.0.0.0/0}'
  • cancellazione di un security group
    aws ec2 delete-security-group --group-id sg-903004f8

La libreria boto3 del SDK mette a disposizione molti metodi per la gestione dei security group, si rimanda alla documentazione ufficiale per tutti i dettagli, il principale metodo è quello per recuperare l’elenco completo delle regole:

ec2_client = boto3.client('ec2')
response = ec2_client.describe_security_groups()

Si rimanda alla documentazione ufficiale per esempi in altri linguaggi di programmazione come java.


Con CloudFormation è possibile definire regole con il tipo specifico dedicato:

InstanceSecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: Enable SSH access via port 22
    VpcId: !Ref 'VpcId'
    SecurityGroupIngress:
    - IpProtocol: TCP
      FromPort: 22
      ToPort: 22
      CidrIp: !Ref 'SSHLocation'
    - CidrIp: '0.0.0.0/0'
      IpProtocol: TCP
      FromPort: 80
      ToPort: 80

E nella definizione delle istanze è possibile collegare una EC2 ad uno o più gruppi con la definizione delle istanze:

EC2Instance:
  Type: AWS::EC2::Instance
  Properties:
    InstanceType: !Ref 'InstanceType'
    KeyName: !Ref 'KeyName'
    ImageId: !Ref 'LatestAmiId'
    NetworkInterfaces: 
    - GroupSet: [!Ref 'InstanceSecurityGroup']
      SubnetId: !Ref SubnetId
      AssociatePublicIpAddress: true
    DeviceIndex: '0'
    DeleteOnTermination: true

Nella definizione di un security group è possibile definire nell’input come sorgente l’output di un altro security group, per esempio il traffico di un ALB verso un WebServer può essere regolato con la definizione:

ALBSecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: Load balancer traffic
    SecurityGroupIngress:
    - IpProtocol: TCP
      FromPort: '80'
      ToPort: '80'
      CidrIp: 0.0.0.0/0
    VpcId: !Ref VpcId 
WebServerSecurityGroup:
  Type: 'AWS::EC2::SecurityGroup'
  Properties:
    GroupDescription: Enable HTTP access via port 80 locked down to the load balancer + SSH access
    SecurityGroupIngress:
    - IpProtocol: TCP
      From Port: '80'
      ToPort: '80'
      SourceSecurityGroupId: !Ref ALBSecurityGroup

Da notare che in tutti i punti è indispensabile indicare sempre la VPC dove la regola deve essere definita. Si rimanda i vari esempi presenti al solito repository

https://github.com/alnao/AWSCloudFormationExamples

Per il collegamento dei Security Group alle istanze EC2 esistono diversi modi ma il principale per le istanze GNU Linux rimane il protocollo SSH (secure shell h), questo viene configurato di default nelle istanze AMI standard di tipo GNU Linux, per il collegamento è sempre necessario usare una chiave privata in formato PEM configurabile nel sotto-servizio Key Pairs previsto dal servizio Ec2, si rimanda alla documentazione ufficiale per i dettagli di questo servizio. La o le chiavi devono essere agganciate alle istanze Ec2, questa associazione può essere effettuata da console, da SDK o anche da CloudFormation con la proprietà specifica

KeyName: !Ref 'KeyName'

Nella regola del security group è necessario configurare la porta 22, senza questa regola la porta di rete rimarrebbe chiusa e il collegamento non potrebbe avvenire

SecurityGroupIngress:
- IpProtocol: tcp
  FromPort: 22
  ToPort: 22
  CidrIp: !Ref 'SSHLocation'

Per il collegamento alla istanza è possibile un qualunque programma shell e/o bash, come un terminale GNU Linux o Putty per Windows.

ssh utente@indirizzoip -i key_privata.pem

Da notare che le chiavi pubbliche abilitate al collegamento vengono salvate nelle istanze nel file:

.ssh/authorized_keys

della utenza principale (bitnami nel caso di AMI di quel tipo o ec2_user nel caso di istanze di tipo Amazon Linux).


Per le istanze Windows, è possibile abilitare la connessione tramite desktop remoto abilitando il protocollo RDP (remote desktop protocol), per le istanze con questo sistema operativo non è possibile usare una chiave privata ma bisogna usare le credenziali con username e password. L’abilitazione del protocollo RDP è molto semplice: basta infatti abilitare la porta 3389 nel protocollo TCP, si rimanda alla documentazione ufficiale per maggiori informazioni.

Nota: è sempre sconsigliato utilizzare la Cidr di tipo 0.0.0.0/0 tranne per quelle connessioni aperte verso tutta la rete internet, in particolare per l’accesso con i protocolli SSH e/o RDP è consigliato impostare un Ip fisso o un range molto più ristretto.

Pubblicato il 03/02/2024 nella categoria AWS
MENU