Help us shape the future of Go! Take the 2026 Go Developer Survey

model

package
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 16, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package model holds postern's domain types.

S2'de bu tipler config'den elle kuruluyordu; S3'ten beri veritabanından geliyorlar (şema bu alanların birebir karşılığı). Kararları veren kod model tiplerine baktığı için, kaynağın değişmesi policy'yi etkilemedi — motorun SQLite'tan PostgreSQL'e geçmesi de bu pakete dokunmadı.

Index

Constants

View Source
const (
	// ManagementAccount, hedefteki yönetim hesabının OS adı.
	ManagementAccount = "postern"

	// ManagementPrincipal, o hesabı açan tek sertifika principal'ı.
	ManagementPrincipal = "postern-manage"
)

* Yönetim hesabının adları. * * ⚠️ BU İKİ AD, HEDEFTE PAROLASIZ ROOT SUDO TUTAN HESABIN ANAHTARI. * deploy/ansible/roles/postern_target, "postern" hesabını açıyor ve onu * yalnızca "postern-manage" principal'ı taşıyan bir sertifikayla * açılabilir kılıyor. Bu yüzden adlar tek bir yerde duruyor: store, * policy ve upstream aynı sabiti okumazsa, birinin reddettiği adı öbürü * sessizce kabul eder. * * ⚠️ YAPILANDIRILAMAZ. Ansible rolünde değişken olarak duruyorlar ama * rol, varsayılandan farklı bir değeri REDDEDİYOR. Operatörün adı * değiştirebildiği bir kurulumda ikili eski adı reddetmeye devam eder, * yeni adı ise sıradan bir hesap sanardı.

View Source
const UnknownGroup = "unknown"

* UnknownGroup, kaynağın CEVAP VERDİĞİ ama hiçbir grup söylemediği * kullanıcıların düştüğü grup. * * ⚠️ ÇÖZÜLDÜ AMA BOŞ ≠ ÇÖZÜLEMEDİ. Bu grup YALNIZCA kaynak "bu kişiyi * tanıyorum ve hiçbir grupta değil" dediğinde uygulanır. Dizin cevap * veremediğinde ya da kullanıcıyı hiç bulamadığında uygulanmaz — o iki * hâlde hiçbir şey bilinmiyor demektir ve bir arızayı yetkiye çevirmek, * default-deny'ın tam tersi olurdu. * * Var olma sebebi somut: grup claim'i göndermeyen bir IdP'de hiç kimse * hiçbir role eşleşmiyor, ProvisionUser hesabı AÇMIYOR ve kullanıcı * kapıda kalıyor — yöneticinin elinde onu düzeltecek bir tutamak bile * olmadan. Bu grup o tutamağı veriyor: yönetici `unknown`'ı bir role * eşler, kullanıcı içeri girer ve doğru grubuna elle atanır.

Variables

This section is empty.

Functions

func ControlCharAt added in v1.2.0

func ControlCharAt(s string) int

* ControlCharAt, dizgideki ilk kontrol karakterinin bayt konumu; yoksa -1. * * ⚠️ TEK TANIM, İKİ KAPI. Aynı kural hem SERTİFİKA İMZALANIRKEN * (ca.Sign: key id ve principal) hem de kullanıcı adı VERİTABANINA * YAZILIRKEN uygulanıyor. İki ayrı kopya yazmak, ikisinin ayrışması * demekti — ve ayrışmanın yönü fark ediyor: yazma kuralı imzalama * kuralından GEVŞEK olursa, açılabilen ama sertifikası hiç kesilemeyen * bir hesap doğar. Bu depo o arızayı bir kez ölçtü (os_user kuralı * yalnızca politika kapısındaydı; hesap "kurulmuş görünüp her oturumda * reddedilen" hâlde doğuyordu, bkz. refuseBadOSUser). * * ⚠️ C1 DE SAYILIYOR (U+0080-U+009F), imzalama tarafındaki bayt * taramasının kaçırdığı aralık: UTF-8'de C2 80 olarak kodlanıyor ve iki * baytın ikisi de 0x20'nin üstünde. Terminal ve günlük ayrıştırıcıları * onları da yorumluyor. Kural bu yüzden rune üzerinden.

func IsManagementName added in v1.2.0

func IsManagementName(name string) bool

