Service Account: ໃຫ້ໂຄ້ດເອີ້ນບໍລິການອື່ນໂດຍບໍ່ຕ້ອງເກັບລະຫັດຜ່ານ

ຕົວຕົນສຳລັບບໍລິການ ແລະ ໂປຣແກຣມຂອງທ່ານ ໃຫ້ສິດເທື່ອລະບໍລິການ ແນວຄິດດຽວກັບ Managed Identity ແລະ App Registration ຂອງ Microsoft Entra ID

ມີ 2 ແບບ

ແບບຂໍ Token ຈາກເໝາະກັບ
ຝັງກັບບໍລິການເຄື່ອງທີ່ບໍລິການແລ່ນຢູ່ ບໍ່ມີ Secret ແລະ ເອີ້ນຈາກພາຍນອກບໍ່ໄດ້ໂຄ້ດໃນ Container ຫຼື Function
Client ID ແລະ Secretບ່ອນໃດກໍໄດ້ດ້ວຍ Secret ບໍລິການກໍເລືອກໃຊ້ໄດ້ເຊັ່ນກັນເຊີບເວີຂອງທ່ານ CI ຫຼື Cloud ອື່ນ

ທຸກ Project ມີ Service Account ແບບຝັງເປັນ ຄ່າເລີ່ມຕົ້ນ 1 ອັນ ທຸກບໍລິການໃຊ້ອັນນີ້ຈົນກວ່າຈະເລືອກອັນອື່ນຕອນສ້າງ ຫຼື ໃນໜ້າຕັ້ງຄ່າ ແລະ ເຮັດຫຍັງບໍ່ໄດ້ຈົນກວ່າຈະໃຫ້ສິດ

ໃຫ້ສິດ

  1. ເປີດ Service Account ໃນ Console ແລ້ວເລືອກ ຫຼື ສ້າງໃໝ່
  2. ທີ່ຫົວຂໍ້ ສິດ ເລືອກບໍລິການ ເລືອກຕົວທີ່ຕ້ອງການ (ຫຼື ທຸກຕົວໃນ Project) ແລະ ລະດັບສິດ
  3. ໃຊ້ໄດ້ພາຍໃນບໍ່ເທົ່າໃດວິນາທີ ບໍລິການທີ່ໃຊ້ Service Account ນີ້ຈະເຂົ້າເຖິງ Database, Cache ຫຼື Container ນັ້ນຜ່ານເຄືອຂ່າຍຂອງ Project ໄດ້ນຳ ເອົາສິດອອກກໍມີຜົນພາຍໃນບໍ່ເທົ່າໃດວິນາທີເຊັ່ນກັນ ເຖິງແມ່ນ Token ທີ່ອອກໄປແລ້ວ
ບໍລິການສິດໂຄ້ດໃຊ້ງານແນວໃດ
Databaseອ່ານຢ່າງດຽວ ອ່ານ ແລະ ຂຽນກົດ Connect ບໍ່ຕ້ອງມີລະຫັດຜ່ານ ຫຼື ໃຊ້ Login ຊົ່ວຄາວຈາກພາຍນອກ
Cacheອ່ານຢ່າງດຽວ ອ່ານ ແລະ ຂຽນກົດ Connect ບໍ່ຕ້ອງມີລະຫັດຜ່ານ ຫຼື ໃຊ້ Login ຊົ່ວຄາວຈາກພາຍນອກ
Object Storageອ່ານ ຂຽນ ລຶບສົ່ງ Token ໄປທີ່ REST API ເຄື່ອງມືແບບ S3 ຍັງຕ້ອງໃຊ້ Access Key
Queueສົ່ງ ຮັບ ຫຼື ທັງສອງຢ່າງ ແລະ ລ້າງຄິວສົ່ງ Token ໄປທີ່ REST API
Container ແລະ Functionເອີ້ນໃຊ້ສົ່ງ Token ທີ່ອອກໃຫ້ບໍລິການນັ້ນໄປທີ່ທີ່ຢູ່ສາທາລະນະຂອງມັນ

Database ແລະ Cache: ກົດ Connect

ໃນໜ້າ Container ຫຼື Function ເປີດແທັບ ເຊື່ອມຕໍ່ ເລືອກປາຍທາງ ແລະ ສິດ ແລ້ວກົດ Connect ລະບົບເພີ່ມຕົວແປ DATABASE_URL ຫຼື REDIS_URL ທີ່ບໍ່ມີລະຫັດຜ່ານ ໂຄ້ດໃຊ້ URL ນີ້ກັບ driver ໄດ້ຕາມປົກກະຕິ ເຄື່ອງທີ່ແລ່ນຢູ່ຈະ Login ໃຫ້ ບໍ່ມີລະຫັດຜ່ານຢູ່ໃນຕົວແປ ໃນໂຄ້ດ ຫຼື ໃນໜ້າ Console ແລະ URL ໃຊ້ໄດ້ສະເພາະຈາກໃນ Service ນັ້ນ

