İçeriğe geç
academia.sh

Ders 08 / 21

Beklemede Şifreleme

Beklemede duran veri üç seçenekle karşılaştırılır: şifreleme yok, sağlayıcı anahtarı, müşteri anahtarı. Kaç öznenin çözebildiği, anahtar kullanımının denetim kaydına düşüp düşmediği ve müşteri anahtarının getirdiği yük gerçek zarf şifrelemesiyle sayılır; anahtar kaybında 14 kümenin 3.973 GB'ı kalıcı olarak okunamaz hale gelir.

İçindekiler

Önceki konu kimin neyi yapabildiğini yazdı: özne–işlem–kaynak matrisi çıkarıldı, politika belgeleri değerlendirildi, hesap sınırları çizildi. O defterin atladığı bir soru var — erişebilen biri veriyi açtığında ne görüyor? Erişim listesi kapının kimlere açıldığını söyler, ardındaki kutunun içini söylemez. Bu ders beklemede duran veri için üç seçeneği tek ölçüyle karşılaştırır: şifreleme yok, sağlayıcı anahtarı, müşteri anahtarı. Ölçü kaç öznenin kaç veri kümesini çözebildiğidir; yanına iki sütun konur — anahtar kullanımının kiracının denetim kaydında görünmesi ve müşteri anahtarının getirdiği yük. Şifreli sırların depoda tutulması ve oradaki anahtar yerleşimi depo tabanlı dağıtım konusunda ölçüldü; burada ölçülen, anahtar kiralanan bir servisin içinde durduğunda kimin elinde olduğudur.

Ölçüm bölgesel ölçüm ağı üzerindedir ve kurgudur. Veri kümeleri, özne kataloğu ve okuma sayıları node ile yazılmış bir modeldir; şifreleme node:crypto ile gerçekten koşar, anahtar türetme tohumları ve içerik değerleri uydurmadır.

BG1. Beklemede duran veri 14 veri kümesindedir: üç ortam, yedi tür (ham ölçüm, özet, fatura, arşiv, yedek, anlık görüntü, günlük arşivi). Hacimler kurgudur. BG2. Özne kataloğu 23 birimdir: beş ekipte 20 kişi ve üç iş yükü kimliği. BG3. Veri erişimi ile anahtar kullanma izni ayrı iki eksendir; müşteri anahtarı seçeneğinde çözme bu iki kümenin kesişimidir. Anahtar ortam başına birdir. BG4. Her öznenin işini yapmak için düz metne ihtiyaç duyup duymadığı yazılıdır: yedekleme işi ve platform ekibi şifreli baytı taşır, açmaz. BG5. Şifreleme zarf biçimindedir: her kümenin bir veri anahtarı vardır, veri anahtarı ana anahtarla sarılır. Sarma ve çözme gerçekten koşar. BG6. Müşteri anahtarında her çözme bir denetim kaydı satırı üretir; sağlayıcı anahtarında anahtar kullanımı kiracının kaydına düşmez. Anahtar döndürme dönemi 365 gündür (kurgu politika).

Üç Seçenek, Tek Soru: Kim Çözebiliyor

// depo.mjs — beklemede duran veri kumeleri, ozneler ve uc sifreleme secenegi. MODELDIR.
// Bolgesel olcum agi KURGUDUR: ekip adlari, kume adlari ve okuma sayilari uydurmadir.
export const ORTAM = ["gelistirme", "hazirlik", "uretim"];
const TEMEL = ["ham-olcum", "ozet", "fatura"];
const EK = { gelistirme: [], hazirlik: ["yedek"],
  uretim: ["arsiv", "yedek", "anlik-goruntu", "gunluk-arsivi"] };
const GB = { "ham-olcum": 420, ozet: 18, fatura: 6, arsiv: 900, yedek: 1340,
  "anlik-goruntu": 760, "gunluk-arsivi": 210 };
const OKUMA = { "ham-olcum": 4, ozet: 9, fatura: 6, arsiv: 1, yedek: 0,
  "anlik-goruntu": 0, "gunluk-arsivi": 2 };   // ozne basina gunluk duz metin okumasi

