As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.
Implementações personalizadas da validação da integridade do arquivo de CloudTrail log
Como CloudTrail usa algoritmos criptográficos e funções de hash padrão do setor e disponíveis abertamente, você pode criar suas próprias ferramentas para validar a integridade dos arquivos de log. CloudTrail Quando a validação da integridade do arquivo de log está habilitada, CloudTrail entrega os arquivos de resumo para o seu bucket do Amazon S3. Você pode usar esses arquivos para implementar sua própria solução de validação. Para obter mais informações sobre os arquivos de resumo, consulte CloudTrail estrutura do arquivo digest.
Este tópico descreve como os arquivos de resumo são assinados e explica detalhadamente as etapas que você precisará seguir para implementar uma solução que valida os arquivos de resumo e os arquivos de log aos quais eles fazem referência.
Entendendo como os arquivos de CloudTrail resumo são assinados
CloudTrail os arquivos de resumo são assinados com assinaturas RSA digitais. Para cada arquivo de resumo, CloudTrail faça o seguinte:
-
Cria uma string para assinatura de dados com base em campos de arquivos de resumo designados (descritos na próxima seção).
-
Obtém uma chave privada exclusiva para a região.
-
Passa o hash SHA -256 da string e da chave privada para o algoritmo de RSA assinatura, que produz uma assinatura digital.
-
Codifica o código de byte da assinatura em formato hexadecimal.
-
Insere a assinatura digital na propriedade de metadados
x-amz-meta-signature
do objeto do arquivo de resumo do Amazon S3.
Conteúdo da string de assinatura de dados
Os seguintes CloudTrail objetos são incluídos na string para assinatura de dados:
-
O carimbo de data/hora final do arquivo de resumo em formato UTC estendido (por exemplo,)
2015-05-08T07:19:37Z
-
O caminho atual do arquivo de resumo do S3
-
O hash SHA -256 codificado em hexadecimal do arquivo de resumo atual
-
A assinatura com codificação hexadecimal do arquivo de resumo anterior
O formato para calcular essa string e uma string de exemplo são fornecidos posteriormente neste documento.
Etapas da implementação da validação personalizada
Ao implementar uma solução de validação personalizada, você precisará validar o arquivo de resumo primeiro e os arquivos de log aos quais ele faz referência.
Validar o arquivo de resumo
Para validar um arquivo de resumo, você precisa da assinatura dele, da chave pública cuja chave privada foi usada para assiná-lo e de uma string de assinatura de dados computada.
-
Obtenha o arquivo de resumo.
-
Verifique se o arquivo de resumo foi recuperado de seu local original.
-
Obtenha a assinatura com codificação hexadecimal do arquivo de resumo.
-
Obtenha a impressão digital com codificação hexadecimal da chave pública cuja chave privada foi usada para assinar o arquivo de resumo.
-
Recupere as chaves públicas do período correspondente ao arquivo de resumo.
-
Entre as chaves públicas recuperadas, escolha aquela cuja impressão digital corresponde à impressão digital do arquivo de resumo.
-
Usando o hash do arquivo de resumo e outros campos de arquivos de resumo, recrie a string de assinatura de dados usada para verificar a assinatura do arquivo de resumo.
-
Valide a assinatura passando o hash SHA -256 da string, da chave pública e da assinatura como parâmetros para o algoritmo de verificação de RSA assinatura. Se o resultado for verdadeiro, o arquivo de resumo será válido.
Validar os arquivos de log
Se o arquivo de resumo for válido, valide cada um dos arquivos de log aos quais o arquivo de resumo faz referência.
-
Para validar a integridade de um arquivo de log, calcule seu valor de hash SHA -256 em seu conteúdo não compactado e compare os resultados com o hash do arquivo de log gravado em hexadecimal no resumo. Se os hashes forem correspondentes, o arquivo de log será válido.
-
Com as informações sobre o arquivo de resumo anterior que está incluído no arquivo de resumo atual, valide os arquivos de resumo anteriores e seus arquivos de log correspondentes de maneira consecutiva.
As seções a seguir descrevem essas etapas em detalhes.
A. Obter o arquivo de resumo
As primeiras etapas são: obter o arquivo de resumo mais recente, verificar se você o recuperou do local original dele, verificar sua assinatura digital e obter a impressão digital da chave pública.
-
Usando a classe S3
GetObject
ou a classe AmazonS3Client (por exemplo), obtenha o arquivo de resumo mais recente do seu bucket do Amazon S3 para o intervalo de tempo que você deseja validar. -
Verifique se o bucket e o objeto do S3 usados para recuperar o arquivo correspondem aos locais do bucket e do objeto do S3 que são registrados no próprio arquivo de resumo.
-
Em seguida, obtenha a assinatura digital do arquivo de resumo da propriedade de metadados
x-amz-meta-signature
do objeto do arquivo de resumo no Amazon S3. -
No arquivo de resumo, obtenha a impressão digital da chave pública cuja chave privada foi usada para assinar o arquivo de resumo do campo
digestPublicKeyFingerprint
.
B. Recupere a chave pública para validar o arquivo de resumo
Para obter a chave pública para validar o arquivo de resumo, você pode usar o AWS CLI ou o. CloudTrail API Em ambos os casos, você especifica um período (ou seja, um horário de início e de término) para os arquivos de resumo que você deseja validar. Uma ou mais chaves públicas podem ser retornadas para o período que você especificar. As chaves retornadas podem ter períodos de validade que se sobrepõem.
nota
Como CloudTrail usa diferentes pares de chaves privadas/públicas por região, cada arquivo de resumo é assinado com uma chave privada exclusiva para sua região. Portanto, quando você valida um arquivo de resumo de uma região específica, precisa recuperar a chave pública da mesma região.
Use o AWS CLI para recuperar chaves públicas
Para recuperar chaves públicas para arquivos de resumo usando o AWS CLI, use o cloudtrail list-public-keys
comando. O comando tem o formato a seguir:
aws cloudtrail list-public-keys [--start-time <start-time>] [--end-time <end-time>]
Os parâmetros de hora de início e hora de término são registros de data e UTC hora e são opcionais. Se eles não forem especificados, a hora atual será usada, e a chave ou as chaves públicas atualmente ativas serão retornadas.
Exemplo de resposta
A resposta será uma lista de JSON objetos representando a chave (ou chaves) retornada:
{ "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" } ] }
Usar a CloudTrail API para recuperar chaves públicas
Para recuperar chaves públicas para arquivos de resumo usando o. CloudTrail API, transmita os valores de hora de início e hora de término para o. ListPublicKeys
API ListPublicKeys
APIRetorna as chaves públicas cujas chaves privadas foram usadas para assinar arquivos de resumo dentro do intervalo de tempo especificado. Para cada chave pública, o API também retorna a impressão digital correspondente.
ListPublicKeys
Esta seção descreve os parâmetros de solicitação e os elementos de resposta para ListPublicKeys
API o.
nota
A codificação dos campos binários de ListPublicKeys
está sujeita a alterações.
Parâmetros de solicitação
Nome | Descrição |
---|---|
StartTime
|
Opcionalmente, especifica, emUTC, o início do intervalo de tempo para pesquisar chaves públicas para arquivos de CloudTrail resumo. Se não StartTime for especificado, a hora atual será usada e a chave pública atual será retornada. Tipo: DateTime |
EndTime
|
Opcionalmente, especifica, emUTC, o final do intervalo de tempo para pesquisar chaves públicas para arquivos de CloudTrail resumo. Se não EndTime for especificado, a hora atual será usada. Tipo: DateTime |
Elementos de resposta
PublicKeyList
, um conjunto de PublicKey
objetos que contém:
Name (Nome) | Descrição |
Value
|
O valor da chave pública DER codificada no formato PKCS #1. Tipo: Blob |
ValidityStartTime
|
O horário de início da validade da chave pública. Tipo: DateTime |
ValidityEndTime
|
O horário de término da validade da chave pública. Tipo: DateTime |
Fingerprint
|
A impressão digital da chave pública. A impressão digital pode ser usada para identificar a chave pública que você precisa usar para validar o arquivo de resumo. Tipo: string |
C. Escolha a chave pública a ser usada para a validação
Entre as chaves públicas recuperadas por list-public-keys
ou ListPublicKeys
, escolha a chave retornada cuja impressão digital corresponde à impressão digital gravada no campo digestPublicKeyFingerprint
do arquivo de resumo. Esta é a chave pública que você usará para validar o arquivo de resumo.
D. Recrie a string de assinatura de dados
Agora que você tem a assinatura do arquivo de resumo e a chave pública associada, precisa calcular a string de assinatura de dados. Depois que você calcular a string de assinatura de dados, terá o necessário para verificar a assinatura.
A string de assinatura de dados tem o seguinte 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
Veja a seguir um exemplo de Data_To_Sign_String
.
2015-08-12T04:01:31Z amzn-s3-demo-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
Depois que você recriar essa string, poderá validar o arquivo de resumo.
E. Valide o arquivo de resumo
Passe o hash SHA -256 da sequência de assinatura de dados, da assinatura digital e da chave pública recriadas para o algoritmo de verificação de RSA assinatura. Se o resultado for verdadeiro, a assinatura do arquivo de resumo será verificada, e o arquivo de resumo será válido.
F. Valide os arquivos de log
Depois que você validar o arquivo de resumo, poderá validar os arquivos de log aos quais ele faz referência. O arquivo de resumo contém os SHA -256 hashes dos arquivos de log. Se um dos arquivos de log foi modificado após a CloudTrail entrega, os hashes SHA -256 serão alterados e a assinatura do arquivo de resumo não corresponderá.
Veja a seguir como validar os arquivos de log:
-
Faça um
S3 Get
do arquivo de log usando as informações de local do S3 nos camposlogFiles.s3Bucket
elogFiles.s3Object
do arquivo de resumo. -
Se a
S3 Get
operação for bem-sucedida, percorra os arquivos de log listados na logFiles matriz do arquivo de resumo usando as seguintes etapas:-
Recupere o hash original do arquivo no campo
logFiles.hashValue
do log correspondente no arquivo de resumo. -
Faça hash do conteúdo descompactado do arquivo de log com o algoritmo de hashing especificado em
logFiles.hashAlgorithm
. -
Compare o valor de hash que você gerou com o valor do log no arquivo de resumo. Se os hashes forem correspondentes, o arquivo de log será válido.
-
G. Valide arquivos de log e de compilação adicionais
Em cada arquivo de resumo, os campos a seguir fornecem o local e a assinatura do arquivo de resumo anterior:
-
previousDigestS3Bucket
-
previousDigestS3Object
-
previousDigestSignature
Use essas informações para acessar os arquivos de resumo anteriores em sequência, validando a assinatura de cada um deles e os arquivos de log aos quais eles fazem referência seguindo as etapas das seções anteriores. A única diferença é que, para os arquivos de resumo anteriores, você não precisa recuperar a assinatura digital das propriedades de metadados do Amazon S3 do objeto do arquivo de resumo. A assinatura do arquivo de resumo anterior é fornecida a você no campo previousDigestSignature
.
Você pode voltar até que o arquivo de resumo inicial seja atingido ou até que a cadeia de arquivos de resumo seja interrompida, o que ocorrer primeiro.
Validar arquivos de log e de resumo offline
Ao validar os arquivos de log e de compilação offline, você pode seguir os procedimentos descritos nas seções anteriores. No entanto, é necessário levar em conta as seguintes áreas:
Processar o arquivo de resumo mais recente
A assinatura digital do arquivo de resumo mais recente (ou seja, "atual") está nas propriedades de metadados do Amazon S3 do objeto do arquivo de resumo. Em um cenário offline, a assinatura digital do arquivo de resumo atual não é disponibilizada.
Veja a seguir duas possíveis maneiras de fazer isso:
-
Como a assinatura digital do arquivo de resumo anterior está no arquivo de resumo atual, comece a validar a partir do next-to-last arquivo de resumo. Com esse método, não é possível validar o arquivo de resumo mais recente.
-
Como etapa preliminar, obtenha a assinatura do arquivo de resumo atual das propriedades de metadados do objeto do arquivo de resumo e armazene-a offline com segurança. Isso permite que o arquivo de resumo atual seja validado, além dos arquivos anteriores da cadeia.
Resolução de caminho
Os campos nos arquivos de resumo obtidos por download, como s3Object
e previousDigestS3Object
, ainda apontarão para os locais online do Amazon S3 dos arquivos de log e de resumo. Uma solução offline precisa encontrar uma maneira de redirecioná-los para o caminho atual dos arquivos de log e de compilação baixados.
Chaves públicas
Para fazer a validação offline, todas as chaves públicas de que você precisa para validar os arquivos de log em um determinado período precisam primeiro ser obtidas online (ao chamar ListPublicKeys
, por exemplo) e, depois, armazenadas offline com segurança. Essa etapa precisará ser repetida sempre que você quiser validar arquivos adicionais fora do período inicial que especificou.
Exemplo de snippet de validação
O trecho de amostra a seguir fornece código básico para validar arquivos de CloudTrail resumo e log. O código esqueleto pode ser online ou offline, ou seja, você decide se o implementará com ou sem conectividade online na AWS. A implementação sugerida usa a Java Cryptography Extension (JCE)
O exemplo de snippet mostra:
-
Como criar a string de assinatura de dados usada para validar a assinatura do arquivo de resumo.
-
Como verificar a assinatura do arquivo de resumo.
-
Como verificar os hashes do arquivo de log.
-
Uma estrutura de código para validar uma cadeia de arquivos de resumo.
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")); } } } }