Private Vault: Membangun "Zero Trust Intelligence" dengan Keamanan Tingkat Baris AlloyDB

1. Ringkasan

Dalam terburu-buru membangun aplikasi AI generatif, kita sering kali melupakan komponen yang paling penting: Keamanan.

Bayangkan Anda sedang membangun Chatbot HR. Anda ingin model menjawab pertanyaan seperti "Berapa gaji saya?" atau "Bagaimana performa tim saya?"

  • Jika Alice (karyawan biasa) bertanya, dia hanya akan melihat datanya.
  • Jika Bob (seorang pengelola) bertanya, dia akan melihat data timnya.

Masalah

Sebagian besar arsitektur RAG (Retrieval Augmented Generation) mencoba menanganinya di Lapisan Aplikasi. Mereka memfilter potongan setelah mengambilnya, atau mengandalkan LLM untuk "berperilaku". Ini rapuh. Jika logika aplikasi gagal, data akan bocor.

Solusi

Mendorong keamanan ke Lapisan Database. Dengan menggunakan Keamanan Tingkat Baris (RLS) PostgreSQL di AlloyDB, kami memastikan bahwa database secara fisik menolak untuk menampilkan data yang tidak boleh dilihat pengguna — apa pun yang diminta AI.

Dalam panduan ini, kita akan membuat "The Private Vault": Asisten HR yang Aman yang mengubah jawabannya secara dinamis berdasarkan siapa yang login.

1e095ac5fe069bb6.png

Arsitektur

Kita tidak membuat logika izin yang kompleks di Python. Kita menggunakan mesin database itu sendiri.

  1. Antarmuka: Aplikasi Streamlit sederhana yang menyimulasikan login.
  2. The Brain: AlloyDB AI (kompatibel dengan PostgreSQL).
  3. Mekanisme: Kami menetapkan variabel sesi (app.active_user) di awal setiap transaksi. Kebijakan database secara otomatis memeriksa tabel user_roles (yang bertindak sebagai Penyedia Identitas kami) untuk memfilter baris.

Yang akan Anda build

Aplikasi Asisten SDM yang aman. Daripada mengandalkan logika aplikasi untuk memfilter data sensitif, Anda akan menerapkan Keamanan Tingkat Baris (RLS) langsung di mesin database AlloyDB. Hal ini memastikan bahwa meskipun model AI Anda berhalusinasi atau mencoba mengakses data yang tidak sah, database akan secara fisik menolak untuk menampilkannya.

Yang akan Anda pelajari

Anda akan mempelajari:

  • Cara mendesain skema untuk RLS (memisahkan Data vs. Identitas).
  • Cara menulis Kebijakan PostgreSQL (CREATE POLICY).
  • Cara melewati pengecualian "Pemilik Tabel" menggunakan FORCE ROW LEVEL SECURITY.
  • Cara membuat aplikasi Python yang melakukan "Pengalihan Konteks" untuk pengguna.

Persyaratan

  • Browser, seperti Chrome atau Firefox.
  • Project Google Cloud yang mengaktifkan penagihan.
  • Akses ke Cloud Shell atau terminal dengan gcloud dan psql yang sudah diinstal.

2. Sebelum memulai

Membuat project

  1. Di Konsol Google Cloud, di halaman pemilih project, pilih atau buat project Google Cloud.
  2. Pastikan penagihan diaktifkan untuk project Cloud Anda. Pelajari cara memeriksa apakah penagihan telah diaktifkan pada suatu project.
  1. Anda akan menggunakan Cloud Shell, lingkungan command line yang berjalan di Google Cloud. Klik Activate Cloud Shell di bagian atas konsol Google Cloud.

Gambar tombol Activate Cloud Shell

  1. Setelah terhubung ke Cloud Shell, Anda dapat memeriksa bahwa Anda sudah diautentikasi dan project sudah ditetapkan ke project ID Anda menggunakan perintah berikut:
