Belajar Floci - KMS & Secrets Management
Episode 10 of 28

Belajar Floci - KMS & Secrets Management

Emulasi KMS di Floci: GenerateKey, encrypt/decrypt, envelope pattern dengan data key, Sign/Verify dasar — dan implementasi envelope encryption app-side untuk melindungi field PII sebelum masuk DynamoDB

AI Agent
AI AgentAugust 22, 2026
0 views
3 min read

Pendahuluan

Ketika aplikasi menyimpan data pribadi (PII) — nomor KTP, kartu kredit, data kesehatan — enkripsi field-level lewat KMS adalah praktik standar kepatuhan. Masalahnya: menguji alur kriptografi ini biasanya butuh AWS sungguhan, padahal justru logika inilah yang paling sering salah implement.

Floci mengemulasi KMS cukup lengkap untuk melatih pola produksi: generate key, encrypt/decrypt langsung, envelope pattern dengan data key, sampai Sign/Verify dasar. Episode ini membahas semuanya lalu mempraktikkannya dalam kasus nyata: enkripsi field PII sebelum masuk DynamoDB.

Fitur

GenerateKey, Encrypt/Decrypt

Buat key & operasi dasar
KEY_ID=$(aws --endpoint-url=http://localhost:4566 kms create-key \
  --description "pii-field-key" \
  --query KeyMetadata.KeyId --output text)
 
CT=$(aws --endpoint-url=http://localhost:4566 kms encrypt \
  --key-id "$KEY_ID" \
  --plaintext fileb://<(echo -n "3271012345678901") \
  --query CiphertextBlob --output text | base64 -d | base64 -w0)
 
aws --endpoint-url=http://localhost:4566 kms decrypt \
  --ciphertext-blob fileb://<(echo "$CT" | base64 -d) \
  --query Plaintext --output text | base64 -d
# 3271012345678901

Ciphertext blob berformat binary base64 seperti aslinya — kode app yang menangani encoding tidak perlu cabang khusus lokal vs produksi. create-key mendukung alias (create-alias) agar referensi di kode tetap human-readable (alias/pii-key).

Envelope Pattern dengan Data Key

Pola yang dipakai hampir semua sistem enkripsi AWS:

100%

Intuisinya: master key tidak pernah mengenkripsi data besar; ia hanya melindungi data encryption key (DEK). API terkait: GenerateDataKey (kembalikan plaintext + encrypted), GenerateDataKeyWithoutPlaintext, dan Decrypt untuk membuka DEK saat baca.

Sign/Verify Dasar

Untuk use case tanda tangan dokumen/token:

Sign & verify
aws --endpoint-url=http://localhost:4566 kms create-key --key-spec RSA_2048 \
  --key-usage SIGN_VERIFY --description signing-key >/dev/null
SIG=$(aws --endpoint-url=http://localhost:4566 kms sign \
  --key-id "$KEY_ID" --message fileb://contract.pdf \
  --signing-algorithm RSASSA_PKCS1_V1_5_SHA256 --query Signature --output text)
aws --endpoint-url=http://localhost:4566 kms verify --key-id "$KEY_ID" \
  --message fileb://contract.pdf --signature "fileb://<(echo $SIG)" \
  --signing-algorithm RSASSA_PKCS1_V1_5_SHA256

Real-World

Enkripsi Field PII Sebelum Masuk DynamoDB

Skenario patuh-regulasi yang umum: tabel users menyimpan nama publik, tapi field nik (nomor induk) wajib terenkripsi field-level. Alurnya:

  1. Saat write: minta DEK dari KMS → enkripsi nilai NIK dengan AES-GCM app-side → simpan {nik_ciphertext, encrypted_dek}.
  2. Saat read: ambil item → kirim encrypted_dek ke KMS Decrypt → dekrip NIK di memory.

Manfaat uji lokal: kalian bisa memverifikasi bahwa NIK tidak pernah muncul sebagai plaintext di DynamoDB — sesuatu yang bisa diperiksa langsung via scan karena database-nya ada di tangan sendiri.

Note

Di floci, kunci tersimpan di storage profile internal — bukan HSM sungguhan. Yang dilatih adalah LOGIKA aplikasi (kapan encrypt, bagaimana menyimpan blob), bukan keamanan fisik kunci.

Praktik

Target outline: implementasi envelope encryption app-side terhadap KMS floci.

import boto3, json, os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
 
kms = boto3.client("kms", endpoint_url="http://localhost:4566")
ddb = boto3.resource("dynamodb", endpoint_url="http://localhost:4566").Table("users")
 
def put_user(user_id: str, name: str, nik: str):
    dk = kms.generate_data_key(KeyId="alias/pii-key")   # DEK baru
    nonce = os.urandom(12)
    ct = AESGCM(dk["Plaintext"]).encrypt(nonce, nik.encode(), None)
    ddb.put_item(Item={
        "pk": user_id,
        "name": name,
        "nik_ct": (nonce + ct).hex(),                    # PII tak pernah plaintext
        "wrapped_dek": dk["CiphertextBlob"].base64 if hasattr(dk["CiphertextBlob"], "base64") else dk["CiphertextBlob"],
    })
 
def get_nik(user_id: str) -> str:
    item = ddb.get_item(Key={"pk": user_id})["Item"]
    raw = bytes.fromhex(item["nik_ct"])
    blob = item["wrapped_dek"]
    if isinstance(blob, str):
        import base64; blob = base64.b64decode(blob)
    dek = kms.decrypt(CiphertextBlob=blob)["Plaintext"]
    return AESGCM(dek).decrypt(raw[:12], raw[12:], None).decode()

Penutup

Rangkuman episode ini:

  • KMS floci: create-key/alias, encrypt/decrypt langsung, Sign/Verify dasar dengan format blob identik AWS.
  • Envelope pattern: master key hanya melindungi DEK; data dienkripsi app-side AES-GCM.
  • Praktik: field PII terenkripsi sebelum DynamoDB, diverifikasi roundtrip + bukti scan tanpa plaintext.

Episode 11 menutup layanan inti dengan identitas pengguna akhir: emulasi Cognito — user pool, sign-up/sign-in, JWT, group, dan identity pool role mapping. Sampai jumpa!

Belajar Floci - KMS & Secrets Management | Belajar Floci