export const KUME = ORTAM.flatMap((o) => [...TEMEL, ...EK[o]].map((t) => ({
  ad: `${o}/${t}`, ortam: o, tur: t,
  gb: o === "uretim" ? GB[t] : Math.round(GB[t] / (o === "hazirlik" ? 6 : 20)) })));

// duzMetin: isini yapmak icin cozulmus veriye ihtiyaci var mi. Yedekleme sifreli bayti kopyalar.
export const OZNE = [
  { ad: "olcum ekibi", n: 6, duzMetin: true, anahtar: ["gelistirme", "hazirlik"],
    erisim: [["*", "ham-olcum"], ["*", "ozet"]] },
  { ad: "fatura ekibi", n: 4, duzMetin: true, anahtar: ["gelistirme", "hazirlik"],
    erisim: [["*", "fatura"]] },
  { ad: "veri ekibi", n: 5, duzMetin: true, anahtar: ["uretim"], erisim: [["uretim", "*"]] },
  { ad: "platform ekibi", n: 3, duzMetin: false, anahtar: [], erisim: [["*", "*"]] },
  { ad: "uretim nobeti", n: 2, duzMetin: true, anahtar: ["uretim"],
    erisim: [["uretim", "ozet"], ["uretim", "fatura"]] },
  { ad: "toplayici kimligi", n: 1, duzMetin: true, anahtar: ORTAM, erisim: [["*", "ham-olcum"]] },
  { ad: "raporlama kimligi", n: 1, duzMetin: true, anahtar: ["uretim"],
    erisim: [["*", "ozet"], ["*", "fatura"]] },
  { ad: "yedekleme isi", n: 1, duzMetin: false, anahtar: [],
    erisim: [["*", "yedek"], ["*", "arsiv"], ["*", "anlik-goruntu"]] },
];

export const YAS = { gelistirme: 288, hazirlik: 141, uretim: 322 };  // musteri anahtarinin yasi
export const OMUR = 365;                                  // kurgu dondurme donemi, gun

const uyar = (k, [o, t]) => (o === "*" || k.ortam === o) && (t === "*" || k.tur === t);
export const erisir = (z, k) => z.erisim.some((c) => uyar(k, c));
export const anahtarVar = (z, k) => z.anahtar.includes(k.ortam);
export const OZNE_SAYISI = OZNE.reduce((a, z) => a + z.n, 0);
export const okuma = (z, k) => (z.duzMetin ? z.n * OKUMA[k.tur] : 0);

// Uc secenek: cozmeyi hangi kosul belirliyor. "tam" = eksik anahtar izinleri tamamlanmis hali.
export const SECENEK = {
  "sifreleme yok": (z, k) => erisir(z, k),
  "saglayici anahtari": (z, k) => erisir(z, k),
  "musteri anahtari": (z, k) => erisir(z, k) && anahtarVar(z, k),
  "musteri anahtari (tam)": (z, k) => erisir(z, k) && (anahtarVar(z, k) || z.duzMetin),
};

export const cift = (f) => OZNE.flatMap((z) => KUME.filter((k) => f(z, k)).map((k) => ({ z, k })));
export const cozer = (f) => OZNE.filter((z) => KUME.some((k) => f(z, k)))
  .reduce((a, z) => a + z.n, 0);

