Blog Personal Inganta

Berbagi pengetahuan untuk memperkaya pemahaman

15 Feb 2022

Mengelola Modul Privat Terraform Menggunakan GitHub dan AWS S3

Bagi pengguna Terraform tingkat lanjut, seringkali menemukan pekerjaan yang bersifat repetitif. Menulis ulang kode Terraform untuk menyelesaikan tugas yang berulang merupakan pekerjaan yang tidak efektif. Untuk mengatasi permasalahan tersebut, kita bisa menggunakan modul Terraform. Kode Terraform untuk menyelesaikan tugas-tugas repetitif digabungkan ke dalam satu modul. Modul ini nantinya dipanggil dari proyek Terraform lain tanpa harus menulis ulang kode tersebut.

Ada banyak modul Terraform yang tersedia di luar sana. Berbagai modul diciptakan dan dibagikan secara terbuka oleh para kontributor. Daftar modul Terraform yang siap untuk dipakai bisa dilihat pada halaman https://registry.terraform.io/browse/modules.

Adakalanya kita membutuhkan modul yang dibuat dan digunakan oleh kalangan terbatas. Untuk mengatasi hal ini kita bisa menggunakan GitHub untuk menyimpan sumber kode modul tersebut. Selanjutnya sumber kode tersebut diterbitkan ke dalam keranjang S3 untuk dikonsumsi oleh kalangan tertentu saja. AWS S3 merupakan layanan penyimpanan yang memiliki tingkat ketersediaan yang tinggi. Selain itu, Terraform memiliki dukungan bawaan dalam hal authentikasi untuk mengunduh modul yang diterbitkan pada keranjang S3.

Repositori GitHub sebagai tempat penyimpanan sumber kode modul Terraform

Kita memerlukan repositori git untuk menyimpan sumber kode modul Terraform. Repositori git mempermudah kita dalam mengelola versi dari sumber kode modul Terraform. Sumber kode modul Terraform yang sudah dinyatakan lengkap perlu diarsipkan menjadi sebuah berkas zip. Berkas zip yang dihasilkan perlu diberikan nomor versi yang terpisah dari versi sumber kode. Maka dari itu kita perlu memikirkan mekanisme pengelolaan versi yang cocok untuk berkas zip modul Terraform. Salah satu metode pengelolaan versi yang banyak dipakai dalam pengembangan perangkat lunak adalah aturan Versi Semantik 2.0.0. Kita bisa mengadopsi versi semantik untuk mengelola versi dari berkas zip modul Terraform.

Misalkan kita akan membuat modul Terraform dengan nama aplikasi-internal dengan nomor versi 1.0.0. Berkas zip yang dihasilkan akan memiliki nama lengkap aplikasi-internal-1.0.0.zip. Ketika ditemukan kesalahan pada modul Terraform yang telah diterbitkan maka modul tersebut perlu diperbarui. Setelah kesalahan pada modul diperbaiki maka diterbitkan modul dengan versi baru dengan menaikan angka versi PATCH sehingga nama lengkap berkas zip menjadi aplikasi-internal-1.0.1.zip. Ketika fungsionalitas dari modul dirasa tidak cukup lagi maka modul perlu diperbarui dengan penambahan fitur baru. Setelah penambahan fitur selesai maka modul akan diterbitkan dengan meningkatkan nomor versi MINOR sehingga berkas zip memiliki nama lengkap aplikasi-internal-1.1.0.zip.

Kode sumber modul Terraform yang tersimpan pada repositori git sebaiknya dikirim ke repositori jarak jauh seperti GitHub. Hal ini akan mempermudah ketika kita ingin berkolaborasi mengembang modul Terraform dengan kontributor lain. GitHub menyediakan fitur yang bisa kita gunakan untuk membuat berkas zip dari sumber kode yang tersimpan di GitHub. Fitur tersebut bernama Github Actions. Selain untuk membuat berkas zip, kita bisa menggunakan Github Actions untuk menerbitkan berkas zip tersebut ke keranjang S3. Github Actions membutuhkan kredensial dan izin akses untuk menerbitkan berkas zip ke dalam keranjang S3. Kita bisa menggunakan protokol OpenID Connect (OIDC) untuk memperbolehkan Github Actions menulis berkas zip ke dalam keranjang S3 yang telah ditentukan secara aman.

Keranjang S3 sebagai tempat penerbitan modul privat Terraform

Untuk menerbitkan modul privat Terraform di S3, kita membutuhkan keranjang S3 yang privat pula. Berikut contoh kode Terraform yang bisa digunakan untuk membuat keranjang privat S3 dengan nama modul-privat-terraform.

module "s3_bucket" {
  source = "terraform-aws-modules/s3-bucket/aws"
  version = "2.14.1"

  bucket = "modul-privat-terraform"
  acl    = "private"
}

GitHub Actions sebagai penyedia identitas OIDC untuk layanan AWS IAM

Sebelum Github Actions bisa mengakses layanan AWS menggunakan protokol OIDC, kita perlu mendaftarkan GitHub Action sebagai penyedia identitas yang sah pada layanan AWS IAM. Berikut contoh kode Terraform yang bisa kita gunakan untuk mendaftakan GitHub sebagai penyedia identitas pada AWS IAM.

locals {
  oidc_provider_url = "https://token.actions.githubusercontent.com"
}

data "tls_certificate" "gh_actions" {
  url = local.oidc_provider_url
}

resource "aws_iam_openid_connect_provider" "gh_actions" {
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = [data.tls_certificate.gh_actions.certificates.0.sha1_fingerprint]
  url             = local.oidc_provider_url
}

IAM Role untuk menggelar modul private Terraform