* IsManagementName, adın yönetim hesabına ait olup olmadığı. * * ⚠️ İKİSİ DE REDDEDİLİYOR, YALNIZCA HESAP ADI DEĞİL. Sıradan oturumlarda * sertifikanın principal'ı kullanıcının os_user'ı. os_user'ı * "postern-manage" olan bir panel kullanıcısı için postern tam da yönetim * principal'ını imzalardı; os_user'ı "postern" olan biri ise yönetim * hesabına giriş denerdi. Hedefin principal dosyası bugün ikisini de * durduruyor — ama elle kurulmuş, eski bir playbook'la ya da başka bir * araçla yapılandırılmış bir makinede o dosya daha gevşek olabilir ve * postern bunu göremez. Savunma hedefe bırakılmıyor.

func ResolvedGroups

func ResolvedGroups(groups []string) []string

* ResolvedGroups, çözülmüş bir grup listesini role çevrilmeye hazırlar. * * ⚠️ YALNIZCA PRESENCE=PRESENT olan çağrı noktalarından çağrılmalı. * İmzası bunu zorlayamıyor (bir []string alıyor), o yüzden kural her * çağrı yerinde yazılı: "kaynak cevap verdi" bilgisi orada duruyor, * burada değil.

func ValidOSUserName

func ValidOSUserName(name string) bool

ValidOSUserName reports whether name may be used as a target account.

func ValidUsername added in v1.2.0

func ValidUsername(name string) error

* ValidUsername, adın postern kullanıcı adı olarak yazılabilir olduğu. * * ⚠️ YALNIZCA KONTROL KARAKTERİ ELENİYOR, ŞEKİL DEĞİL. Kullanıcı adı * kimlik sağlayıcısından geliyor ve e-posta, UPN ya da uzun bir dizin * adı olabiliyor; ona bir desen dayatmak kurumun kendi ad alanını * reddetmek olurdu. Elenen şey ÖLÇÜLEN zarar: ad, sertifikanın key * id'sine giriyor ve hedefin sshd günlüğüne olduğu gibi yazılıyor — * satır sonu taşıyan bir ad, o günlüğe kendi satırını yazdırıyordu.

Types

type PathRule added in v1.2.0

type PathRule struct {
	// Prefix, mutlak yol öneki. Eşleşme DİZİN SINIRINDA yapılıyor.
	Prefix string

	// Allow false ise açık ret: izinli bir ağacın içinden dal kesmeye
	// yarıyor. En uzun eşleşen önek kazandığı için çalışıyor.
	Allow bool

	// CanWrite, iznin yazmayı da kapsayıp kapsamadığı.
	CanWrite bool
}

PathRule, bir yol öneği üzerindeki karar.

type Role

type Role struct {
	Name string

	// Targets, bu rolün erişebildiği hedef adları.
	Targets []string

	/*
	 * Paths, bu rolün SFTP yol kuralları.
	 *
	 * ⚠️ BOŞ LİSTE "HİÇBİR ŞEY" DEĞİL, "KISIT YOK" DEMEK. Kuralı olmayan
	 * bir rol bugünkü gibi her yola erişiyor; kısıtlama kural
	 * EKLENDİĞİNDE başlıyor. Aksi hâli, yükseltmenin ertesi sabahı her
	 * kurulumun SFTP'sini kırmak olurdu.
	 */
	Paths []PathRule
}

Role, bir hedef kümesine erişim yetkisi.

S3 şemasında roles + role_targets tablolarının karşılığı.

type SFTPJournal added in v1.2.0

