Implementaciones personalizadas de la validación de la integridad de los archivos de CloudTrail registro - AWS CloudTrail

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Implementaciones personalizadas de la validación de la integridad de los archivos de CloudTrail registro

Como CloudTrail utiliza algoritmos criptográficos y funciones de hash estándares del sector y disponibles de forma abierta, puede crear sus propias herramientas para validar la integridad de los archivos de CloudTrail registro. Cuando la validación de integridad de los archivos de registro está habilitada, CloudTrail envía los archivos de resumen a su bucket de Amazon S3. Puede utilizar estos archivos para implementar su propia solución de validación. Para obtener más información sobre los archivos de resumen, consulte CloudTrail estructura de archivos de resumen.

En este tema se describe cómo se firman los archivos de resumen. A continuación, se detallan los pasos que debe seguir para implementar una solución que valide los archivos de resumen y los archivos de registro a los que hacen referencia.

Comprenda cómo se firman los archivos de CloudTrail resumen

CloudTrail los archivos de resumen se firman con firmas digitales RSA. Para cada archivo de resumen, CloudTrail hace lo siguiente:

  1. Crea una cadena para firmar datos en función de campos del archivo de resumen designados (que se describen en la sección siguiente).

  2. Obtiene una clave privada única para la región.

  3. Pasa el hash SHA-256 de la cadena y la clave privada al algoritmo de firma RSA, que produce una firma digital.

  4. Codifica el código de bytes de la firma en formato hexadecimal.

  5. Coloca la firma digital en la propiedad de metadatos x-amz-meta-signature del objeto del archivo de resumen de Amazon S3.

Contenido de la cadena de firma de datos

Los siguientes CloudTrail objetos se incluyen en la cadena para la firma de datos:

  • La marca de tiempo de finalización del archivo de resumen en formato extendido UTC (por ejemplo, 2015-05-08T07:19:37Z)

  • La ruta S3 del archivo de resumen actual

  • El hash SHA-256 en codificación hexadecimal del archivo de resumen actual

  • La firma en codificación hexadecimal del archivo de resumen anterior

Más adelante en este documento se proporciona el formato de cálculo de esta cadena y una cadena de ejemplo.

Pasos de implementación de la validación personalizada

Cuando implemente una solución de validación personalizada, deberá validar en primer lugar el archivo de resumen y, a continuación, los archivos de registro a los que hace referencia.

Validar el archivo de resumen

Para validar un archivo de resumen, necesita su firma, la clave pública cuya clave privada se ha utilizado para firmarlo y una cadena de firma de datos que debe calcular.

  1. Obtenga el archivo de resumen.

  2. Compruebe que el archivo de resumen se haya recuperado de su ubicación original.

  3. Obtenga la firma en codificación hexadecimal del archivo de resumen.

  4. Obtenga la huella en codificación hexadecimal de la clave pública cuya clave privada se ha utilizado para firmar el archivo de resumen.

  5. Recupere las claves públicas para el intervalo de tiempo correspondiente al archivo de resumen.

  6. De entre las claves públicas recuperadas, elija la clave pública cuya huella coincida con la del archivo de resumen.

  7. Con el hash y otros campos del archivo de resumen, vuelva a crear la cadena de firma que se utiliza para verificar la firma de dicho archivo.

  8. Valide la firma pasando el hash SHA-256 de la cadena, la clave pública y la firma como parámetros al algoritmo de verificación de firmas RSA. Si el resultado es verdadero, el archivo de resumen es válido.

Validar los archivos de registros

Si el archivo de resumen es válido, valide cada uno de los archivos de registro a los que hace referencia.

  1. Para validar la integridad de un archivo de registro, calcule su valor de hash SHA-256 en su contenido sin comprimir y compare los resultados con el hash del archivo de registro (registrado en formato hexadecimal) en el resumen. Si los hash coinciden, el archivo de registro es válido.

  2. Sírvase de la información del archivo de resumen anterior que se incluye en el archivo de resumen actual para validar los archivos de resumen anteriores y sus correspondientes archivos de registro de manera sucesiva.

En las siguientes secciones se describen estos pasos de manera detallada.

A. Obtener el archivo de resumen

