İçeriğe atla

2026-03-22

SaaS Yetkilendirme için AWS Cognito + Verified Permissions

AWS Cognito ve Verified Permissions ile SaaS yetkilendirme mimarisi. Cedar politika dili, çok kiracılı desenler, JWT token akışı, maliyet analizi ve TypeScript örnekleriyle yaygın hatalar.

Abstract

AWS Cognito kimlik doğrulamayı yönetir. AWS Verified Permissions (AVP) yetkilendirmeyi yönetir. Birlikte AWS’nin yerel SaaS yetkilendirme altyapısını oluşturur. Bu yazıda iki servisin nasıl entegre edildiğini, Cedar politikalarının kiracı izolasyonunu nasıl sağladığını ve B2B SaaS ürünleri için çok kiracılı yetkilendirmenin nasıl yapılandırılacağını inceliyoruz. TypeScript entegrasyon kodu, Cedar politika örnekleri, maliyet analizi ve Microsoft Entra ID yaklaşımıyla bir karşılaştırma içerir.

Note: Bu yazı Harici Yetkilendirme Sistemleri serisinin 2. bölümüdür. 1. bölüm, daha geniş yetkilendirme platformu haritasını ve karar çerçevesini kapsar.

Cognito’nun Yetkilendirmedeki Rolü

Cognito bir kimlik doğrulama servisidir, yetkilendirme motoru değildir. Ancak kimlik doğrulama ve yetkilendirme SaaS sistemlerinde sıkı sıkıya bağlıdır. Cognito’nun çıktısı — claim’ler içeren JWT token’lar — yetkilendirme kararlarının girdisi olur.

JWT Token’lar ve Claim’ler

Kullanıcı kimliğini doğruladıktan sonra Cognito üç token verir:

  • ID Token: Kullanıcı kimlik claim’lerini içerir (e-posta, ad, özel nitelikler). Kullanıcı profil bilgileri için kullanılır.
  • Access Token: Scope’lar ve yetkilendirmeyle ilgili claim’leri içerir. API yetkilendirmesi için kullanılır.
  • Refresh Token: Yeniden kimlik doğrulama olmadan yeni ID ve access token almak için kullanılır.

Yetkilendirme açısından access token en önemlisidir. AVP Cedar politikalarının değerlendirdiği claim’leri taşır.

Özel Claim’ler ve Kiracı Bağlamı

Cognito, kullanıcı profillerinde özel nitelikler destekler (custom: ön ekiyle). SaaS için kritik özel nitelikler, kiracı tanımlayıcıları ve organizasyon rolleridir:

  • custom:tenantId — Kullanıcının ait olduğu kiracı
  • custom:orgRole — Kullanıcının kiracı içindeki rolü (admin, editor, viewer)
  • custom:tenantTier — Kiracının abonelik katmanı (free, pro, enterprise)

Bu nitelikler kullanıcı kaydı sırasında veya bir admin API’si aracılığıyla ayarlanır. Kullanıcı tarafından değiştirilemez (uygulama istemcisinde salt okunur) ve kimlik doğrulamadan sonra JWT token’lara dahil edilir.

Pre Token Generation Trigger

Pre Token Generation Lambda trigger’ı, Cognito ile AVP arasındaki anahtar entegrasyon noktasıdır. Cognito access token’ı vermeden önce çalışır ve Cedar politikalarının tükettiği ek claim’lerle token’ı zenginleştirmenize olanak tanır.

// Pre Token Generation V2 trigger -- token'ları kiracı bağlamıyla zenginleştir
// Cognito, access token'ı vermeden önce bu Lambda'yı çağırır

import { PreTokenGenerationV2TriggerEvent } from "aws-lambda";

export const handler = async (
  event: PreTokenGenerationV2TriggerEvent
) => {
  const tenantId = event.request.userAttributes["custom:tenantId"];
  const orgRole = event.request.userAttributes["custom:orgRole"];
  const tenantTier = event.request.userAttributes["custom:tenantTier"];

  // Kiracı bağlamını claim olarak ekle -- AVP Cedar politikaları bunları okur
  event.response = {
    claimsAndScopeOverrideDetails: {
      accessTokenGeneration: {
        claimsToAddOrOverride: {
          tenantId: tenantId,
          orgRole: orgRole,
          tenantTier: tenantTier,
        },
        scopesToAdd: orgRole === "admin" ? ["tenant:admin"] : [],
      },
    },
  };

  return event;
};

Tip: Özel claim’leri minimal tutun. Her ek claim token boyutunu artırır. Cognito access token’larının boyut limiti vardır ve şişkin token’lar her API çağrısına gecikme ekler. Yalnızca Cedar politikalarının aktif olarak değerlendirdiği claim’leri dahil edin.