gcloud auth list
  1. Jalankan perintah berikut di Cloud Shell untuk mengonfirmasi bahwa perintah gcloud mengetahui project Anda.
gcloud config list project
  1. Jika project Anda belum ditetapkan, gunakan perintah berikut untuk menetapkannya:
gcloud config set project <YOUR_PROJECT_ID>
  1. Aktifkan API yang diperlukan: Ikuti link dan aktifkan API.

Atau, Anda dapat menggunakan perintah gcloud untuk melakukannya. Baca dokumentasi untuk mempelajari perintah gcloud dan penggunaannya.

gcloud services enable \
  alloydb.googleapis.com \
  compute.googleapis.com \
  cloudresourcemanager.googleapis.com \
  servicenetworking.googleapis.com \
  aiplatform.googleapis.com

Gotcha & Pemecahan Masalah

Sindrom "Project Hantu"

Anda menjalankan gcloud config set project, tetapi sebenarnya Anda melihat project lain di UI Konsol. Periksa project ID di dropdown kiri atas.

Penghalang Penagihan

Anda mengaktifkan project, tetapi lupa akun penagihan. AlloyDB adalah mesin berperforma tinggi; mesin ini tidak akan dimulai jika "tangki bahan bakar" (penagihan) kosong.

Keterlambatan Penyebaran API

Anda mengklik "Aktifkan API", tetapi command line masih menampilkan Service Not Enabled. Tunggu 60 detik. Cloud memerlukan waktu beberapa saat untuk mengaktifkan neuronnya.

Quags Kuota

Jika menggunakan akun uji coba yang baru, Anda mungkin mencapai kuota regional untuk instance AlloyDB. Jika us-central1 gagal, coba us-east1.

3. Penyiapan database

Di lab ini, kita akan menggunakan AlloyDB sebagai database untuk data pengujian. Cloud SQL menggunakan cluster untuk menyimpan semua resource, seperti database dan log. Setiap cluster memiliki instance utama yang menyediakan titik akses ke data. Tabel akan menyimpan data sebenarnya.

Mari kita buat cluster, instance, dan tabel AlloyDB tempat set data pengujian akan dimuat.

  1. Klik tombol atau Salin link di bawah ke browser tempat Anda login sebagai pengguna Konsol Google Cloud.

  1. Setelah langkah ini selesai, repo akan di-clone ke editor Cloud Shell lokal Anda dan Anda akan dapat menjalankan perintah di bawah dari folder project (penting untuk memastikan Anda berada di direktori project):
