Encryption #
Enkripsi adalah lapisan pertahanan terakhir dalam arsitektur keamanan Ansible. Ia tidak menggantikan kontrol akses atau audit, tapi memastikan bahwa bahkan ketika kontrol lain gagal — laptop dicuri, disk backup bocor, log terekspos ke pihak ketiga — data yang dicuri tetap tidak bisa dibaca tanpa kunci yang benar. Ansible menyentuh enkripsi di banyak titik: variabel yang berisi password di-enkripsi dengan Vault, koneksi transport ke managed node diamankan dengan SSH/TLS, sertifikat SSL/TLS untuk service internal harus didistribusikan dan di-rotate, dan data sensitif di log harus di-redact. Artikel ini membahas setiap titik tersebut secara sistematis — kapan pakai algoritma simetris versus asimetris, bagaimana mengelola key lifecycle, dan pola umum yang aman untuk masing-masing skenario. Pemahaman yang baik tentang kekuatan dan kelemahan setiap algoritma mencegah pilihan yang kelihatannya aman tapi sebenarnya rapuh.
Kapan Enkripsi Dibutuhkan? #
DATA SENSITIF:
✓ Password dan API key → ENCRYPT REQUIRED (Vault)
✓ Private key (SSH, TLS) → ENCRYPT REQUIRED (file permission + Vault)
✓ Database connection string dengan credential → ENCRYPT REQUIRED
✓ File konfigurasi production (web server, app config) → ENCRYPT REQUIRED
✓ Backup file yang berisi data → ENCRYPT REQUIRED (LUKS/dm-crypt)
✓ Token sesi untuk user → ENCRYPT in transit (TLS), EXPIRE cepat
DATA NON-SENSITIF:
✗ Hostname dan IP server → tidak perlu
✗ Path direktori (/var/log/app) → tidak perlu
✗ Nama user biasa → tidak perlu
✗ Konfigurasi non-secret (port, log level) → tidak perlu
Enkripsi menambah overhead CPU dan kompleksitas operasional. Tidak semua data butuh di-enkripsi — hanya yang risikonya material jika bocor. Klasifikasi data sensitif adalah langkah pertama sebelum menentukan strategi enkripsi yang sesuai.
Arsitektur Enkripsi di Ansible #
flowchart LR
A["Ansible<br/>Control Node"] -->|"SSH/TLS"| B["Managed Node"]
A -->|"Vault encrypt"| C["Vault File<br/>AES256"]
A -->|"TLS"| D["Secret Manager<br/>Vault/AWS SM"]
B -->|"SSH key"| E["authorized_keys"]
B -->|"TLS cert"| F["Service<br/>nginx/postgres"]
D -->|"runtime inject"| A
C -->|"decrypt saat runtime"| A
A -->|"AnsibleModule"| B
Enkripsi terjadi di empat titik dalam ekosistem Ansible: file Vault di control node (dienkripsi saat commit, didekripsi saat runtime), koneksi transport (SSH antara control dan managed node, atau HTTPS ke API), sertifikat di managed node (TLS untuk service internal), dan secret manager eksternal (Vault, AWS Secrets Manager) yang menyediakan secret ke playbook saat runtime tanpa pernah menyimpan plaintext di disk Ansible.
Algoritma Simetris vs Asimetris #
flowchart TD
A["Pilih Algoritma"] --> B{"Jenis data?"}
B -->|"File/data besar<br/>dienkrip sekali<br/>dan dibaca berkali-kali"| C["Simetris<br/>AES-256-GCM"]
B -->|"Kunci perlu<br/>dibagikan ke<br/>banyak pihak"| D["Asimetris<br/>RSA/Ed25519/ECDSA"]
C --> E["Vault file<br/>LUKS disk<br/>TLS bulk encryption"]
D --> F["SSH key pair<br/>TLS handshake<br/>Digital signature"]
Pemilihan algoritma simetris versus asimetris menentukan seluruh operasional enkripsi. Simetris (AES-256-GCM) cocok untuk data dalam jumlah besar yang dienkripsi sekali dan dibaca berkali-kali — file Vault, full disk encryption, atau bulk data encryption. Asimetris (RSA, Ed25519, ECDSA) cocok untuk situasi di mana kunci publik harus dibagikan ke banyak pihak tanpa mengorbankan kunci privat — handshake TLS, SSH key pair, dan tanda tangan digital. Hampir semua sistem modern menggunakan keduanya secara hybrid: TLS misalnya menggunakan RSA/ECDSA untuk pertukaran kunci sesi, lalu AES untuk bulk encryption.
Tabel Perbandingan Algoritma #
| Algoritma | Tipe | Panjang kunci | Use case | Catatan |
|---|---|---|---|---|
| AES-256-GCM | Simetris | 256 bit | File Vault, disk encryption, TLS bulk | Standar industri, hardware acceleration di CPU modern |
| ChaCha20-Poly1305 | Simetris | 256 bit | Lingkungan tanpa hardware AES acceleration | Cepat di software, populer di mobile |
| RSA-2048 | Asimetris | 2048 bit | Legacy TLS, signature | Sudah tua, migrasi ke ECDSA direkomendasikan |
| RSA-4096 | Asimetris | 4096 bit | High-security signature | Lambat untuk handshake, gunakan hanya jika benar-benar perlu |
| ECDSA P-256 | Asimetris | 256 bit | TLS 1.3, SSH, modern | Cepat, ukuran signature kecil |
| Ed25519 | Asimetris | 256 bit (key) | SSH (disukai), signature | Paling cepat, signature 64 byte |
| bcrypt | Hash + salt | variable | Password hashing | Cost factor 12 minimum di 2024 |
| Argon2id | Hash + memory-hard | variable | Password hashing baru | Lebih kuat dari bcrypt untuk GPU attack |
| scrypt | Hash + memory-hard | variable | Password hashing | Alternatif Argon2id |
Untuk Ansible, AES-256 via Vault adalah pilihan default. Untuk SSH key, Ed25519 memberikan keamanan dan performa terbaik. Untuk password, gunakan bcrypt cost factor ≥ 12 atau Argon2id jika library-nya tersedia.
Ansible Vault — Enkripsi At Rest #
Vault mengenkripsi file YAML dengan AES-256. File Vault tetap bisa di-include ke playbook seperti biasa, tapi isinya tidak terbaca tanpa vault password. Ansible mengenali file Vault otomatis berdasarkan header $ANSIBLE_VAULT;1.1;AES256.
# Buat file Vault baru
ansible-vault create secrets/production.yml
# Edit file Vault (prompt untuk password)
ansible-vault edit secrets/production.yml
# Enkripsi file YAML yang sudah ada
ansible-vault encrypt existing-file.yml
# Lihat isi tanpa edit
ansible-vault view secrets/production.yml
# Decrypt untuk operasi yang perlu plaintext (jarang)
ansible-vault decrypt secrets/production.yml
Setiap operasi membutuhkan vault password. Password bisa dimasukkan interaktif (--ask-vault-pass), dari file (--vault-password-file), dari environment variable (ANSIBLE_VAULT_PASSWORD_FILE), atau dari script kustom (--vault-password-client) yang mengambil password dari secret manager eksternal saat runtime.
# ANTI-PATTERN: vault password di Git
# .gitignore salah: lupa ignore vault password file
# Akibatnya: vault_password_prod.txt ter-commit, attacker bisa decrypt semua vault
# $ cat /var/log/git-history/vault_password_prod.txt
# my-s3cr3t-vault-password
# BENAR: vault password dari secret manager, inject saat runtime
# playbooks/deploy.yml
- name: Deploy dengan vault password dari AWS Secrets Manager
hosts: production
vars:
vault_password: "{{ lookup('aws_secret', 'ansible/vault-password', region='ap-southeast-1') }}"
vars_files:
- secrets/production.yml # File Vault, decrypted saat runtime
tasks:
- name: Deploy aplikasi
template:
src: app.conf.j2
dest: /etc/myapp/app.conf
mode: '0640'
owner: root
group: myapp
Inject vault password saat runtime dari secret manager eksternal memastikan password tidak pernah tersimpan di Git, di file konfigurasi Ansible, atau di environment variable yang persisten.
Strategi Multi-Vault #
Satu vault password untuk semua environment sangat tidak fleksibel. Setiap environment harus punya vault terpisah, dengan password yang berbeda, sehingga kebocoran satu vault tidak mengekspos environment lain.
# group_vars/all/vaults.yml
# Definisi vault per environment — di-include di vars_files
vault_files:
development: secrets/dev.yml
staging: secrets/staging.yml
production: secrets/production.yml
# Vault password juga per environment
vault_passwords:
development: "{{ lookup('env', 'ANSIBLE_VAULT_DEV_PASSWORD') }}"
staging: "{{ lookup('env', 'ANSIBLE_VAULT_STAGING_PASSWORD') }}"
production: "{{ lookup('aws_secret', 'ansible/vault-password', region='ap-southeast-1') }}"
# ANTI-PATTERN: satu vault untuk semua environment
# secrets/all.yml — berisi password production DAN dev DAN staging
# vault_password: 'one-password-for-everyone'
# Kebocoran = compromise seluruh organisasi
# BENAR: vault per environment + audit
# secrets/production.yml
---
production_db_password: "strong-random-32-char-password"
production_api_key: "very-long-random-api-key"
production_tls_cert: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
Pisahkan vault per environment memungkinkan audit terpisah — vault production hanya diakses dari CI/CD yang terpercaya, vault development bisa diakses dari workstation developer tanpa mengorbankan keamanan production.
Rotasi password secara berkala. Password Vault, password database, dan API key harus di-rotate minimal setiap 90 hari. Ansible dapat mengotomasi rotasi dengan playbook yang generate password baru, update Vault, dan restart service yang bergantung pada secret tersebut. Tanpa rotasi, password yang bocor akan tetap valid sampai kebocoran itu terdeteksi — yang bisa bertahun-tahun.
Enkripsi Transport dengan SSH #
Koneksi antara Ansible control node dan managed node selalu dienkripsi oleh SSH. Tapi konfigurasi SSH yang lemah (protokol lama, cipher lemah, key exchange lemah) mengurangi efektivitas enkripsi transport.
# roles/ssh-hardening/tasks/main.yml
---
- name: Deploy sshd_config yang aman
template:
src: sshd_config.j2
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: '0600'
notify: Restart sshd
- name: Disable protokol dan cipher lama
lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
state: present
loop:
- regexp: '^#?Protocol'
line: 'Protocol 2'
- regexp: '^#?Ciphers'
line: 'Ciphers [email protected],[email protected],[email protected]'
- regexp: '^#?MACs'
line: 'MACs [email protected],[email protected]'
- regexp: '^#?KexAlgorithms'
line: 'KexAlgorithms [email protected],diffie-hellman-group-exchange-sha256'
Kombinasi chacha20-poly1305 + curve25519-sha256 + hmac-sha2-512-etm memberikan keamanan transport yang kuat tanpa mengorbankan performa, bahkan di CPU tanpa hardware AES acceleration.
Distribusi SSH Key #
SSH key pair memberikan autentikasi yang lebih aman dari password. Distribusi kunci publik ke managed node harus diotomasi, tapi kunci privat harus tetap aman.
# Generate SSH key pair di control node
ssh-keygen -t ed25519 -C "ansible-control-prod" -f ~/.ssh/ansible_ed25519
# Public key di-distribute ke managed node via Ansible
ansible all -m authorized_key -a "
user=ansible
key='{{ lookup('file', '~/.ssh/ansible_ed25519.pub') }}'
state=present
"
# ANTI-PATTERN: kunci SSH tanpa passphrase, copy manual ke setiap server
# ssh-keygen -t rsa -b 2048 -N "" -f deploy_key
# scp deploy_key.pub user@server1:~/.ssh/authorized_keys
# scp deploy_key.pub user@server2:~/.ssh/authorized_keys
# ... (ribuan server)
# scp deploy_key user@laptop:/tmp/ # bocor ke laptop baru
# BENAR: passphrase + Ansible push + rotation berkala
# 1. Generate key dengan passphrase, simpan passphrase di Vault
# 2. Ansible push public key ke semua managed node
# 3. ssh-agent di control node memegang decrypted key saat runtime
# 4. Rotate keypair setiap 6-12 bulan
- name: Distribusikan SSH public key baru ke managed node
hosts: all
tasks:
- name: Tambahkan ansible public key ke authorized_keys
authorized_key:
user: ansible
key: "{{ lookup('file', '~/.ssh/ansible_ed25519.pub') }}"
state: present
exclusive: true # Hapus key lain, pastikan hanya key baru yang valid
notify: Audit SSH key change
Kunci SSH tanpa passphrase di laptop develop adalah mimpi buruk keamanan — begitu laptop dicuri, attacker punya akses ke seluruh infrastruktur. Passphrase + ssh-agent memberikan keamanan tanpa mengorbankan kenyamanan.
Sertifikat SSL/TLS #
Service internal (nginx, PostgreSQL, dll) sering menggunakan TLS untuk komunikasi terenkripsi. Sertifikat harus di-generate, didistribusikan, dan di-rotate secara berkala.
# roles/tls-cert/tasks/main.yml
---
- name: Generate private key
community.crypto.openssl_privatekey:
path: /etc/ssl/private/{{ service_name }}.key
size: 4096
type: RSA
mode: '0600'
owner: root
group: ssl-cert
register: private_key
- name: Generate CSR (Certificate Signing Request)
community.crypto.openssl_csr:
path: /etc/ssl/csr/{{ service_name }}.csr
privatekey_path: /etc/ssl/private/{{ service_name }}.key
common_name: "{{ service_name }}.internal.example.com"
subject_alt_name:
- "DNS:{{ service_name }}.internal.example.com"
- "DNS:{{ service_name }}"
organization_name: "Example Corp"
organizational_unit_name: "Infrastructure"
country_name: "ID"
key_usage:
- digitalSignature
- keyEncipherment
extended_key_usage:
- serverAuth
- clientAuth
when: private_key.changed
- name: Self-sign certificate (untuk internal CA)
community.crypto.x509_certificate:
path: /etc/ssl/certs/{{ service_name }}.crt
privatekey_path: /etc/ssl/private/{{ service_name }}.key
csr_path: /etc/ssl/csr/{{ service_name }}.csr
provider: selfsigned
selfsigned_not_after: "+365d" # Berlaku 1 tahun
mode: '0644'
owner: root
group: root
when: private_key.changed
Untuk service internal, self-signed certificate dari private CA internal sudah cukup. Untuk service yang diakses dari internet, gunakan Let’s Encrypt atau CA eksternal lain dengan ACME protocol untuk auto-renewal.
Sertifikat self-signed perlu di-trust secara eksplisit. Browser dan client TLS lain akan menolak sertifikat self-signed dari CA yang tidak dikenal. Untuk infrastruktur internal, deploy CA certificate ke semua managed node (via Ansible, tentu) dan tambahkan ke system trust store. Tanpa langkah ini, service TLS internal akan selalu gagal handshake dengan error “certificate verify failed”.
Enkripsi Backup #
Backup sering menjadi titik lemah dalam strategi enkripsi — dibuat dengan database aktif (plaintext), disimpan di disk atau cloud storage tanpa enkripsi, dan membawa data sensitif ke permukaan attack yang lebih luas. Backup harus dienkripsi sebelum meninggalkan host asal.
# Backup PostgreSQL + encrypt dengan GPG sebelum upload
pg_dump -Fc production_db > /tmp/production_db.dump
gpg --symmetric --cipher-algo AES256 \
--output /backup/production_db.dump.gpg \
/tmp/production_db.dump
rm -f /tmp/production_db.dump # Hapus plaintext
aws s3 cp /backup/production_db.dump.gpg \
s3://company-backups/production/$(date +%Y%m%d)/
shred -u /backup/production_db.dump.gpg # Hapus lokal setelah upload
Atau gunakan LUKS/dm-crypt untuk full disk encryption pada volume backup — seluruh volume dienkripsi pada level block device, transparan untuk aplikasi.
Redact Data Sensitif di Log #
Log yang menampilkan password, API key, atau private key di plaintext adalah kebocoran data yang tertunda — biasanya tidak terdeteksi sampai audit atau sampai log terekspos ke pihak ketiga.
# ANTI-PATTERN: log output yang menampilkan rendered template
# ansible-playbook site.yml -vvv
# TASK [Deploy config] ****
# ok: [server1] => {
# "msg": "Rendered template content: db_password=MyS3cretP@ss"
# }
# Log ini sekarang ada di syslog, journal, dan mungkin CI artifact
# BENAR: no_log: true untuk task yang render secret
- name: Deploy konfigurasi database
template:
src: db.conf.j2
dest: /etc/myapp/db.conf
mode: '0640'
no_log: true # Jangan log output task ini
- name: Test koneksi database
command: psql -f /etc/myapp/db.conf -c "SELECT 1"
no_log: true # Output query mungkin bocor credential
changed_when: false
no_log: true adalah satu line yang mencegah banyak insiden. Output task tidak akan muncul di Ansible log, syslog, atau CI artifact. Untuk CI/CD yang menyimpan log artifact, tanpa no_log: true kita secara efektif menulis password ke public storage.
Decision Tree — Pilih Pendekatan Enkripsi #
flowchart TD
A["Data apa<br/>yang dienkripsi?"] --> B{"Kategori"}
B -->|"Secret variable<br/>password, API key"| C["Vault file<br/>AES-256"]
B -->|"Transport<br/>SSH/TLS"| D["SSH key pair<br/>atau TLS cert"]
B -->|"Disk/storage"| E["LUKS/dm-crypt"]
B -->|"Backup file"| F["gpg symmetric<br/>atau LUKS"]
B -->|"Password user"| G["bcrypt cost 12+<br/>atau Argon2id"]
C --> H{"Environment?"}
H -->|"Production"| I["Vault terpisah<br/>+ AWS SM inject"]
H -->|"Dev/staging"| J["Vault terpisah<br/>+ env var password"]
D --> K{"Internal atau<br/>public-facing?"}
K -->|"Internal"| L["Self-signed cert<br/>+ private CA"]
K -->|"Public"| M["Let's Encrypt<br/>+ ACME renewal"]
Decision tree ini membantu memilih pendekatan enkripsi yang tepat untuk berbagai jenis data. Kuncinya adalah klasifikasi data dulu — baru pilih algoritma.
Ringkasan #
- AES-256 via Vault adalah default untuk data at rest di Ansible. Gunakan Vault terpisah per environment, dan inject vault password dari secret manager eksternal saat runtime.
- Ed25519 adalah pilihan terbaik untuk SSH key — cepat, kecil, dan aman. Selalu gunakan passphrase dan simpan decrypted key di ssh-agent, jangan pernah di file tanpa passphrase.
- TLS internal bisa pakai self-signed certificate dari private CA — deploy CA certificate ke semua managed node via Ansible untuk trust.
- Backup harus dienkripsi sebelum meninggalkan host — GPG symmetric untuk file individual, LUKS untuk full disk encryption pada volume backup.
no_log: trueadalah satu line wajib untuk task yang render template berisi credential atau yang output-nya mungkin bocor secret.- bcrypt cost factor ≥ 12 atau Argon2id untuk password hashing. Jangan pernah simpan password plaintext atau hash dengan SHA1/MD5.
- Rotasi berkala — password Vault, API key, dan SSH key harus di-rotate minimal setiap 90 hari. Ansible dapat mengotomasi seluruh proses rotasi.