AizuDemy

Tutorial OpenFGA & Go: Solusi Otorisasi ReBAC Zero Trust di VPS

Tutorial OpenFGA & Go: Solusi Otorisasi ReBAC Zero Trust di VPS
IKLAN
IDCloudHost
🎧
Dengarkan Artikel Ini
Suara AI Otomatis β€’ 9 mnt baca baca
⚑ TL;DR

Poin Kunci Artikel Ini:

  • Jam empat sore di hari Jumat biasanya jadi waktu paling rawan buat developer backend.
  • Kopi sudah dingin, mental sudah siap menyambut akhir pekan, lalu tiba-tiba notifikasi Slack menjerit.
  • Anda langsung membuka repositori kode Go, menyisir baris-baris middleware otorisasi, dan menemukan tumpukan yang sudah mirip mi goreng instan.
πŸ“‹ Daftar Isi Materi Tutup β–΄

Jam empat sore di hari Jumat biasanya jadi waktu paling rawan buat developer backend. Kopi sudah dingin, mental sudah siap menyambut akhir pekan, lalu tiba-tiba notifikasi Slack menjerit. Ada tiket bug darurat: akun mitra vendor yang kontraknya sudah habis tadi siang ternyata masih bisa mengunduh file laporan keuangan sensitif di aplikasi dashboard.

Kepanikan dimulai. Anda langsung membuka repositori kode Go, menyisir baris-baris middleware otorisasi, dan menemukan tumpukan if-else yang sudah mirip mi goreng instan. Logikanya hanya mengecek apakah isi token JWT memiliki role vendor_editor. Masalahnya, role itu berlaku menyeluruh di sistem tanpa peduli siapa pemilik file atau folder yang diakses.

Kondisi seperti ini sangat wajar terjadi ketika aplikasi bertumbuh cepat. Pendekatan otorisasi lama yang mengandalkan peran pengguna mulai kewalahan menghadapi kebutuhan bisnis yang makin rumit. Misalnya saat tim produk minta aturan baru: User hanya boleh membaca dokumen finansial kalau dia anggota tim keuangan atau atasan langsung dari pembuat dokumen.

Di panduan ini, kita bakal membedah solusi otorisasi modern yang dipakai raksasa teknologi seperti Google, Airbnb, dan Carta: Relationship-Based Access Control (ReBAC) berbasis OpenFGA. Kita akan langsung mempraktikkan cara install OpenFGA di VPS dan menghubungkannya dengan microservice Go berarsitektur Zero Trust.

Kenapa RBAC Biasa Bikin Pusing dan Kenapa Harus ReBAC?

Saat aplikasi masih kecil, sistem Role-Based Access Control (RBAC) terasa sangat praktis. Anda cukup membuat tabel users, roles, dan permissions di database relational. Di sisi backend Go, middleware tinggal membaca isi token JWT lalu mengecek apakah role user bernilai admin atau editor.

Namun begitu sistem berkembang menjadi arsitektur microservices dan hirarki data makin rumit, RBAC mulai menunjukkan titik lelahnya:

  • Role Explosion (Ledakan Role): Jumlah role mendadak membengkak tak terkendali. Anda mendadak punya role seperti editor_folder_a, viewer_finance_v2, atau admin_subteam_3. Database pun penuh dengan data role redundan.
  • Keterikatan Ketat (Tight Coupling): Kode otorisasi tersebar acak di puluhan microservice backend. Tiap kali ada perubahan kebijakan akses dari manajemen, Anda harus mengubah logika dan melakukan deploy ulang pada banyak service secara bersamaan.
  • Kehilangan Konteks Hubungan: RBAC tahu siapa Anda, tetapi RBAC tidak tahu apa hubungan Anda dengan objek data yang ingin Anda akses. RBAC kesulitan menangani hirarki bertingkat seperti folder di dalam folder.

Untuk mengatasi kebuntuan ini, Google menerbitkan paper ilmiah bertajuk Zanzibar pada tahun 2019. Zanzibar adalah sistem otorisasi terpusat milik Google yang mengamankan Google Drive, YouTube, dan Google Cloud IAM. Zanzibar menggeser fokus otorisasi dari sekadar stempel role ke rantai relasi (relationship) antara objek dan subjek.