sh run.sh
  1. Sekarang gunakan UI (dengan mengklik link di terminal atau mengklik link "preview on web" di terminal.
  2. Masukkan detail Anda untuk project id, nama cluster, dan nama instance untuk memulai.
  3. Ambil kopi sambil melihat log yang bergulir dan Anda dapat membaca tentang cara kerjanya di balik layar di sini. Proses ini mungkin memerlukan waktu sekitar 10-15 menit.

Gotcha & Pemecahan Masalah

Masalah "Kesabaran"

Cluster database adalah infrastruktur yang berat. Jika Anda memuat ulang halaman atau menghentikan sesi Cloud Shell karena "tampaknya macet", Anda mungkin akan mendapatkan instance "hantu" yang disediakan sebagian dan tidak dapat dihapus tanpa intervensi manual.

Ketidakcocokan Region

Jika Anda mengaktifkan API di us-central1 tetapi mencoba menyediakan cluster di asia-south1, Anda mungkin mengalami masalah kuota atau penundaan izin Akun Layanan. Tetap gunakan satu region untuk seluruh lab.

Cluster Zombie

Jika sebelumnya Anda menggunakan nama yang sama untuk cluster dan tidak menghapusnya, skrip mungkin akan menyatakan bahwa nama cluster sudah ada. Nama cluster harus unik dalam project.

Waktu Tunggu Cloud Shell

Jika istirahat kopi Anda berlangsung selama 30 menit, Cloud Shell mungkin akan memasuki mode tidur dan menghentikan proses sh run.sh. Biarkan tab tetap aktif.

4. Penyediaan Skema

Pada langkah ini, kita akan membahas hal-hal berikut:

d05d7d2706c689dc.png

Berikut adalah tindakan langkah demi langkah yang mendetail:

Setelah cluster dan instance AlloyDB Anda berjalan, buka editor SQL AlloyDB Studio untuk mengaktifkan ekstensi AI dan menyediakan skema.

1e3ac974b18a8113.png

Anda mungkin perlu menunggu hingga instance selesai dibuat. Setelah selesai, login ke AlloyDB menggunakan kredensial yang Anda buat saat membuat cluster. Gunakan data berikut untuk melakukan autentikasi ke PostgreSQL:

  • Nama pengguna : "postgres"
  • Database : "postgres"
  • Sandi : "alloydb" (atau apa pun yang Anda tetapkan pada saat pembuatan)

Setelah Anda berhasil diautentikasi ke AlloyDB Studio, perintah SQL dimasukkan di Editor. Anda dapat menambahkan beberapa jendela Editor menggunakan tanda plus di sebelah kanan jendela terakhir.

28cb9a8b6aa0789f.png

Anda akan memasukkan perintah untuk AlloyDB di jendela editor, menggunakan opsi Jalankan, Format, dan Hapus sesuai kebutuhan.

Membuat tabel

Kita memerlukan dua tabel: satu untuk data sensitif (karyawan) dan satu untuk aturan identitas (user_roles). Memisahkannya sangat penting untuk menghindari error "Infinite Recursion" dalam kebijakan.

Anda dapat membuat tabel menggunakan pernyataan DDL di bawah di AlloyDB Studio:

-- 1. Create User Roles (The Identity Provider)
CREATE TABLE user_roles (
    username TEXT PRIMARY KEY,
    role TEXT -- 'employee', 'manager', 'admin'
);

INSERT INTO user_roles (username, role) VALUES
('Alice', 'employee'),
('Bob', 'manager'),
('Charlie', 'employee');

-- 2. Create the Data Table
CREATE TABLE employees (
    id SERIAL PRIMARY KEY,
    name TEXT,
    salary INTEGER,
    performance_review TEXT
);

INSERT INTO employees (name, salary, performance_review) VALUES
('Alice', 80000, 'Alice meets expectations but needs to improve punctuality.'),
('Bob', 120000, 'Bob is a strong leader. Team morale is high.'),
('Charlie', 85000, 'Charlie exceeds expectations. Ready for promotion.');

Gotcha & Pemecahan Masalah

Rekursi tak terbatas terdeteksi saat menentukan peran di dalam tabel karyawan

Alasan kegagalan: Jika kebijakan Anda menyatakan "Periksa tabel karyawan untuk melihat apakah saya seorang manajer", database harus mengkueri tabel untuk memeriksa kebijakan, yang memicu kebijakan lagi.Hasil: Rekursi tak terbatas terdeteksi.Perbaikan: Selalu simpan tabel lookup terpisah (user_roles) atau gunakan Pengguna Database yang sebenarnya untuk peran.

Verifikasi data:

SELECT count(*) FROM employees;
-- Output: 3

5. Mengaktifkan & Menerapkan Keamanan

Sekarang kita mengaktifkan perisai. Kita juga akan membuat "Pengguna Aplikasi" generik yang akan digunakan kode Python kita untuk terhubung.

Jalankan pernyataan SQL di bawah dari Editor Kueri AlloyDB:

-- 1. Activate RLS
ALTER TABLE employees ENABLE ROW LEVEL SECURITY;


-- 2. CRITICAL: Force RLS for Table Owners
ALTER TABLE employees FORCE ROW LEVEL SECURITY;


-- 3. Create the Application User
DO
$do$
BEGIN
   IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'app_user') THEN
      CREATE ROLE app_user LOGIN PASSWORD 'password';
   END IF;
