Integrasi

Integrasi HashiCorp Vault untuk Manajemen API Key CaptchaAI

Kunci API yang di-hardcode dalam kode sumber merupakan tanggung jawab keamanan. HashiCorp Vault memusatkan manajemen rahasia – milik AndaCaptchaAIKunci API disimpan terenkripsi, diambil saat runtime, dan setiap akses dicatat. Panduan ini menunjukkan cara mengintegrasikan Vault ke dalam alur penyelesaian CAPTCHA Anda.

Mengapa Vault untuk Kunci API CAPTCHA

Tanpa Gudang Dengan Gudang
Kunci API dalam file atau kode .env Kunci disimpan terenkripsi di Vault
Kunci dibagikan melalui Slack atau email Akses melalui API yang diautentikasi
Tidak ada jejak audit akses Setiap pembacaan dicatat dengan identitas
Rotasi kunci manual Dukungan rotasi otomatis
Kunci yang sama di seluruh lingkungan Kunci per lingkungan dengan kebijakan

Prasyarat

  • Server HashiCorp Vault (dihosting sendiri atau HCP Vault)
  • Akses Vault CLI atau API
  • Kunci API CaptchaAI
  • Python 3.8+ atau Node.js 18+

Simpan Kunci API di Vault

# Enable the KV secrets engine (if not already enabled)
vault secrets enable -path=secret kv-v2

# Store the CaptchaAI API key
vault kv put secret/captchaai api_key="YOUR_API_KEY"

# Verify
vault kv get secret/captchaai

Buat Kebijakan Vault

Batasi pekerja CAPTCHA untuk akses hanya baca:

# captcha-worker-policy.hcl
path "secret/data/captchaai" {
  capabilities = ["read"]
}

path "secret/metadata/captchaai" {
  capabilities = ["read"]
}

Terapkan kebijakan:

vault policy write captcha-worker captcha-worker-policy.hcl

Integrasi Python

# vault_solver.py
import os
import time
import hvac
import requests

# Connect to Vault
vault_client = hvac.Client(
    url=os.environ.get("VAULT_ADDR", "http://127.0.0.1:8200"),
    token=os.environ.get("VAULT_TOKEN"),
)

def get_api_key():
    """Retrieve CaptchaAI API key from Vault."""
    secret = vault_client.secrets.kv.v2.read_secret_version(
        path="captchaai",
        mount_point="secret",
    )
    return secret["data"]["data"]["api_key"]

class CaptchaSolver:
    """CAPTCHA solver with Vault-managed credentials."""

    def __init__(self):
        self.api_key = get_api_key()
        self.session = requests.Session()
        self._key_fetched_at = time.time()
        self._key_refresh_interval = 3600  # Re-fetch key hourly

    def _refresh_key_if_needed(self):
        """Periodically refresh the key from Vault."""
        if time.time() - self._key_fetched_at > self._key_refresh_interval:
            self.api_key = get_api_key()
            self._key_fetched_at = time.time()

    def solve(self, sitekey, pageurl):
        """Solve reCAPTCHA v2 using Vault-managed key."""
        self._refresh_key_if_needed()

        # Submit
        resp = self.session.get("https://ocr.captchaai.com/in.php", params={
            "key": self.api_key,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": pageurl,
            "json": "1",
        })
        result = resp.json()

        if result.get("status") != 1:
            raise Exception(f"Submit failed: {result.get('request')}")

        task_id = result["request"]
        time.sleep(15)

        for _ in range(25):
            poll = self.session.get("https://ocr.captchaai.com/res.php", params={
                "key": self.api_key,
                "action": "get",
                "id": task_id,
                "json": "1",
            })
            poll_result = poll.json()

            if poll_result.get("status") == 1:
                return poll_result["request"]
            if poll_result.get("request") != "CAPCHA_NOT_READY":
                raise Exception(f"Error: {poll_result.get('request')}")

            time.sleep(5)

        raise Exception("Timeout")

# Usage
solver = CaptchaSolver()
token = solver.solve(
    "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
    "https://www.google.com/recaptcha/api2/demo"
)
print(f"Token: {token[:30]}...")

Integrasi JavaScript

// vault_solver.js
const axios = require('axios');

const VAULT_ADDR = process.env.VAULT_ADDR || 'http://127.0.0.1:8200';
const VAULT_TOKEN = process.env.VAULT_TOKEN;

async function getApiKey() {
  const resp = await axios.get(
    `${VAULT_ADDR}/v1/secret/data/captchaai`,
    { headers: { 'X-Vault-Token': VAULT_TOKEN } }
  );
  return resp.data.data.data.api_key;
}