type SFTPJournal struct {
	/*
	 * Measured, kaydın mühür satırındaki sayının bilindiği.
	 *
	 * ⚠️ FALSE "GEÇTİ" DEĞİL, "KARŞILAŞTIRILAMAZ" DEMEK — zincir
	 * başındaki (034) boş baş kararının aynısı. Göç 037'den önce
	 * kapanmış oturumlarda ve kaydı hiç tutulmamış oturumlarda mühür
	 * yok; onları "defteri tam" diye göstermek, hiç yapılmamış bir
	 * kontrolü yapılmış saymak olurdu.
	 */
	Measured bool

	// Events, kaydın mühür satırındaki olay sayısı (internal/sftpcast).
	Events int64

	/*
	 * Digest, mühür satırındaki özet: kayda giren satırların
	 * XOR'lanmış SHA-256'sı, onaltılık.
	 *
	 * ⚠️ SAYININ YANINDA DURUYOR ÇÜNKÜ AYRI BİR SORUYU CEVAPLIYOR.
	 * Sayı "kaç satır" diyor; özet "hangi satırlar" diyor. Sayı tutup
	 * özet tutmuyorsa satır SİLİNMEMİŞ, DEĞİŞTİRİLMİŞ demektir — ve o,
	 * defterden satır silmekten daha ince bir müdahale: silinen satır
	 * en azından bir boşluk bırakıyor, değiştirilen satır tam bir
	 * denetim kaydı gibi duruyor.
	 *
	 * ⚠️ OLAY YOKKEN BOŞ — sıfırların onaltılığı DEĞİL. Mühür satırı
	 * da yazılmıyor; dosyada karşılığı olmayan bir değeri saklamak,
	 * kontrolün "kayıt böyle diyor" dediği şeyi uydurmak olurdu.
	 */
	Digest string

	/*
	 * Lost, postern'in deftere koyamadığını BİLDİĞİ olay sayısı:
	 * tampon taştığı için atılanlar ve kapanışta yazılamamış olarak
	 * elde kalanlar.
	 *
	 * ⚠️ AYRI DURUYOR ÇÜNKÜ AYRI BİR BULGU. Aritmetiği "satırlar
	 * silinmiş" hâliyle aynı (satır sayısı mühürden eksik) ama olayı
	 * bambaşka: biri postern'in kendi arızası, öbürü müdahale.
	 */
	Lost int64

	/*
	 * Denied, POSTERN'İN KENDİ reddettiği istek sayısı — defterdeki
	 * "denied." önekli satırlar (sftpaudit/policy.go).
	 *
	 * ⚠️ HEDEFİN "permission denied"I BURAYA GİRMİYOR. O, hedefin dosya
	 * izinleri hakkında bir şey söylüyor; bu, postern'in kurallarının
	 * çiğnenmeye çalışıldığını. İkisini tek sayıya katlamak, denetçiye
	 * "kural sınandı" ile "kullanıcının o dosyaya erişimi yok"u aynı
	 * rakamla gösterirdi.
	 *
	 * ⚠️ SAYI, DEFTERDEKİ SATIR ADEDİNDEN BÜYÜK OLABİLİR. Ardışık aynı
	 * retler tek satıra katlanıyor ve sayı katlananları da içeriyor:
	 * "kaç satır var" ile "kaç kez denendi" apayrı iki soru, ve
	 * denetçinin sorduğu ikincisi.
	 *
	 * ⚠️ Counted FALSE İKEN SIFIR OKUNMAMALI. Göç 038'den önce kapanmış
	 * oturumlarda sayım yapılmadı; sıfır göstermek "hiçbir şey
	 * reddedilmedi" demek olurdu — Measured'ın aynı gerekçesi.
	 */
	Denied int64

	// Counted, Denied'in gerçekten sayıldığı (göç 038 sonrası).
	Counted bool
}

* SFTPJournal, bir oturumun SFTP denetim defterinin kapanıştaki durumu. * * ⚠️ ÜÇ ALAN, ÇÜNKÜ ÜÇ AYRI SORU. "Kayıt kaç olay saydı", "postern * bunların kaçını deftere koyamadığını BİLİYOR" ve "bu ikisi ölçüldü * mü". Üçüncüsü olmadan diğer ikisi yanıltıcı: ölçülmemiş bir oturumda * Events sıfırdır ve sıfır, "hiç olay olmadı" gibi okunur.

type Session

