Common Mistake #
Sebagian besar insiden keamanan dalam otomasi Ansible bukan disebabkan oleh kelemahan kriptografi atau zero-day exploit — melainkan oleh kesalahan konfigurasi yang sederhana dan pola yang tampaknya tidak berbahaya tapi punya konsekuensi serius. Artikel ini mengumpulkan kesalahan keamanan yang paling sering ditemukan, menjelaskan mengapa berbahaya, dan memberikan cara yang benar.
Kesalahan 1: Secret dalam Plaintext di Repository #
Ini adalah kesalahan paling umum dan paling berbahaya:
# ANTI-PATTERN: secret dalam plaintext
# group_vars/production/vars.yml
db_password: MyDatabasePassword123
aws_access_key: AKIAIOSFODNN7EXAMPLE
aws_secret_key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
slack_webhook: https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
Satu kali file ini masuk ke Git, secret tersebut ada di history selamanya — bahkan setelah dihapus di commit berikutnya. Bot pemindai repositori di internet secara aktif mencari pola seperti ini.
# BENAR: gunakan Ansible Vault
# group_vars/production/vault.yml (enkripsi dengan ansible-vault encrypt)
vault_db_password: MyDatabasePassword123
# group_vars/production/vars.yml (plaintext, aman di Git)
db_password: "{{ vault_db_password }}"
Kesalahan 2: Menonaktifkan Host Key Checking di Production #
# ANTI-PATTERN: di ansible.cfg production
[defaults]
host_key_checking = False # JANGAN di production!
host_key_checking = False memungkinkan man-in-the-middle attack — Ansible akan terhubung ke server manapun yang menjawab, bahkan jika itu bukan server yang seharusnya. Penyerang bisa mengarahkan koneksi ke server mereka sendiri dan menerima semua secret yang dikirim Ansible.
# BENAR: aktifkan di production
[defaults]
host_key_checking = True
# Untuk server baru yang belum ada di known_hosts, gunakan:
[ssh_connection]
ssh_args = -o StrictHostKeyChecking=accept-new
# Ini menerima key baru tapi tetap validasi key yang sudah dikenal
Kesalahan 3: Privilege Escalation yang Terlalu Luas #
# ANTI-PATTERN: sudoers yang terlalu permisif
ansible-deploy ALL=(ALL) NOPASSWD: ALL
# User ansible-deploy bisa melakukan APA SAJA sebagai root
Jika credential ansible-deploy bocor, penyerang mendapat akses root penuh ke semua server. Batasi privilege escalation hanya ke perintah yang benar-benar diperlukan:
# BENAR: sudoers yang spesifik
ansible-deploy ALL=(ALL) NOPASSWD: /bin/systemctl restart myapp
ansible-deploy ALL=(ALL) NOPASSWD: /usr/bin/pip3 install -r /opt/app/requirements.txt
ansible-deploy ALL=(ALL) NOPASSWD: /usr/bin/rsync --archive /tmp/release/ /opt/app/
Kesalahan 4: Variabel Sensitif di Log #
# ANTI-PATTERN: task yang menampilkan secret di output
- name: Konfigurasi database
command: mysql -u root -p{{ db_root_password }} -e "CREATE USER..."
# Jika task ini gagal, Ansible menampilkan command lengkap beserta password!
- name: Debug nilai variabel
debug:
var: hostvars[inventory_hostname]
# Ini menampilkan SEMUA variabel termasuk yang sensitif!
# BENAR: sembunyikan output yang sensitif
- name: Konfigurasi database
command: mysql -u root -p{{ db_root_password }} -e "CREATE USER..."
no_log: true # Jangan tampilkan apapun dari task ini
- name: Debug variabel (tanpa yang sensitif)
debug:
msg: "Deploy ke {{ inventory_hostname }} dengan user {{ deploy_user }}"
# Hanya tampilkan yang memang aman ditampilkan
Kesalahan 5: Tidak Mem-pin Versi Role dan Collection #
# ANTI-PATTERN: tanpa pin versi
# requirements.yml
roles:
- name: geerlingguy.nginx
# Tidak ada version — selalu ambil terbaru
# Konsekuensi:
# Hari ini: role v3.2 berjalan normal
# Besok: role v3.3 dirilis, CI/CD mengambil versi baru
# Role baru mengubah nama variabel → playbook break
# Tidak ada yang tahu kenapa pipeline tiba-tiba gagal
# BENAR: pin versi secara eksplisit
roles:
- name: geerlingguy.nginx
version: "3.2.0" # Pin ke versi yang sudah ditest
Kesalahan 6: Menjalankan Playbook Langsung ke Production tanpa Staging #
# ANTI-PATTERN: langsung ke production
ansible-playbook -i inventory/production/ site.yml
# Konsekuensi: bug di playbook langsung merusak production
# Tidak ada cara tahu dampaknya sebelum terjadi
# BENAR: staging dulu, production setelah dikonfirmasi
# Langkah 1: Deploy ke staging
ansible-playbook -i inventory/staging/ site.yml
# Langkah 2: Verifikasi staging berjalan normal
# ... test manual atau otomatis ...
# Langkah 3: Dry run ke production
ansible-playbook -i inventory/production/ site.yml --check --diff
# Langkah 4: Deploy ke production
ansible-playbook -i inventory/production/ site.yml
Kesalahan 7: Menggunakan become: true di Semua Task #
# ANTI-PATTERN: semua task berjalan sebagai root
- name: Deploy aplikasi
hosts: appservers
become: true # Root untuk semua task — termasuk yang tidak memerlukannya
tasks:
- name: Install nginx (perlu root)
apt:
name: nginx
state: present
- name: Deploy kode aplikasi (tidak perlu root!)
git:
repo: https://github.com/org/app.git
dest: /opt/app # Sekarang direktori ini dimiliki root
# BENAR: escalate privilege hanya saat diperlukan
- name: Deploy aplikasi
hosts: appservers
become: false # Default: tanpa sudo
tasks:
- name: Install nginx (perlu root)
apt:
name: nginx
state: present
become: true # Eskalasi hanya untuk task ini
- name: Deploy kode aplikasi (sebagai user deployer)
git:
repo: https://github.com/org/app.git
dest: /opt/app
become_user: deployer # Jalankan sebagai deployer, bukan root
become: true
Ringkasan #
- Jangan pernah commit secret dalam plaintext — gunakan Ansible Vault atau external secret manager. Secret di Git history tidak bisa benar-benar dihapus.
host_key_checking = Falsedilarang di production — ini membuka celah man-in-the-middle attack.- Sudoers harus spesifik — bukan
NOPASSWD: ALL, tapi hanya perintah yang benar-benar diperlukan.no_log: trueuntuk semua task yang menangani secret — log adalah storage persistent yang sering diabaikan.- Pin versi semua role dan collection eksternal — tanpa pin, update otomatis bisa membreak playbook kapan saja.
- Selalu test di staging sebelum production — tidak ada alasan yang cukup kuat untuk skip langkah ini.
- Eskalasi privilege hanya saat diperlukan — jangan
become: truedi level play jika hanya satu-dua task yang membutuhkannya.