Ders 02 / 22
Günlük Toplama ve Normalleştirme
Üç ayrı biçimdeki kurgu günlük tek şemaya normalleştirilir ve eşlenemeyen alan sayılır: 24 kaynak alanının 15'i sekiz alanlık şemaya oturuyor, 9'u artık kalıyor; ağ akışı kaydında dört şema alanı boş ve 404 kaydın hiçbirinde aktör yok. Kaynaklar aynı olayı 1, 5 ve 8 dakika sonra yazıyor. Aktör alanını iki ara tablo dolduruyor: 139 yönetim düzlemi kaydının 115'i hesaba çevriliyor, 24'ü çevrilemiyor; beş dakikalık pencerede 404 akış kaydının 190'ına aktör atanıyor, 212'si boş kalıyor, altmış dakikada atama 208'e çıkarken belirsiz kayıt 2'den 39'a fırlıyor. İki kaynakta iz bırakan 26 olayın 21'i toplanıyor, bir dakikalık pencerede hiçbiri toplanmıyor.
İçindekiler
Bir önceki dersin devir notu, analistin belleğindeki bağı yazıya geçiriyordu. O bağın en baştan kayıtta bulunması, yani iki uyarının aynı aktöre ait olduğunun makine tarafından görülebilmesi, önceki derste varsayılmıştı. Bu ders varsayımı kaldırır ve kursun ölçü birimini kurar.
Ölçü şudur: bir kaydın hangi alanı ortak şemaya oturuyor, hangi alanı oturmuyor ve oturmayan alanın yerine ne konuyor. Kaynak envanteri Uç Nokta ve Sistem Sertleştirme kursunda sayılmıştı; burada envanter bir girdidir. Sayılan şey kaynağın varlığı değil, birbirine bağlanabilirliğidir.
- TA7. Bölgesel ölçüm ağında üç günlük kaynağı vardır: bir bulut yönetim düzlemi kaydı, uç noktaların süreç oluşturma kaydı ve ağ akış verisi. Üçü de kurgudur; adresler yönlendirilmeyen kurgu bloklardandır.
- TA8. Hedef şema sekiz alanlıdır: zaman, kaynak, konak, adres, aktör, eylem, hedef, sonuç. Bir
kaynağın dolduramadığı alan
nullkalır ve sayılır. - TA9. Bir kaynak alanı üç durumdan birindedir: şemaya eşlenir, şemada karşılığı olmadığı için artık kalır, ya da şema alanı hiçbir kaynak alanından doldurulamadığı için boş kalır.
- TA10. Kayıt, olayın gerçekleştiği anda değil, kaynağın yazdığı anda oluşur. Model bu farkı kaynak başına veri olarak verir: uç noktada 1, ağ akışında 5, yönetim düzleminde 8 dakika.
- TA11. Otuz kurgu olay birden çok kaynakta iz bırakır. Bu bağ modelin bilgisidir; hiçbir günlük satırına yazılmaz.
- TA12. Aktör kimliği üç kaynakta üç biçimdedir: portal kimliği, etki alanı hesabı ve yalnız adres. Ara tablolar günlükte değil, varlık envanterindedir.
Üç Biçim, Tek Şema
// kaynak.mjs — uc ayri bicimdeki kurgu gunluk uretilir ve tek semaya normallestirilir. // MODELDIR. Adresler RFC1918 kurgu bloklarindandir; gercek kurum ve konak yoktur. export const TOHUM = 20260402; const uretec = (t) => { let s = t >>> 0; return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; }; const r = uretec(TOHUM); const tam = (n) => Math.floor(r() * n); const sec = (d) => d[tam(d.length)]; export const KONAK = Array.from({ length: 60 }, (_, i) => `uc-${101 + i}`); export const HESAP = Array.from({ length: 40 }, (_, i) => `sh-${201 + i}`); export const ADRES = KONAK.map((_, i) => `10.40.${1 + (i % 3)}.${10 + i}`); // Portal kimligi: 28 hesabin karsiligi var, alti tanesinin (servis kimligi) hic yok. const PORTAL = [...HESAP.slice(0, 28).map((_, i) => `ab-${4401 + i}`), ...Array.from({ length: 6 }, (_, i) => `ab-${4429 + i}`)]; const EYLEM = ["nesne.oku", "nesne.yaz", "yetki.degistir", "anahtar.kullan"]; const YOL = ["/opt/olcum/toplayici", "/usr/bin/arsivle", "/opt/olcum/dogrulayici"]; // Hedef sema: sekiz alan. Her kaynak bunun bir bolumunu doldurur. export const SEMA = ["t", "kaynak", "konak", "adres", "aktor", "eylem", "hedef", "sonuc"]; // [kaynak, bicim, kaynak alani, semaya eslenen kaynak alani, varis gecikmesi dk, cozunurluk] export const KAYNAK = [["yonetim-duzlemi", "json", 8, 6, 8, "1 ms"], ["uc-nokta", "anahtar=deger", 8, 5, 1, "1 s"], ["ag-akisi", "csv", 8, 4, 5, "1 s"]]; const GUN = Date.UTC(2026, 3, 2); const iso = (ms) => new Date(GUN + ms).toISOString(); export const yd = [], un = [], aa = []; // uc ham gunluk, uc ayri bicim const etiketli = { yd: [], un: [], aa: [] }; // modelin dogrusu; gunluk satirina YAZILMAZ // Ortak olay: ayni is kalemi birden cok kaynakta iz birakir. Model bunu bilir, hat bilmez. export const ORTAK = []; for (let k = 0; k < 30; k++) { const i = tam(KONAK.length), h = HESAP[tam(28)]; ORTAK.push({ t: 3600e3 + tam(50000e3), konak: KONAK[i], adres: ADRES[i], hesap: h, portal: PORTAL[HESAP.indexOf(h)], uc: r() < 0.8, ag: r() < 0.9, yd: r() < 0.7 }); } const yaz = (o, e) => { if (o.yd) { yd.push({ ts: iso(o.t + 480e3 + tam(9000)), actor: { id: o.portal, type: "kullanici" }, op: sec(EYLEM), target: `kova/olcum/${tam(900)}`, result: r() < 0.9 ? "izin-verildi" : "reddedildi", srcIp: o.adres, requestId: `q${tam(1e5)}` }); etiketli.yd.push(e); } if (o.uc) { un.push(`zaman=${Math.floor((GUN + o.t + 60e3 + tam(9000)) / 1000)} ` + `konak=${o.konak} olay=surec-olusturma kullanici=${o.hesap} pid=${1000 + tam(9000)} ` + `ust=${400 + tam(600)} yol=${sec(YOL)} ` + `karma=${tam(1e9).toString(16).padStart(8, "0")}`); etiketli.un.push(e); } if (o.ag) { aa.push([Math.floor((GUN + o.t + 300e3 + tam(9000)) / 1000), 1 + tam(60), o.adres, `10.90.2.${10 + tam(40)}`, sec([443, 8443, 5671]), "giden", 400 + tam(9e5), 5 + tam(900)].join(",")); etiketli.aa.push(e); } }; ORTAK.forEach((o, i) => yaz(o, i)); // Arka plan trafigi: ortak olayla iliskisiz kayitlar. for (let k = 0; k < 480; k++) { const i = tam(KONAK.length); yaz({ t: tam(86400e3), konak: KONAK[i], adres: ADRES[i], hesap: sec(HESAP), portal: sec(PORTAL), uc: r() < 0.45, ag: r() < 0.75, yd: r() < 0.25 }, -1); } // Normallestirme: her kaynak icin bir eslestirici. Doldurulamayan alan null kalir. export const normal = { "yonetim-duzlemi": (s) => { const o = JSON.parse(s); return { t: Date.parse(o.ts), kaynak: "yonetim-duzlemi", konak: null, adres: o.srcIp, aktor: o.actor.id, eylem: o.op, hedef: o.target, sonuc: o.result }; }, "uc-nokta": (s) => { const a = Object.fromEntries(s.split(" ").map((p) => p.split("="))); return { t: Number(a.zaman) * 1000, kaynak: "uc-nokta", konak: a.konak, adres: null, aktor: a.kullanici, eylem: a.olay, hedef: a.yol, sonuc: null }; }, "ag-akisi": (s) => { const [b, , ka, he, p] = s.split(","); return { t: Number(b) * 1000, kaynak: "ag-akisi", konak: null, adres: ka, aktor: null, eylem: null, hedef: `${he}:${p}`, sonuc: null }; }, }; export const HAM = { "yonetim-duzlemi": yd.map((o) => JSON.stringify(o)), "uc-nokta": un, "ag-akisi": aa }; const ETIKETLI = { "yonetim-duzlemi": etiketli.yd, "uc-nokta": etiketli.un, "ag-akisi": etiketli.aa }; const hepsi = Object.entries(HAM).flatMap(([k, l]) => l.map((s, i) => [normal[k](s), ETIKETLI[k][i]])).sort((a, b) => a[0].t - b[0].t); export const OLAY = hepsi.map((x) => x[0]); export const ETIKET = hepsi.map((x) => x[1]); // ortak olay indeksi ya da -1; hat GORMEZ if (import.meta.url === `file://${process.argv[1]}`) { const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j]) : String(v).padEnd(B[0]))).join(""); const yz = gen([18, 15, 8, 7, 14, 12, 11, 13, 14]); console.log(`model (tohum ${TOHUM}): ${OLAY.length} kayit, ${SEMA.length} alanlik sema`); for (const k of ["yonetim-duzlemi", "uc-nokta", "ag-akisi"]) console.log(HAM[k][0]); console.log(); console.log(yz(["kaynak", "bicim", "kayit", "alan", "eslenen alan", "artik alan", "bos sema", "zaman coz.", "aktarim gec."])); for (const [ad, bicim, alan, esl, gec, coz] of KAYNAK) { const ornek = normal[ad](HAM[ad][0]); const dolu = SEMA.filter((a) => a !== "kaynak" && ornek[a] !== null).length; console.log(yz([ad, bicim, HAM[ad].length, alan, esl, alan - esl, SEMA.length - 1 - dolu, coz, `${gec} dk`])); } const t = KAYNAK.reduce((a, k) => a + k[2], 0), e = KAYNAK.reduce((a, k) => a + k[3], 0); console.log(`\ntoplam ${t} kaynak alani: ${e} tanesi semaya esleniyor, ` + `${t - e} tanesi artik kaliyor; aktor alani ag akisinda hicbir kayitta yok`); }
model (tohum 20260402): 787 kayit, 8 alanlik sema
{"ts":"2026-04-02T10:26:21.519Z","actor":{"id":"ab-4401","type":"kullanici"},"op":"yetki.degistir","target":"kova/olcum/888","result":"izin-verildi","srcIp":"10.40.1.22","requestId":"q96644"}
zaman=1775125160 konak=uc-113 olay=surec-olusturma kullanici=sh-201 pid=4052 ust=405 yol=/usr/bin/arsivle karma=3718b893
1775125395,7,10.40.1.22,10.90.2.18,5671,giden,120991,443
kaynak bicim kayit alan eslenen alan artik alan bos sema zaman coz. aktarim gec.
yonetim-duzlemi json 139 8 6 2 1 1 ms 8 dk
uc-nokta anahtar=deger 244 8 5 3 2 1 s 1 dk
ag-akisi csv 404 8 4 4 4 1 s 5 dk
toplam 24 kaynak alani: 15 tanesi semaya esleniyor, 9 tanesi artik kaliyor; aktor alani ag akisinda hicbir kayitta yok
Üç örnek satır üç ayrı dünya gösteriyor. Yönetim düzlemi kaydı iç içe geçmiş bir nesne yazıyor ve
aktörü actor.id yolunda saklıyor. Uç nokta kaydı düz anahtar=deger çiftleri yazıyor ve aktörü
kullanici diye adlandırıyor. Ağ akış kaydı ise başlıksız bir virgüllü satırdır: alan adı kaydın
içinde yoktur, yalnız sıradadır. İlk sütunun zaman olduğunu bilen tek şey ayrıştırıcıdır.
Yirmi dört kaynak alanının 15’i şemaya oturuyor, 9’u artık kalıyor. Artık alan tam bir kayıp değildir — ham kayıt saklanır — ama ortak şema üzerinden sorgulanamaz; süreç kimliği ya da bayt sayısı şemada yer bulmadığı için hiçbir bağıntı kuralı onu ölçüt olarak kullanamaz.
Asıl kayıp bos sema sütunundadır. Ağ akış kaydında dört şema alanı boştur: konak, aktör, eylem ve
sonuç. Bunların içinde en ağırı aktördür, çünkü kursun bütün bağıntı işlemi aktör ekseninde
yürüyecektir. 404 akış kaydının hiçbirinde kimin yaptığı yazmaz. Uç nokta kaydında sonuç alanı
boştur: bir sürecin çalıştığı yazılır, izin verilip verilmediği yazılmaz.
Son iki sütun zamanın iki ayrı sorununu ayırıyor. Çözünürlük iki kaynağın olayları saniyeye yuvarlaması demektir; aynı saniyedeki iki kaydın sırası kaybolur. Yazma gecikmesi daha belirleyicidir: aynı olay uç noktada bir, ağ akışında beş, yönetim düzleminde sekiz dakika sonra kayda geçer. Hat üç kaydı yedi dakikaya yayılmış görür ve yayılmanın gerçek mi aktarımdan mı geldiğini ayırt edemez.
Eşlenemeyen Alanı Doldurmak
Aktör alanı boş bırakılamaz, çünkü boş kalırsa üç kaynak birbirine hiç bağlanmaz. Doldurmanın iki yolu vardır ve ikisi de günlüğün dışındaki bir tabloya dayanır: portal kimliğini hesaba çeviren statik bir eşleme ve adresi konağa, konağı da o andaki oturuma bağlayan zamana duyarlı bir arama.
// birlestir.mjs — eslenemeyen aktor alani ara tablolarla doldurulur, sonra kayitlar toplanir. import { OLAY, ETIKET, ORTAK, KONAK, ADRES, HESAP } from "./kaynak.mjs"; // Ara tablolar model verisidir: gunlukte yoktur, varlik envanterinden gelir. const adresKonak = new Map(ADRES.map((a, i) => [a, KONAK[i]])); const portalHesap = new Map(HESAP.slice(0, 28).map((h, i) => [`ab-${4401 + i}`, h])); const uc = OLAY.filter((o) => o.kaynak === "uc-nokta"); // Ag akisi kaydinda aktor yok: adres konaga, konak da +/- W dakikalik pencerede // uc nokta kaydindaki hesaba baglanmaya calisilir. function aktorAta(pencere) { const cozum = new Array(OLAY.length).fill(null); let atanan = 0, belirsiz = 0, bos = 0, portalCevrilen = 0; for (const [i, o] of OLAY.entries()) { if (o.kaynak === "uc-nokta") { cozum[i] = o.aktor; continue; } if (o.kaynak === "yonetim-duzlemi") { cozum[i] = portalHesap.get(o.aktor) || null; if (cozum[i]) portalCevrilen++; continue; } const k = adresKonak.get(o.adres); const aday = [...new Set(uc.filter((u) => u.konak === k && Math.abs(u.t - o.t) <= pencere * 60e3).map((u) => u.aktor))]; if (aday.length === 1) { cozum[i] = aday[0]; atanan++; } else if (aday.length > 1) belirsiz++; else bos++; } return { cozum, atanan, belirsiz, bos, portalCevrilen }; } // Aktor alani dolu kayitlar hesap ekseninde, W dakikalik bosluk kuralina gore kumelenir. function kumele(cozum, pencere) { const grup = new Map(); for (const [i, a] of cozum.entries()) if (a) (grup.get(a) || grup.set(a, []).get(a)).push(i); const kume = []; for (const [, l] of grup) { let s = [l[0]]; for (const i of l.slice(1)) { if (OLAY[i].t - OLAY[s[s.length - 1]].t <= pencere * 60e3) s.push(i); else { kume.push(s); s = [i]; } } kume.push(s); } const cok = kume.filter((s) => new Set(s.map((i) => OLAY[i].kaynak)).size >= 2); const toplanan = new Set(), karisik = cok.filter((s) => { const e = new Set(s.map((i) => ETIKET[i]).filter((x) => x >= 0)); for (const x of e) if (s.filter((i) => ETIKET[i] === x).length >= 2) toplanan.add(x); return e.size >= 2; }); const ucKaynak = [...toplanan].filter((x) => cok.some((s) => new Set(s.filter((i) => ETIKET[i] === x) .map((i) => OLAY[i].kaynak)).size === 3)).length; return { kume: cok.length, toplanan: toplanan.size, ucKaynak, karisik: karisik.length }; } const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j]) : String(v).padEnd(B[0]))).join(""); const yz = gen([12, 11, 11, 9, 9, 15, 13, 11]); const ag = OLAY.filter((o) => o.kaynak === "ag-akisi").length; console.log(`${OLAY.length} normallestirilmis kayit; ${ag} ag akisi kaydinin aktor alani bos, ` + `${OLAY.filter((o) => o.kaynak === "yonetim-duzlemi").length} yonetim duzlemi kaydinda ` + `aktor portal kimligi olarak yaziyor`); const ikiUstu = ORTAK.filter((o) => [o.uc, o.ag, o.yd].filter(Boolean).length >= 2).length; console.log(`modelin bildigi ortak olay ${ORTAK.length}, bunlarin ${ikiUstu} tanesi en az iki ` + `kaynakta iz birakiyor (hat bunu gormez)`); console.log(); console.log(yz(["pencere", "aktor atn.", "belirsiz", "bos", "kume", "toplanan olay", "uc kaynakli", "karisik"])); for (const p of [1, 5, 15, 60]) { const a = aktorAta(p), k = kumele(a.cozum, p); console.log(yz([`${p} dk`, a.atanan, a.belirsiz, a.bos, k.kume, `${k.toplanan}/${ikiUstu}`, k.ucKaynak, k.karisik])); } const a5 = aktorAta(5); console.log(`\nportal kimligi hesaba cevrilen yonetim duzlemi kaydi: ${a5.portalCevrilen}; ` + `cevrilemeyen ${OLAY.filter((o) => o.kaynak === "yonetim-duzlemi").length - a5.portalCevrilen}`); console.log(`aktor alani dolu kayit ${a5.cozum.filter(Boolean).length}/${OLAY.length}`);
787 normallestirilmis kayit; 404 ag akisi kaydinin aktor alani bos, 139 yonetim duzlemi kaydinda aktor portal kimligi olarak yaziyor modelin bildigi ortak olay 30, bunlarin 26 tanesi en az iki kaynakta iz birakiyor (hat bunu gormez) pencere aktor atn. belirsiz bos kume toplanan olay uc kaynakli karisik 1 dk 3 0 401 3 0/26 0 0 5 dk 190 2 212 184 21/26 13 1 15 dk 195 7 202 179 21/26 13 1 60 dk 208 39 157 145 20/26 12 1 portal kimligi hesaba cevrilen yonetim duzlemi kaydi: 115; cevrilemeyen 24 aktor alani dolu kayit 549/787
Statik eşleme kolay olanıdır ve o bile tam değildir: 139 yönetim düzlemi kaydının 115’i bir hesaba çevriliyor, 24’ü çevrilemiyor. Karşılığı olmayan altı portal kimliği servis kimliğidir ve envanterde bir kişiye bağlı değildir. Bu 24 kayıt şemada aktör alanı dolu görünür, ama içindeki değer öteki iki kaynakla hiçbir zaman eşleşmez — dolu bir alan boş bir alandan daha yanıltıcıdır.
Zamana duyarlı arama ise doğrudan pencereye bağlıdır ve tablo pencerenin iki yönlü etkisini gösteriyor. Bir dakikalık pencerede 404 akış kaydının yalnız 3’üne aktör atanabiliyor; kaynakların yazma gecikmeleri 1 ve 5 dakika olduğu için akış kaydı ile uç nokta kaydı arasında zaten dört dakika vardır. Beş dakikaya çıkıldığında atama 190’a fırlıyor. Altmış dakikada atama yalnız 18 kayıt daha kazanıyor, buna karşılık belirsiz kayıt 2’den 39’a çıkıyor: pencere genişledikçe aynı konakta birden çok hesabın oturumu görünür oluyor ve hangisinin akışı olduğu söylenemez hâle geliyor.
Son iki sütun ölçünün karşılığını veriyor. En az iki kaynakta iz bırakan 26 kurgu olayın beş dakikalık pencerede 21’i toplanıyor, 13’ü üç kaynağın hepsiyle birlikte. Bir dakikalık pencerede hiçbiri toplanmıyor — bu sıfır, verinin eksikliğinden değil, kaynakların farklı anlarda yazmasından geliyor. Toplanamayan beş olayın çoğunda ağ akışı kaydı yoktur; geriye kalan uç nokta ve yönetim düzlemi kayıtları arasında yedi dakika vardır ve beş dakikalık pencere onları köprüleyemez.
Karışık küme sayısı birde kalıyor: bu modelde pencereyi genişletmenin bedeli yanlış birleştirme değil, belirsizliktir. Yoğun bir ortamda o sütun büyür.
Özet
- Üç kaynağın 24 alanının 15’i sekiz alanlık şemaya eşleniyor, 9’u artık kalıyor; artık alan saklanır ama ortak şema üzerinden sorgulanamaz, bu yüzden hiçbir kurala ölçüt olamaz.
- Ağ akış kaydında dört şema alanı boştur ve en ağırı aktördür: 404 kaydın hiçbirinde kimin yaptığı yazmaz. Uç nokta kaydında sonuç alanı boştur.
- Aynı olay uç noktada 1, ağ akışında 5, yönetim düzleminde 8 dakika sonra kayda geçiyor; hat üç kaydı yedi dakikaya yayılmış görür ve yayılmanın gerçek mi aktarımdan mı olduğunu ayıramaz.
- Portal kimliğini hesaba çeviren statik eşleme 139 kaydın 115’ini çeviriyor, 24’ünü çeviremiyor; karşılığı olmayan servis kimliklerinde aktör alanı dolu görünür ama hiçbir şeyle eşleşmez.
- Pencere iki yönlü çalışıyor: bir dakikada 3 atama ve toplanan olay sıfır, beş dakikada 190 atama ve 21/26, altmış dakikada 208 atama ama belirsiz kayıt 2’den 39’a çıkıyor.
Sonraki Adım
Bu derste kümeleme tek ölçütle yapıldı: aynı aktör ve bir zaman penceresi. Bu ölçüt 184 küme üretti ve bunların yalnız 21’i modelin bildiği bir olaya karşılık geliyor; geri kalanı aynı hesabın gün içindeki olağan işidir. Bir güvenlik bilgi ve olay yönetimi sistemi kümelemeyi böyle yapmaz; koşul dizisi yazar — hangi kaynaktan hangi alan, hangi sırayla, hangi sayıdan sonra. Sonraki ders bu derste normalleştirilmiş akışın üzerine bir bağıntı kuralı koşturur ve iki sayı çıkarır: kural kaç olayı tek uyarıda birleştiriyor ve birleştirdiklerinin dışında neyi hiç görmüyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.