type Session struct {
	// ID, record.NewSessionID()'nin ürettiği değer. Kayıt dosyasının adı
	// da bu olduğu için, denetim kaydı ile .cast dosyası arasındaki bağ
	// tek bir alanla kuruluyor.
	ID string

	// User ve Target, id değil AD tutar. Denetim kaydını okuyan insan
	// "hangi kullanıcı" diye sorduğunda cevabın bir JOIN'e ihtiyacı olmasın.
	User   string
	Target string

	// OSUser, oturumun AÇILDIĞI hesap.
	//
	// users.os_user'ın kopyası gibi görünür ama değildir: policy o an
	// başka bir hesaba karar vermiş olabilir ve kullanıcının bugünkü
	// os_user'ı o günkü kararı değiştirmemeli. Denetim, kaydın alındığı
	// andaki gerçeği saklar.
	OSUser string

	// SrcIP, kullanıcının bastion'a bağlandığı adres.
	SrcIP string

	/*
	 * Temporary: oturumu bir ROL değil, SÜRELİ BİR HAK açtı (göç 044).
	 *
	 * ⚠️ KARAR ANINDA YAZILIYOR, SONRADAN TÜRETİLMİYOR. Hak geri
	 * alındığında ya da süresi dolduğunda jit_grants'tan bakarak "o
	 * saatte açık bir hak var mıydı" demek, denetim kaydını başka bir
	 * tablonun sonraki hâline bağlar; denetçi bunu satırda görmeli.
	 */
	Temporary bool

	// RecordingChain ve RecordingLinks, kaydın zincir başı ve halka
	// sayısı (göç 034).
	//
	// ⚠️ BOŞ BAŞ "DOĞRULANDI" DEĞİL, "DOĞRULANAMAZ" DEMEK. Göç öncesi
	// kapanmış oturumlarda ve çökme sonrası süpürülen oturumlarda baş
	// yok; ikisini "geçti" gibi göstermek, kanıtı olmayan bir kaydı
	// kanıtlanmış saymak olurdu.
	RecordingChain string
	RecordingLinks int64

	// SFTPJournal, oturum kapanırken defterin durumu (göç 037).
	SFTPJournal SFTPJournal

	StartedAt time.Time

	// EndedAt sıfır değerse oturum hâlâ açık (şemada NULL).
	EndedAt time.Time

	// RecordingPath, .cast dosyasının yolu. Kayıt açılamadıysa boş —
	// ama o durumda oturum zaten reddedilmiş olmalı (S1.8 kararı).
	RecordingPath string
}

Session, açılmış bir oturumun denetim kaydı.

S3 şemasında sessions tablosu. Bu kayıt oturumdan DAHA UZUN yaşar: kullanıcı ya da hedef sonradan silinse bile "kim, nereye, ne zaman girdi" sorusunun cevabı durmak zorunda.

func (Session) Open

func (s Session) Open() bool

Open, oturumun hâlâ sürüp sürmediğini söyler.

type Target

type Target struct {
	Name    string
	Host    string
	Port    int
	HostKey string

	// Labels, operatörün iliştirdiği key=value notları ("env=prod").
	//
	// ⚠️ YETKİ DEĞİL: erişimi rol → hedef bağı veriyor. Etiket yalnızca
	// hedefleri gruplayıp bulmak için — etiketten yetki türetmek,
	// etiket ekleyebilen herkese yetki dağıtmak olurdu.
	//
	// Yalnızca LİSTELEME yollarında dolu (store.Targets). Oturum açma
	// yolundaki tekil okuma bunu çekmiyor: her bağlantıda ikinci bir
	// sorgu, hiç kullanılmayan bir alan için.
	Labels map[string]string
}

type TargetFacts

type TargetFacts struct {
	// ServerVersion, sunucunun kendi afişi: "SSH-2.0-OpenSSH_9.6p1 Debian-3".
	ServerVersion string
	// HostKeyType, pinlenmiş anahtarın türü (ssh-ed25519 …).
	HostKeyType string
	// LastSeenAt, son BAŞARILI bağlantı. Sıfır ise hiç bağlanılmadı.
	LastSeenAt time.Time
	// ConnectMS, o bağlantının el sıkışma süresi.
	ConnectMS int
	// LastErrorAt/LastError, son BAŞARISIZ deneme. Başarıyı silmiyor.
	LastErrorAt time.Time
	LastError   string

	// Probe, yalnızca target_probe.enabled ile dolar — yani hedefte
	// komut çalıştırıldıysa. ProbedAt sıfırsa hedefe hiç dokunulmadı.
	//
	// İç içe duruyor ki paneli çizen de, koda bakan da "bu satırı
	// öğrenmek için makineye dokunduk mu" sorusunu tek bakışta
	// cevaplayabilsin.
	Probe    TargetProbe
	ProbedAt time.Time
}

TargetFacts, hedefe BAĞLANIRKEN öğrenilenler.

⚠️ Yapılandırma değil GÖZLEM: Target operatörün yazdığını, bu yapı makinenin söylediğini tutuyor. İçeriği el sıkışmadan ve (açıksa) kullanıcının kendi bağlantısındaki tanımadan geliyor.

⚠️ Bu yorum önceden "postern kullanıcının oturumu dışında hedefte iş çalıştırmaz" diyordu. Yönetim hesabıyla bu artık yalnızca rolü postern_manage_host ile koşmuş hedefler için doğru değil — ve o koşuların sonucu BURAYA yazılmıyor: bu yapı hâlâ yalnızca bağlanırken öğrenilenleri tutuyor.

