Dołącz dane do obiektu S3

91

Powiedzmy, że mam maszynę, na której chcę mieć możliwość zapisu w określonym pliku dziennika przechowywanym w zasobniku S3.

Tak więc maszyna musi mieć możliwości zapisu w tym zasobniku, ale nie chcę, aby miała możliwość nadpisywania lub usuwania jakichkolwiek plików w tym zasobniku (w tym tego, w którym chcę zapisywać).

Zasadniczo chcę, aby mój komputer mógł tylko dołączać dane do tego pliku dziennika, bez nadpisywania go lub pobierania.

Czy istnieje sposób, aby skonfigurować mój S3, aby działał w ten sposób? Może jest jakaś zasada IAM, którą mogę do niej dołączyć, aby działała tak, jak chcę?

Teodor
źródło
Nie możesz modyfikować obiektów w S3. Czy mógłbyś po prostu dołączyć nowy plik dziennika? Byłby to lepszy model i obsługiwałby wielu jednoczesnych klientów.
jarmod
@jarmod Tak, myślałem o tym, ale problem polega na tym, że jeśli atakującemu uda się uzyskać dostęp do mojego serwera, będzie mógł usunąć zapisany na nim plik lokalny, zanim zostanie wysłany do wiadra S3 (co powiedzmy dzieje się pod koniec dnia).
Theodore
Możesz również rzucić okiem na dzienniki CloudWatch. Pozwól mu zarządzać złożonością gromadzenia i przechowywania dzienników, zapewnia funkcje wyszukiwania, zasady przechowywania i pozwala generować alerty na podstawie wskaźników, które możesz dostosować do swoich dzienników.
jarmod
1
Możesz też rzucić okiem na Google BigQuery. Możesz go użyć do rozwiązania swojego problemu.
Daniel777,

Odpowiedzi:

133

Niestety nie możesz.

S3 nie ma operacji „dołączania”. * Po przesłaniu obiektu nie ma możliwości modyfikacji go na miejscu; jedyną opcją jest przesłanie nowego obiektu, aby go zastąpić, który nie spełnia Twoich wymagań.

*: Tak, wiem, że ten post ma kilka lat. Jednak nadal jest dokładna.

duskwuff-nieaktywny-
źródło
Czy mogę wiedzieć, czy korzystając z przesyłania wieloczęściowego możemy to osiągnąć?
Anjali
1
Przesyłanie wieloczęściowe pozwoli ci przenieść dane do S3 bez pobierania oryginalnego obiektu, ale nie pozwoli ci nadpisać oryginalnego obiektu bezpośrednio. Zobacz np. Docs.aws.amazon.com/AmazonS3/latest/API/… Możesz wtedy usunąć stary obiekt / zmienić nazwę nowego. Jednak nie o to chodzi w pytaniu.
MikeGM
Myślę, że użycie przesyłania wieloczęściowego może faktycznie zadziałać. Wszystkie twoje części są sekwencyjnymi segmentami tego samego pliku. Jeśli załadowanie części powiedzie się, możesz ostatecznie zatwierdzić przesyłanie, aby móc odczytać plik. Tak więc, o ile nie musisz czytać zawartości pliku, możesz dołączyć do tego samego przesyłania wieloczęściowego.
cerebrotecnologico
@cerebrotecnologico Nadal nie sądzę, że spełnia wymagania PO. Nie ma sposobu, abym mógł ograniczyć użytkownika S3 do wykonywania przesyłania wieloczęściowego, które dołącza do obiektu - jeśli może wykonać przesyłanie wieloczęściowe, może przesłać dowolną zawartość.
duskwuff
16

Jak stwierdza przyjęta odpowiedź, nie możesz. Najlepszym znanym mi rozwiązaniem jest użycie:

AWS Kinesis Firehose

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

Ich przykładowy kod wygląda na skomplikowany, ale Twój może być naprawdę prosty. Wciąż wykonujesz operacje PUT (lub BATCH PUT) na strumieniu dostarczania Kinesis Firehose w swojej aplikacji (używając AWS SDK) i konfigurujesz strumień dostarczania Kinesis Firehose, aby wysyłać strumieniowane dane do wybranego przez Ciebie wiadra AWS S3 (w Konsola AWS Kinesis Firehose).