if (import.meta.url === `file://${process.argv[1]}`) {
  const toplamGb = KUME.reduce((a, k) => a + k.gb, 0);
  console.log(`model: ${KUME.length} veri kumesi (${toplamGb} GB, kurgu), ` +
    `${OZNE_SAYISI} ozne / ${OZNE.length} grup, ${OZNE_SAYISI * KUME.length} olasi cift`);
  const B = [23, 15, 13, 10, 11, 17];
  const yz = (h) => h.map((v, j) => j ? String(v).padStart(B[j]) : String(v).padEnd(B[0])).join("");
  console.log("\n" + yz(["secenek", "cozebilen ozne", "cozme cifti", "en genis",
    "kayit/gun", "altyapi yolu"]));
  for (const [ad, f] of Object.entries(SECENEK)) {
    const c = cift(f);
    const kayit = ad === "sifreleme yok" || ad === "saglayici anahtari" ? 0
      : c.reduce((a, x) => a + okuma(x.z, x.k), 0);
    console.log(yz([ad, cozer(f), c.length,
      Math.max(...OZNE.map((z) => KUME.filter((k) => f(z, k)).length)), kayit,
      ad === "sifreleme yok" ? "acik, sayilamaz" : "kapali"]));
  }
  const acik = cift(SECENEK["sifreleme yok"]);
  const musteri = new Set(cift(SECENEK["musteri anahtari"]).map((x) => `${x.z.ad}|${x.k.ad}`));
  const kirik = acik.filter((x) => !musteri.has(`${x.z.ad}|${x.k.ad}`));
  console.log(`\nmusteri anahtarina gecince kapanan cift: ${kirik.length}; ` +
    `bunlarin ${kirik.filter((x) => x.z.duzMetin).length} tanesi duz metin isteyen mesru is`);
  for (const z of OZNE) {
    const d = kirik.filter((x) => x.z.ad === z.ad);
    if (d.length) console.log(`  ${z.ad.padEnd(20)} ${String(d.length).padStart(3)} cift, ` +
      `${String(d.reduce((a, x) => a + okuma(x.z, x.k), 0)).padStart(3)} gunluk okuma, ` +
      `duz metin gerek: ${z.duzMetin}`);
  }
  const her = cift(SECENEK["musteri anahtari"]).length;
  console.log(`\nsifrelemenin hicbir secenekte kapatmadigi cift: ${her} ` +
    `(yetkili kimlik zaten okuyor); izinler tamamlaninca ${cift(SECENEK["musteri anahtari (tam)"]).length}`);

  const tam = cift(SECENEK["musteri anahtari (tam)"]);
  console.log("\n" + yz(["anahtar (ortam)", "yas (gun)", "kalan gun", "kume", "cozme/gun"]));
  for (const o of ORTAM) {
    const k = tam.filter((x) => x.k.ortam === o);
    console.log(yz([o, YAS[o], OMUR - YAS[o], KUME.filter((x) => x.ortam === o).length,
      k.reduce((a, x) => a + okuma(x.z, x.k), 0)]));
  }
}
model: 14 veri kumesi (3973 GB, kurgu), 23 ozne / 8 grup, 322 olasi cift

secenek                 cozebilen ozne  cozme cifti  en genis  kayit/gun     altyapi yolu
sifreleme yok                       23           45        14          0  acik, sayilamaz
saglayici anahtari                  23           45        14          0           kapali
musteri anahtari                    19           20         7        371           kapali
musteri anahtari (tam)              19           27         7        503           kapali

musteri anahtarina gecince kapanan cift: 25; bunlarin 7 tanesi duz metin isteyen mesru is
  olcum ekibi            2 cift,  78 gunluk okuma, duz metin gerek: true
  fatura ekibi           1 cift,  24 gunluk okuma, duz metin gerek: true
  platform ekibi        14 cift,   0 gunluk okuma, duz metin gerek: false
  raporlama kimligi      4 cift,  30 gunluk okuma, duz metin gerek: true
  yedekleme isi          4 cift,   0 gunluk okuma, duz metin gerek: false

sifrelemenin hicbir secenekte kapatmadigi cift: 20 (yetkili kimlik zaten okuyor); izinler tamamlaninca 27

anahtar (ortam)              yas (gun)    kalan gun      kume  cozme/gun
gelistirme                         288           77         3        121
hazirlik                           141          224         4        121
uretim                             322           43         7        261

Tablonun ilk iki satırı birbirinin aynısıdır ve dersin ilk kararı oradadır. Sağlayıcı anahtarına geçmek çözebilen özne sayısını bir tane bile azaltmıyor: 23 özne, 45 çift, en geniş öznenin elinde 14 kümenin hepsi. Sağlayıcı anahtarında çözme veri erişimiyle birlikte otomatik gerçekleşir; okuma isteğini yapan özne için şifreleme görünmez bir katmandır. Değiştirdiği tek sütun altyapı yoludur: disk, yedek ortamı, elden çıkarılan donanım ve sağlayıcı tarafındaki işletim erişimi kapanır. O sütunun “açık, sayılamaz” değeri kendi başına bir kalemdir; kaç öznenin bu yoldan okuyabildiği kiracının defterinde yazmaz.