Github Actions memiliki identitas OIDC secara bawaan. Identitas ini bisa ditukarkan dengan kredensial AWS yang selanjutnya bisa digunakan dalam proses authentikasi ketika menyimpan objek ke dalam keranjang S3. Berikut contoh AWS IAM Role yang memiliki izin untuk menyimpan objek ke dalam keranjang S3 dengan nama modul-privat-terraform. IAM Role ini bisa digunakan oleh Github Actions yang berjalan pada organisasi GitHub dengan nama organisasi-kita dan repositori dengan nama repositori-kita.

data "aws_iam_policy_document" "produsen_modul_privat_terraform" {
  statement {
    sid = "IzinkanPendaftaranKerangjang"

    actions = [
      "s3:ListBucket",
    ]

    resources = [
      "arn:aws:s3:::modul-privat-terraform",
    ]
  }

  statement {
    sid = "IzinkanPenulisanObjekKedalamKeranjang"

    actions = [
      "s3:GetObject",
      "s3:PutObject",
      "s3:DeleteObject",
    ]

    resources = [
      "arn:aws:s3:::modul-privat-terraform/*",
    ]
  }
}

data "aws_iam_policy_document" "github_actions" {
  statement {
    actions = ["sts:AssumeRoleWithWebIdentity"]

    principals {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.gh_actions.arn]
    }

    condition {
      test = "StringLike"
      variable = "token.actions.githubusercontent.com:sub"
      values = [
        "repo:<organisasi-kita>/<repositori-kita>:*"
      ]
    }
  }
}

resource "aws_iam_role" "produsen_modul_privat_terraform" {
    name = "produsen-modul-privat-terraform"

    inline_policy {
        name = "produsen-modul-privat-terraform"
        policy = data.aws_iam_policy_document.produsen_modul_privat_terraform.json
    }

    assume_role_policy = data.aws_iam_policy_document.github_actions.json
}

IAM Policy untuk mengunduh modul private Terraform

Proyek Terraform yang menggunakan modul privat yang tersimpan di keranjang S3 membutuhkan kredensial AWS dengan izin yang memadai. Berikut contoh IAM Policy yang memiliki izin untuk mengunduh modul dari keranjang S3 modul-privat-terraform.

data "aws_iam_policy_document" "konsumen_modul_privat_terraform" {
  statement {
    sid = "IzinkanPendaftaranKerangjang"

    actions = [
      "s3:ListBucket",
    ]

    resources = [
      "arn:aws:s3:::modul-privat-terraform",
    ]
  }

  statement {
    sid = "IzinkanMembacaObjek"

    actions = [
      "s3:GetObject",
    ]

    resources = [
      "arn:aws:s3:::modul-privat-terraform/*",
    ]
  }
}

resource "aws_iam_policy" "konsumen_modul_privat_terraform" {
  name   = "konsumen-modul-privat-terraform"
  policy = data.aws_iam_policy_document.konsumen_modul_privat_terraform.json
}

Mengunggah modul menggunakan Github Actions

Ketika kode sumber modul Terraform dinyatakan selesai pengembangannya maka langkah selanjutnya adalah pemilihan nomor versi yang sesuai dengan aturan versi semantik. Pengembang perlu mendaftarkan nomor versi yang telah dipilih sebagai tag di dalam git. Misalkan untuk versi 1.0.0 maka tag yang digunakan adalah v1.0.0. Perintah git tag v1.0.0 bisa digunakan untuk mendaftarkan tag tersebut. Informasi tag git ini perlu dikirim ke GitHub dengan perintah git push --tags. Informasi tag selanjutnya digunakan oleh alur kerja GitHub Actions untuk membuat berkas zip dan mengirimkan berkas tersebut ke dalam keranjang S3 modul-privat-terraform.

name: Terbitkan modul privat Terraform
on:
  push:
    tags:
      - 'v[0-9]+.[0-9]+.[0-9]+'
jobs:
  gelar:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
    - name: Kalkulasi versi
      run: echo "VERSI=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_ENV
    - name: Arsip berkas
      run: zip aplikasi-internal-${{ env.VERSI }}.zip ./* -r
    - name: Tukar identitas OIDC jadi kredensial AWS
      uses: aws-actions/configure-aws-credentials@v1
      with:
        role-to-assume: <ganti-dengan-arn-iam-role-produsen_modul_privat_terraform>
    - name: Unggah objek ke keranjang S3
      run: |
    aws s3 cp aplikasi-internal-${{ env.VERSI }}.zip s3://modul-privat-terraform/aplikasi-internal/aplikasi-internal-${{ env.VERSI }}.zip

Mengkonsumsi modul privat Terraform

Modul privat Terraform yang tersimpan di keranjang S3 bisa dikonsumsi oleh proyek Terraform menggunakan prefik spesial s3:: yang diikuti dengan URL objek S3. Berikut contoh proyek Terraform yang menggunakan modul aplikasi-internal versi 1.0.0 yang tersimpan pada keranjang S3 modul-privat-terraform pada region Jakarta.

module "aplikasi" {
  source = "s3::https://ap-southeast-3.amazonaws.com/modul-privat-terraform/aplikasi-internal/aplikasi-internal-1.0.0.zip"
}

Kesimpulan

Pada tulisan ini dijelaskan kasus penggunaan modul privat Terraform untuk pengguna pada tingkat lanjut. Komponen-komponen yang diperlukan untuk membangun sistem untuk mengelola modul privat Terraform dijabarkan secara bertahap satu per satu. Komponen sistem tersebut meliputi GitHub, GitHub Actions, AWS IAM, dan AWS S3. Kode Terraform juga disediakan pada setiap bagian tulisan untuk memberi gambaran implementasi secara nyata. Tulisan diakhiri dengan penjelasan alur kerja beserta peran dan izin yang dibutuhkan untuk menerbitkan dan mengkonsumsi modul privat Terraform.