wprowadź opis obrazu tutaj

Nadal nie jest to tak wygodne, jak >>z wiersza poleceń Linuksa, ponieważ po utworzeniu pliku na S3 ponownie musisz poradzić sobie z pobieraniem, dołączaniem i przesyłaniem nowego pliku, ale musisz to zrobić tylko raz na partię wierszy, a niż dla każdego wiersza danych, więc nie musisz się martwić ogromnymi opłatami ze względu na liczbę operacji dołączania. Może da się to zrobić, ale nie widzę, jak to zrobić z konsoli.

Sridhar Sarnobat
źródło
8
Zwróć uwagę, że istnieje maksymalny czas (900 sekund od utworzenia pliku) lub maksymalny rozmiar (rozmiar pliku 128 MB) - co oznacza, że ​​Kinesis firehose będzie dołączać do tego samego pliku S3, dopóki nie osiągnie któregokolwiek z tych ograniczeń: docs.aws .amazon.com / firehose / latest / dev / create-configure.html
Yaron Budowski
Czy możesz użyć pojedynczego pliku S3 jako danych wyjściowych w wężu przeciwpożarowym? To brzmi trochę niechlujnie, gdy trzeba scalać wiele plików w wiadrze S3.
Jón Trausti Arason
1
Niestety nie. Żałuję, że nie ma lepszego rozwiązania.
Sridhar Sarnobat
Tak, to niefortunne. Najbardziej martwię się stanem wyścigu, jeśli ręcznie pobieram i dołączam rekordy do pojedynczego obiektu S3. Myślałem o dodaniu rekordów do SQS, a następnie użyciu logiki z SNS + Lambda do odpytywania SQS i zapisania nowych wpisów do obiektu S3.
Jón Trausti Arason
6

Obiekty na S3 nie mogą być dołączane. W tym przypadku masz 2 rozwiązania:

  1. skopiuj wszystkie dane S3 do nowego obiektu, dołącz nową zawartość i zapisz z powrotem do 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. Drugą opcją jest użycie Kinesis Firehose. Jest to dość proste. Musisz utworzyć strumień dostarczania węża strażackiego i połączyć miejsce docelowe z zasobnikiem S3. Otóż ​​to!
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
źródło
Czy możesz użyć pojedynczego pliku S3 jako wyjścia?
Jón Trausti Arason
1

Jak powiedzieli wcześniej inni, obiektów S3 nie można dołączać.
Jednak innym rozwiązaniem byłoby zapisanie w dziennikach CloudWatch, a następnie wyeksportowanie dzienników, które chcesz, do S3 . Uniemożliwiłoby to również atakującym, którzy uzyskują dostęp do twojego serwera, usunięciem z twojego wiadra S3, ponieważ Lambda nie wymagałaby żadnych uprawnień S3.

Leo Głowacki
źródło
1

W przypadku, gdy ktoś chce dołączyć dane do obiektu za pomocą usługi podobnej do S3, Alibaba Cloud OSS (Object Storage Service) obsługuje to natywnie .

OSS zapewnia przesyłanie przez dołączanie (przez AppendObject API), które umożliwia bezpośrednie dołączanie treści na końcu obiektu. Obiekty przesłane przy użyciu tej metody są obiektami, które można dołączyć, podczas gdy obiekty przesłane przy użyciu innych metod są zwykłymi obiektami. Załączone dane są natychmiast czytelne.

wanghq
źródło
-1

Miałem podobny problem io to właśnie prosiłem

jak dołączyć dane do pliku za pomocą AWS Lambda

Oto, co wymyśliłem, aby rozwiązać powyższy problem:

Użyj getObject, aby pobrać z istniejącego pliku

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

Funkcja zapisu do dołączenia do pliku

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

Mam nadzieję, że to pomoże!!

Neeraj Kumar
źródło
13
Twoja writeToS3funkcja nadpisze plik, a nie dołączy do niego.
duskwuff -inactive-
@ duskwuff-inactive- zgodził się, a także cierpi na warunki wyścigu, jeśli dwie metody próbują działać na tym samym obiekcie, ale tak naprawdę nie różni się to od języków, które mają niezmienne ciągi lub typy - symulujesz dołączanie, zwracając / nadpisując za pomocą nowy obiekt.
fatal_error