Müşteri anahtarı satırı ölçüyü ilk kez oynatıyor: 23 özne 19’a, 45 çift 20’ye, en geniş yetki 14 kümeden 7’ye iner. Bunun bedeli aşağıdaki dökümdedir. Kapanan 25 çiftin 7 tanesi düz metne gerçekten ihtiyaç duyan meşru iştir: ölçüm ekibinin üretim ham ölçümü ve özeti, fatura ekibinin üretim faturası, raporlama kimliğinin geliştirme ve hazırlık kümeleri — günde 132 okuma durur. Eksik anahtar izinleri verildiğinde bu işler geri açılır ve çift sayısı 20’den 27’ye çıkar. Kalan fark 45’e göre 18 çifttir ve tamamı düz metne ihtiyacı olmayan öznelerdir: platform ekibinin 14 çifti ve yedekleme işinin 4 çifti. Müşteri anahtarının gerçek kazancı bu 18 çifttir — 45’ten 27’ye, yüzde kırk. Geri kalanı anahtar iznini erişim izninin kopyası haline getirmekle biter.

Son sütun ikinci kazancı veriyor: aynı 503 çözme sağlayıcı anahtarında 0 kayıt satırı üretiyor, müşteri anahtarında 503. Anahtar kullanımının görünürlüğü, çözme yetkisinin daralmasından bağımsız bir kalemdir. Sınır tablosu anahtar ömrünü sayıyor: üretim anahtarı 322 günlük, 365 günlük döneme 43 gün kaldı ve o döndürme 7 kümeyi ilgilendiriyor.

Anahtarın Kendi Yükü: Döndürme, Yedek ve Kayıp

// zarf.mjs — zarf sifreleme gercekten kosar: veri anahtari sarilir, dondurulur, kaybedilir.
// ANAHTAR VE ICERIK DEGERLERI KURGUDUR. Turetme tohumu gorunur ki cikti yeniden uretilebilsin.
import { scryptSync, createCipheriv, createDecipheriv, createHash } from "node:crypto";
import { KUME, cift, okuma, SECENEK } from "./depo.mjs";

const anaAnahtar = (s) => scryptSync(`kurgu-ana-parola-s${s}`, "kurgu-tuz-0001", 32, { N: 16384 });
const veriAnahtari = (k) => createHash("sha256").update(`kurgu-veri-anahtari|${k.ad}`).digest();
const iv = (etiket) => createHash("sha256").update(`iv|${etiket}`).digest().subarray(0, 12);
const icerik = (k) => Buffer.from(`kurgu-kayit|${k.ad}|`.repeat(Math.max(4, k.gb)));

const sar = (k, s) => {                                   // veri anahtarini ana anahtarla sarar
  const c = createCipheriv("aes-256-gcm", anaAnahtar(s), iv(`${k.ad}#${s}`));
  const g = Buffer.concat([c.update(veriAnahtari(k)), c.final()]);
  return { kume: k.ad, surum: s, govde: g, etiket: c.getAuthTag() };
};
const ac = (sarili, s) => {                               // sarili anahtari acar; yanlis anahtar atar
  const d = createDecipheriv("aes-256-gcm", anaAnahtar(s), iv(`${sarili.kume}#${sarili.surum}`));
  d.setAuthTag(sarili.etiket);
  return Buffer.concat([d.update(sarili.govde), d.final()]);
};
const sifrele = (k, va) => {
  const c = createCipheriv("aes-256-gcm", va, iv(k.ad));
  return { govde: Buffer.concat([c.update(icerik(k)), c.final()]), etiket: c.getAuthTag() };
};
const coz = (k, va, kutu) => {
  const d = createDecipheriv("aes-256-gcm", va, iv(k.ad));
  d.setAuthTag(kutu.etiket);
  return Buffer.concat([d.update(kutu.govde), d.final()]);
};

const sarili = KUME.map((k) => sar(k, 1));
const kutu = KUME.map((k, i) => sifrele(k, ac(sarili[i], 1)));
const nesneBayt = kutu.reduce((a, x) => a + x.govde.length, 0);
const sariliBayt = sarili.reduce((a, x) => a + x.govde.length + x.etiket.length, 0);
const dogru = KUME.every((k, i) => coz(k, ac(sarili[i], 1), kutu[i]).equals(icerik(k)));
console.log(`${KUME.length} kume sifrelendi: ${nesneBayt} bayt nesne, ${sariliBayt} bayt ` +
  `sarili anahtar; hepsi geri cozuldu: ${dogru}`);