type TargetProbe

type TargetProbe struct {
	// Kernel, `uname -srm` çıktısı.
	Kernel string
	// OSName, /etc/os-release içindeki PRETTY_NAME (yoksa NAME).
	OSName string
}

TargetProbe, hedefte KOMUT ÇALIŞTIRARAK öğrenilenler.

⚠️ TargetFacts'ten AYRI TUTULUYOR ve bu ayrım kasıtlı: TargetFacts'in içeriği el sıkışmadan gelir ve postern hedefte hiçbir şey çalıştırmadan öğrenilir. Buradakiler ise ancak target_probe.enabled ile, hedefte komut koşturularak elde ediliyor. İkisini aynı yapıya koymak, panele bakan operatörün "bunu öğrenmek için makineye dokunduk mu" sorusunu cevapsız bırakırdı.

type TemporaryAccess added in v1.2.0

type TemporaryAccess struct {
	Target string
	// OSUser, hedefte açılan hesabın adı. Kişinin o günkü os_user'ı;
	// sertifikanın principal'ı da bu olmak zorunda.
	OSUser    string
	ExpiresAt time.Time
	/*
	 * Applied, hesabın hedefte GERÇEKTEN açılmış olduğu. Yarım kalan bir
	 * hak da kayıtta duruyor (süpürücü toplayacak); ona yetki vermek,
	 * var olmayan bir hesaba oturum açtırmaya çalışmak olurdu.
	 */
	Applied bool
}

* TemporaryAccess, bir kişinin bir hedefte SÜRELİ hesabı — politikanın * gördüğü hâli (jit_grants satırının yetkiye dair kısmı). * * ⚠️ ROL DEĞİL, AYRI BİR YETKİ KAYNAĞI. Rol, rolü taşıyan herkese kalıcı * erişim; bu ise tek kişiye, tek hedefte, bir vadeye kadar. İkisini aynı * yapıya sıkıştırmak — geçici hakkı bir role çevirmek — süresi dolunca * silinmesi gereken şeyi rol tablosuna sızdırırdı.

func (TemporaryAccess) Live added in v1.2.0

func (a TemporaryAccess) Live(now time.Time) bool

Live, hakkın şu an yetki verip vermediği.

type User

type User struct {
	// Name, postern kullanıcı adı ("yigit"). auth.go'nun doğruladığı ve
	// Permissions'a koyduğu değer.
	Name string

	// OSUser, kişinin hedeflerdeki VARSAYILAN hesabı. İstek boş geldiğinde
	// principal bu olur.
	//
	// S3 şemasında users.os_user (NOT NULL) — kişiye özel, paylaşılmaz.
	// Driver 1'in özü bu alan: herkes hedefe kendi adıyla düşüyor.
	OSUser string

	// Roles, kişinin sahip olduğu roller. Hedef erişimi rollerden gelir.
	Roles []Role

	// SSOOnly true ise bu kullanıcı YALNIZCA kimlik sağlayıcı üzerinden
	// girebilir; public key ile girişi reddedilir.
	//
	// IdP'den otomatik oluşan (JIT) kullanıcılar böyle doğar: erişimleri
	// IdP'de kapatılınca gerçekten bitsin ve rolleri her girişte
	// tazelensin diye. Elle oluşturulan servis hesapları false kalır.
	SSOOnly bool

	/*
	 * DirBound, hesabın bir DİZİN kimliğine bağlı olduğu.
	 *
	 * ⚠️ Oturum açılışında dizine yeniden sorulup sorulmayacağının
	 * DOĞRU koşulu bu — SSOOnly değil. Ölçüldü: yetkisi dizinden gelen
	 * bir yönetici (admin_via='group') sso_only=false ile duruyordu,
	 * yani dizinde kapatılsa bile anahtarıyla oturum açardı.
	 */
	DirBound bool

	// Admin, uygulama YÖNETİM yetkisi (kullanıcı/rol/hedef değiştirme,
	// web'deki yönetim sayfaları). Hedef erişimiyle ilgisi yok: admin
	// olmayan biri terminale girebilir, admin olan biri rolü yoksa hiçbir
	// hedefe giremez. İki eksen bilerek ayrık.
	Admin bool
}

User, bastion'da kimliği doğrulanmış kişi.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL