Bir VPN daemon'undaki bağlantı hook'ları daemon olarak çalışır ve bu genellikle root olarak çalıştıkları anlamına gelir. Bu hook'lardan biri birinin ev dizinine yazdığında veya bir masaüstü yardımcısını yeniden başlattığında, bir ağ olayına herhangi bir yerel kullanıcı olarak davranma yeteneği vermiş olursunuz. Alışılmış kısa yol, yani bir ortam değişkeninden kullanıcı adını okuyup iletmek, bunu düzeltmez. Yalnızca eylemi yeniden etiketler, onu hangi hesabın yürüttüğünü değiştirmez. İşe yarayan şey üç parçalı bir devir teslimdir: ayrıcalıklı adım ne olduğunu söyler ve ayrı bir birim eylemi doğru kimlik altında gerçekleştirir.

Ortamdaki kullanıcı adı bir kimlik anahtarı değildir

Unix, bir sürecin neye dokunabileceğine etkin kullanıcı kimliğine göre karar verir, ortamındaki dizelere göre değil. USER=alice ayarlamak veya LOGNAME dışa aktarmak, dikkatsiz yazılımın çıktısına ne bastığını değiştirir; dosya sahipliği denetimlerinde hiçbir şeyi değiştirmez. O değişkenle root olarak çalışan bir hook hâlâ Alice'in dosyalarını root olarak açar.

Adlar da aynı ad değildir. Uzak erişim oturum açması, yerel Unix hesabı ve sertifikanın ortak adı, sık sık örtüşen ve bazen örtüşmeyen üç tanımlayıcıdır. a.smith olarak kimlik doğrulayan bir kullanıcının hiç yerel hesabı olmayabilir ya da bir dizin hizmeti aracılığıyla asmith ile eşleştirilebilir. Tek bir dizenin üç rolü birden karşıladığını varsayan her tasarım ilk yüklenicide kırılır.

Yani ilk soru «hangi kullanıcı bağlı» değil, «hangi yerel hesabın bu eylemi yapmasına izin var». Bunu istemcinin gönderdiğinden değil, kendi hesap veritabanınızdan yanıtlayın:

id -u alice
getent passwd alice | cut -d: -f1,3,6
stat -c '%U:%G %a %n' /home/alice/.local/state/vpn-status.json

Üçüncü komut, insanların atladığı komuttur. Hedef dosya root'a aitse çünkü önceki hook onu oluşturmuşsa, doğru yapılandırılmış bir kullanıcı eylemi systemd sorunu gibi görünen ama olmayan bir izin hatasıyla başarısız olur.

Daemon olduğu yerde kalır

VPN hizmetinin kendi User= değerini Alice yapmak yanlış koldur. Daemon'un arayüzleri nasıl bağladığını, anahtarları nasıl okuduğunu, durum dosyasını nasıl yazdığını ve yolları nasıl yönettiğini değiştirir ve tüm bu riski çalışan bir birime taşır. Daemon'un kendi ayrıcalıklarına ihtiyacı vardır; sonraki eylemin yoktur.

Birime dokunmadan önce gerçekte ne yaptığına bakın. İki komut size yürütme kimliğini ve yürürlükteki tam komut satırlarını söyler, bir geçersiz kılmanın eklediği her şey dahil:

systemctl show -p User -p Group -p ExecStart openvpn-server@server
systemctl cat openvpn-server@server

Varsayılan paket kurulumunda daemon root'tır ve --up betiği bunu devralır. Varsaymak yerine doğrulayın, çünkü sertleştirilmiş bir dağıtım onu özel bir hesaba taşımış olabilir ve elle yazılmış bir drop-in hook'u farklı kurallara sahip bir sarmalayıcı üzerinden çalıştırabilir.

Üç adlandırılmış parça, tek dar tetikleyici

Bakımı atlatan düzenlemede bir olay, bir tetikleyici ve bir eylem vardır. Daemon adlandırılmış bir oturumun açıldığını bildirir. Tetikleyici bu küçük olguyu kabul eder ve tek bir sabit eylem ister. Eylem, dokunduğu dosyaların sahibi olan yerel hesap altında çalışır. Zincirde hiçbir şey rastgele bir komut yolu kabul etmez.

