Skip to content

S3 Health Check

By Romi Fadli, S.Kom. 12 min read Storage & Data
On this page
A terminal window listing passing checks, connected to a blue storage bucket with a padlock and a green storage bucket without one.

S3 Health Check adalah satu script Python yang membuktikan server storage kompatibel S3 sudah siap sebelum aplikasi mana pun diizinkan bergantung padanya. Ia tak sekadar bertanya apakah server menjawab; ia memakai server itu persis seperti client sungguhan — dengan kredensial yang sama dan lewat jenis tautan yang sama — lalu melaporkan, satu pemeriksaan demi satu pemeriksaan, apakah tiap bucket berperilaku sebagaimana mestinya.

Object storage menyimpan file sebagai objek di dalam bucket bernama, yang dijangkau lewat HTTP; Amazon S3 yang mendefinisikan antarmukanya, dan server seperti MinIO mengimplementasikannya untuk dipasang sendiri. Presigned URL adalah tautan sementara yang ditandatangani dengan kredensial storage, sehingga browser bisa mengunggah atau mengunduh satu objek tertentu tanpa pernah memegang kredensial itu. Kebanyakan kesalahan pada object storage terjadi di tautan-tautan itu, dan kebanyakan terjadi tanpa suara — itulah alasan tool ini ada.

Sekilas

BentukSatu script command-line
BahasaPython 3, dengan boto3 dan requests
StatusStabil, dipakai
Kode sumberPrivat
Apa tool ini, dibangun dengan apa, dan keadaannya.

Yang dikerjakannya

A. Terhubung lebih dulu, dan berhenti di situ bila gagal

Pemeriksaan pertama adalah terhubung dan login ke server. Bila gagal, tak ada pemeriksaan lain yang dijalankan: endpoint yang salah, persoalan sertifikat, atau key yang ditolak dilaporkan sekali dengan jelas, bukan sebagai rentetan kegagalan di setiap bucket yang menyembunyikan satu-satunya penyebab sebenarnya. Koneksinya diuji dengan mendaftar bucket, jadi jawaban pertama pun sudah membuktikan kredensialnya diterima.

B. Memakai tiap bucket seperti client memakainya

Setiap bucket di konfigurasi menyatakan apakah upload dan download butuh autentikasi, dan script mengikuti kedua flag itu persis. Bucket yang flag-nya tak ditulis dianggap privat. Bila autentikasi dibutuhkan, ia membuat presigned link lalu mengirim objek acak kecil lewat tautan itu; bila tidak, ia mengunggah atau mengunduh tanpa kredensial sama sekali. Sebelum semua itu ia bertanya ke server apakah bucket-nya ada dan boleh dipakai key tersebut, jadi bucket yang hilang disebut hilang, tak terkubur di bawah error upload, dan bucket yang tercantum di konfigurasi tapi tak dimiliki server langsung dilaporkan di awal. Sesudah itu ia memeriksa policy akses bucket yang sebenarnya secara tersendiri: bucket privat wajib menolak orang asing, dan bucket publik wajib melayaninya.

C. Membuktikan file besar selamat

File besar diunggah dalam beberapa part, dan server atau proxy di depannya yang salah menangani part itu biasanya melakukannya tanpa error. Objek uji bawaannya 16 MiB, cukup besar sehingga ujinya tak mungkin lolos tanpa part sungguhan. Script mengunggahnya dalam part-part, lalu membaca jumlah part dari jawaban server sendiri, dan memakai akhiran ETag bila server tak melaporkannya. Ukuran yang tersimpan diperiksa dengan bertanya sekali lagi tanpa nomor part, karena ukuran yang dilaporkan bersama nomor part hanyalah ukuran satu part itu. Sesudah itu objeknya diunduh dan MD5 byte-nya dibandingkan, karena ETag objek multipart bukan MD5 isinya. Kedua arah berjalan sebagai stream: upload dibangkitkan sambil dikirim dan download di-hash sambil tiba, jadi memory tetap datar walau ukurannya gigabyte. Run ini melaporkan lama upload dan throughput-nya, dan uji besar hanya jalan bila pemeriksaan kecil bucket itu lolos, supaya jalur dasar yang rusak tak tertutup oleh noise multipart.

D. Menguji batas proxy

Bila ukuran part disamakan dengan ukuran objek, upload dikirim sebagai satu request, bukan part-part, dan berubah menjadi uji langsung atas batas ukuran request di proxy. Ukuran part diperiksa sebelum apa pun dikirim: di bawah minimum 5 MiB, atau lebih dari 10.000 part, run berhenti dan menyarankan ukuran part terkecil yang bisa dipakai. Uji multipart dan uji satu-request memakai SDK storage terhadap endpoint di konfigurasi, bukan presigned link, karena upload multipart adalah tiga panggilan API berurutan yang tak bisa diwakili satu presigned link, sementara jalur presigned sudah diuji oleh file kecil.