User Pool vs. Identity Pool

Cognito’nun farklı amaçlara hizmet eden iki bileşeni vardır:

  • User Pool: Kullanıcı kimlik doğrulamasını yönetir (kayıt, giriş, MFA, parola kurtarma). JWT token’ları verir. Kiracı bağlamı burada yaşar.
  • Identity Pool: Kimliği doğrulanmış kullanıcıları geçici AWS kimlik bilgilerine (IAM rolleri) eşler. Doğrudan AWS kaynak erişimi (S3, DynamoDB) için kullanılır.

AVP ile SaaS yetkilendirmesi için öncelikle User Pool kullanılır. Identity Pool yalnızca uygulamanızın istemci tarafından doğrudan AWS kaynak erişimine ihtiyacı varsa geçerlidir.

AWS Verified Permissions Derinlemesine İnceleme

AVP, Cedar politika dilini kullanan yönetilen bir yetkilendirme servisidir. Yetkilendirme isteklerini Cedar politikalarına göre değerlendirir ve izin ver veya reddet kararları döndürür.

Cedar Politika Dili

Cedar bildirimsel, statik olarak analiz edilebilir ve formal olarak doğrulanmıştır. Politikalar kimin (principal) ne yapabileceğini (action) hangi kaynağa (resource) hangi koşullar altında ifade eder.

Temel bir Cedar politikası:

// Kiracı yöneticilerinin kendi kiracılarındaki tüm kaynakları yönetmesine izin ver
permit(
  principal,
  action in [Action::"ViewReport", Action::"EditReport", Action::"DeleteReport"],
  resource
)
when {
  principal.orgRole == "admin" &&
  principal.tenantId == resource.tenantId
};

Cedar iki politika türünü destekler:

  • permit: Koşullar eşleştiğinde erişim verir
  • forbid: Bir permit politikası eşleşse bile erişimi reddeder (forbid her zaman kazanır)

Bu “reddet, izni geçersiz kılar” modeli güvenlik kısıtlamaları eklemeyi basitleştirir:

// Rolden bağımsız olarak arşivlenmiş kaynaklara erişimi yasakla
forbid(
  principal,
  action,
  resource
)
when {
  resource.status == "archived"
};

Şema Tanımı

AVP, varlık türlerinizi, niteliklerini ve geçerli eylem-varlık kombinasyonlarını tanımlamak için bir Cedar şeması kullanır. Şema isteğe bağlıdır ancak üretim ortamı için kesinlikle önerilir. Politika oluşturma zamanında doğrulama sağlayarak, yazım hatalarını ve yapısal hataları üretime ulaşmadan yakalar.

{
  "SaasApp": {
    "entityTypes": {
      "User": {
        "shape": {
          "type": "Record",
          "attributes": {
            "tenantId": { "type": "String", "required": true },
            "orgRole": { "type": "String", "required": true },
            "tenantTier": { "type": "String", "required": true },
            "email": { "type": "String", "required": true }
          }
        },
        "memberOfTypes": ["TenantGroup"]
      },
      "TenantGroup": {
        "shape": {
          "type": "Record",
          "attributes": {
            "tenantId": { "type": "String", "required": true }
          }
        }
      },
      "Document": {
        "shape": {
          "type": "Record",
          "attributes": {
            "tenantId": { "type": "String", "required": true },
            "ownerId": { "type": "String", "required": true },
            "status": { "type": "String", "required": true },
            "sensitivity": { "type": "String", "required": false }
          }
        }
      }
    },
    "actions": {
      "ViewDocument": {
        "appliesTo": {
          "principalTypes": ["User"],
          "resourceTypes": ["Document"]
        }
      },
      "EditDocument": {
        "appliesTo": {
          "principalTypes": ["User"],
          "resourceTypes": ["Document"]
        }
      },
      "DeleteDocument": {
        "appliesTo": {
          "principalTypes": ["User"],
          "resourceTypes": ["Document"]
        }
      }
    }
  }
}

Policy Store Yapılandırması

Policy store, Cedar şemanız, politikalarınız ve kimlik kaynağı yapılandırmanızın konteyneridir. Temel mimari karar, kiracı başına bir policy store mu yoksa tüm kiracılar için paylaşımlı bir policy store mu kullanılacağıdır.

SaaS Çok Kiracılı Desenler

Çok kiracılık, SaaS yetkilendirmesindeki temel zorluktur. Soru, kiracıları birbirinden nasıl izole edecek ve yetkilendirme altyapısını yönetilebilir tutmaktır.