Los primeros pasos sirven para obtener el archivo de resumen más reciente, verificar que lo ha recuperado de la ubicación original, verificar su firma digital y obtener la huella de la clave pública.

  1. Con S3 GetObjecto la clase AmazonS3Client (por ejemplo), obtenga el archivo de resumen más reciente de su bucket de Amazon S3 para el intervalo de tiempo que desee validar.

  2. Verifique que el bucket de S3 y el objeto de S3 utilizados para recuperar el archivo coinciden con las ubicaciones del objeto S3 y el bucket de S3 registradas en el propio archivo de resumen.

  3. A continuación, obtenga la firma digital del archivo de resumen desde la propiedad de metadatos x-amz-meta-signature del objeto del archivo de resumen en Amazon S3.

  4. En el archivo de resumen, obtenga la huella de la clave pública cuya clave privada se ha utilizado para firmar el archivo de resumen en el campo digestPublicKeyFingerprint.

B. Recuperar la clave pública para validar el archivo de resumen

Para obtener la clave pública que valide el archivo de resumen, puede utilizar la API AWS CLI o la misma. CloudTrail En ambos casos, debe especificar un intervalo de tiempo (es decir, una hora de inicio y una de finalización) para los archivos de resumen que desea validar. Se podrían devolver una o varias claves públicas para el intervalo de tiempo que se especifique. Las claves devueltas pueden tener intervalos de tiempo de validez que se solapan.

nota

Como CloudTrail utiliza diferentes pares de claves públicas y privadas por región, cada archivo de resumen se firma con una clave privada exclusiva de su región. Por lo tanto, al validar un archivo de resumen desde una región determinada, debe recuperar su clave pública desde la misma región.

Utilícela AWS CLI para recuperar las claves públicas

Para recuperar las claves públicas de los archivos de resumen mediante el AWS CLI, utilice el cloudtrail list-public-keys comando. El comando tiene el siguiente formato:

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

Los parámetros de la hora de inicio y de finalización son marcas de tiempo UTC (opcionales). Si no se especifica, se utiliza la hora actual y se devuelven las claves públicas que actualmente están activas.

Respuesta de ejemplo

La respuesta será una lista de objetos JSON que representan las claves devueltas:

{ "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" } ] }

Utilice la CloudTrail API para recuperar las claves públicas

Para recuperar las claves públicas de los archivos de resumen mediante la CloudTrail API, transfiere los valores de la hora de inicio y finalización a la ListPublicKeys API. La API ListPublicKeys devuelve las claves públicas cuyas claves privadas se han utilizado para firmar archivos de resumen en el intervalo de tiempo especificado. Para cada clave pública, la API también devuelve la huella correspondiente.

ListPublicKeys

En esta sección se describen los parámetros de solicitud y los elementos de respuesta de la API ListPublicKeys.

nota

La codificación de los campos binarios de ListPublicKeys está sujeta a cambios.

Parámetros de solicitud

Nombre Descripción
StartTime

Si lo desea, especifica, en UTC, el inicio del intervalo de tiempo para buscar las claves públicas de los archivos de CloudTrail resumen. Si no StartTime se especifica, se utiliza la hora actual y se devuelve la clave pública actual.

Tipo: DateTime

EndTime

Si lo desea, especifica, en UTC, el final del intervalo de tiempo para buscar las claves públicas de los archivos de CloudTrail resumen. Si no EndTime se especifica, se utiliza la hora actual.

Tipo: DateTime

Elementos de respuesta

PublicKeyList, una matriz de objetos PublicKey que contiene:

Nombre Descripción
Value

El valor de clave pública codificado de DER en formato PKCS # 1.

Tipo: Blob

ValidityStartTime

La hora de inicio de la validez de la clave pública.

Tipo: DateTime

ValidityEndTime

La hora de finalización de la validez de la clave pública.

Tipo: DateTime

Fingerprint

La huella de la clave pública. La huella puede utilizarse para identificar la clave pública que debe usar para validar el archivo de resumen.

Tipo: cadena

C. Elegir la clave pública que va a utilizar para la validación

De entre las claves públicas recuperadas por list-public-keys o ListPublicKeys, elija la clave pública devuelta cuya huella coincida con la registrada en el campo digestPublicKeyFingerprint del archivo de resumen. Esta es la clave pública que utilizará para validar el archivo de resumen.

D. Volver a crear la cadena de la firma de datos

Ahora que ya tiene la firma del archivo de resumen y la clave pública asociada, debe calcular la cadena de firma de datos. Después de haber calculado la cadena de la firma de datos, tendrá las entradas necesarias para verificar la firma.

La cadena de firma de datos tiene el siguiente formato:

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

Este es un ejemplo de 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

Después de volver a crear esta cadena, puede validar el archivo de resumen.

E. Validar el archivo de resumen

Pase el hash SHA-256 de la cadena de firma de datos recreada, la firma digital y la clave pública al algoritmo de verificación de la firma RSA. Si el resultado es verdadero, la firma del archivo de resumen se verifica y el archivo de resumen es válido.

F. Validar los archivos de registros