console.log(`ornek sarili anahtar ${sarili[0].kume} -> ${sarili[0].govde.toString("base64")}`);

const B = [36, 8, 8, 16];
const yz = (h) => h.map((v, j) => j ? String(v).padStart(B[j]) : String(v).padEnd(B[0])).join("");
console.log("\n" + yz(["dondurme bicimi", "sarma", "nesne", "dokunulan bayt"]));
const yeniSarili = KUME.map((k) => sar(k, 2));             // ana anahtar 1 -> 2
const acilan = KUME.map((k, i) => coz(k, ac(yeniSarili[i], 2), kutu[i]).equals(icerik(k)));
console.log(yz(["ana anahtar (yalniz sarma)", KUME.length, 0, sariliBayt]));
console.log(yz(["veri anahtari (yeniden sifreleme)", KUME.length, KUME.length,
  nesneBayt + sariliBayt]));
console.log(`ana anahtar dondurulduktan sonra nesneler bozulmadan aciliyor: ` +
  `${acilan.every(Boolean)} (${acilan.filter(Boolean).length}/${KUME.length})`);

// anahtar kaybi: sarili anahtarlar duruyor, ana anahtar surum 2 elde yok. Sahte surumle denenir.
let kayipKume = 0, kayipGb = 0;
for (const [i, s] of yeniSarili.entries()) {
  try { coz(KUME[i], ac(s, 9), kutu[i]); } catch { kayipKume++; kayipGb += KUME[i].gb; }
}
console.log(`\nana anahtar kaybi: sarili anahtar acilmiyor, ${kayipKume}/${KUME.length} kume ` +
  `okunamiyor, ${kayipGb} GB kalici kayip`);
const geri = yeniSarili.map((s, i) => coz(KUME[i], ac(s, 2), kutu[i]).equals(icerik(KUME[i])));
console.log(`anahtar yedeginden geri getirilince: ${geri.filter(Boolean).length}/` +
  `${KUME.length} kume dogru cozuluyor — sifreli bayt yedegi tek basina yetmiyor`);

const gunluk = cift(SECENEK["musteri anahtari (tam)"]).reduce((a, x) => a + okuma(x.z, x.k), 0);
console.log(`\ndenetim kaydi: musteri anahtarinda ${gunluk} anahtar kullanimi/gun, ` +
  `30 gunde ${gunluk * 30} satir; saglayici anahtarinda ayni ${gunluk} cozme icin 0 satir`);
14 kume sifrelendi: 110110 bayt nesne, 672 bayt sarili anahtar; hepsi geri cozuldu: true
ornek sarili anahtar gelistirme/ham-olcum -> ZlpDt4j6C7N+EAH7PufTZiBJ2rlZSinVP8dhgHFvKic=

dondurme bicimi                        sarma   nesne  dokunulan bayt
ana anahtar (yalniz sarma)                14       0             672
veri anahtari (yeniden sifreleme)         14      14          110782
ana anahtar dondurulduktan sonra nesneler bozulmadan aciliyor: true (14/14)

ana anahtar kaybi: sarili anahtar acilmiyor, 14/14 kume okunamiyor, 3973 GB kalici kayip
anahtar yedeginden geri getirilince: 14/14 kume dogru cozuluyor — sifreli bayt yedegi tek basina yetmiyor

denetim kaydi: musteri anahtarinda 503 anahtar kullanimi/gun, 30 gunde 15090 satir; saglayici anahtarinda ayni 503 cozme icin 0 satir

Şifreleme gerçekten koştu: 14 küme şifrelendi, sarılı anahtarlar açıldı ve içerik bire bir geri geldi. Ana anahtarı döndürmek 14 sarma işlemi ve 672 bayta dokunur; nesne baytına hiç dokunmaz. Veri anahtarını döndürmek aynı 14 sarmaya ek olarak 14 nesnenin tamamını yeniden şifreler: 110.782 bayt, yüz altmış kat. Sarma katmanının varlık sebebi budur — sık döndürülen anahtar veriye değil, anahtara dokunur.