Pool Modeli vs. Silo Modeli

Silo Modeli

User Pool

Kiraci A

Policy Store

Kiraci A

User Pool

Kiraci B

Policy Store

Kiraci B

Pool Modeli

Tek

User Pool

Paylasimli

Policy Store

Pool modeli: custom:tenantId niteliğiyle tek Cognito User Pool. Kiracı kapsamlı Cedar politikalarıyla tek AVP policy store.

  • Yönetmesi ve dağıtması daha basit
  • Daha düşük maliyet (tek User Pool, tek policy store)
  • Kiracı izolasyonu Cedar politika seviyesinde sağlanır
  • Çoğu B2B SaaS ürünü için yeterli
  • Risk: bir politika hatası kiracılar arası veri sızıntısına yol açabilir

Silo modeli: Kiracı başına ayrı User Pool ve policy store.

  • Daha güçlü izolasyon sınırı (altyapı seviyesinde ayrım)
  • Uyumluluk gereksinimleri yoğun sektörler için gerekli (sağlık, finans, kamu)
  • Daha yüksek operasyonel yük ve maliyet
  • Her kiracının özelleştirilmiş politikaları olabilir
  • Daha karmaşık dağıtım ve yönetim

Tip: Pool modeliyle başlayın. Çoğu durumu iyi yönetir. Silo modeline yalnızca uyumluluk veya sözleşme gereksinimleri altyapı seviyesinde kiracı izolasyonu talep ettiğinde geçin.

Çok Kiracılık için Cedar Politikaları

Pool modelinde, kiracı izolasyonu tamamen politika güdümlüdür. Her kaynak erişim politikası bir kiracı kontrolü içermelidir:

// Temel politika: belge görüntüleme için kiracı izolasyonu
// Her kaynak politikası tenantId eşleşmesini doğrulamalı
permit(
  principal,
  action == Action::"ViewDocument",
  resource is SaasApp::Document
)
when {
  principal.tenantId == resource.tenantId &&
  principal.orgRole in ["admin", "editor", "viewer"]
};

// Editörler kendi kiracılarındaki belgeleri değiştirebilir
permit(
  principal,
  action == Action::"EditDocument",
  resource is SaasApp::Document
)
when {
  principal.tenantId == resource.tenantId &&
  principal.orgRole in ["admin", "editor"]
};

// Yalnızca yöneticiler belgeleri silebilir
permit(
  principal,
  action == Action::"DeleteDocument",
  resource is SaasApp::Document
)
when {
  principal.tenantId == resource.tenantId &&
  principal.orgRole == "admin"
};

Katman bazlı özellik sınırlama için Cedar politikaları kiracı katmanını kontrol edebilir:

// Yalnızca enterprise kiracılar gelişmiş analizlere erişebilir
permit(
  principal,
  action == Action::"ViewAdvancedAnalytics",
  resource
)
when {
  principal.tenantId == resource.tenantId &&
  principal.tenantTier == "enterprise"
};

Kiracılar Arası Erişim

Bazı SaaS ürünleri kontrollü kiracılar arası erişime ihtiyaç duyar — örneğin, birden fazla müşteri kiracısına erişen bir danışman. Bu, açık kiracılar arası politikalar gerektirir:

// Açık paylaşım yoluyla kiracılar arası erişime izin ver
// Bu politika yalnızca sharedTenants niteliğine sahip kullanıcılar için geçerlidir
permit(
  principal,
  action == Action::"ViewDocument",
  resource is SaasApp::Document
)
when {
  resource.tenantId in principal.sharedTenants
};

Warning: Kiracılar arası politikalar güçlü ve risklidir. Standart kiracı izolasyon sınırını aşarlar. Bunları dikkatle gözden geçirin ve özel entegrasyon testleriyle test edin.

Entegrasyon Mimarisi

Aşağıdaki diyagram, Cognito token’larının yetkilendirme kararları için AVP’ye nasıl ulaştığını gösterir.

Istemci

Uygulama

API

Gateway

Cognito

Authorizer

Lambda

Fonksiyonu

Verified

Permissions

Izin Ver

veya Reddet

Akış iki katmanlı çalışır:

  1. API Gateway + Cognito Authorizer (kaba taneli): JWT token’ı doğrular, kullanıcının kimliğinin doğrulandığını ve token’ın süresinin dolmadığını kontrol eder. Kimliği doğrulanmamış istekleri Lambda’ya ulaşmadan reddeder.
  2. Lambda + AVP (ince taneli): Doğrulanmış token’dan kiracı bağlamını çıkarır, principal, action ve resource ile AVP’yi çağırır. AVP Cedar politikalarını değerlendirir ve izin ver veya reddet döndürür.

