Anexar dados a um objeto S3

91

Digamos que eu tenha uma máquina que deseja que possa gravar em um determinado arquivo de log armazenado em um balde S3.

Portanto, a máquina precisa ter capacidade de gravação nesse intervalo, mas não quero que ela tenha a capacidade de sobrescrever ou excluir quaisquer arquivos nesse intervalo (incluindo aquele em que desejo gravar).

Então, basicamente, eu quero que minha máquina seja capaz de apenas anexar dados a esse arquivo de log, sem substituí-lo ou baixá-lo.

Existe uma maneira de configurar meu S3 para funcionar assim? Talvez haja alguma política IAM que eu possa anexar a ele para que funcione como eu desejo?

Theodore
fonte
Você não pode modificar objetos no S3. Você poderia apenas anexar um novo arquivo de log? Esse seria um modelo melhor e ofereceria suporte a vários clientes simultâneos.
jarmod
@jarmod Sim, eu pensei sobre isso, mas o problema é que se um invasor conseguir acessar meu servidor, ele terá a capacidade de excluir o arquivo local armazenado nele, antes de ser enviado para o balde S3 (digamos acontece no final do dia).
Theodore
Você também pode querer dar uma olhada nos logs do CloudWatch. Deixe que ele gerencie a complexidade de coletar e armazenar seus logs, fornecer recursos de pesquisa, políticas de retenção e permitir que você gere alertas com base em métricas que você pode personalizar para seus logs.
jarmod de
1
Você também pode dar uma olhada no Google BigQuery. Você pode usá-lo para resolver seu problema.
Daniel777,

Respostas:

133

Infelizmente, você não pode.

S3 não tem uma operação "anexar". * Uma vez que um objeto foi carregado, não há como modificá-lo no local; sua única opção é enviar um novo objeto para substituí-lo, o que não atende aos seus requisitos.

*: Sim, eu sei que este post tem alguns anos. Ainda é preciso, no entanto.

Crepúsculo-inativo-
fonte
Posso saber, usando o upload de várias partes, podemos conseguir isso?
Anjali
1
O Upload de várias partes permitirá que você coloque os dados no S3 sem baixar o objeto original, mas não permitirá que você sobrescreva o objeto original diretamente. Veja, por exemplo, docs.aws.amazon.com/AmazonS3/latest/API/… Você pode então deletar o objeto antigo / renomear o novo. Isso, entretanto, não é o que a pergunta está perguntando.
MikeGM
Acho que usar o Upload de várias partes pode realmente funcionar. Todas as suas peças são segmentos sequenciais do mesmo arquivo. Se o upload da parte for bem-sucedido, você pode eventualmente enviar o upload para poder ler o arquivo. Portanto, desde que você não precise ler o conteúdo do arquivo, você pode anexar usando o mesmo upload multiparte.
cerebrotecnologico de
@cerebrotecnologico Ainda acho que não atende aos requisitos do OP. Não tenho conhecimento de nenhuma maneira de restringir um usuário S3 a fazer uploads de várias partes que se anexam a um objeto - se eles podem fazer um upload de várias partes, eles podem fazer upload de qualquer conteúdo que quiserem.
crepúsculo-inativo-
16

Como afirma a resposta aceita, você não pode. A melhor solução que conheço é usar:

AWS Kinesis Firehose

https://aws.amazon.com/kinesis/firehose/

O exemplo de código deles parece complicado, mas o seu pode ser muito simples. Você continua realizando operações PUT (ou BATCH PUT) em um fluxo de entrega Kinesis Firehose em seu aplicativo (usando o AWS SDK) e configura o fluxo de entrega Kinesis Firehose para enviar seus dados transmitidos para um balde AWS S3 de sua escolha (no Console AWS Kinesis Firehose).

insira a descrição da imagem aqui

Ainda não é tão conveniente quanto >>na linha de comando do Linux, porque uma vez que você criou um arquivo no S3, você novamente tem que lidar com o download, anexar e enviar o novo arquivo, mas você só tem que fazer isso uma vez por lote de linhas. do que para cada linha de dados, então você não precisa se preocupar com cobranças enormes por causa do volume de operações de acréscimo. Talvez isso possa ser feito, mas não consigo ver como fazer no console.

