Skip to content

Key Rotation Tool

By Romi Fadli, S.Kom. 8 min read Security & Secrets
On this page
Four identical grey keys on the left each become a key of its own colour on the right, every new key marked with a green check; below, a purple key stays behind a red bar

Key Rotation Tool adalah satu perintah yang mengganti kredensial internal satu environment, kunci demi kunci, dan membuktikan setiap kredensial baru bekerja sebelum beralih ke kunci berikutnya. Secara default ia hanya memperlihatkan rencananya; begitu benar-benar dijalankan, ia membuat backup lebih dulu, memberi tiap kunci nilai tersendiri, dan mengembalikan kunci yang tak bisa dibuktikan ke keadaan semula.

Merotasi password tampak seperti menyunting file konfigurasi. Untuk database, object storage, atau mesin pencari, kenyataannya tidak begitu, karena password sesungguhnya tinggal di dalam datanya, dan file itu hanya berarti pada hari data directory-nya masih kosong.

Sekilas

BentukScript command-line
BahasaBash dengan Python tertanam untuk konfigurasi JSON, yang mengendalikan Docker dan openssl
StatusStabil, berjalan di production
Kode sumberPrivat
Apa tool ini, dibangun dengan apa, dan keadaannya.

Yang dikerjakannya

A. Merotasi kredensial internal, masing-masing ke nilainya sendiri

Cakupannya setiap kredensial internal stack: database, cache, object storage, dan mesin pencari. Setiap kunci menerima nilai acak baru miliknya sendiri, jadi rotasi sekaligus mengakhiri password yang dulu dipakai bersama oleh beberapa service. Nilainya dibuat dalam bentuk yang tak butuh escaping di URL, file environment, maupun shell. Kelompok-kelompok itu bisa dirotasi bersamaan atau satu per satu.

B. Membuktikan setiap kredensial baru sebelum melanjutkan

Urutan tiap kelompok tetap: ubah kredensial di tempat ia sungguh tinggal, tulis ke file milik pemiliknya dan setiap konsumennya, buat ulang container-nya, lalu sambungkan dengan kredensial baru. Setiap file disalin sebelum ditulis, dan salinannya dipulihkan bila gagal atau dibuang bila berhasil. Login database dilakukan persis seperti client sungguhan melakukannya, jadi password yang salah tak bisa lolos secara kebetulan. Di mesin pencari, superuser diganti paling akhir, karena ia yang mengautentikasi setiap perubahan lainnya. Kelompok yang container-nya tak berjalan dilewati, bukan digagalkan. Bila sambungan dengan kredensial baru gagal, password lama dipasang kembali, file-nya dipulihkan, dan service dinyalakan ulang dengan nilai lamanya. Satu kelompok yang gagal tak menghentikan yang lain; ringkasan akhir mendaftar mana yang berhasil, gagal, dan dilewati.

C. Backup lebih dulu, dengan mode aman yang paling hemat

Sebelum mengubah apa pun, ia menjalankan toolkit backup, dan backup yang gagal membatalkan rotasi. Ia memilih backup full bila belum ada satu pun, bila yang terakhir sudah melewati ambang umur, atau bila umurnya tak terbaca, dan incremental bila tidak, lalu mencetak alasan pilihannya. Backup bisa dilewati dengan flag berlabel tidak disarankan, untuk hari ketika sistem backup itu sendiri yang rusak.

D. Memperlihatkan rencana tanpa memperlihatkan rahasia

Tanpa --apply tak ada yang berubah; perintah ini mencetak mode backup yang akan dipakai beserta alasannya, dan tiap kelompok dengan hash pendek dari nilai lama dan barunya. Rahasia tak pernah muncul di output maupun log milik tool ini, tapi dua run tetap bisa dibandingkan.

Cara saya memakainya

bash
rotate-keys                          # dry run: the plan only
rotate-keys --apply                  # back up, then rotate everything
rotate-keys --apply --only storage   # one group
rotate-keys --list                   # available groups
StoreTempat perubahan dilakukanCara membuktikannya
PostgreSQLALTER USER di dalam databasequery yang login dengan password baru
Rediskonfigurasinya, berlaku saat restartPING yang terautentikasi
Object storagekredensial root-nya, berlaku saat restartmendaftar bucket dengan key baru, sebelum konsumennya di-restart
Mesin pencarisecurity API-nya, per user, superuser paling akhirrequest terautentikasi dengan password baru superuser
Kunci enkripsi bersamakedua service sekaliguskedua container kembali berjalan
Cara tiap jenis kredensial diubah dan dibuktikan.
Exit codeArti
0setiap kelompok yang dijalankan sudah dirotasi dan terbukti, atau memang tak ada yang diminta berjalan
1backup gagal dan tak ada yang dirotasi, setidaknya satu kelompok gagal dan sudah dikembalikan, atau folder environment-nya tak ada
2argumen tak dikenal
Cara perintah ini melaporkan hasilnya.

Keputusan rancangan

Dry run adalah default, dan backup selalu didahulukan. Menyentuh kredensial production tanpa sengaja harus mustahil, jadi perintah ini tak melakukan apa pun sampai disuruh. Rotasi yang berhasil pun masih bisa membuat service tak sanggup membaca apa yang pernah ditulisnya, jadi ia tak pernah mulai tanpa backup segar kecuali sengaja saya lewati. Mode backup-nya dipilih, bukan dipatok: ketika setiap rotasi memaksa backup full, dua run berjarak 38 menit menghasilkan dua salinan full yang nyaris identik, masing-masing sekitar 294 MB, dan dengan retensi yang tetap keduanya mendorong keluar titik pemulihan yang lebih lama. Run incremental atas data yang sama hanya 66 MB, dan ia ter-restore sebagai rantai satu full dan satu incremental dengan setiap tabel utuh. Operasi yang dimaksudkan untuk melindungi data ternyata mengikis riwayatnya.