JWT Çıkarma ve Kiracı Bağlamı

// Doğrulanmış Cognito JWT'den kiracı bağlamını çıkar
// API Gateway Cognito Authorizer token'ı zaten doğrulamıştır

import { APIGatewayProxyEventV2WithJWTAuthorizer } from "aws-lambda";

interface TenantContext {
  userId: string;
  tenantId: string;
  orgRole: string;
  tenantTier: string;
  email: string;
}

function extractTenantContext(
  event: APIGatewayProxyEventV2WithJWTAuthorizer
): TenantContext {
  const claims = event.requestContext.authorizer.jwt.claims;

  return {
    userId: claims.sub as string,
    tenantId: claims.tenantId as string,
    orgRole: claims.orgRole as string,
    tenantTier: claims.tenantTier as string,
    email: claims.email as string,
  };
}

IsAuthorized ve IsAuthorizedWithToken

AVP iki yetkilendirme API’si sağlar:

  • IsAuthorized: Principal varlığını manuel olarak oluşturursunuz. Çağıran bir backend servisi olduğunda, JWT’si olan bir kullanıcı olmadığında kullanışlıdır.
  • IsAuthorizedWithToken: Ham Cognito JWT token’ını geçersiniz. AVP token’ı doğrular ve principal’ı otomatik olarak çıkarır. Kullanıcıya yönelik istekler için daha basit ve daha güvenlidir.
import {
  VerifiedPermissionsClient,
  IsAuthorizedCommand,
  IsAuthorizedWithTokenCommand,
  BatchIsAuthorizedCommand,
} from "@aws-sdk/client-verifiedpermissions";

const avpClient = new VerifiedPermissionsClient({ region: "eu-central-1" });
const POLICY_STORE_ID = "ps-your-store-id";

// Seçenek 1: IsAuthorizedWithToken -- ham JWT gönder
// AVP token'ı doğrular ve claim'lerden principal'ı çıkarır
async function checkWithToken(
  accessToken: string,
  action: string,
  resourceType: string,
  resourceId: string,
  resourceAttrs: Record<string, { string: string }>
): Promise<boolean> {
  const command = new IsAuthorizedWithTokenCommand({
    policyStoreId: POLICY_STORE_ID,
    accessToken: accessToken,
    action: {
      actionType: "SaasApp::Action",
      actionId: action,
    },
    resource: {
      entityType: `SaasApp::${resourceType}`,
      entityId: resourceId,
      entityAttributes: resourceAttrs,
    },
  });

  const response = await avpClient.send(command);
  return response.decision === "ALLOW";
}

// Seçenek 2: IsAuthorized -- principal'ı manuel olarak oluştur
// Kullanıcı JWT'si olmadan servisler arası çağrılar için kullanışlı
async function checkWithPrincipal(
  userId: string,
  userAttrs: Record<string, { string: string }>,
  action: string,
  resourceType: string,
  resourceId: string,
  resourceAttrs: Record<string, { string: string }>
): Promise<boolean> {
  const command = new IsAuthorizedCommand({
    policyStoreId: POLICY_STORE_ID,
    principal: {
      entityType: "SaasApp::User",
      entityId: userId,
      entityAttributes: userAttrs,
    },
    action: {
      actionType: "SaasApp::Action",
      actionId: action,
    },
    resource: {
      entityType: `SaasApp::${resourceType}`,
      entityId: resourceId,
      entityAttributes: resourceAttrs,
    },
  });

  const response = await avpClient.send(command);
  return response.decision === "ALLOW";
}

UI Oluşturma için BatchIsAuthorized

Birden fazla kaynak içeren bir UI oluştururken (belge listesi, izin kapılı özelliklerle pano), tek tek yetkilendirme çağrıları yapmak pahalıdır. BatchIsAuthorizedCommand tek bir API çağrısında 30’a kadar kontrol gönderir.

Kısıtlama: batch’teki tüm isteklerde principal veya resource aynı olmalıdır. UI oluşturma için genellikle principal’ı (mevcut kullanıcı) sabitler ve action/resource’u değiştirirsiniz.

