Agregar datos a un objeto S3

91

Digamos que tengo una máquina que quiero poder escribir en un determinado archivo de registro almacenado en un bucket de S3.

Entonces, la máquina necesita tener habilidades de escritura en ese depósito, pero no quiero que tenga la capacidad de sobrescribir o eliminar ningún archivo en ese depósito (incluido el que quiero que escriba).

Entonces, básicamente, quiero que mi máquina solo pueda agregar datos a ese archivo de registro, sin anularlo ni descargarlo.

¿Hay alguna forma de configurar mi S3 para que funcione así? Tal vez haya alguna política de IAM que pueda adjuntar para que funcione como quiero.

Theodore
fuente
No puede modificar objetos en S3. ¿Podría agregar un nuevo archivo de registro? Ese sería un modelo mejor y admitiría múltiples clientes simultáneos.
jarmod
@jarmod Sí, pensé en eso, pero el problema es que si un atacante logra acceder a mi servidor, tendrá la capacidad de eliminar el archivo local almacenado en él, antes de que se envíe al bucket de S3 (que digamos sucede al final del día).
Theodore
Es posible que también desee echar un vistazo a los registros de CloudWatch. Deje que administre la complejidad de recopilar y almacenar sus registros, proporcione servicios de búsqueda, políticas de retención y le permita generar alertas basadas en métricas que puede personalizar para sus registros.
jarmod
1
También puede echar un vistazo a Google BigQuery. Puedes usarlo para resolver tu problema.
Daniel777

Respuestas:

133

Desafortunadamente, no puedes.

S3 no tiene una operación de "agregar". * Una vez que se ha cargado un objeto, no hay forma de modificarlo en su lugar; su única opción es cargar un nuevo objeto para reemplazarlo, que no cumple con sus requisitos.

*: Sí, sé que esta publicación tiene un par de años. Sin embargo, sigue siendo exacto.

anochecer-inactivo-
fuente
¿Puedo saber si podemos lograr esto al usar la carga multiparte?
Anjali
1
La carga multiparte le permitirá obtener los datos en S3 sin descargar el objeto original, pero no le permitirá sobrescribir el objeto original directamente. Consulte, por ejemplo, docs.aws.amazon.com/AmazonS3/latest/API/… A continuación, puede eliminar el objeto antiguo o cambiar el nombre del nuevo. Sin embargo, esto no es lo que plantea la pregunta.
MikeGM
Creo que el uso de Multipart Upload puede funcionar. Todas sus partes son segmentos secuenciales del mismo archivo. Si la parte se carga correctamente, eventualmente podría confirmar la carga para poder leer el archivo. Por lo tanto, siempre que no necesite leer el contenido del archivo, podría agregar el uso de la misma carga de varias partes.
cerebrotecnologico
@cerebrotecnologico Todavía no creo que cumpla con los requisitos del OP. No conozco ninguna forma de restringir a un usuario de S3 para que realice cargas de varias partes que se adjuntan a un objeto; si pueden realizar una carga de varias partes, pueden cargar cualquier contenido que deseen.
anochecer-inactivo-
16

Como dice la respuesta aceptada, no puede. La mejor solución que conozco es usar:

AWS Kinesis Firehose

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

Su ejemplo de código parece complicado, pero el tuyo puede ser realmente simple. Continúa realizando operaciones PUT (o BATCH PUT) en un flujo de entrega de Kinesis Firehose en su aplicación (utilizando el AWS SDK) y configura el flujo de entrega de Kinesis Firehose para enviar sus datos transmitidos a un bucket de AWS S3 de su elección (en el Consola de AWS Kinesis Firehose).

ingrese la descripción de la imagen aquí

Todavía no es tan conveniente como >>desde la línea de comandos de Linux, porque una vez que haya creado un archivo en S3, nuevamente tendrá que lidiar con descargar, agregar y cargar el nuevo archivo, pero solo tiene que hacerlo una vez por lote de líneas. que por cada línea de datos, por lo que no necesita preocuparse por los enormes cargos debido al volumen de operaciones de adición. Tal vez se pueda hacer, pero no veo cómo hacerlo desde la consola.

Sridhar Sarnobat
fuente
8
Tenga en cuenta que hay un tiempo máximo (900 segundos desde la creación del archivo) o un tamaño máximo (tamaño de archivo de 128 MB
Yaron Budowski
¿Puede usar un solo archivo S3 como salida en Firehose? Suena un poco complicado tener que fusionar varios archivos en un bucket de S3.
Jón Trausti Arason
1
Lamentablemente no. Yo también desearía que hubiera una solución mejor.
Sridhar Sarnobat
Sí, es lamentable. Lo que más me preocupa es la condición de carrera si descargo y añado registros manualmente a un solo objeto S3. He estado pensando en agregar los registros a SQS y luego usar algo de lógica con SNS + Lambda para sondear el SQS y luego escribir las nuevas entradas en el objeto S3.
Jón Trausti Arason
6

Los objetos en S3 no se pueden agregar. Tienes 2 soluciones en este caso:

  1. copie todos los datos de S3 en un nuevo objeto, agregue el nuevo contenido y vuelva a escribir en 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. La segunda opción es utilizar Kinesis Firehose. Esto es bastante sencillo. Debe crear su flujo de entrega de manguera de incendios y vincular el destino al depósito S3. ¡Eso es!
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
fuente
¿Puede utilizar un solo archivo S3 como salida?
Jón Trausti Arason
1

Como otros han dicho anteriormente, los objetos S3 no se pueden adjuntar.
Sin embargo, otra solución sería escribir en los registros de CloudWatch y luego exportar los registros que desee a S3 . Esto también evitaría que los atacantes que accedan a su servidor eliminen de su bucket de S3, ya que Lambda no requeriría ningún permiso de S3.

Leo Glowacki
fuente
1

En caso de que alguien quiera agregar datos a un objeto con un servicio similar a S3, Alibaba Cloud OSS (Object Storage Service) lo admite de forma nativa .

OSS permite agregar contenido (a través de la API AppendObject), lo que le permite agregar contenido directamente al final de un objeto. Los objetos cargados mediante este método son objetos que se pueden agregar, mientras que los objetos cargados mediante otros métodos son objetos normales. Los datos adjuntos se pueden leer al instante.

wanghq
fuente
-1

Tuve un problema similar y esto es lo que había preguntado

cómo agregar datos en un archivo usando AWS Lambda

Esto es lo que se me ocurre para resolver el problema anterior:

Utilice getObject para recuperar del archivo 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
});

Escribir función para agregar en el archivo

   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 que esto ayude!!

Neeraj Kumar
fuente
13
Su writeToS3función sobrescribirá un archivo, no lo agregará.
anochecer-inactivo-
@ Sunsetwuff-inactive- estuvo de acuerdo, y también sufre de condiciones de carrera si dos métodos intentan trabajar en el mismo objeto, pero esto no es realmente diferente de los lenguajes que tienen cadenas o tipos inmutables: usted simula un anexo devolviendo / sobrescribiendo con un nuevo objeto.
fatal_error