Dev ທີ່ Deploy ໄດ້ຍັງອ່ານຂໍ້ມູນຜ່ານ connection ນີ້ໄດ້ ຖ້າບໍ່ຕ້ອງການໃຫ້ເຫັນຂໍ້ມູນຈິງ ໃຫ້ແຍກ Production ເປັນອີກ Project ລະຫັດຜ່ານຫຼັກຂອງຖານຂໍ້ມູນເບິ່ງໄດ້ສະເພາະ Owner ແລະ Admin

ໂປຣແກຣມນອກລະບົບໃຊ້ Service Account ແບບມີ Client ID ແລະ Secret ແລກ Token ເປັນ Login ຊົ່ວຄາວຕາມຕົວຢ່າງດ້ານລຸ່ມ ໂຄ້ດໃນ Container ຫຼື Function ແລກບໍ່ໄດ້

SDK

ພາສາຕ້ອງການຕິດຕັ້ງ
Node.js18.17+npm install @thailandhosting/identity
Python3.9+pip install thailandhosting-identity
Go1.23+go get github.com/mrzack99s/thailandhosting-identity-sdk-go
Node.js
import { defaultCredential } from '@thailandhosting/identity';
import { Client as Queues } from '@thailandhosting/queue-service';

// In a Container or Function this needs nothing. Elsewhere set
// TH_CLIENT_ID and TH_CLIENT_SECRET.
const cred = defaultCredential();

const queues = new Queues({ region: 'th-bkk-1', tokenProvider: () => cred.getToken() });

// From outside the platform. In a Container or Function, click Connect instead.
const login = await cred.databaseCredentials('orders');
const pool = new pg.Pool({ connectionString: login.private.url });
Python
from thailandhosting_identity import default_credential
from thailandhosting_queueservice import Client as Queues

# In a Container or Function this needs nothing. Elsewhere set
# TH_CLIENT_ID and TH_CLIENT_SECRET.
cred = default_credential()

queues = Queues(region="th-bkk-1", token_provider=cred.get_token)

# From outside the platform. In a Container or Function, click Connect instead.
login = cred.database_credentials("orders")
conn = psycopg.connect(login["private"]["url"])
Go
import identity "github.com/mrzack99s/thailandhosting-identity-sdk-go"

// In a Container or Function this needs nothing. Elsewhere set
// TH_CLIENT_ID and TH_CLIENT_SECRET.
cred, err := identity.Default()

queues, err := queueservice.New(queueservice.Config{Region: "th-bkk-1", TokenSource: cred.TokenSource("")})

// From outside the platform. In a Container or Function, click Connect instead.
login, err := cred.DatabaseCredentials(ctx, "orders")
db, err := sql.Open("pgx", login.Private.URL)

ພາສາອື່ນ: ເອີ້ນ HTTP ໂດຍກົງ

ຈາກໃນ Container ຫຼື Function ໃຫ້ຖາມເຄື່ອງທີ່ແລ່ນຢູ່ ຄຳຂໍຕ້ອງມີ Metadata: true ເກັບຄຳຕອບໄວ້ໃຊ້ຈົນໃກ້ຮອດ expires_on

Shell
# Inside a Container or Function. The address answers only there.
curl -H 'Metadata: true' http://169.254.169.254/identity/oauth2/token

# For calling another Container, name it as the audience:
curl -H 'Metadata: true' 'http://169.254.169.254/identity/oauth2/token?audience=https://orders.containers.th-bkk-1.thailandhosting.com'

# {"access_token":"eyJ...","token_type":"Bearer","expires_in":3600,"expires_on":1793355792,"client_id":"sa-..."}

ຖ້າໃຊ້ Client ID ແລະ Secret ໃຫ້ຂໍຈາກ Token Endpoint:

Shell
# From anywhere, with a client ID and secret (OAuth 2.0 client credentials).
curl https://api.thailandhosting.com/v1/identity/token \
  -d grant_type=client_credentials \
  -d client_id=$TH_CLIENT_ID \
  -d client_secret=$TH_CLIENT_SECRET

ແລ້ວນຳ Token ໄປໃຊ້:

Shell
# Queue Service and Object Storage: send the token as a bearer.
curl -H "Authorization: Bearer $TOKEN" https://queues.thailandhosting.com/th-bkk-1/v1/queues/jobs/messages -d '{"body":"hello"}'

# Database or Cache, from outside the platform: exchange the token for a login.
# In a Container or Function, click Connect and use the URL it adds instead.
curl -H "Authorization: Bearer $TOKEN" https://api.thailandhosting.com/v1/identity/database-credentials -d '{"database":"orders"}'
# {"username":"sa_...","password":"...","database":"orders","expiresAt":"...","private":{"host":"orders.internal","port":5432,"url":"postgresql://..."}}