E. Melapor dalam bentuk yang bisa dipakai orang maupun script

Ia mencetak satu baris per pemeriksaan, ringkasan per bucket yang mendaftar kegagalannya, dan status keseluruhan: HEALTHY bila semua bucket lolos, DEGRADED bila hanya sebagian, dan UNHEALTHY bila tak satu pun lolos atau server tak terjangkau. Semuanya diakhiri exit code. Pemeriksaan yang gagal diterjemahkan ke penyebabnya yang paling mungkin: 413 menunjuk ke batas ukuran request di proxy, part yang terlalu kecil menunjuk ke ukuran part, dan error sertifikat, timeout koneksi, serta timeout baca dibedakan satu sama lain. Orang membaca baris-barisnya; script deployment membaca exit code-nya dan berhenti sebelum aplikasi menyala di atas storage yang belum siap.

F. Membersihkan jejaknya sendiri

Setiap objek uji diberi nama berawalan tetap, timestamp, dan akhiran acak, lalu dihapus begitu pemeriksaannya selesai, juga ketika pemeriksaan sebelumnya gagal. Penghapusan itu sendiri dihitung sebagai pemeriksaan: objek yang tak bisa dihapus script menandai bucket-nya gagal. Bila satu run terputus, sisa-sisanya mudah ditemukan lewat awalan itu, jadi menjalankan tool ini terhadap server production tak meninggalkan jejak di bucket.

Cara saya memakainya

Tiga perintah mencakup hampir semua pemakaian: run penuh, run cepat tanpa uji file besar, dan run dengan objek uji yang jauh lebih besar ketika ada proxy yang dicurigai.

bash
python s3-tools.py --config=config.json
python s3-tools.py --config=config.json --skip-large
python s3-tools.py --config=config.json --large-size 1GiB --part-size 64MiB

Konfigurasi menyebut server, kredensial, alamat yang sebenarnya dipakai client, dan tiap bucket beserta kedua flag-nya. File aslinya menyimpan kredensial hidup dan tak pernah meninggalkan mesin; salinan berisi placeholder disimpan di samping script sebagai titik awal.

json
{
  "s3": {
    "endpoint": "https://s3.example.com",
    "region": "us-east-1",
    "addressing_style": "path",
    "verify_ssl": true,
    "access_key": "YOUR-ACCESS-KEY",
    "secret_key": "YOUR-SECRET-KEY"
  },
  "public_origin": "https://s3.example.com",
  "buckets": [
    { "name": "documents", "upload_auth": true, "download_auth": true },
    { "name": "assets",    "upload_auth": true, "download_auth": false }
  ]
}
OpsiBawaanEfek
--config FILEconfig.jsonfile konfigurasi yang dibaca
--large-size SIZE16MiBukuran objek uji multipart, mis. 512MB, 1GiB
--part-size SIZE5MiBukuran tiap part; 5 MiB adalah minimum protokol, dan ukuran objek penuh menghasilkan uji satu-request
--skip-largematilewati uji multipart untuk run cepat
--timeout SECONDS30batas waktu tiap operasi jaringan
--keep-artifactsmatisimpan objek uji untuk diperiksa
--verbosematicetak detail tambahan, dengan signature di URL disamarkan
Opsi command-line.

Exit code adalah bagian dari kontraknya: 0 bila semua pemeriksaan lolos, 1 bila setidaknya satu gagal, 2 bila konfigurasi atau nilai command-line tak sah atau library yang dibutuhkan belum terpasang — disertai perintah pemasangannya, bukan traceback — dan 130 bila run dihentikan. Berikut run sungguhan yang dipendekkan, terhadap server dengan satu bucket privat dan satu bucket publik, dengan nama host diganti; tool ini melapor dalam bahasa Indonesia:

bash
$ python s3-tools.py --config=config.json
=== Konektivitas ===
  [ OK ] Koneksi & autentikasi ke server — https://s3.example.com

=== Bucket: documents ===
  [ OK ] Upload via presigned URL — HTTP 200
  [ OK ] Integritas isi file (MD5) — cocok
  [ OK ] Verifikasi policy akses anonim — HTTP 403 — akses anonim ditolak, sesuai download_auth=true
  [ OK ] Multipart benar-benar terjadi — ETag …-4 → 4 part
  …
  STATUS: HEALTHY  (2/2 bucket sehat)

Keputusan rancangan

