Pubblicato il 02/03/2024 da alnao nella categoria AWS

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)
MENU