// UI oluşturma için batch yetkilendirme
// Tek bir API çağrısında tek kullanıcı için birden fazla izni kontrol et
async function checkBatchPermissions(
  userId: string,
  userAttrs: Record<string, { string: string }>,
  checks: Array<{
    action: string;
    resourceType: string;
    resourceId: string;
    resourceAttrs: Record<string, { string: string }>;
  }>
): Promise<boolean[]> {
  const command = new BatchIsAuthorizedCommand({
    policyStoreId: POLICY_STORE_ID,
    requests: checks.map((check) => ({
      principal: {
        entityType: "SaasApp::User",
        entityId: userId,
        entityAttributes: userAttrs,
      },
      action: {
        actionType: "SaasApp::Action",
        actionId: check.action,
      },
      resource: {
        entityType: `SaasApp::${check.resourceType}`,
        entityId: check.resourceId,
        entityAttributes: check.resourceAttrs,
      },
    })),
  });

  const response = await avpClient.send(command);
  return response.results!.map((r) => r.decision === "ALLOW");
}

// Kullanım: kullanıcının belge listesiyle neler yapabileceğini kontrol et
const permissions = await checkBatchPermissions(
  "user-123",
  { tenantId: { string: "tenant-abc" }, orgRole: { string: "editor" } },
  [
    {
      action: "ViewDocument",
      resourceType: "Document",
      resourceId: "doc-1",
      resourceAttrs: { tenantId: { string: "tenant-abc" } },
    },
    {
      action: "EditDocument",
      resourceType: "Document",
      resourceId: "doc-1",
      resourceAttrs: { tenantId: { string: "tenant-abc" } },
    },
    {
      action: "DeleteDocument",
      resourceType: "Document",
      resourceId: "doc-1",
      resourceAttrs: { tenantId: { string: "tenant-abc" } },
    },
  ]
);
// permissions: [true, true, false] -- görüntüleyebilir ve düzenleyebilir, silemez

API Middleware Deseni

Cognito kimlik doğrulamasını AVP yetkilendirmesiyle birleştiren yeniden kullanılabilir bir middleware:

// Cognito JWT ile AVP yetkilendirmesini birleştiren middleware
// Lambda handler'ları otomatik izin kontrolüyle sarar

import { APIGatewayProxyEventV2WithJWTAuthorizer } from "aws-lambda";

interface AuthorizationConfig {
  action: string;
  resourceType: string;
  getResourceId: (event: APIGatewayProxyEventV2WithJWTAuthorizer) => string;
  getResourceAttrs: (
    event: APIGatewayProxyEventV2WithJWTAuthorizer
  ) => Record<string, { string: string }>;
}

function withAuthorization(config: AuthorizationConfig) {
  return function (
    handler: (
      event: APIGatewayProxyEventV2WithJWTAuthorizer
    ) => Promise<unknown>
  ) {
    return async (event: APIGatewayProxyEventV2WithJWTAuthorizer) => {
      const context = extractTenantContext(event);

      const allowed = await checkWithPrincipal(
        context.userId,
        {
          tenantId: { string: context.tenantId },
          orgRole: { string: context.orgRole },
          tenantTier: { string: context.tenantTier },
        },
        config.action,
        config.resourceType,
        config.getResourceId(event),
        config.getResourceAttrs(event)
      );

      if (!allowed) {
        return {
          statusCode: 403,
          body: JSON.stringify({ error: "Access denied" }),
        };
      }

      return handler(event);
    };
  };
}

// Lambda handler'da kullanım
export const getDocument = withAuthorization({
  action: "ViewDocument",
  resourceType: "Document",
  getResourceId: (event) => event.pathParameters?.documentId ?? "",
  getResourceAttrs: (event) => {
    // Pratikte, yetkilendirme kontrolünden önce
    // kaynak niteliklerini veritabanından getirin
    return { tenantId: { string: "tenant-abc" }, status: { string: "active" } };
  },
})(async (event) => {
  // Handler yalnızca yetkilendirme geçerse çalışır
  const documentId = event.pathParameters?.documentId;
  // ... belgeyi getir ve döndür
  return { statusCode: 200, body: JSON.stringify({ id: documentId }) };
});

Entra ID Alternatifi

Microsoft ekosistemindeki takımlar için eşdeğer desen, kimlik doğrulama için Microsoft Entra External ID ve ince taneli kararlar için ayrı bir yetkilendirme katmanı kullanır.

Temel Farklar

KonuAWS (Cognito + AVP)Microsoft (Entra + özel yetkilendirme)
Kimlik doğrulamaCognito User PoolEntra External ID
Yetkilendirme motoruCedar ile AVP (yönetilen)Yerel eşdeğer yok — Cerbos, OPA veya özel kullanın
Politika diliCedar (formal olarak doğrulanmış)Seçilen motora bağlı
Kiracı izolasyonuCedar politikaları veya ayrı policy store’larApp role’leri + gruplar + harici PDP
Token zenginleştirmePre Token Generation Lambda triggerUygulama kaydında claim eşleme
Fiyatlandırma modeliMAU başına (Cognito) + istek başına (AVP)MAU başına (Entra) + harici PDP maliyeti
Çok kiracı desteğiÖzel nitelikler + Cedar politikalarıÇok kiracılı uygulama kaydı