Ia menguji seperti client menguji, jadi lolosnya berarti sesuatu. Server yang menjawab koneksi baru membuktikan ada proses yang mendengarkan. Saya membuat script memakai presigned link di tempat client memakainya dan request anonim di tempat client melakukannya, lalu mengirim keduanya ke alamat publik yang sebenarnya dipakai client. Jadi lolos berarti tautan berfungsi bagi user sungguhan di alamat yang sebenarnya mereka pakai, bukan sekadar pintu belakang yang terbuka.

Ia menangkap kegagalan yang tak mengumumkan dirinya. HTTP 200 tak membuktikan byte-nya tiba utuh, jadi setiap unduhan dibandingkan lewat MD5. Flag bucket di konfigurasi tak membuktikan policy-nya yang sebenarnya, jadi policy diuji terpisah, dan perbedaan keduanya dilaporkan sebagai POLICY MISMATCH yang menyebut kedua sisi. Upload multipart yang berhasil tak membuktikan ia benar-benar dipecah, jadi tool membaca jumlah part dari ETag objeknya. Tanpa itu, masing-masing kegagalan baru muncul jauh belakangan, sebagai gambar yang rusak, atau lebih buruk lagi, sebagai file privat yang ternyata publik.

Ia gagal cepat, jadi bisa duduk di dalam otomasi. Client storage hanya diberi dua percobaan per operasi, bukan bawaannya yang banyak: health check yang diam-diam me-retry berulang-ulang justru menyembunyikan kelambatan yang semestinya ia laporkan. Ditambah berhenti di kegagalan konektivitas pertama dan exit code yang artinya tetap, deployment bisa menjalankannya sebagai gerbang dan bertindak atas jawabannya.

Ia aman dijalankan di mana saja, sesering apa pun. Objek uji membawa awalan yang mudah dikenali dan dihapus sesudah dipakai. Payload besar dibangkitkan sambil dikirim, bukan ditampung di memory, dan dibangkitkan dari seed, sehingga posisi yang sama selalu menghasilkan byte yang sama — penting karena SDK mengirim ulang satu part saat me-retry, dan byte ulangan yang berbeda akan menggagalkan checksum dengan alasan yang tak ada hubungannya dengan server. Stream yang dibangkitkan itu juga menjawab panggilan close yang dilakukan SDK pada upload satu-request, panggilan yang dulu pernah menghentikan run dengan error atribut. Di mode verbose, signature dan kredensial di URL disamarkan, jadi log satu run bisa dibagikan, dan baik konfigurasi asli maupun output yang disimpan dijauhkan dari version control, karena output-nya menyebut endpoint yang sebenarnya.

Setelan yang terlupa gagal ke arah aman, dan setelan yang salah gagal sejak awal. Bucket tanpa flag upload atau download diharapkan privat, jadi lupa menulis flag tak akan pernah membuat script menerima bucket publik sebagai benar. Konfigurasi divalidasi sebelum koneksi apa pun: flag harus boolean sungguhan, umur tautan tak boleh melewati tujuh hari yang diizinkan signature SigV4, gaya addressing harus yang dikenal, nama bucket tak boleh berulang, dan kredensial tak boleh kosong. Salah ketik pun berakhir dengan exit code 2, bukan muncul sebagai kegagalan uji yang menyesatkan. Endpoint-nya juga dinormalkan — skema yang hilang ditambahkan, dan port hanya disambung bila bukan port bawaan — supaya host yang ditandatangani SDK sama dengan host yang benar-benar dikirim.

Spesifikasi

MasukanKonfigurasi JSON: endpoint, region, gaya addressing, kredensial, alamat publik, umur tautan, dan bucket beserta flag upload dan download-nya
KeluaranSatu baris per pemeriksaan, ringkasan per bucket, status keseluruhan HEALTHY, DEGRADED, atau UNHEALTHY, throughput upload, dan exit code 0, 1, 2, atau 130
PemeriksaanKonektivitas, keberadaan dan akses bucket, upload dan download presigned maupun anonim, integritas MD5, policy akses anonim, upload multipart beserta jumlah part dan ukurannya, batas ukuran satu request, pembersihan
KonfigurasiSusunan bersarang atau susunan datar yang lebih lama; umur tautan diatur global atau per bucket, paling lama tujuh hari; ukuran dalam satuan desimal maupun biner seperti MB atau MiB; verifikasi TLS menyala kecuali sengaja dimatikan
KetergantunganPython 3, boto3, botocore, requests
KeamananObjek uji berawalan dihapus sesudah dipakai; bisa disimpan untuk diperiksa; rahasia disamarkan di keluaran verbose; tak mengubah bucket maupun policy
Bekerja denganServer apa pun yang kompatibel S3, seperti MinIO, termasuk yang berada di balik reverse proxy
Masukan, keluaran, dan jaminan tool ini.

Terkait

Cerita di balik pemeriksaan-pemeriksaan ini, dan alasan masing-masing ada.