Una vez que haya validado el archivo de resumen, puede validar los archivos de registro a los que hace referencia. El archivo de resumen contiene hashes SHA-256 de los archivos de registro. Si uno de los archivos de registro se modificó después de CloudTrail entregarlo, los hashes del SHA-256 cambiarán y la firma del archivo de resumen no coincidirá.

A continuación se muestra cómo validar los archivos de registro:

  1. Realice una operación S3 Get para el archivo de registro utilizando la información de la ubicación de S3 en los campos logFiles.s3Bucket y logFiles.s3Object del archivo de resumen.

  2. Si la operación S3 Get se realiza correctamente, itérela en los archivos de registro que se encuentran en la matriz logFiles del archivo de resumen mediante los siguientes pasos:

    1. Recupere el hash original del archivo desde el campo logFiles.hashValue del registro correspondiente en el archivo de resumen.

    2. Convierta en hash el contenido sin comprimir del archivo de registro con el algoritmo de hash especificado en logFiles.hashAlgorithm.

    3. Compare el valor de hash que ha generado con el valor para el registro en el archivo de resumen. Si los hash coinciden, el archivo de registro es válido.

G. Validar los archivos de registros y de resumen adicionales

En cada archivo de resumen, los siguientes campos proporcionan la ubicación y la firma del archivo de resumen anterior:

  • previousDigestS3Bucket

  • previousDigestS3Object

  • previousDigestSignature

Utilice esta información para visitar archivos de resumen anteriores de forma secuencial. Para ello, valide la firma de cada archivo de resumen y de los archivos de registro a los que hacen referencia mediante los pasos que se indican en las secciones anteriores. La única diferencia es que, para los archivos de resumen anteriores, no es necesario recuperar la firma digital de las propiedades de los metadatos de Amazon S3 del objeto del archivo de resumen. La firma del archivo de resumen anterior se proporciona automáticamente en el campo previousDigestSignature.

Puede retroceder hasta llegar al archivo de resumen de partida o hasta que la cadena de archivos de resumen se rompa, lo que ocurra primero.

Validación de archivos de registros y de resumen sin conexión

Cuando valida archivos de registro y de resumen sin conexión, generalmente puede seguir los procedimientos descritos en las secciones anteriores. No obstante, debe tener en cuenta lo siguiente:

Uso del archivo de resumen más reciente

La firma digital del archivo de resumen más reciente (es decir, “actual”) se encuentra en las propiedades de metadatos de Amazon S3 del objeto del archivo de resumen. En una situación sin conexión, la firma digital del archivo de resumen actual no estará disponible.

Hay dos maneras posibles de abordar esta situación:

  • Como la firma digital del archivo de resumen anterior se encuentra en el archivo de resumen actual, comience a validar desde el archivo de resumen. next-to-last Con este método, el archivo de resumen más reciente no se puede validar.

  • Como primer paso, obtenga la firma del archivo de resumen actual de las propiedades de metadatos del objeto del archivo de resumen y, a continuación, guárdelo de forma segura sin conexión. Esto permite que el archivo de resumen actual se valide junto con los archivos anteriores de la cadena.

Resolución de la ruta de acceso

Los campos de los archivos de resumen descargados, como s3Object y previousDigestS3Object, seguirán apuntando a ubicaciones de Amazon S3 en línea para archivos de registros y archivos de resumen. Las soluciones sin conexión deben encontrar una forma de volverlos a direccionar a la ruta actual de los archivos de registro y de resumen descargados.

Claves públicas

Para realizar la validación sin conexión, primero se deben obtener en línea todas las claves públicas que necesita para validar los archivos de registro en un intervalo de tiempo determinado (llamando a ListPublicKeys, por ejemplo) y, a continuación, guardarlos de forma segura sin conexión. Este paso debe repetirse siempre que desee validar más archivos fuera del intervalo de tiempo inicial especificado.

Fragmento de código de validación de ejemplo

El siguiente fragmento de ejemplo proporciona un código básico para validar los archivos de CloudTrail resumen y registro. El código básico no depende del estado en línea o sin conexión; es decir, el usuario es quien debe decidir si lo implementará en línea o sin conexión a AWS. La implementación sugerida utiliza Java Cryptography Extension (JCE) y Bouncy Castle como proveedor de seguridad.

En el fragmento de código de ejemplo, se muestra lo siguiente:

  • Cómo crear la cadena de firma de datos que se utiliza para validar la firma de archivos de resumen.

  • Cómo verificar la firma de archivos de resumen.

  • Cómo verificar los valores hash del archivo de registro.

  • Una estructura de código para validar una cadena de archivos de resumen.

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")); } } } }