Implementazioni personalizzate della convalida dell'integrità dei file di CloudTrail registro - AWS CloudTrail

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Implementazioni personalizzate della convalida dell'integrità dei file di CloudTrail registro

Poiché CloudTrail utilizza algoritmi crittografici e funzioni hash standard del settore e disponibili apertamente, è possibile creare strumenti personalizzati per convalidare l'integrità dei file di registro. CloudTrail Quando la convalida dell'integrità dei file di log è abilitata, CloudTrail invia i file digest al tuo bucket Amazon S3. Puoi utilizzare questi file per implementare la tua soluzione di convalida personalizzata. Per ulteriori informazioni sui file digest, consulta CloudTrail struttura del file digest.

Questo argomento descrive come vengono firmati i file digest e illustra in dettaglio le procedure necessarie per implementare una soluzione che convalida i file digest e i file di log a cui fanno riferimento.

Comprendere come CloudTrail vengono firmati i file digest

CloudTrail i file digest sono firmati con firme digitali RSA. Per ogni file digest, CloudTrail effettua le seguenti operazioni:

  1. Crea una stringa per la firma dei dati in base ai campi del file digest designato (descritti nella sezione successiva).

  2. Recupera una chiave privata univoca per la Regione.

  3. Passa l'hash SHA-256 della stringa e la chiave privata all'algoritmo di firma RSA, che genera una firma digitale.

  4. Codifica il codice byte della firma in formato esadecimale.

  5. Inserisce la firma digitale nella proprietà metadati x-amz-meta-signature dell'oggetto file digest Amazon S3.

Contenuto della stringa di firma dei dati

I seguenti CloudTrail oggetti sono inclusi nella stringa per la firma dei dati:

  • Time stamp finale del file digest nel formato UTC esteso (ad esempio, 2015-05-08T07:19:37Z)

  • Percorso S3 del file digest corrente

  • Hash SHA-256 con codifica esadecimale del file digest corrente

  • Firma con codifica esadecimale del precedente file digest

Il formato per calcolare questa stringa e un esempio di stringa vengono forniti più avanti in questo documento.

Fasi di implementazione della convalida personalizzata

Durante l'implementazione di una soluzione di convalida personalizzata, devi convalidare il file digest per primo e quindi i file di log a cui fa riferimento.

Convalida del file digest

Per convalidare un file digest, devi disporre della relativa firma, della chiave pubblica la cui chiave privata è stata utilizzata per firmare il file e di una stringa di firma dei dati che elaborerai personalmente.

  1. Recuperare il file digest.

  2. Verificare che il file digest sia stato recuperato dal relativo percorso originale.

  3. Recuperare la firma con codifica esadecimale del file digest.

  4. Recuperare l'impronta con codifica esadecimale della chiave pubblica la cui chiave privata è stata utilizzata per firmare il file digest.

  5. Recuperate le chiavi pubbliche per l'intervallo di tempo corrispondente al file digest.

  6. Tra le chiavi pubbliche recuperate scegliere la chiave pubblica con l'impronta corrispondente a quella nel file digest.

  7. Utilizzando l'hash del file digest e gli altri campi del file, ricreare la stringa di firma dei dati per verificare la firma del file digest.

  8. Per convalidare la firma, passare l'hash SHA-256 della stringa, la chiave pubblica e la firma come parametri all'algoritmo RSA di verifica della firma. Se il risultato è true, il file digest è valido.

Convalida dei file di log

Se il file digest è valido, convalidare ciascun file di log a cui il file digest fa riferimento.

  1. Per convalidare l'integrità di un file di log, calcolare il relativo valore hash SHA-256 per il relativo contenuto non compresso e confrontare i risultati con il valore hash per il file di log registrato in formato esadecimale nel digest. Se i valori hash corrispondono, il file di log è valido.

  2. Utilizzando le informazioni relative al file digest precedente incluse nel file digest corrente, convalidare in sequenza i file digest precedenti e i corrispondenti file di log.

Le seguenti sezioni descrivono in dettaglio queste fasi.

A. Recupero del file digest

Durante la fase iniziale di recupero del file digest più recente, devi assicurarsi di avere recuperato il file dalla relativa posizione originale, verificarne la firma digitale e recuperare l'impronta della chiave pubblica.

  1. Utilizzando S3 GetObjecto la classe AmazonS3Client (ad esempio), ottieni il file digest più recente dal tuo bucket Amazon S3 per l'intervallo di tempo che desideri convalidare.

  2. Verificare che il bucket S3 e l'oggetto S3 utilizzati per recuperare il file corrispondano alla posizione del bucket S3 e a quella dell'oggetto S3 registrate nel file digest stesso.

  3. Recupera quindi la firma digitale del file digest dalla proprietà metadati x-amz-meta-signature dell'oggetto del file digest in Amazon S3.

  4. Nel file digest recuperare l'impronta della chiave pubblica la cui chiave privata è stata utilizzata per firmare il file digest dal campo digestPublicKeyFingerprint.