END
$do$;


-- 4. Grant Access
GRANT SELECT ON employees TO app_user;
GRANT SELECT ON user_roles TO app_user;

Gotcha & Pemecahan Masalah

Menguji sebagai postgres (Pengguna Super) dan melihat semua data.

Alasan kegagalan: Secara default, RLS tidak berlaku untuk pemilik tabel atau pengguna super. Kebijakan ini melewati semua kebijakan.Pemecahan masalah: Jika kebijakan Anda tampak "rusak" (mengizinkan semuanya), periksa apakah Anda login sebagai postgres.Perbaikan: Perintah FORCE ROW LEVEL SECURITY memastikan bahwa bahkan pemilik tunduk pada aturan. Hal ini sangat penting untuk pengujian.

6. Buat Kebijakan Akses

Kita akan menentukan dua aturan menggunakan Variabel Sesi (app.active_user) yang akan kita tetapkan dari kode aplikasi nanti.

Jalankan pernyataan SQL di bawah dari Editor Kueri AlloyDB:

-- Policy 1: Self-View
-- Users can see rows where their name matches the session variable
CREATE POLICY "view_own_data" ON employees
FOR SELECT
USING (name = current_setting('app.active_user', true));

-- Policy 2: Manager-View
-- Managers can see ALL rows.
CREATE POLICY "manager_view_all" ON employees
FOR SELECT
USING (
    EXISTS (
        SELECT 1 FROM user_roles
        WHERE username = current_setting('app.active_user', true)
        AND role = 'manager'
    )
);

Gotcha & Pemecahan Masalah

Menggunakan current_user, bukan app.active_user.

Masalah: Current_user adalah kata kunci SQL yang dicadangkan dan menampilkan peran database (misalnya, app_user). Kita memerlukan pengguna aplikasi (misalnya, Alice).Perbaikan: Selalu gunakan namespace kustom seperti app.variable_name.

Lupa parameter true di current_setting.

Masalah: Jika variabel tidak disetel, kueri akan error.Perbaikan: current_setting('...', true) menampilkan NULL, bukan error, yang dengan aman menghasilkan 0 baris yang ditampilkan.

7. Membangun Aplikasi "Chameleon"

Kita akan menggunakan Python dan Streamlit untuk menyimulasikan logika aplikasi.

296a980887b5c700.png

Buka Terminal Cloud Shell dalam mode Editor, buka folder root Anda atau direktori tempat Anda ingin membuat aplikasi ini. Buat folder baru.

1. Instal Dependensi:

Jalankan perintah berikut di Terminal Cloud Shell dari dalam direktori project baru Anda:

pip install streamlit psycopg2-binary

2. Buat app.py:

Buat file baru bernama app.py dan salin konten dari file repo.

import streamlit as st
import psycopg2

# CONFIGURATION (Replace with your IP)
DB_HOST = "10.x.x.x"
DB_NAME = "postgres"
DB_USER = "postgres"
DB_PASS = "alloydb"

def get_db_connection():
    return psycopg2.connect(
        host=DB_HOST, database=DB_NAME, user=DB_USER, password=DB_PASS
    )

def query_database(user_name):
    conn = get_db_connection()
    try:
        with conn.cursor() as cur:
            # THE SECURITY HANDSHAKE
            # We tell the database: "For this transaction, I am acting as..."
            cur.execute(f"SET app.active_user = '{user_name}';")
            
            # THE BLIND QUERY
            # We ask for EVERYTHING. The database silently filters it.
            cur.execute("SELECT name, role, salary, performance_review FROM employees;")
            return cur.fetchall()
    finally:
        conn.close()

# UI
st.title("🛡️ The Private Vault")
user = st.sidebar.radio("Act as User:", ["Alice", "Bob", "Charlie", "Eve"])