Eylemin kendisi sıradan bir hizmet birimidir ve kimlik onun içindeki tek bir direktiftir:

[Service]
Type=oneshot
User=alice
Group=alice
ExecStart=/usr/local/bin/refresh-vpn-status --slot %i

User=alice değerinin tüm birim için geçerli olduğuna dikkat edin ve systemd bilinmeye değer bir istisnayı belgeler: + önekiyle başlayan bir komut buna bakılmaksızın tam ayrıcalıklarla çalışır. Bu önek tek bir ayrıcalıklı adım için meşru bir araçtır ve az önce kurduğunuz ayrımı geri almanın kolay bir yoludur, bu yüzden o birimdeki her + değerini incelemede gerekçelendirilmesi gereken bir şey olarak görün.

Tetikleyicinin girdisini asgari ve gizli olmayan tutun. Oturum tanımlayıcısı, eşlenen hesap ve bir zaman damgası genellikle gereken her şeydir. Sınırın ötesine asla bir kabuk parçası, yürütülebilir dosya yolu veya istemci tarafından sağlanan bir ortam bloğu geçirmeyin, çünkü alan taraf meşru bir değeri enjekte edilmiş olandan ayırmanın bir yoluna sahip değildir.

Gerçekte çalışan kimliği doğrulayın

Yapılandırma incelemesi kanıt değildir. Onaylanmış bir test bağlantısından sonra dosyaya dokunan UID'i ve daemon'un hâlâ kullandığı UID'i doğrulayın:

stat -c '%U %G %y %n' /home/alice/.local/state/vpn-status.json
ps -o user=,pid=,cmd= -p "$(pgrep -o -f 'openvpn --daemon')"
systemd-run --uid=alice --pipe /usr/local/bin/refresh-vpn-status --dry-run

İlk satır Alice'i ve test pencerenizin içinde bir zaman damgasını göstermelidir. İkinci satır hâlâ root'u veya paketin hizmet hesabını göstermelidir, bu da daemon'un yerinden kımıldamadığını kanıtlar. Üçüncü, gerçek bir yeniden bağlanmayı beklemeden eylemin izinlerini test etmenin en ucuz yoludur.

Dosyanın sahibi Alice ise ama grubu veya kipi çalıştırmalar arasında değişmişse, mantık hatası yerine bir UMask= veya dizin izni farkı arayın. Zaman damgası hiç kımıldamadıysa, tetikleyici hiç ateşlenmemiştir ve yararlı sonraki adım başka bir istemci yeniden bağlanması değil, eylem birimi için journalctl -u.

Bir bağlantı olayının hâlâ kanıtlamadığı şey

Kurulmuş bir tünel tek bir olgudur. Masaüstü oturumunun kilidinin açık olduğu, oturum veriyolunun erişilebilir olduğu veya eylemin istediği özel kaynağın şimdiden hazır olduğu anlamına gelmez. Alice'in UID'i altındaki bir oneshot birimi onun kimliğine sahiptir ve oturumundan hiçbir şeye sahip değildir, bu yüzden grafik veriyolu gerektiren her şey desteklenen kullanıcı oturumu mekanizmasından geçmeli ve o oturumu kapattığında ne olacağını tanımlamalıdır.

Yeniden bağlanmalar da yinelenir. Trende uyuyan bir dizüstü bir saat içinde bir düzine bağlantı olayı üretebilir ve her seferinde bir satır ekleyen bir hook durum dosyasını kimsenin okuyamadığı bir günlüğe dönüştürür. Eylemi idempotent yapın ya da oturuma göre anahtarlanmış tek bir kaydı değiştirmesine izin verin.

Son olarak hasar yarıçapını birimin içinde sınırlayın: durum dizininin dışında salt okunur bir dosya sistemi görünümü, yeni ayrıcalık yok ve açık bir zaman aşımı. Daemon ile kullanıcı eylemi arasındaki ayrım kendi başına değerlidir, ama eylem onayladığınız tek şeyden başka hiçbir şey yapamadığında çok daha değerlidir.

İlgili makaleler