B. Recupero della chiave pubblica per la convalida del file digest

Per ottenere la chiave pubblica per convalidare il file digest, puoi utilizzare l'o l'API. AWS CLI CloudTrail In entrambi i casi, puoi specificare un intervallo di tempo (ovvero un'ora di inizio e una di fine) per il file digest da convalidare. È possibile che vengano restituite una o più chiavi pubbliche per l'intervallo di tempo specificato. Le chiavi restituite possono avere intervalli di tempo di validità sovrapposti.

Nota

Poiché CloudTrail utilizza diverse coppie di chiavi pubblice/private per regione, ogni file digest è firmato con una chiave privata unica per la sua regione. Pertanto, quando convalidi un file digest da una determinata Regione, devi recuperare la relativa chiave pubblica dalla stessa Regione.

Usa il per recuperare le chiavi pubbliche AWS CLI

Per recuperare le chiavi pubbliche per i file digest utilizzando il AWS CLI, usa il comando. cloudtrail list-public-keys Il comando ha il formato seguente:

aws cloudtrail list-public-keys [--start-time <start-time>] [--end-time <end-time>]

I parametri relativi all'ora di inizio e all'ora di fine sono time stamp UTC facoltativi. Se non specificata, verrà utilizzata l'ora corrente e verranno restituite la chiave o le chiavi pubbliche attualmente attive.

Risposta di esempio

La risposta sarà un elenco di oggetti JSON che rappresentano la chiave o le chiavi restituite:

{ "publicKeyList": [ { "ValidityStartTime": "1436317441.0", "ValidityEndTime": "1438909441.0", "Value": "MIIBCgKCAQEAn11L2YZ9h7onug2ILi1MWyHiMRsTQjfWE+pHVRLk1QjfWhirG+lpOa8NrwQ/r7Ah5bNL6HepznOU9XTDSfmmnP97mqyc7z/upfZdS/AHhYcGaz7n6Wc/RRBU6VmiPCrAUojuSk6/GjvA8iOPFsYDuBtviXarvuLPlrT9kAd4Lb+rFfR5peEgBEkhlzc5HuWO7S0y+KunqxX6jQBnXGMtxmPBPP0FylgWGNdFtks/4YSKcgqwH0YDcawP9GGGDAeCIqPWIXDLG1jOjRRzWfCmD0iJUkz8vTsn4hq/5ZxRFE7UBAUiVcGbdnDdvVfhF9C3dQiDq3k7adQIziLT0cShgQIDAQAB", "Fingerprint": "8eba5db5bea9b640d1c96a77256fe7f2" }, { "ValidityStartTime": "1434589460.0", "ValidityEndTime": "1437181460.0", "Value": "MIIBCgKCAQEApfYL2FiZhpN74LNWVUzhR+VheYhwhYm8w0n5Gf6i95ylW5kBAWKVEmnAQG7BvS5g9SMqFDQx52fW7NWV44IvfJ2xGXT+wT+DgR6ZQ+6yxskQNqV5YcXj4Aa5Zz4jJfsYjDuO2MDTZNIzNvBNzaBJ+r2WIWAJ/Xq54kyF63B6WE38vKuDE7nSd1FqQuEoNBFLPInvgggYe2Ym1Refe2z71wNcJ2kY+q0h1BSHrSM8RWuJIw7MXwF9iQncg9jYzUlNJomozQzAG5wSRfbplcCYNY40xvGd/aAmO0m+Y+XFMrKwtLCwseHPvj843qVno6x4BJN9bpWnoPo9sdsbGoiK3QIDAQAB", "Fingerprint": "8933b39ddc64d26d8e14ffbf6566fee4" }, { "ValidityStartTime": "1434589370.0", "ValidityEndTime": "1437181370.0", "Value": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqlzPJbvZJ42UdcmLfPUqXYNfOs6I8lCfao/tOs8CmzPOEdtLWugB9xoIUz78qVHdKIqxbaG4jWHfJBiOSSFBM0lt8cdVo4TnRa7oG9io5pysS6DJhBBAeXsicufsiFJR+wrUNh8RSLxL4k6G1+BhLX20tJkZ/erT97tDGBujAelqseGg3vPZbTx9SMfOLN65PdLFudLP7Gat0Z9p5jw/rjpclKfo9Bfc3heeBxWGKwBBOKnFAaN9V57pOaosCvPKmHd9bg7jsQkI9Xp22IzGLsTFJZYVA3KiTAElDMu80iFXPHEq9hKNbt9e4URFam+1utKVEiLkR2disdCmPTK0VQIDAQAB", "Fingerprint": "31e8b5433410dfb61a9dc45cc65b22ff" } ] }

Utilizza l' CloudTrail API per recuperare le chiavi pubbliche

Per recuperare le chiavi pubbliche per i file digest utilizzando l' CloudTrail API, trasmetti i valori dell'ora di inizio e dell'ora di fine all'API. ListPublicKeys L'API ListPublicKeys restituisce le chiavi pubbliche le cui chiavi private sono state utilizzate per firmare i file digest compresi nell'intervallo di tempo specificato. Per ogni chiave pubblica, l'API restituisce anche le corrispondenti impronte.

ListPublicKeys

Questa sezione descrive i parametri di richiesta e gli elementi di risposta dell'API ListPublicKeys.

Nota

La codifica dei campi binari per ListPublicKeys è soggetta a modifiche.

Parametri della richiesta

Nome Descrizione
StartTime

Facoltativamente, in UTC, l'inizio dell'intervallo di tempo per la ricerca delle chiavi pubbliche per i file digest. CloudTrail Se non StartTime è specificato, viene utilizzata l'ora corrente e viene restituita la chiave pubblica corrente.

Tipo: DateTime

EndTime

Facoltativamente, in UTC, la fine dell'intervallo di tempo per la ricerca delle chiavi pubbliche per CloudTrail i file digest. Se non EndTime è specificato, viene utilizzata l'ora corrente.

Tipo: DateTime

Elementi di risposta

PublicKeyList, una matrice di oggetti PublicKey contenenti:

Nome Descrizione
Value

Valore della chiave pubblica con codifica DER in formato PKCS #1.

Tipo: Blob

ValidityStartTime

Ora di inizio della validità della chiave pubblica.

Tipo: DateTime

ValidityEndTime

Ora di fine della validità della chiave pubblica.

Tipo: DateTime

Fingerprint

Impronta della chiave pubblica. L'impronta può essere utilizzata per identificare la chiave pubblica da utilizzare per convalidare il file digest.

▬Tipo: stringa

C. Scelta della chiave pubblica da utilizzare per la convalida

Tra le chiavi pubbliche recuperate da list-public-keys o ListPublicKeysscegliere la chiave pubblica restituita con l'impronta corrispondente all'impronta registrata nel campo digestPublicKeyFingerprint del file digest. Questa è la chiave pubblica che verrà utilizzata per convalidare il file digest.

D. Creazione di una nuova stringa di firma dei dati

Ora che disponi della firma del file digest e della chiave pubblica associata, devi calcolare la stringa di firma dei dati. Dopo aver calcolato tale stringa, si disporrà di tutte le informazioni necessarie per verificare la firma.

La stringa di firma dei dati ha il formato seguente:

Data_To_Sign_String = Digest_End_Timestamp_in_UTC_Extended_format + '\n' + Current_Digest_File_S3_Path + '\n' + Hex(Sha256(current-digest-file-content)) + '\n' + Previous_digest_signature_in_hex

Di seguito è riportato un esempio di stringa Data_To_Sign_String.

2015-08-12T04:01:31Z DOC-EXAMPLE-BUCKET/AWSLogs/111122223333/CloudTrail-Digest/us-east-2/2015/08/12/111122223333_us-east-2_CloudTrail-Digest_us-east-2_20150812T040131Z.json.gz 4ff08d7c6ecd6eb313257e839645d20363ee3784a2328a7d76b99b53cc9bcacd 6e8540b83c3ac86a0312d971a225361d28ed0af20d70c211a2d405e32abf529a8145c2966e3bb47362383a52441545ed091fb81 d4c7c09dd152b84e79099ce7a9ec35d2b264eb92eb6e090f1e5ec5d40ec8a0729c02ff57f9e30d5343a8591638f8b794972ce15bb3063a01972 98b0aee2c1c8af74ec620261529265e83a9834ebef6054979d3e9a6767dfa6fdb4ae153436c567d6ae208f988047ccfc8e5e41f7d0121e54ed66b1b904f80fb2ce304458a2a6b91685b699434b946c52589e9438f8ebe5a0d80522b2f043b3710b87d2cda43e5c1e0db921d8d540b9ad5f6d4$31b1f4a8ef2d758424329583897339493a082bb36e782143ee5464b4e3eb4ef6

Dopo aver ricreato questa stringa, puoi convalidare il file digest.

E. Convalida del file digest

A questo punto puoi passare l'hash SHA-256 della stringa di firma dei dati ricreata, la firma digitale e la chiave pubblica all'algoritmo RSA di verifica della firma. Se l'output è true, la firma del file digest è verificata e il file digest è valido.

F. Convalida dei file di log

Dopo aver convalidato il file digest, puoi convalidare il file di log a cui fa riferimento. Il file digest contiene gli hash SHA-256 dei file di log. Se uno dei file di registro è stato modificato dopo la CloudTrail consegna, gli hash SHA-256 cambieranno e la firma del file digest non corrisponderà.

Di seguito è descritto come convalidare i file di log:

  1. Eseguire un comando S3 Get sul file di log utilizzando le informazioni sulla posizione S3 nei campi logFiles.s3Bucket e logFiles.s3Object del file digest.

  2. Se l'operazione S3 Get ha esito positivo, ripetere l'operazione nei file di log elencati nella matrice logFiles del file digest utilizzando la procedura seguente:

    1. Recuperate il valore hash originale del file dal campo logFiles.hashValue del log corrispondente nel file digest.

    2. Eseguire l'hashing dei contenuti non compressi del file di log con l'algoritmo di hashing specificato in logFiles.hashAlgorithm.

    3. Confrontare il valore hash generato con quello del log nel file digest. Se i valori hash corrispondono, il file di log è valido.

G. Convalida di file digest e file di log aggiuntivi

In ogni file digest, i seguenti campi forniscono le informazioni su posizione e firma del file digest precedente:

  • previousDigestS3Bucket

  • previousDigestS3Object

  • previousDigestSignature

Utilizzare queste informazioni per recuperare i file digest precedenti in sequenza, convalidare la firma di ciascuno di essi e i file di log a cui fanno riferimento mediante le procedure descritta nelle sezioni precedenti. L'unica differenza risiede nel fatto che, per i file digest precedenti, non devi recuperare la firma digitale dalle proprietà metadati Amazon S3 dell'oggetto file digest. La firma del file digest precedente è disponibile automaticamente nel campo previousDigestSignature.

Puoi andare a ritroso nel tempo finché non raggiungi il file digest iniziale o fino all'interruzione della sequenza di file digest, a seconda di quale evento si verifica prima.

Convalida di file digest e file di log offline

Durante la convalida di file digest e file di log offline, in genere puoi fare riferimento alle procedure descritte nelle sezioni precedenti. Devi tuttavia tenere in considerazione i seguenti punti:

Utilizzo del file digest più recente

La firma digitale del file digest più recente (ovvero "corrente") si trova nelle proprietà metadati Amazon S3 dell'oggetto file digest. In uno scenario offline, la firma digitale del file digest corrente non sarà disponibile.

Per gestire questa situazione sono disponibili due modi:

  • Poiché la firma digitale per il file digest precedente si trova nel file digest corrente, iniziate la convalida dal file digest. next-to-last Con questo metodo il file digest più recente non può essere convalidato.

  • Come prima cosa recupera la firma del file digest corrente dalle proprietà metadati dell'oggetto del file digest e quindi memorizzala in modo sicuro offline. In questo modo il file digest corrente verrà convalidato assieme ai file precedenti nella sequenza.

Risoluzione del percorso

I campi nei file digest scaricati, ad esempio s3Object e previousDigestS3Object, continueranno a fare riferimento alle posizioni Amazon S3 online dei file di log e file digest. Una soluzione offline deve trovare un modo per reindirizzare queste posizioni al percorso corrente dei file di log e file digest scaricati.

Chiavi pubbliche

Per eseguire la convalida offline, tutte le chiavi pubbliche necessarie per convalidare i file di log in un determinato intervallo di tempo devono prima essere recuperate online (chiamando ListPublicKeys, ad esempio) e quindi memorizzate in modo sicuro offline. Questo passaggio deve essere ripetuto ogni volta che si vuole convalidare altri file non compresi nell'intervallo di tempo iniziale specificato.

Esempio di frammento di codice di convalida

Il seguente frammento di esempio fornisce un codice scheletrico per la convalida dei file digest e di registro. CloudTrail Il codice di base non fa distinzione tra le modalità online/offline, ovvero si potrà a scegliere autonomamente se implementare il codice con o senza una connessione online ad AWS. L'implementazione suggerita usa i provider di sicurezza Java Cryptography Extension (JCE) e Bouncy Castle.

Il frammento di codice di esempio mostra:

  • Come creare la stringa di firma dei dati utilizzata per convalidare la firma del file digest.

  • Come verificare la firma del file digest.

  • Come verificare gli hash del file di log.

  • Una struttura di codice per convalidare una sequenza di file digest.

import java.util.Arrays; import java.security.MessageDigest; import java.security.KeyFactory; import java.security.PublicKey; import java.security.Security; import java.security.Signature; import java.security.spec.X509EncodedKeySpec; import org.json.JSONObject; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.apache.commons.codec.binary.Hex; public class DigestFileValidator { public void validateDigestFile(String digestS3Bucket, String digestS3Object, String digestSignature) { // Using the Bouncy Castle provider as a JCE security provider - http://www.bouncycastle.org/ Security.addProvider(new BouncyCastleProvider()); // Load the digest file from S3 (using Amazon S3 Client) or from your local copy JSONObject digestFile = loadDigestFileInMemory(digestS3Bucket, digestS3Object); // Check that the digest file has been retrieved from its original location if (!digestFile.getString("digestS3Bucket").equals(digestS3Bucket) || !digestFile.getString("digestS3Object").equals(digestS3Object)) { System.err.println("Digest file has been moved from its original location."); } else { // Compute digest file hash MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); messageDigest.update(convertToByteArray(digestFile)); byte[] digestFileHash = messageDigest.digest(); messageDigest.reset(); // Compute the data to sign String dataToSign = String.format("%s%n%s/%s%n%s%n%s", digestFile.getString("digestEndTime"), digestFile.getString("digestS3Bucket"), digestFile.getString("digestS3Object"), // Constructing the S3 path of the digest file as part of the data to sign Hex.encodeHexString(digestFileHash), digestFile.getString("previousDigestSignature")); byte[] signatureContent = Hex.decodeHex(digestSignature); /* NOTE: To find the right public key to verify the signature, call CloudTrail ListPublicKey API to get a list of public keys, then match by the publicKeyFingerprint in the digest file. Also, the public key bytes returned from ListPublicKey API are DER encoded in PKCS#1 format: PublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier, PublicKey BIT STRING } AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, parameters ANY DEFINED BY algorithm OPTIONAL } */ pkcs1PublicKeyBytes = getPublicKey(digestFile.getString("digestPublicKeyFingerprint"))); // Transform the PKCS#1 formatted public key to x.509 format. RSAPublicKey rsaPublicKey = RSAPublicKey.getInstance(pkcs1PublicKeyBytes); AlgorithmIdentifier rsaEncryption = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, null); SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo(rsaEncryption, rsaPublicKey); // Create the PublicKey object needed for the signature validation PublicKey publicKey = KeyFactory.getInstance("RSA", "BC").generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded())); // Verify signature Signature signature = Signature.getInstance("SHA256withRSA", "BC"); signature.initVerify(publicKey); signature.update(dataToSign.getBytes("UTF-8")); if (signature.verify(signatureContent)) { System.out.println("Digest file signature is valid, validating log files…"); for (int i = 0; i < digestFile.getJSONArray("logFiles").length(); i++) { JSONObject logFileMetadata = digestFile.getJSONArray("logFiles").getJSONObject(i); // Compute log file hash byte[] logFileContent = loadUncompressedLogFileInMemory( logFileMetadata.getString("s3Bucket"), logFileMetadata.getString("s3Object") ); messageDigest.update(logFileContent); byte[] logFileHash = messageDigest.digest(); messageDigest.reset(); // Retrieve expected hash for the log file being processed byte[] expectedHash = Hex.decodeHex(logFileMetadata.getString("hashValue")); boolean signaturesMatch = Arrays.equals(expectedHash, logFileHash); if (!signaturesMatch) { System.err.println(String.format("Log file: %s/%s hash doesn't match.\tExpected: %s Actual: %s", logFileMetadata.getString("s3Bucket"), logFileMetadata.getString("s3Object"), Hex.encodeHexString(expectedHash), Hex.encodeHexString(logFileHash))); } else { System.out.println(String.format("Log file: %s/%s hash match", logFileMetadata.getString("s3Bucket"), logFileMetadata.getString("s3Object"))); } } } else { System.err.println("Digest signature failed validation."); } System.out.println("Digest file validation completed."); if (chainValidationIsEnabled()) { // This enables the digests' chain validation validateDigestFile( digestFile.getString("previousDigestS3Bucket"), digestFile.getString("previousDigestS3Object"), digestFile.getString("previousDigestSignature")); } } } }