Microsoft altyapısındaki kritik eksiklik, yönetilen ince taneli bir yetkilendirme servisinin olmamasıdır. Entra kimlik doğrulama ve kaba taneli yetkilendirmeyi (app role’leri, grup üyelikleri, Conditional Access) yönetir, ancak “kullanıcı X, kiracı Z’deki belge Y’yi düzenleyebilir mi?” gibi kaynak seviyesinde kararlar için harici bir PDP gereklidir.

Pratikte Microsoft altyapısı kullanan takımlar, ince taneli kararlar için Entra’yı Cerbos veya OPA ile birleştirir. Entra token’ı kimlik bağlamını (kullanıcı ID, roller, gruplar, kiracı ID) sağlar ve harici PDP bu bağlam ile kaynak niteliklerini kullanarak politikaları değerlendirir.

// Entra ID token claim'leri ince taneli yetkilendirme için Cerbos'a beslenir
// Entra kimliği sağlar; Cerbos yetkilendirme kararını verir

import { GRPC as Cerbos } from "@cerbos/grpc";

const cerbos = new Cerbos("localhost:3593");

async function checkAccess(
  entraToken: { oid: string; roles: string[]; tid: string; groups: string[] },
  resource: { type: string; id: string; ownerId: string; tenantId: string }
) {
  const decision = await cerbos.checkResource({
    principal: {
      id: entraToken.oid,
      roles: entraToken.roles,
      attr: {
        tenantId: entraToken.tid,
        groups: entraToken.groups,
      },
    },
    resource: {
      kind: resource.type,
      id: resource.id,
      attr: {
        owner: resource.ownerId,
        tenantId: resource.tenantId,
      },
    },
    actions: ["read", "update", "delete"],
  });

  return decision.isAllowed("update");
}

AWS burada net bir avantaja sahiptir: Cognito + AVP tam entegre, yönetilen bir yetkilendirme altyapısıdır. Microsoft ekosisteminde ise birden fazla parçadan birleştirmeniz gerekir.

Maliyet Analizi

AVP Fiyatlandırması

Amazon Verified Permissions, tek yetkilendirme API’leri, toplu (batch) yetkilendirme API’leri ve politika yönetimi API’leri için farklı tarifeler uygular. Her API türü için tek bir “sabit” oran yoktur. Ayrıntılar için bkz. Amazon Verified Permissions Pricing.

Tek yetkilendirme (IsAuthorized, IsAuthorizedWithToken): Her API çağrısı, faturalanan tek bir yetkilendirme isteğidir; istek başına 0,000005 USD (milyon başına 5 USD).

Toplu yetkilendirme (BatchIsAuthorized, BatchIsAuthorizedWithToken): Her batch API çağrısı tek bir istek olarak sayılır; çağrının içinde kaç kontrol olduğu (servis limitine kadar) fatura birimini çoğaltmaz. Batch çağrıları kademeli istek başına fiyatlandırılır (örneğin yayındaki ABD tarifesinde ayda ilk 40 milyon batch çağrısı için batch çağrısı başına 0,00015 USD). Bu, içerideki her kontrol için tek yetkilendirme tarifesinin uygulanması anlamına gelmez.

Aşağıdaki tablo, her ince taneli kararın bir IsAuthorized veya IsAuthorizedWithToken çağrısına karşılık geldiği varsayımıyla geçerlidir.

Aylık tek yetkilendirme API çağrısıAylık AVP maliyeti (tek API’ler)
1 milyon5$
10 milyon50$
100 milyon500$
1 milyar5.000$

Not: İş yükünüzde batch API’lere ağırlıklı olarak güveniyorsanız maliyeti fiyatlandırma sayfasındaki batch kademeleriyle modelleyin. Politika oluşturma, güncelleme, listeleme gibi politika yönetimi çağrıları ayrı faturalandırılır.

Cognito Fiyatlandırması

Cognito fiyatlandırması katmana bağlıdır:

KatmanÜcretsiz MAUMAU Başına Fiyat (ücretsiz üstü)Temel Özellikler
Lite10.0000,0055$Temel kimlik doğrulama, özel nitelikler
Essentials10.0000,015$Parolasız, yönetilen giriş
Plus00,02$Tehdit koruması, risk tabanlı kimlik doğrulama