OpenFGA (Fine-Grained Authorization) merupakan proyek open-source di bawah naungan CNCF (Cloud Native Computing Foundation) yang mengimplementasikan konsep Google Zanzibar. Dalam filosofi Zero Trust, aplikasi backend tidak boleh percaya begitu saja hanya karena request membawa token JWT yang valid atau berasal dari jaringan internal. Setiap ada pemanggilan API ke resource penting, backend Go akan langsung bertanya ke server OpenFGA: Apakah user A punya relasi viewer pada objek document:123?

Setup Server OpenFGA di VPS Menggunakan Docker Compose

Mari kita langsung praktik. Kita bakal menyiapkan server OpenFGA bersama database PostgreSQL sebagai media penyimpanan data relasi (tuples) di VPS Ubuntu.

1. Menyiapkan Docker Compose

Login ke VPS Anda melalui SSH, buat direktori baru bernama openfga-setup, lalu buat file docker-compose.yml dengan isi berikut:

version: '3.8'

services:
  postgres:
    image: postgres:15-alpine
    container_name: openfga-postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: secretpassword
      POSTGRES_DB: openfga
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

  openfga-migrate:
    image: openfga/openfga:latest
    container_name: openfga-migrate
    command: migrate
    environment:
      OPENFGA_DATASTORE_ENGINE: postgres
      OPENFGA_DATASTORE_URI: postgres://postgres:secretpassword@postgres:5432/openfga?sslmode=disable
    depends_on:
      postgres:
        condition: service_healthy

  openfga:
    image: openfga/openfga:latest
    container_name: openfga-server
    command: run
    environment:
      OPENFGA_DATASTORE_ENGINE: postgres
      OPENFGA_DATASTORE_URI: postgres://postgres:secretpassword@postgres:5432/openfga?sslmode=disable
      OPENFGA_HTTP_ADDR: 0.0.0.0:8080
      OPENFGA_GRPC_ADDR: 0.0.0.0:8081
    ports:
      - "8080:8080"
      - "8081:8081"
      - "3000:3000"
    depends_on:
      openfga-migrate:
        condition: service_completed_successfully

volumes:
  pgdata:

Jalankan seluruh service di latar belakang dengan perintah berikut:

docker compose up -d

Setelah container berjalan, OpenFGA HTTP API akan aktif di port 8080, gRPC API di port 8081, dan dashboard UI Playground di port 3000.

2. Merancang Schema Otorisasi (FGA DSL)

OpenFGA memakai bahasa deklaratif yang sederhana (DSL) untuk mendefinisikan hubungan antar objek. Bayangkan kasus berikut: kita ingin mengatur akses folder dan dokumen di aplikasi perusahaan.

  • Objek user bertindak sebagai pengakses.
  • Objek folder punya relasi owner dan viewer. Siapa saja yang menjadi owner otomatis berhak menjadi viewer.
  • Objek doc punya relasi parent yang menunjuk ke folder, serta relasi owner dan viewer. Hak akses viewer pada dokumen bisa didapat secara langsung atau diwarisi otomatis dari folder induknya.

Buat file baru bernama model.fga di server Anda:

model
  schema 1.1

type user

type folder
  relations
    define owner: [user]
    define viewer: [user] or owner

type doc
  relations
    define parent: [folder]
    define owner: [user]
    define viewer: [user] or owner or viewer from parent

3. Membuat Store dan Mengunggah Schema

Kita dapat memanfaatkan alat bantu Curl untuk membuat Store baru di OpenFGA dan mendaftarkan schema yang sudah dirancang tadi.

Jalankan perintah ini untuk membuat Store baru:

curl -X POST http://localhost:8080/stores \
  -H "Content-Type: application/json" \
  -d '{"name": "otorisasi-perusahaan"}'

Response dari API akan mengembalikan JSON yang berisi id store (contoh: 01H8...). Simpan ID tersebut karena akan dipakai untuk langkah selanjutnya.

Selanjutnya, daftarkan schema otorisasi kita menggunakan endpoint penulisan authorization model:

curl -X POST http://localhost:8080/stores/YOUR_STORE_ID/authorization-models \
  -H "Content-Type: application/json" \
  -d '{
    "schema_version": "1.1",
    "type_definitions": [
      {"type": "user"},
      {
        "type": "folder",
        "relations": {
          "owner": {"this": {}},
          "viewer": {"union": {"child": [{"this": {}}, {"computedUserset": {"relation": "owner"}}]}}
        }
      },
      {
        "type": "doc",
        "relations": {
          "parent": {"this": {}},
          "owner": {"this": {}},
          "viewer": {
            "union": {
              "child": [
                {"this": {}},
                {"computedUserset": {"relation": "owner"}},
                {"tupleToUserset": {"tupleset": {"relation": "parent"}, "computedUserset": {"relation": "viewer"}}}
              ]
            }
          }
        }
      }
    ]
  }'