if st.button("Access Data"):
    results = query_database(user)
    if not results:
        st.error("🚫 Access Denied.")
    else:
        st.success(f"Viewing data as {user}")
        for row in results:
            st.write(row)

3. Jalankan aplikasi:

Jalankan perintah berikut di Terminal Cloud Shell dari dalam direktori project baru Anda:

streamlit run app.py --server.port 8080 --server.enableCORS false

Gotcha & Pemecahan Masalah

Penggabungan Koneksi.

Risiko: Jika Anda menggunakan kumpulan koneksi, variabel sesi SET app.active_user mungkin tetap ada di koneksi dan "bocor" ke pengguna berikutnya yang mengambil koneksi tersebut.Perbaikan:Dalam produksi, selalu gunakan RESET app.active_user atau DISCARD ALL saat mengembalikan koneksi ke kumpulan.

Layar Kosong di Cloud Shell.

Perbaikan: Gunakan tombol "Web Preview" di port 8080. Jangan klik link localhost di terminal.

8. Verifikasi Zero Trust

Coba aplikasi untuk memastikan penerapan Zero Trust:

Pilih "Alice": Dia akan melihat 1 baris (Dirinya sendiri).

b3b7e374fa66ac87.png

Pilih "Bob": Dia akan melihat 3 baris (Semua Orang).

fdc65cb1acdee8a4.png

Mengapa hal ini penting bagi Agen AI

Bayangkan menghubungkan model Anda ke database ini. Jika pengguna bertanya kepada model Anda: "Summarize all performance reviews", model akan menghasilkan SELECT performance_review FROM employees.

  1. Tanpa RLS: Model Anda mengambil ulasan pribadi semua orang dan membocorkannya kepada Alice.
  2. Dengan RLS: Model Anda menjalankan kueri yang sama persis, tetapi database hanya menampilkan ulasan Alice.

Ini adalah AI Zero-Trust. Anda tidak memercayai model untuk memfilter data; Anda memaksa database untuk menyembunyikannya.

Menerapkan ini ke Produksi

Arsitektur yang ditunjukkan di sini adalah tingkat produksi, tetapi implementasi spesifiknya disederhanakan untuk pembelajaran. Untuk men-deploy-nya secara aman di lingkungan perusahaan dunia nyata, Anda harus menerapkan peningkatan berikut:

  1. Autentikasi Nyata: Ganti dropdown "Pengganti Identitas" dengan Penyedia Identitas (IDP) yang andal seperti Google Identity Platform, Okta, atau Auth0. Aplikasi Anda harus memverifikasi token pengguna dan mengekstrak identitasnya secara aman sebelum menyetel variabel sesi database, sehingga memastikan pengguna tidak dapat memalsukan identitas mereka.
  2. Keamanan Penggabungan Koneksi: Saat menggunakan kumpulan koneksi, variabel sesi terkadang tetap ada di berbagai permintaan pengguna jika tidak ditangani dengan benar. Pastikan aplikasi Anda mereset variabel sesi (misalnya, RESET app.active_user) atau menghapus status koneksi saat mengembalikan koneksi ke kumpulan untuk mencegah kebocoran data antar-pengguna.
  3. Pengelolaan Secret: Menyandikan kredensial database secara langsung merupakan risiko keamanan. Gunakan layanan pengelolaan secret khusus seperti Google Secret Manager untuk menyimpan dan mengambil sandi database dan string koneksi Anda secara aman saat runtime.

9. Pembersihan

Setelah lab ini selesai, jangan lupa untuk menghapus cluster dan instance AlloyDB.

Tindakan ini akan membersihkan cluster beserta instance-nya.

10. Selamat

Selamat! Anda telah berhasil menurunkan keamanan ke lapisan data. Meskipun kode Python Anda memiliki bug yang mencoba print(all_salaries), database tidak akan menampilkan apa pun kepada Alice.

Langkah Berikutnya