Note: Kasım 2024 öncesinde aktif Cognito user pool’ları olan hesaplar 50.000 MAU’luk daha yüksek bir ücretsiz katman için uygundur.

Toplam SaaS Kimlik Doğrulama Maliyeti Örneği

Günde ortalama 200 API çağrısı yapan 5.000 MAU’lu bir B2B SaaS ürünü için:

  • Cognito (Lite): Ücretsiz (10.000 MAU eşiğinin altında)
  • AVP: 5.000 kullanıcı x 200 çağrı x 30 gün = 30 milyon tek yetkilendirme API çağrısı/ay = 150$/ay (her çağrının IsAuthorized veya IsAuthorizedWithToken ve tek yetkilendirme tarifesiyle faturalandığı varsayımıyla)
  • Toplam: Kimlik doğrulama + ince taneli yetkilendirme için ~150$/ay

Aynı kontrolleri batch API’lerle karşılıyorsanız AWS, iç yetkilendirme sayısı yerine batch API çağrılarını batch tarifesine göre faturalandırır.

Karşılaştırma olarak, kendi sunucularınızda barındırılan bir çözüm (Kubernetes üzerinde SpiceDB + PostgreSQL) yalnızca altyapı olarak aylık 500-2.000$ tutar, artı operasyonlar için mühendislik zamanı.

Tip: Her API çağrısının AVP kontrolüne ihtiyacı yoktur. İki katmanlı deseni kullanın: API Gateway kaba taneli kontrolleri yönetir (kullanıcı kimliği doğrulanmış mı? token doğru scope’a sahip mi?). Yalnızca ince taneli kararları AVP’ye yönlendirin. Bu, AVP istek hacmini %60-80 azaltabilir.

Yaygın Hatalar

Policy Store’ları Aşırı Kapsamlama

Mikroservis başına ayrı bir policy store oluşturmak politika parçalanmasına yol açar. Birden fazla servisi kapsayan yetkilendirme kararları tek bir policy store içinde imkansız hale gelir. Çoğu durumda ortam başına (dev, staging, production) tek bir policy store yeterlidir. Politikaları mantıksal olarak düzenlemek için Cedar ad alanlandırmasını (varlık türü ön ekleri) kullanın.

Politikalarda Kiracı İzolasyonunu Atlamak

Çok kiracılı SaaS’ta en tehlikeli hata: kiracı kontrolü olmadan permit politikası yazmak.

// TEHLİKELİ: kiracı izolasyonu yok
permit(
  principal,
  action == Action::"ViewDocument",
  resource is SaasApp::Document
)
when {
  principal.orgRole in ["admin", "editor", "viewer"]
};

Bu politika, kiracıdan bağımsız olarak kimliği doğrulanmış herhangi bir kullanıcının herhangi bir belgeyi görüntülemesine izin verir. Düzeltme basittir ama unutulması kolaydır:

// DOĞRU: kiracı izolasyonu uygulanmış
permit(
  principal,
  action == Action::"ViewDocument",
  resource is SaasApp::Document
)
when {
  principal.tenantId == resource.tenantId &&
  principal.orgRole in ["admin", "editor", "viewer"]
};

Warning: Kiracılar arası erişimin reddedildiğini açıkça doğrulayan bir Cedar politika testi yazın. CI/CD’de çalıştırın. Bu, yanlışlıkla kiracı verisi sızıntısına karşı güvenlik ağınızdır.

Token Şişkinliği

Pre Token Generation trigger aracılığıyla Cognito token’larına çok fazla claim eklemek token boyutunu artırır. Büyük token’lar her API çağrısına gecikme ekler ve boyut limitlerini aşabilir. Claim’leri Cedar politikalarının gerçekten değerlendirdiğiyle sınırlı tutun. Yetkilendirme için ek bağlama ihtiyacınız varsa, token claim’leri yerine AVP isteğinde kaynak nitelikleri olarak geçirin.

IsAuthorizedWithToken Kullanmamak

JWT claim’lerini manuel olarak çıkarmak ve principal varlıkları oluşturmak hataya açıktır. IsAuthorizedWithToken, AVP’nin token doğrulamasını ve claim çıkarmasını yönetmesini sağlar. Daha güvenlidir (AVP token imzasını doğrular) ve bakımı gereken daha az kod vardır.

UI için Batch Yetkilendirmeyi Göz Ardı Etmek