Menulis Data Relasi (Tuples) ke OpenFGA

Di OpenFGA, hak akses tidak disimpan sebagai flag atribut biasa, melainkan berbentuk tuple relasi dengan format: user:siapa#relasi@objek:apa.

Mari masukkan data skenario nyata:

  1. User budi adalah owner dari folder:keuangan.
  2. Dokumen doc:gaji-2024 memiliki parent folder:keuangan.
  3. User siti hanya diberikan akses viewer langsung ke doc:gaji-2024.

Jalankan perintah Curl untuk menulis tuple data ini ke server OpenFGA:

curl -X POST http://localhost:8080/stores/YOUR_STORE_ID/write \
  -H "Content-Type: application/json" \
  -d '{
    "writes": {
      "tuple_keys": [
        {"user": "user:budi", "relation": "owner", "object": "folder:keuangan"},
        {"user": "folder:keuangan", "relation": "parent", "object": "doc:gaji-2024"},
        {"user": "user:siti", "relation": "viewer", "object": "doc:gaji-2024"}
      ]
    }
  }'

Perhatikan hal ajaib di sini: Kita tidak perlu mendaftarkan user:budi secara eksplisit sebagai viewer pada doc:gaji-2024. Karena budi adalah owner folder:keuangan, dan folder tersebut adalah parent dari doc:gaji-2024, OpenFGA secara otomatis mengevaluasi bahwa budi sah menjadi viewer dokumen tersebut berdasarkan aturan hirarki schema yang kita buat.

Integrasi SDK OpenFGA ke Microservice Go

Sekarang saatnya menghubungkan logika otorisasi terpusat ini ke dalam aplikasi backend berbasis Go. Kita akan memanfaatkan SDK resmi Go dari OpenFGA.

1. Inisialisasi Project Go

Buat folder baru untuk project Go Anda, lalu unduh library SDK OpenFGA:

mkdir go-openfga-demo && cd go-openfga-demo
go mod init go-openfga-demo
go get github.com/openfga/go-sdk

2. Membuat Code Client dan Middleware Otorisasi

Buat file main.go dan tuliskan kode berikut. Kode ini menyimulasikan service HTTP backend Go yang mencegat request masuk dan memverifikasi izin akses ke OpenFGA server sebelum merespons client.

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"

	openfga "github.com/openfga/go-sdk"
	"github.com/openfga/go-sdk/client"
)

type AuthzService struct {
	FgaClient *client.OpenFgaClient
}

func NewAuthzService(apiUrl string, storeId string) (*AuthzService, error) {
	configuration := &client.ClientConfiguration{
		ApiUrl:  apiUrl,
		StoreId: storeId,
	}

	fgaClient, err := client.NewSdkClient(configuration)
	if err != nil {
		return nil, err
	}

	return &AuthzService{FgaClient: fgaClient}, nil
}

// CheckAccess mengecek apakah seorang user boleh melakukan aksi terhadap objek tertentu
func (a *AuthzService) CheckAccess(ctx context.Context, user string, relation string, object string) (bool, error) {
	body := client.ClientCheckRequest{
		User:     user,
		Relation: relation,
		Object:   object,
	}

	response, err := a.FgaClient.Check(ctx).Body(body).Execute()
	if err != nil {
		return false, err
	}

	return response.GetAllowed(), nil
}