# Another Container or Function: a token made for its address.
curl -H "Authorization: Bearer $TOKEN" https://orders.containers.th-bkk-1.thailandhosting.com/items

ຄຳຂໍດຽວກັນໃນພາສາອື່ນ:

Shell
<?php // PHP, inside a Container or Function
$ctx = stream_context_create(['http' => ['header' => "Metadata: true\r\n"]]);
$token = json_decode(file_get_contents('http://169.254.169.254/identity/oauth2/token', false, $ctx))->access_token;
Shell
// Java 11+, inside a Container or Function
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("http://169.254.169.254/identity/oauth2/token"))
    .header("Metadata", "true").build();
var body = client.send(request, HttpResponse.BodyHandlers.ofString()).body();
// Read access_token and expires_on with your JSON library.
Shell
// C#, inside a Container or Function
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("Metadata", "true");
var body = await http.GetStringAsync("http://169.254.169.254/identity/oauth2/token");
var token = JsonDocument.Parse(body).RootElement.GetProperty("access_token").GetString();
Shell
# Ruby, inside a Container or Function
require 'net/http'; require 'json'
uri = URI('http://169.254.169.254/identity/oauth2/token')
token = JSON.parse(Net::HTTP.get(uri, 'Metadata' => 'true'))['access_token']

ກວດ Token ທີ່ຄົນອື່ນສົ່ງມາ

SDK ມີ Verifier ໃຫ້ Token ອອກໃຫ້ຜູ້ຮັບ (audience) ຄົນດຽວ ຈຶ່ງຕ້ອງກວດວ່າເປັນຂອງທ່ານ Token ທີ່ສົ່ງໃຫ້ບໍລິການອື່ນຈະໄດ້ນຳມາໃຊ້ກັບບໍລິການຂອງທ່ານບໍ່ໄດ້ ລະບົບກວດ Token ໃຫ້ສະເພາະທີ່ທີ່ຢູ່ສາທາລະນະຂອງ Container ຖ້າເອີ້ນໂດຍກົງຜ່ານເຄືອຂ່າຍຂອງ Project ໃຫ້ກວດໃນໂຄ້ດຂອງທ່ານ

Shell
# Published keys (JWKS) and discovery, for any JWT library:
https://api.thailandhosting.com/v1/identity/keys
https://api.thailandhosting.com/v1/identity/.well-known/openid-configuration
# Check: alg ES256, iss https://api.thailandhosting.com/v1/identity, aud your own name, exp, nbf.

Token ໃຊ້ໄດ້ 1 ຊົ່ວໂມງ ໃຜໄດ້ໄປກໍໃຊ້ໄດ້ຈົນໝົດອາຍຸເຖິງແມ່ນຈາກພາຍນອກ ຢ່າຂຽນລົງ Log ແລະ ຢ່າສົ່ງໃຫ້ບໍລິການທີ່ບໍ່ໄວ້ໃຈ

ຖ້າພົບບັນຫາ

ໄດ້ 403 ຫຼື no_identity ຈາກທີ່ຢູ່ຂອງ Identity

ສະເພາະ Container ແລະ Function ທີ່ຂໍ Token ທີ່ນີ້ໄດ້ ເວັບໄຊ Database Cache ແລະ Mail ບໍ່ໄດ້ແລ່ນໂຄ້ດຂອງທ່ານຈຶ່ງຂໍບໍ່ໄດ້

ເຊື່ອມຕໍ່ 169.254.169.254 ບໍ່ໄດ້

ໂຄ້ດບໍ່ໄດ້ແລ່ນໃນ Container ຫຼື Function ຖ້າແລ່ນເທິງເຄື່ອງຂອງທ່ານ ໃຫ້ໃຊ້ແບບ Client ID ແລະ Secret ແລ້ວຕັ້ງ TH_CLIENT_ID ແລະ TH_CLIENT_SECRET

Login ຂອງຖານຂໍ້ມູນໃຊ້ບໍ່ໄດ້ແລ້ວ

Login ມີອາຍຸເປັນຊົ່ວໂມງ ໃຫ້ຂໍໃໝ່ ສ່ວນ Connection ທີ່ເປີດຢູ່ຍັງໃຊ້ຕໍ່ໄດ້

ຍັງແກ້ບໍ່ໄດ້? ໃຫ້ທີມງານຊ່ວຍ

ເປີດ ticket ຈາກໜ້າຈັດການ ບອກຊື່ເວັບ ຫຼື ບໍລິການ ສິ່ງທີ່ເຮັດ ແລະ ຂໍ້ຄວາມທີ່ເຫັນເທິງຈໍ ທີມງານຈະຕອບກັບໃນເລື່ອງດຽວກັນ ຕິດຕາມໄດ້ໃນບ່ອນດຽວ