Bentuknya mengikuti bentuk yang saya berikan pada setiap tool kecil: satu file, satu tugas, dan kontrak exit code di bagian atas.

Inilah jenis pemeriksaan kesiapan yang dijalankan prosedur rilis saya sebelum kode mulai bergantung pada layanan eksternal.

Template yang melahirkan bucket privat dan publik yang kesiapannya dibuktikan pemeriksaan ini.

Istilah

Presigned URL
Tautan sementara yang ditandatangani dengan kredensial storage, yang membolehkan satu upload atau download tertentu tanpa memberikan kredensial itu kepada client.
Upload multipart
Mengunggah objek besar sebagai beberapa part yang dikirim terpisah, lalu disatukan server menjadi satu objek.
ETag
Identifier yang dikembalikan server untuk objek yang tersimpan; untuk upload multipart ia diakhiri tanda hubung dan jumlah part-nya.
Checksum MD5
Sidik jari pendek dari isi file; dua salinan dengan checksum yang sama, untuk keperluan ini, dianggap identik.
Exit code
Angka yang dikembalikan program saat selesai, yang dibaca script lain untuk menentukan langkah berikutnya.

Technologies covered

  • Python
  • boto3
  • MinIO
  • S3

About the author

Photo of Romi Fadli

Romi Fadli, S.Kom.

Solution Architect · Backend Engineer · Embedded Systems

In my day job I work as a solution architect. I design the system, lead the team that builds it — quality assurance, backend developers, a UI developer, DevOps and DevSecOps — and write the most critical modules myself, such as a certificate authority, a long-term PDF signer, and the core API of a personnel system.

I work across the whole stack that a running system actually needs. On the hardware side that means PCB design, microcontrollers, and embedded firmware — including RISC-V boards running FreeRTOS and Embassy, speaking MQTT over mutually authenticated TLS on a microcontroller with 64 KB of SRAM.

Most of my day-to-day work is software: Rust backends and API modules built on Clean Architecture, an OAuth2/OpenID Connect authorization server written from scratch, PAdES document signing, and certificate authorities — root CAs, timestamping authorities, and OCSP responders. I also build the frontends that sit on top of them.

Running all of that means infrastructure: Docker Compose stacks, networking, Mikrotik and RADIUS, observability with OpenTelemetry, and a steady habit of writing command-line tools and utilities for Linux when the existing ones do not fit.

Share

Enjoyed this?

Get an email when a new article is published.

Referenced by

A purple root circle linked to a blue and an orange intermediate circle, which lead to a signed document with a green seal and to a clock.

Aurograf

DevOps

Platform tanda tangan digital Pemerintah Kota Tangerang Selatan: penanda tangan membuktikan identitasnya, menandatangani PDF hingga PAdES B-LTA dengan sertifikat dari otoritas milik platform sendiri, dan siapa pun bisa memverifikasinya — versi 2, yang saya rancang, bangun, dan operasikan.

10 min read Read more →
A browser window connected directly to a storage bucket by a thick green band, while an orange box with a key above them hands the browser a dashed link.

Service Rust kecil di antara aplikasi dan storage kompatibel S3: ia membagikan presigned link supaya browser berbicara langsung dengan storage, memberi tiap file siklus hidup, menyalin antar-bucket di sisi server, dan menjauhkan kredensial storage dari setiap aplikasi.

12 min read Read more →

Related Articles

A stack of Markdown documents and an orange arrow leading to a browser page with a side menu, a heading, paragraphs, a dark code panel, and a table of contents with its active entry highlighted

Satu script yang mengubah dokumentasi Markdown satu project menjadi situs statis yang terbuka dari folder tanpa server maupun internet: menu, daftar isi yang mengikuti pembaca, tabel yang tak pernah terpotong, kode dengan tombol salin, dan tautan yang tetap berfungsi.

7 min read Read more →
An old layout with a grey banner and a new structure with a green banner, each holding a blue database, a purple document store, and an orange telemetry store; three coloured paths pass through one export package marked with a green check

Empat perintah yang memindahkan stack dari layout lama ke struktur baru melintasi versi mayor: export tanpa mengubah data sumber, import tiap store sesuai cara yang diizinkan versinya, verifikasi apa yang benar-benar tiba, dan rename modul sambil memindahkan datanya.

11 min read Read more →
Three image layer stacks, each with a version tag of its own colour, blue, orange, and green, each leading to an archive file banded in the same colour

Perintah yang memberi versi tersendiri pada tiap modul stack, mem-build image-nya di bawah tag yang berarti tepat satu build, menolak memakai ulang versi atau menelan compile yang gagal, dan mengarsipkan image menurut nama dan tag supaya versi tak saling menimpa.

7 min read Read more →