Ia bekerja dari daftar putih, tak pernah dengan mencari nilai lama. Dua secret yang tak berhubungan bisa saja bernilai sama, jadi rotasi yang mencari nilai lama lalu menggantinya bisa merusak integrasi yang sama sekali tak ingin disentuhnya. Karena itu perintah ini hanya menyentuh kunci yang ia sebut, di file yang ia sebut, dan memberi masing-masing nilai berbeda, sehingga pemakaian bersama berakhir untuk selamanya. Password yang tersimpan di dalam URL koneksi ter-URL-encode, jadi pencarian biasa bahkan tak akan menemukannya; tool ini membongkar URL-nya, mengganti field password, lalu menyusunnya kembali, termasuk URL yang bersarang jauh di dalam file JSON.

Kredensial baru dianggap terotasi hanya bila sudah ada yang login dengannya. Exit code nol dari perintah yang mengubahnya tak membuktikan apa pun. Satu-satunya pengecualian adalah kunci enkripsi bersama, yang tak dipakai untuk login; di sana buktinya adalah kedua service menyala lagi. Container dibuat ulang, bukan sekadar di-restart, karena service yang konfigurasinya di-mount dari host akan tetap berjalan dengan connection pool berpassword lama, lalu melaporkan database-nya mati padahal file-nya tampak benar. Konsumen object storage baru di-restart sesudah key barunya terbukti, jadi percobaan yang gagal tak pernah meninggalkan mereka memegang key yang ditolak storage. Setiap kelompok berdiri sendiri: yang gagal dikembalikan ke password dan file lamanya, dan sisanya terus berjalan.

Mengetahui apa yang tak boleh dirotasi adalah bagian dari tool ini. Beberapa rahasia tak bisa diganti dengan nilai acak tanpa akibat yang melampaui sekadar restart, jadi setiap keputusan semacam itu membawa alasannya di dalam kode, dan tak ada yang mengubahnya tanpa memahami harganya. Kunci enkripsi bersama hanya dirotasi bila tak ada job di antrean yang masih memegang nilai terenkripsi dengan kunci lama; bila masih ada, ia dilewati dan disebut namanya, untuk dijalankan ulang begitu antreannya kosong.

Baca dan tulis kecil dikerjakan hati-hati, karena satu kesalahan saja tak bersuara. Nilai dibaca dengan carriage return dan tanda kutip di sekelilingnya dibuang. Satu kunci ditulis ulang sendirian, di tempatnya, jadi file-nya tetap mempertahankan pemilik dan mode-nya, dan filter yang tak menemukan apa pun tak lagi menghentikan run di bawah penanganan error yang ketat, seperti yang dulu pernah terjadi tanpa sepatah kata. Daftar kelompok disimpan di variable yang tak bertabrakan dengan variable read-only bawaan shell, setelah daftar itu pernah mencetak user id, bukan nama-nama kelompok.

Spesifikasi

MasukanNama environment (default production); opsional kelompok tertentu, backup full yang dipaksa, backup yang dilewati, atau ambang umur backup full yang berbeda, yang juga bisa diatur dari environment
KeluaranKredensial baru yang diterapkan di tiap store dan di konfigurasi setiap konsumennya, serta ringkasan apa yang berhasil, gagal, atau dilewati
KeamananDry run sebagai default; backup sebelum rotasi; daftar putih kunci dan file; verifikasi dan rollback per kelompok; rahasia hanya tampil sebagai hash pendek
DowntimeRestart singkat tiap service yang kredensialnya berubah
PrasyaratDocker, openssl, dan Python 3 di host; toolkit backup, yang menulis ke path backup yang disusun dari nama project; akses jaringan untuk menarik image client storage
Masukan, keluaran, dan jaminan tool ini.

Terkait

Cerita tentang merotasi setiap kredensial internal tanpa merusak satu service pun.

Toolkit yang membuat backup di awal setiap rotasi.

Prosedur rilis yang menjaga production tetap berubah dengan aman; rotasi berjalan di sampingnya dengan jadwalnya sendiri.

Script ini mengikuti bentuk yang saya berikan pada setiap tool kecil, dalam varian Bash-nya.

Kenapa rotasi tak pernah dimulai tanpa titik segar untuk kembali.

Kenapa user telemetry punya password sendiri, yang ikut dirotasi bersama yang lain.

Istilah

Rotasi kredensial
Mengganti password atau key dengan nilai baru secara terjadwal, supaya nilai lama yang bocor tak lagi berguna.
Dry run
Menjalankan perintah supaya ia melaporkan apa yang akan berubah tanpa mengubah apa pun.
Daftar putih
Daftar eksplisit tentang apa yang boleh disentuh; yang tak tercantum dibiarkan.
Rollback
Mengembalikan perubahan ke keadaan sebelumnya ketika ia tak bisa dituntaskan atau dibuktikan.
Fingerprint
Hash pendek dari satu nilai, cukup untuk membedakan dua nilai tanpa membuka isi keduanya.

Technologies covered

  • Bash
  • Elasticsearch
  • PostgreSQL
  • Redis
  • Docker
  • MinIO

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 →

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 →