UI oluşturma için bir döngüde tek tek IsAuthorized çağrıları yapmak gecikme sorunları yaratır ve tek yetkilendirme fatura birimlerini artırır. Aynı principal için birçok kontrol gerekiyorsa BatchIsAuthorizedCommand tek bir batch çağrısında en fazla 30 kontrol paketler; bu çağrı faturalamada tek bir batch isteği olarak sayılır (kendi kademeli fiyatıyla). Trafik profilinize göre tek ve batch toplamlarını fiyatlandırma sayfasında karşılaştırın.

Şema Doğrulamasını Atlamak

Cedar politikalarını şemasız dağıtmak, nitelik adlarındaki yazım hatalarının sessizce başarısız olması anlamına gelir. principal.tenantId yerine principal.tenantid (küçük ‘d’) kontrol eden bir politika hiçbir zaman eşleşmez ve hiçbir hata raporlanmaz. Bu sorunları politika oluşturma zamanında yakalamak için şema doğrulamasını etkinleştirin.

Sonuç

Cognito + AVP, AWS üzerindeki SaaS ürünleri için yönetilen, entegre bir yetkilendirme altyapısı sağlar. Bu kombinasyon, kendi sunucularınızda barındırılan altyapı olmadan kimlik doğrulama, kiracı bağlamı zenginleştirme ve ince taneli politika değerlendirmesini yönetir.

Temel çıkarımlar:

  1. Pre Token Generation trigger’ını kullanın ve access token’ları Cedar politikalarının tükettiği kiracı bağlamıyla zenginleştirin.
  2. Pool modeliyle başlayın (tek User Pool, tek policy store) ve yalnızca uyumluluk gerektirdiğinde silo modeline geçin.
  3. Her Cedar politikası kiracı kontrolü içermeli çok kiracılı uygulamalarda. Kiracılar arası izolasyonu CI/CD’de test edin.
  4. Kullanıcıya yönelik istekler için IsAuthorizedWithToken kullanın. Servisler arası çağrılar için IsAuthorized kullanın.
  5. İki katmanlı deseni kullanın (kaba kontroller için API Gateway, ince taneli için AVP) ve maliyeti ve gecikmeyi kontrol edin.
  6. UI oluşturma için BatchIsAuthorized kullanarak API çağrılarını ve gecikmeyi azaltın.

Bu serinin sonraki yazısı, burada ele alınan nitelik tabanlı yaklaşımdan temelden farklı bir yetkilendirme modeli olan ilişki tabanlı erişim kontrolü için SpiceDB vs Auth0 FGA konusunu kapsar.

Kaynaklar

Harici Yetkilendirme Sistemleri

Dağıtık sistemler için harici yetkilendirme platformlarına kapsamlı bir rehber. Platform seçimi, politika dili karşılaştırması, AWS ile bulut tabanlı yetkilendirme ve SpiceDB ile Auth0 FGA kullanarak ilişki tabanlı erişim kontrolünü kapsar.

İlerleme 2 / 4 yazı

İlgili yazılar

Harici Yetkilendirme Yönetim Sistemleri: Mimarınız İçin Doğru Platformu Seçmek

AWS Verified Permissions, SpiceDB, OpenFGA, Cerbos ve OPA dahil harici yetkilendirme platformlarının tarafsız değerlendirmesi. Mimari desenler, maliyet analizi ve mühendislik ekipleri için karar çerçevesi.

authorizationsecurityarchitecture+5
Cedar vs Rego vs OpenFGA: Politika Dili Karşılaştırması

Cedar, Rego, OpenFGA DSL ve Cerbos YAML/CEL politika dillerinin derinlemesine teknik karşılaştırması. Söz dizimi, performans kıyaslamaları, biçimsel doğrulama, araç desteği ve her dil için TypeScript entegrasyon örneklerini kapsar.

authorizationsecurityarchitecture+3
SpiceDB vs Auth0 FGA: İlişki Tabanlı Yetkilendirme Karşılaştırması

SpiceDB ve Auth0 FGA (OpenFGA) arasında detaylı bir teknik karşılaştırma -- şema tasarımı, tutarlılık modelleri, dağıtım ve ölçeklenebilirlik açısından farklı tercihler yapan iki Zanzibar tabanlı yetkilendirme sistemi.

authorizationsecurityarchitecture+3
Yetkilendirme Temelleri ve İzin Sistemleri Neden Bozulur

Authentication ve authorization farkı, yaygın izin sistemi tuzakları, fail-closed prensibi ve her izin sisteminin karşılaması gereken hedefler.

typescriptnextjsauthorization+2
Service Layer ile Merkezi Yetkilendirme

Dağınık izin kontrollerini merkezi bir service layer'a taşıyın, Next.js middleware guard'ları ekleyin ve derinlemesine savunma yetkilendirme mimarisi oluşturun.

typescriptnextjsauthorization+2