Karşılığında şu doğar: ana anahtar döndürüldükten sonra da veri anahtarı aynı veri anahtarıdır. Sarılı hali değişti, sardığı şey değişmedi. Veri anahtarı bir yerde açık kalmışsa döndürme onu kapatmaz; kapatmak için 110.782 baytlık satıra geçmek gerekir. Ucuz döndürme ile kapatıcı döndürme aynı işlem değildir ve tabloda ayrı satırlarda durur.

Kayıp satırı müşteri anahtarının en sert kalemidir ve çalıştırılmış bir denemedir: ana anahtar sürüm 2 elde yokken 14 kümenin hiçbiri açılmıyor, 3.973 GB kalıcı olarak okunamaz. Şifreli baytların yedeği duruyordu ve işe yaramadı; anahtar yedeğinden gelen sürüm 2 ile aynı 14 küme doğru çözüldü. Müşteri anahtarına geçmek, yedekleme planının kapsamına veriyi değil anahtarı eklemek demektir.

Şifrelemenin Kapatmadığı Yol

Üç seçenekte de açık kalan 20 çift — izinler tamamlandığında 27 — bu dersin adı konması gereken kalemidir. Bunlar yetkili kimliklerin okumasıdır. Veri ekibinin 5 üyesi üretim ortamının yedi kümesini açar, çünkü hem veri erişimi hem anahtar izni onda toplanmıştır. Beklemede şifreleme bu yola karşı hiçbir şey yapmaz ve yapması da beklenmez: özne kimlik doğrulamasından geçmiş, politika belgesi izin vermiş, anahtar servisi çözmüştür.

Şifrelemenin kapattığı yol tek bir sütundur: kiracının okuyamadığı, sayamadığı ve denetleyemediği altyapı tarafı. Sağlayıcı anahtarı o sütunu kapatır ve karşılığında hiçbir şey istemez. Müşteri anahtarı iki şey daha ekler — çözme yetkisini erişim yetkisinden ayırır (45 çiftten 27’ye) ve anahtar kullanımını kiracının kendi kaydına düşürür (0 satırdan günde 503’e) — istediği bedel de sayılıdır: 7 meşru işin durması, yedeklenmesi gereken yeni bir sır ve kaybedildiğinde 3.973 GB’ı geri getirilemez bir anahtar.

Özet

  • Sağlayıcı anahtarı çözebilen özneyi 23’ten indirmiyor, çifti 45’te bırakıyor; kapattığı tek şey kiracının sayamadığı altyapı yoludur.
  • Müşteri anahtarı çiftleri 45’ten 20’ye indiriyor; eksik izinler tamamlanınca 27’ye çıkıyor ve kalıcı kazanç, düz metne ihtiyacı olmayan öznelerin 18 çiftidir.
  • Daraltmanın bedeli: kapanan 25 çiftin 7’si düz metin isteyen meşru iştir, günde 132 okuma durur; en geniş öznenin yetkisi 14 kümeden 7’ye iner.
  • Ana anahtar döndürme 14 sarma ve 672 bayt, veri anahtarı döndürme 14 nesne ve 110.782 bayttır; ucuz döndürme veri anahtarını değiştirmediği için açık kalmış bir veri anahtarını kapatmaz.
  • Anahtar kaybı çalıştırılarak gösterildi: 14/14 küme açılmıyor, 3.973 GB kalıcı kayıp; şifreli bayt yedeği yetmiyor, anahtar yedeği 14/14 kümeyi geri getiriyor.
  • Anahtar kullanımı yalnız müşteri anahtarında görünüyor: aynı 503 çözme için 0 satıra karşı günde 503, 30 günde 15.090 satır; üretim anahtarının 365 günlük dönemine 43 gün kaldı.

Sonraki Adım

Beklemede duran veri için soru yanıtlandı. Ama veri yalnız beklemede durmuyor — kümeler, ortamlar ve ölçüm uçlarıyla toplayıcı arasında sürekli hareket ediyor. Bir sonraki ders o hareketi ölçer: bağlantı bacaklarının kaçı şifreli, kaçı “iç ağ” gerekçesiyle açık bırakılmış, şifreleme politikayla zorunlu kılındığında kaç bağlantı kırılıyor ve kaç kalem yapılandırma değişiyor.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat