Menggunakan Environment Variables di Lambda: Konfigurasi dan Enkripsi KMS
Saat pertama kali deploy Lambda yang perlu terhubung ke RDS, godaan terbesar adalah hardcode endpoint database langsung di kode — cepat, tapi berbahaya. Setiap rotasi endpoint, setiap perpindahan environment dari staging ke production, memaksa kamu ubah kode dan redeploy. Lambda Environment Variables hadir untuk memisahkan konfigurasi dari kode, dan dengan integrasi KMS, nilai sensitif seperti connection string bisa dienkripsi saat istirahat.
TL;DR: Lambda Environment Variables dan Enkripsi KMS
| Aspek | Detail |
|---|---|
| Cara set variable | Console, CLI (--environment), atau IaC (SAM/CDK/Terraform) |
| Enkripsi default | AWS mengelola enkripsi at-rest menggunakan kunci terkelola Lambda (aws/lambda) |
| Enkripsi dengan CMK | Bisa menggunakan Customer Managed Key (CMK) KMS — membutuhkan izin IAM tambahan |
| Akses di runtime | process.env.VAR_NAME (Node.js), os.environ['VAR_NAME'] (Python) |
| Batas ukuran | Total semua environment variables maksimal 4 KB |
| Enkripsi transit | Helper enkripsi di console menggunakan KMS untuk enkripsi sebelum deployment |
Bagaimana Lambda Environment Variables Bekerja
Environment variables di Lambda disimpan sebagai bagian dari konfigurasi fungsi, bukan di dalam deployment package. Saat Lambda service membuat execution environment baru (cold start), variabel-variabel ini di-inject ke dalam proses sebelum handler kamu dipanggil. Artinya, kamu bisa baca nilainya kapan saja selama lifecycle fungsi — termasuk di initialization code di luar handler.
Enkripsi bekerja di dua lapisan yang sering disalahpahami:
- Encryption at rest: Secara default, Lambda mengenkripsi environment variables menggunakan kunci terkelola AWS (
aws/lambda). Kamu bisa mengganti ini dengan CMK milikmu sendiri. - Encryption in transit (helper enkripsi): Fitur 'Encrypt in transit' di console memungkinkan kamu mengenkripsi nilai menggunakan KMS sebelum dikirim ke Lambda — sehingga nilai tidak pernah muncul sebagai plaintext di konfigurasi fungsi. Ini membutuhkan kode tambahan di Lambda untuk memanggil KMS Decrypt saat runtime.
- Konfigurasi fungsi menyimpan environment variables dalam keadaan terenkripsi menggunakan kunci KMS yang dipilih.
- Saat cold start, Lambda service mendekripsi nilai dan meng-inject-nya ke execution environment sebagai variabel lingkungan OS biasa.
- Handler code membaca nilai via
os.environatauprocess.env— sudah dalam bentuk plaintext di memori. - Jika menggunakan helper enkripsi, nilai tetap terenkripsi di memori sampai kode Lambda secara eksplisit memanggil KMS Decrypt.
Menyetel Environment Variables via AWS CLI
Cara paling reproducible untuk mengelola environment variables adalah lewat CLI atau IaC — bukan console — supaya konfigurasi bisa di-version control dan diaudit.
Saat membuat fungsi baru
aws lambda create-function \
--function-name my-db-function \
--runtime python3.12 \
--role arn:aws:iam::123456789012:role/my-lambda-role \
--handler app.handler \
--zip-file fileb://function.zip \
--environment 'Variables={DB_ENDPOINT=mydb.cluster-xxxx.us-east-1.rds.amazonaws.com,DB_PORT=5432,DB_NAME=appdb}'
Update environment variables pada fungsi yang sudah ada
Perlu diingat: update-function-configuration dengan flag --environment akan mengganti seluruh set environment variables, bukan menambahkan. Jika kamu hanya ingin mengubah satu variabel, kamu harus menyertakan semua variabel yang ada.
aws lambda update-function-configuration \
--function-name my-db-function \
--environment 'Variables={DB_ENDPOINT=mydb-new.cluster-yyyy.us-east-1.rds.amazonaws.com,DB_PORT=5432,DB_NAME=appdb}'
Membaca konfigurasi yang ada (untuk tidak kehilangan variabel lain)
aws lambda get-function-configuration \
--function-name my-db-function \
--query 'Environment.Variables'
Mengenkripsi Environment Variables dengan KMS CMK
Default encryption menggunakan aws/lambda sudah cukup untuk banyak kasus, tapi jika kamu perlu kontrol penuh atas key rotation, key policy, dan audit trail per-key, gunakan Customer Managed Key (CMK).
Langkah 1: Buat atau identifikasi CMK
aws kms create-key \
--description 'CMK untuk Lambda environment variables' \
--key-usage ENCRYPT_DECRYPT \
--origin AWS_KMS
Catat KeyId atau ARN dari output. Buat alias agar mudah direferensikan:
aws kms create-alias \
--alias-name alias/lambda-env-key \
--target-key-id <KeyId-dari-output-sebelumnya>
Langkah 2: Berikan izin ke Lambda execution role
Lambda execution role membutuhkan izin kms:Decrypt untuk mendekripsi environment variables saat runtime. Tanpa ini, fungsi akan gagal saat cold start dengan error terkait KMS.
🔽 Klik untuk lihat IAM policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowLambdaDecryptEnvVars",
"Effect": "Allow",
"Action": [
"kms:Decrypt"
],
"Resource": "arn:aws:kms:us-east-1:123456789012:key/<your-key-id>"
}
]
}
Attach policy ke execution role:
aws iam put-role-policy \
--role-name my-lambda-role \
--policy-name LambdaKMSDecryptPolicy \
--policy-document file://kms-decrypt-policy.json
Langkah 3: Set fungsi Lambda untuk menggunakan CMK
aws lambda update-function-configuration \
--function-name my-db-function \
--kms-key-arn arn:aws:kms:us-east-1:123456789012:key/<your-key-id> \
--environment 'Variables={DB_ENDPOINT=mydb.cluster-xxxx.us-east-1.rds.amazonaws.com,DB_PORT=5432,DB_NAME=appdb}'
Verifikasi enkripsi aktif
aws lambda get-function-configuration \
--function-name my-db-function \
--query '{KMSKeyArn:KMSKeyArn,EnvVars:Environment.Variables}'
Jika field KMSKeyArn muncul di output, enkripsi dengan CMK sudah aktif. Jika kosong, Lambda menggunakan kunci default terkelola AWS.
Membaca Environment Variables di Kode Lambda
Setelah konfigurasi selesai, akses di kode sangat straightforward — tidak ada SDK call yang diperlukan untuk enkripsi at-rest biasa.
Python
import os
import boto3
def handler(event, context):
db_endpoint = os.environ['DB_ENDPOINT']
db_port = os.environ['DB_PORT']
db_name = os.environ['DB_NAME']
# Gunakan nilai untuk koneksi database
connection_string = f'postgresql://{db_endpoint}:{db_port}/{db_name}'
# ... logika koneksi
return {'statusCode': 200}
Node.js
exports.handler = async (event) => {
const dbEndpoint = process.env.DB_ENDPOINT;
const dbPort = process.env.DB_PORT;
const dbName = process.env.DB_NAME;
// Gunakan nilai untuk koneksi database
const connectionString = `postgresql://${dbEndpoint}:${dbPort}/${dbName}`;
// ... logika koneksi
return { statusCode: 200 };
};
Pola Enkripsi Transit: Nilai Sensitif Tidak Pernah Plaintext di Konfigurasi
Ada skenario di mana enkripsi at-rest saja tidak cukup — misalnya password database atau API key yang tidak boleh muncul sebagai plaintext bahkan di konfigurasi Lambda (yang bisa dilihat siapa saja dengan akses lambda:GetFunctionConfiguration). Untuk ini, gunakan pola enkripsi sebelum penyimpanan.
Tidak ada plaintext di konfigurasi LambdaCfg->>Exec: Cold start — inject ciphertext Exec->>KMS: kms:Decrypt(ciphertext) KMS-->>Exec: plaintext_password Note over Exec: Plaintext hanya ada
di memori, sekali per cold start Exec->>Code: DB_PASSWORD tersedia di memori
- Enkripsi nilai menggunakan KMS Encrypt sebelum disimpan ke konfigurasi Lambda.
- Simpan ciphertext (base64-encoded) sebagai nilai environment variable.
- Saat runtime, kode Lambda memanggil KMS Decrypt untuk mendapatkan plaintext.
- Nilai plaintext hanya ada di memori execution environment, tidak pernah di konfigurasi yang tersimpan.
Enkripsi nilai sebelum disimpan (dilakukan sekali, di luar Lambda)
aws kms encrypt \
--key-id alias/lambda-env-key \
--plaintext fileb://<(echo -n 'password-database-saya') \
--query CiphertextBlob \
--output text
Output adalah ciphertext base64. Simpan string ini sebagai nilai environment variable, misalnya DB_PASSWORD_ENCRYPTED.
Dekripsi di kode Lambda saat runtime
🔽 Klik untuk lihat kode dekripsi Python
import os
import boto3
import base64
kms_client = boto3.client('kms')
# Dekripsi dilakukan sekali saat initialization (di luar handler)
# untuk menghindari KMS call di setiap invocation
def decrypt_env_var(encrypted_value):
response = kms_client.decrypt(
CiphertextBlob=base64.b64decode(encrypted_value)
)
return response['Plaintext'].decode('utf-8')
# Initialization code — berjalan sekali per execution environment
DB_PASSWORD = decrypt_env_var(os.environ['DB_PASSWORD_ENCRYPTED'])
def handler(event, context):
# DB_PASSWORD sudah tersedia sebagai plaintext di memori
# Gunakan untuk koneksi database
return {'statusCode': 200}
Pola ini mirip seperti menaruh kunci brankas di dalam brankas lain — nilai sensitif hanya 'terbuka' di dalam execution environment yang terisolasi, bukan di konfigurasi yang bisa dibaca via API.
Pengalaman Lapangan: Misdiagnosis yang Sering Terjadi
Skenario yang cukup sering ditemui: fungsi Lambda tiba-tiba gagal dengan AccessDeniedException dari KMS setelah berjalan normal berbulan-bulan. Log CloudWatch menunjukkan error di saat cold start, bukan di dalam handler. Asumsi pertama biasanya 'key KMS dihapus' atau 'key policy berubah'.
Ternyata penyebabnya berbeda: CMK dirotasi secara otomatis, dan Lambda execution role tidak memiliki izin kms:Decrypt yang cukup luas untuk mencakup semua versi key. Rotasi KMS membuat key material baru, tapi ciphertext lama tetap bisa didekripsi selama key tidak dihapus — asalkan policy mengizinkan akses ke semua versi.
Cara verifikasi cepat:
aws kms describe-key \
--key-id alias/lambda-env-key \
--query 'KeyMetadata.{Status:KeyState,Rotation:KeyRotationStatus}'
aws kms get-key-rotation-status \
--key-id alias/lambda-env-key
Jika rotasi aktif, pastikan IAM policy di execution role menggunakan ARN key (bukan versi spesifik) agar berlaku untuk semua key material.
Alternatif: Kapan Gunakan SSM Parameter Store atau Secrets Manager
Environment variables cocok untuk nilai konfigurasi yang tidak terlalu sensitif dan jarang berubah. Untuk kebutuhan yang lebih kompleks, pertimbangkan alternatif berikut:
| Kebutuhan | Rekomendasi |
|---|---|
| Endpoint, nama bucket, flag konfigurasi | Lambda Environment Variables |
| Password, API key — rotasi manual | SSM Parameter Store (SecureString) |
| Credentials database — rotasi otomatis | AWS Secrets Manager |
| Nilai yang sama dipakai banyak fungsi | SSM Parameter Store atau Secrets Manager |
Environment variables memiliki batas total 4 KB untuk semua variabel. Jika konfigurasi kamu mendekati batas ini, itu sinyal untuk memindahkan sebagian ke Parameter Store.
Menggunakan Lambda Environment Variables dengan AWS SAM
Untuk deployment yang reproducible, definisikan environment variables langsung di template SAM:
🔽 Klik untuk lihat template SAM
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
MyDbFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: my-db-function
Handler: app.handler
Runtime: python3.12
CodeUri: ./src
Role: !GetAtt LambdaExecutionRole.Arn
KmsKeyArn: !GetAtt LambdaEnvKey.Arn
Environment:
Variables:
DB_ENDPOINT: !Ref DbEndpoint
DB_PORT: '5432'
DB_NAME: appdb
Parameters:
DbEndpoint:
Type: String
Description: RDS cluster endpoint
LambdaEnvKey:
Type: AWS::KMS::Key
Properties:
Description: CMK untuk Lambda environment variables
KeyPolicy:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
Action: 'kms:*'
Resource: '*'
Wrap-Up: Lambda Environment Variables dan Enkripsi KMS
Memisahkan konfigurasi dari kode adalah praktik dasar yang membuat Lambda function portabel antar environment. Untuk Lambda environment variables yang berisi nilai sensitif, enkripsi dengan CMK memberikan kontrol audit dan rotasi yang lebih granular dibanding kunci default. Pilih pola enkripsi transit jika nilai tidak boleh muncul sebagai plaintext di konfigurasi yang tersimpan.
Langkah selanjutnya yang direkomendasikan:
- Pelajari dokumentasi resmi Lambda environment variables untuk detail terbaru tentang batasan dan perilaku enkripsi.
- Untuk credential database dengan rotasi otomatis, evaluasi AWS Secrets Manager.
- Tinjau KMS key policies untuk memastikan execution role memiliki izin yang tepat.
Glosarium
| Istilah | Penjelasan |
|---|---|
| Environment Variable | Pasangan key-value yang di-inject ke execution environment Lambda sebelum handler dipanggil, diakses via variabel lingkungan OS standar. |
| CMK (Customer Managed Key) | Kunci KMS yang dibuat dan dikelola oleh pengguna, memberikan kontrol penuh atas key policy, rotasi, dan audit trail. |
| Encryption at Rest | Enkripsi data saat disimpan — dalam konteks ini, nilai environment variables dienkripsi di storage Lambda. |
| Execution Environment | Sandbox terisolasi tempat Lambda menjalankan kode; environment variables di-inject di sini saat initialization. |
| Cold Start | Proses inisialisasi execution environment baru, termasuk dekripsi environment variables — titik di mana error KMS paling sering muncul. |
Komentar
Posting Komentar