Sridhar Sarnobat
fonte
8
Observe que há um tempo máximo (900 segundos desde a criação do arquivo) ou um tamanho máximo (tamanho do arquivo de 128 MB
Yaron Budowski
Você pode usar um único arquivo S3 como saída no Firehose? Parece um pouco confuso ter que mesclar vários arquivos em um balde S3.
Jón Trausti Arason
1
Infelizmente não. Eu também gostaria que houvesse uma solução melhor.
Sridhar Sarnobat
Sim, é lamentável. Estou mais preocupado com a condição de corrida se eu baixar e anexar manualmente os registros a um único objeto S3. Tenho pensado em adicionar os registros ao SQS e, em seguida, usar alguma lógica com SNS + Lambda para pesquisar o SQS e, em seguida, gravar as novas entradas no objeto S3.
Jón Trausti Arason
6

Os objetos no S3 não podem ser acrescentados. Você tem 2 soluções neste caso:

  1. copie todos os dados do S3 para um novo objeto, anexe o novo conteúdo e grave de volta no S3.
function writeToS3(input) {
    var content;
    var getParams = {
        Bucket: 'myBucket', 
        Key: "myKey"
    };

    s3.getObject(getParams, function(err, data) {
        if (err) console.log(err, err.stack);
        else {
            content = new Buffer(data.Body).toString("utf8");
            content = content + '\n' + new Date() + '\t' + input;
            var putParams = {
                Body: content,
                Bucket: 'myBucket', 
                Key: "myKey",
                ACL: "public-read"
             };

            s3.putObject(putParams, function(err, data) {
                if (err) console.log(err, err.stack); // an error occurred
                else     {
                    console.log(data);           // successful response
                }
             });
        }
    });  
}
  1. A segunda opção é usar Kinesis Firehose. Isso é bastante simples. Você precisa criar seu fluxo de entrega firehose e vincular o destino ao balde S3. É isso aí!
function writeToS3(input) {
    var content = "\n" + new Date() + "\t" + input;
    var params = {
      DeliveryStreamName: 'myDeliveryStream', /* required */
      Record: { /* required */
        Data: new Buffer(content) || 'STRING_VALUE' /* Strings will be Base-64 encoded on your behalf */ /* required */
      }
    };

    firehose.putRecord(params, function(err, data) {
      if (err) console.log(err, err.stack); // an error occurred
      else     console.log(data);           // successful response
    }); 
}
Bharthan
fonte
Você pode usar um único arquivo S3 como saída?
Jón Trausti Arason
1

Como outros afirmaram anteriormente, os objetos S3 não podem ser acrescentados.
No entanto, outra solução seria gravar nos logs do CloudWatch e, em seguida, exportar os logs que deseja para o S3 . Isso também evitaria que qualquer invasor que acessar seu servidor excluísse de seu bucket S3, uma vez que o Lambda não exigiria nenhuma permissão S3.

Leo Glowacki
fonte
1

Caso alguém queira anexar dados a um objeto com um serviço semelhante ao S3, o Alibaba Cloud OSS (Object Storage Service) oferece suporte nativo .

OSS fornece upload de acréscimo (por meio da API AppendObject), que permite anexar conteúdo diretamente ao final de um objeto. Objetos carregados usando este método são objetos anexáveis, enquanto objetos carregados usando outros métodos são objetos normais. Os dados anexados podem ser lidos instantaneamente.

wanghq
fonte
-1

Tive um problema semelhante e foi isso que perguntei

como anexar dados no arquivo usando AWS Lambda

Aqui está o que eu proponho para resolver o problema acima:

Use getObject para recuperar do arquivo existente

   s3.getObject(getParams, function(err, data) {
   if (err) console.log(err, err.stack); // an error occurred
   else{
       console.log(data);           // successful response
       var s3Projects = JSON.parse(data.Body);
       console.log('s3 data==>', s3Projects);
       if(s3Projects.length > 0) {
           projects = s3Projects;
       }   
   }
   projects.push(event);
   writeToS3(); // Calling function to append the data
});

Função de gravação para anexar ao arquivo

   function writeToS3() {
    var putParams = {
      Body: JSON.stringify(projects),
      Bucket: bucketPath, 
      Key: "projects.json",
      ACL: "public-read"
     };

    s3.putObject(putParams, function(err, data) {
       if (err) console.log(err, err.stack); // an error occurred
       else     console.log(data);           // successful response
        callback(null, 'Hello from Lambda');
     });
}

Espero esta ajuda !!

Neeraj Kumar
fonte
13
Sua writeToS3função substituirá um arquivo, não acrescentará a ele.
duskwuff -inactive-
@ Crepúsculo-inativo- concordado, e também sofre de condições de corrida se dois métodos tentarem trabalhar no mesmo objeto, mas isso não é realmente diferente de linguagens que têm strings ou tipos imutáveis ​​- você simula um append retornando / sobrescrevendo com um novo objeto.
fatal_error