func main() {
	// Ganti dengan Store ID hasil setup Anda di VPS
	storeID := "YOUR_STORE_ID"
	fgaApiUrl := "http://localhost:8080"

	authz, err := NewAuthzService(fgaApiUrl, storeID)
	if err != nil {
		log.Fatalf("Gagal inisialisasi OpenFGA Client: %v", err)
	}

	// Handler simulasi baca dokumen
	http.HandleFunc("/document/read", func(w http.ResponseWriter, r *http.Request) {
		// Di aplikasi nyata, userID didapat dari parsing token JWT
		userID := r.URL.Query().Get("user_id")
		docID := r.URL.Query().Get("doc_id")

		if userID == "" || docID == "" {
			http.Error(w, "Parameter user_id dan doc_id wajib diisi", http.StatusBadRequest)
			return
		}

		userFormat := fmt.Sprintf("user:%s", userID)
		docFormat := fmt.Sprintf("doc:%s", docID)

		// Terapkan prinsip Zero Trust: selalu verifikasi ke OpenFGA
		allowed, err := authz.CheckAccess(r.Context(), userFormat, "viewer", docFormat)
		if err != nil {
			http.Error(w, "Gagal memproses otorisasi", http.StatusInternalServerError)
			log.Printf("Error check FGA: %v\n", err)
			return
		}

		if !allowed {
			http.Error(w, "Akses Ditolak: Anda tidak memiliki izin membaca dokumen ini", http.StatusForbidden)
			return
		}

		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "Akses Diterima! Selamat datang %s. Berikut isi dokumen %s...", userID, docID)
	})

	log.Println("Server Go berjalan di port 8082...")
	log.Fatal(http.ListenAndServe(":8082", nil))
}

Pengujian Skenario Zero Trust

Jalankan aplikasi backend Go Anda:

go run main.go

Mari kita uji beberapa skenario akses menggunakan perintah cURL di terminal berbeda untuk membuktikan bahwa logika otorisasi ReBAC bekerja sesuai ekspektasi:

Skenario 1: Budi membaca dokumen gaji (Pewarisan Akses)

curl -i "http://localhost:8082/document/read?user_id=budi&doc_id=gaji-2024"

Hasil: HTTP/1.1 200 OK. Budi berhasil mengakses dokumen ini karena Budi adalah owner dari folder induknya, meskipun kita tidak pernah mendaftarkan izin Budi secara langsung di dokumen tersebut.

Skenario 2: Siti membaca dokumen gaji (Akses Langsung)

curl -i "http://localhost:8082/document/read?user_id=siti&doc_id=gaji-2024"

Hasil: HTTP/1.1 200 OK. Siti berhasil membaca dokumen karena ada relasi viewer langsung yang terdaftar untuknya.

Skenario 3: Joko mencoba membobol akses (User Tanpa Relasi)

curl -i "http://localhost:8082/document/read?user_id=joko&doc_id=gaji-2024"

Hasil: HTTP/1.1 403 Forbidden. Server menolak request Joko karena tidak ada relasi langsung maupun tidak langsung yang menghubungkan Joko dengan dokumen tersebut.

Langkah Keamanan & Kesimpulan

Menggeser sistem otorisasi dari RBAC biasa ke ReBAC berbasis OpenFGA membuat arsitektur aplikasi Anda jauh lebih rapi, scalable, dan aman. Logika bisnis otorisasi kini terisolasi sepenuhnya di server OpenFGA. Jika suatu saat tim produk ingin menambahkan aturan baruβ€”misalnya menambahkan role editor atau hak akses terbatas waktuβ€”Anda cukup memperbarui schema FGA tanpa perlu membongkar atau merombak ulang kode microservice Go Anda.

Sebelum menerapkan arsitektur ini ke lingkungan produksi (production VPS), pastikan Anda melakukan langkah-langkah pengamanan ekstra berikut:

  • Amankan Port OpenFGA: Jangan buka port 8080 dan 8081 ke publik secara bebas. Gunakan firewall VPS (UFW) agar port tersebut hanya bisa diakses oleh jaringan internal backend Go Anda.
  • Aktifkan Otentikasi Pihak Ketiga: Konfigurasikan OpenFGA agar membutuhkan token Preshared Key (PSK) atau OIDC/OAuth2 pada setiap request API yang masuk.
  • Gunakan Pre-authorization Caching: Untuk request berfrekuensi sangat tinggi, manfaatkan fitur in-memory cache di Go agar tidak menembak server OpenFGA secara terus-menerus untuk query yang sama.

Sekarang saatnya Anda mencoba sendiri. Ambil salah satu VPS percontohan Anda, jalankan file Docker Compose OpenFGA di atas, dan mulailah membersihkan tumpukan if-else otorisasi di repositori Go Anda sebelum tiket bug Jumat sore kembali menghantui!

A
Aizu Dev

Tim penulis AizuDemy yang menyajikan tutorial teknologi, cloud, dan pengembangan perangkat lunak dalam Bahasa Indonesia.

πŸ“– Artikel Terkait