class CaptchaSolver {
  constructor() {
    this.apiKey = null;
    this.keyFetchedAt = 0;
    this.refreshInterval = 3600000; // 1 hour
  }

  async init() {
    this.apiKey = await getApiKey();
    this.keyFetchedAt = Date.now();
  }

  async refreshKeyIfNeeded() {
    if (Date.now() - this.keyFetchedAt > this.refreshInterval) {
      this.apiKey = await getApiKey();
      this.keyFetchedAt = Date.now();
    }
  }

  async solve(sitekey, pageurl) {
    await this.refreshKeyIfNeeded();

    const submit = await axios.get('https://ocr.captchaai.com/in.php', {
      params: {
        key: this.apiKey, method: 'userrecaptcha',
        googlekey: sitekey, pageurl, json: '1',
      },
    });

    if (submit.data.status !== 1) throw new Error(submit.data.request);
    const taskId = submit.data.request;

    await new Promise(r => setTimeout(r, 15000));

    for (let i = 0; i < 25; i++) {
      const poll = await axios.get('https://ocr.captchaai.com/res.php', {
        params: { key: this.apiKey, action: 'get', id: taskId, json: '1' },
      });

      if (poll.data.status === 1) return poll.data.request;
      if (poll.data.request !== 'CAPCHA_NOT_READY') throw new Error(poll.data.request);
      await new Promise(r => setTimeout(r, 5000));
    }
    throw new Error('Timeout');
  }
}

(async () => {
  const solver = new CaptchaSolver();
  await solver.init();

  const token = await solver.solve(
    '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
    'https://www.google.com/recaptcha/api2/demo'
  );
  console.log(`Token: ${token.slice(0, 30)}...`);
})();

Metode Otentikasi

Vault mendukung beberapa metode autentikasi untuk pekerja:

Metode Terbaik Untuk Pengaturan
Tanda Pengembangan, CI/CD VAULT_TOKEN env var
Peran Aplikasi Layanan produksi ID Peran + ID Rahasia
Kubernet beban kerja K8 Akun layanan JWT
AWS IAM Pekerja EC2/Lambda Peran contoh

Contoh AppRole (Direkomendasikan untuk Produksi)

# AppRole authentication — no static token needed
vault_client = hvac.Client(url=os.environ["VAULT_ADDR"])
vault_client.auth.approle.login(
    role_id=os.environ["VAULT_ROLE_ID"],
    secret_id=os.environ["VAULT_SECRET_ID"],
)

# Now read the secret
secret = vault_client.secrets.kv.v2.read_secret_version(path="captchaai")
api_key = secret["data"]["data"]["api_key"]

Alur Kerja Rotasi Kunci

  1. Hasilkan kunci API CaptchaAI baru di dashboard CaptchaAI
  2. Perbarui Gudang: vault kv put secret/captchaai api_key="NEW_KEY"
  3. Pekerja secara otomatis mengambil kunci baru pada siklus penyegaran berikutnya
  4. Cabut kunci lama di dashboard CaptchaAI setelah semua pekerja melakukan penyegaran

Tidak diperlukan perubahan atau penerapan kode.

Pemecahan masalah

Masalah Sebab Perbaiki
403 Forbidden dari Vault Kebijakan tidak mengizinkan membaca Periksa jalur captcha-worker-policy.hcl
VAULT_TOKEN expiry Token TTL terlampaui Gunakan AppRole untuk token yang dapat diperpanjang secara otomatis
Kunci tidak menyegarkan Interval penyegaran terlalu lama Kurangi _key_refresh_interval
Gudang tidak tersedia Masalah jaringan atau server Kunci cache secara lokal dengan fallback

Pertanyaan Umum

Apa yang terjadi jika Vault tidak aktif?

Simpan kunci API dalam cache di memori saat pertama kali diambil. Jika Vault tidak tersedia selama penyegaran, terus gunakan kunci cache dan catat kegagalannya.

Haruskah saya menyimpan satu kunci per lingkungan?

Ya. Gunakan jalur Vault terpisah: secret/captchaai/dev, secret/captchaai/staging, secret/captchaai/prod.

Bisakah saya menggunakan AWS Secrets Manager alih-alih Vault?

Ya. Polanya identik – mengambil rahasia saat runtime dari AWS Secrets Manager menggunakan boto3 Prinsip intinya (tanpa kunci hardcode, rotasi tanpa penerapan) tetap sama.

Artikel Terkait

Langkah Selanjutnya

Amankan kredensial CaptchaAI Anda dengan Vault —dapatkan kunci API Anda.

Panduan terkait:

  • Rotasi Kunci API
  • Mengamankan Kredensial di Env Vars
  • Daftar Putih IP
Komentar dinonaktifkan untuk artikel ini.