# Using Ansible on Google Compute Engine behind Identity Aware Proxy

>This article in Bahasa, are you looking for English language? Google Translate is your friend, or simply click [here](https://blog-mhrdn-com.translate.goog/using-ansible-on-google-compute-engine-behind-identity-aware-proxy?_x_tr_sl=id&_x_tr_tl=en&_x_tr_hl=id).

Ansible adalah aplikasi yang biasa saya gunakan untuk membantu proses *deployment*. Mulai dari instalasi paket dasar, hingga konfigurasi spesifik dapat dilakukan menggunakan aplikasi ini. Syarat utama ansible adalah koneksi ssh, khususnya ketika saya melakukan manajemen pada server linux secara *remote*. Masalahnya adalah linux server yang saya kelola pada google cloud platform hanya bisa diakses melalui Google IAP (identity Aware Proxy). Hal tersebut membuat perintah dan sintaks dasar ssh yang ada pada modul ansible gagal mengakses linux server tersebut.

Setelah *gugling*, saya menemukan permasalah yang sama di  [stackexchange](https://unix.stackexchange.com/questions/545034/with-ansible-is-it-possible-to-connect-connect-to-hosts-that-are-behind-cloud-i/). Jawaban pada tautan tersebut mengatakan bahwa salah satu solusinya adalah membuat sebuah *ssh wrapper script* yang menjalankan perintah `gcloud compute ssh --tunnel-through-iap`.

*So, lets try it*!. Saya membuat beberapa file, yaitu konfigurasi ansible `ansible.cfg`, inventori file `hosts`, playbook yaml `update.yml`, dan *ssh wrapper script* yang saya simpan di `misc/gssh.sh`. Jika dilihat struktur direktorinya akan seperti ini:
```
.
├── ansible.cfg
├── hosts
├── misc
│   └── gssh.sh
└── update.yml

1 directory, 4 files
```
`ansible.cfg` adalah konfigurasi file yang akan dibaca bersamaan dengan direktori tempat menjalankan perintah ansible. Jika diperhatikan ada nilai yang mungkin agak aneh bagi kalian, yaitu `forks = 1`. Dasarnya ansible forks memiliki nilai 5, dan disini saya hanya menggunakan satu. Hal ini saya lakukan karena perintah gcloud  [tidak dibuat untuk dijalankan secara paralel atau bersamaan](https://cloud.google.com/sdk/docs/scripting-gcloud), sehingga akan terjadi error jika diset lebih dari satu. Yup, itu berarti setiap perintah pada playbook ansible akan diselesaikan lebih lama. *Ya bisa ditinggal ngopi jika perintah yang dijalankan dan target servernya banyak*.

```bash
# ansible configuration file
# ansible.cfg

[ssh_connection]
pipelining = True
ssh_executable = misc/gssh.sh
ssh_args =
transfer_method = piped

[defaults]
forks = 1
interpreter_python = '/usr/bin/env python3'
gathering = False
strategy = free
```

Selanjutnya adalah `ssh wrapper script` yang diletakkan pada `misc/gssh.sh`. Sederhananya skrip ini menjalankan perintah `gcloud compute ssh --tunnel-through-iap` dan tambahan argumen lain dari ansible.

```bash
#!/bin/bash
# ssh wrapper using gcloud command
# misc/gssh.sh

host="${@: -2: 1}"
cmd="${@: -1: 1}"

socket="/tmp/ansible-ssh-${target_host}-22-iap"

gcloud_args="--tunnel-through-iap \
--project=corp-project-id \
--zone=us-central1-a
--quiet
--no-user-output-enabled
--
-C
-o ControlMaster=auto
-o ControlPersist=20
-o PreferredAuthentications=publickey
-o KbdInteractiveAuthentication=no
-o PasswordAuthentication=no
-o ConnectTimeout=20"

if [ -e "$socket" ]; then
  exec gcloud compute ssh "$host" \
       $gcloud_args \
       -o ControlPath="$socket" \
       "$cmd"
else
  exec gcloud compute ssh "$host" \
       $gcloud_args \
       -o ControlPath="$socket" \
       "$cmd"
fi
```
Sebuah file inventori ansible yang berisikan nama vm, dan konfigurasi user yang digunakan untuk login.
```
[gcp:vars]
ansible_user='ubuntu'

[gcp]
n1-elastic-corp
n2-elastic-corp
```

Terakhir adalah file ansible playbook yang berisi perintah `apt update && apt upgrade`, serta melakukan reboot jika diperlukan. File tersebut saya simpan pada `update.yml`
```
---
- hosts: gcp
  become: yes
  become_user: root
  tasks:
    - name: Update apt repo and cache on all Debian/Ubuntu boxes
      apt:
        update_cache : yes
        force_apt_get : yes
        cache_valid_time : 3600

    - name: Upgrade all packages on servers
      apt:
        upgrade : 'yes'
        force_apt_get : yes

    - name: Check if a reboot is needed on all servers
      register: reboot_required_file
      stat:
        path : /var/run/reboot-required
        get_md5 : no

    - name: Reboot the box if kernel updated
      reboot:
        msg: "Reboot initiated by Ansible for kernel updates"
        connect_timeout: 5
        reboot_timeout: 300
        pre_reboot_delay: 0
        post_reboot_delay: 30
        test_command: uptime
      when: reboot_required_file.stat.exists
```

Selanjutnya jalankan menggunakan perintah berikut dan lihat hasilnya:
```
ansible-playbook -i hosts update.yml
```
**Catatan**: 
Ternyata sudah ada tulisan yang lebih lengkap membahas hal ini setelah artikel saya, bisa dibaca pada tautan berikut  [https://binx.io/blog/2021/03/10/how-to-tell-ansible-to-use-gcp-iap-tunneling/](https://binx.io/blog/2021/03/10/how-to-tell-ansible-to-use-gcp-iap-tunneling/) .
