Sorun giderme
queryproxy:doctor ile başlayın, her kontrolü okuyun ve operatörlerin en sık karşılaştığı hataları giderin; takılan taleplerden TLS ve secret sorunlarına.
Güncelleme:
Doctor ile başlayın. Kurulumu okur ve loglarda kazı yapmadan önce neyin yanlış olduğunu söyler.
docker exec queryproxy php artisan queryproxy:doctor
Docker olmadan, uygulama dizininde php artisan queryproxy:doctor çalıştırın.
Doctor çıktısını okuma
Komut, her biri bir durum taşıyan kontrollerden oluşan bir tablo basar:
| Durum | Anlamı |
|---|---|
ok |
Kontrol geçti |
warn |
Dikkat edilmesi gereken bir şey var; çalıştırma yine de 0 ile çıkar |
fail |
Kurulumu bozan ya da tehlikeye atan bir sorun; çalıştırma 1 ile çıkar |
skip |
Kontrol uygulanmıyor (hiçbir SIEM sink’i açık değil, cache ya da kuyruk kontrolün okuyabileceği türde değil, vb.) |
Seçenekler:
--strictuyarıların da1ile çıkmasını sağlar. Deploy pipeline’ında kullanın.--full-audittüm denetim zincirini dolaşır. Onsuz doctor en yeni kayıtları ve zincirin başını kontrol eder; bu daha hızlıdır.--jsonbetikler için{"ok": …, "strict": …, "checks": […]}basar.
Doctor yalnızca okur. Kurulumda hiçbir şeyi değiştirmez.
Her kontrol ne anlama gelir
| Kontrol | ok değilse şunu yapın |
|---|---|
app_environment |
fail: APP_ENV=production iken APP_DEBUG açık. warn: başka bir ortamda açık. APP_DEBUG’ı kapatın |
app_key |
fail: anahtar eksik ya da bozuk ya da geçerli ama saklanan kimlik bilgilerinin şifresini çözemiyor; yani anahtar değişmiş. Eski anahtarı geri getirin ya da APP_PREVIOUS_KEYS içine yazın |
app_key_location |
warn: APP_KEY dosyası SQLite veritabanıyla aynı volume’de. APP_KEY ya da APP_KEY_FILE’ı volume’ün dışından verin |
database |
fail: uygulama veritabanına ulaşılamıyor ya da bekleyen migration’lar var. php artisan migrate --force çalıştırın |
queue_timing |
fail: kuyruğun retry_after değeri işçi timeout’undan büyük değil; bu yüzden uzun bir sorgu ikinci kez başlatılır. retry_after’ı yükseltin ya da QUERYPROXY_EXECUTION_TIMEOUT’u düşürün |
worker |
warn: işler çalıştırma timeout’u artı bir dakikadan uzun süre beklemiş; çalışan bir kuyruk işçisi yok gibi. php artisan queue:work --queue=queries,default başlatın. fail: kuyruk tablosu yok, php artisan migrate --force çalıştırın. skip: yalnızca database kuyruğunu ölçer |
scheduler |
warn: heartbeat yok ya da eski. php artisan schedule:work başlatın. Başlatmanın hemen ardından bir dakika bekleyin |
failed_jobs |
warn: işler başarısız oldu. php artisan queue:failed ile inceleyin; başarısız SIEM teslimleri de buraya düşer |
storage_permissions |
fail: storage/ altındaki bir yol, QueryProxy’yi çalıştıran kullanıcı tarafından yazılamıyor |
result_disk |
fail: QUERYPROXY_RESULT_DISK’in adını verdiği disk yok ya da herkese açık. Özel bir disk kullanın |
trusted_proxies |
fail: TRUSTED_PROXIES * ya da başka bir hepsini-kapsar değer (**, 0.0.0.0/0, ::/0). Vekilin IP’lerini ya da CIDR’larını yazın. 10.0.0.0/8 gibi geniş ama geçerli bir aralık geçer; bu yüzden ağınızın izin verdiği kadar dar tutun |
sqlite_allowed_dir |
warn: SQLite bağlantıları var ve QUERYPROXY_SQLITE_ALLOWED_DIR boş ya da var olmayan bir dizine işaret ediyor. SQLite bağlantısı ve ayar yoksa kontrol ok olur |
masking_coverage |
warn: bir takımın etkin maskeleme kuralı yok, dolayısıyla sonuçları maskelenmiyor. Maskeleme sayfasında varsayılan kuralları kurun |
tls_enforcement |
warn: bazı bağlantılar TLS istemiyor (bkz. TLS hataları). Onları düzenleyip TLS’i zorunlu kılın |
tls_files |
fail: saklanan bir PEM’in şifresi çözülemiyor, genellikle anahtar değiştiği için. warn: storage/app/tls altındaki dosyaların izinleri yanlış |
secret_files |
fail: bir *_FILE değişkeni okunamıyor, boş ya da düz karşılığıyla birlikte ayarlanmış |
metrics |
warn: token 24 karakterden kısa ya da QUERYPROXY_METRICS_ALLOWED_IPS IP adresi ya da CIDR aralığı olmayan bir girdi içeriyor (asla eşleşmez). fail: token’ın _FILE’ı okunamıyor. skip: /metrics kapalı |
siem_sinks |
fail: yapılandırılmış bir sink kullanılmayacak, dolayısıyla denetim olayları dışa aktarılmıyor. warn: düz http:// üzerinde bir webhook ya da UDP üzerinden syslog (şifresiz ve onaysız); --strict bunları çalıştırmanın başarısızlığına çevirir |
audit_chain |
fail: zincir kopuk ya da kayıtlar kaldırılmış. php artisan audit:verify çalıştırın |
Talepler
Bir talep queued kalıyor
Olasılık sırasına göre üç neden:
- İşçi yok. Doctor’ın
workerkontrolü uyarır. İşçiyi başlatın ya da konteynerdeQUERYPROXY_RUN_WORKER=trueayarlayın. - Her bağlantı slot’u meşgul. Bir bağlantıda aynı anda en fazla
QUERYPROXY_CONNECTION_SLOTStalep (varsayılan2) çalışır; geri kalanlar bekler ve kendiliğinden başlar. Denetim günlüğüreason=connection_slots_busyilerequest.execution_deferredgösterir vequeryproxy_slot_deferred_requests_totalmetriği bunu sayar. Hedef veritabanı daha fazlasını kaldırabiliyorsa ayarı yükseltin ya da0yapın. - İşçi yanlış kuyruğu dinliyor.
queriesvedefaultkuyruklarına hizmet etmelidir:--queue=queries,default.
Bir okuma “tried to change data” ile başarısız oluyor
Mesaj şöyledir: This statement tried to change data, but read requests run
in a read-only database session. Submit it as a write request if the change is
intended. Veritabanı, salt okunur oturum içindeki bir yazmayı reddetti.
PostgreSQL’de buna SELECT … FOR UPDATE ve FOR SHARE da dahildir. İfadeyi
yazma olarak gönderin ya da kilit ifadesini kaldırın.
Veritabanı bağlantıyı düşürdükten sonra bir okuma başarısız oluyor
Bir ifade başladıktan sonra QueryProxy yeniden bağlanmaz; bu yüzden kısa bir ağ kopması çalıştırmayı başarısız kılar. Talebi yeniden gönderin.
MySQL’de bir yazma çalıştırma timeout’unu aşıyor
Veritabanı tarafı statement timeout’u MySQL’de yalnızca SELECT’e ulaşır
(MAX_EXECUTION_TIME); bu yüzden uzun bir MySQL yazması veritabanı tarafından
kesilmez. İş QUERYPROXY_EXECUTION_TIMEOUT dolunca biter ve talep başarısız
olur; yazma yine de sunucuda çalışmış olabilir. Daha erken iptal etmek için
Stop query kullanın.
“Stop query”, sorgunun sinyallenemediğini söylüyor
Talep cancelled olarak işaretlenir, ancak veritabanı iptal sinyalini almamıştır
ve ifade timeout’unda sona erer. Düğme yalnızca veritabanı oturumu bilinen
çalışan bir talep için görünür, SQLite için görünmez. Bağlantının kullanıcısının
ihtiyaç duyduğu yetkileri kontrol edin:
- PostgreSQL: aynı kullanıcı ya da
pg_signal_backendrolü. - MySQL ve MariaDB: aynı kullanıcı ya da
CONNECTION_ADMIN. Yalnızca ifade iptal edilir. - SQL Server:
VIEW SERVER STATE(onsuz çalıştırmanın oturumu kontrol bağlantısına görünmez) veALTER ANY CONNECTION(KILLbuna ihtiyaç duyar). SQL Server’da Stop oturumu sonlandırır ve açık bir transaction sunucuda geri alınır.
Chat’teki SQL önizlemesi “SQL hidden” diyor
İfade güvenle redakte edilemedi, bu yüzden önizleme gösterilmiyor.
QUERYPROXY_CHAT_INCLUDE_SQL=none önizlemeyi her yerde gizler; full
ifadeyi gönderildiği gibi gösterir.
TLS hataları
v0.3.0’da oluşturulan bir bağlantı TLS ister ve sunucu sunmuyorsa başarısız olur. Bağlantı testi sonucunu okuyun: TLS durumunu gösterir.
| Belirti | Neden ve çözüm |
|---|---|
| PostgreSQL: server does not support SSL, but SSL was required | Sunucuda TLS yok. Sunucuda etkinleştirin. Yalnızca tamamen güvendiğiniz bir ağda, düz metne izin veren prefer ya da disable seçeneğini bağlantının SSL modunda seçin |
| MySQL veya MariaDB: bağlantı handshake’ten hemen sonra kapanıyor (hata 2006) | Sunucu TLS sunmuyor. Sunucuda etkinleştirin |
PostgreSQL verify-full ya da MySQL “Verify the server certificate” başarısız oluyor |
Sunucu sertifikası yapıştırdığınız CA’ya zincirlenmiyor ya da adı host’la eşleşmiyor. Doğru CA PEM’ini yapıştırın; verify-full için host sertifikayla eşleşmelidir |
| SQL Server: sertifika hatası | Sunucu sertifikası güvenilen bir CA’dan değil. CA’yı QueryProxy host’una kurun ya da self-signed bir sertifika için TrustServerCertificate’i bilerek açın |
SQL Server: pdo_sqlsrv eksik diyen RuntimeException |
TLS zorunlu bir SQL Server bağlantısı pdo_sqlsrv eklentisine ihtiyaç duyar. Onsuz Laravel şifresiz bir dblib bağlantısına düşerdi; bu yüzden QueryProxy bağlanmayı reddeder |
Yükseltmeden önceki bağlantılar eski davranışını korur; tls_enforcement
onları listeler.
Chat
Bir Slack ya da Teams düğmesi “has expired” diyor
this button has expired. Use the button in the newer message mesajı, talep
hâlâ pending iken o kartın 24 saatlik action token’ının bittiği anlamına gelir.
Talepler süresi dolup düşmez; talebi QueryProxy’de açın ya da yeni token’lı bir
kart gönderen hatırlatmayı bekleyin (bkz. QUERYPROXY_PENDING_REMIND_AFTER).
Teams hiçbir şey almıyor ya da flow boş alanlar okuyor
Önce webhook host’unu kontrol edin. *.powerplatform.com ve
*.logic.azure.com bir Adaptive Card alır; eski connector URL’leri
(*.webhook.office.com ve allowlist’e eklediyseniz outlook.office.com)
MessageCard alır. Bir Workflows URL’sinden eski MessageCard alanlarını okuyan
özel bir flow boş değerler alır. Bkz. Teams entegrasyonu.
Allowlist dışındaki bir host reddedilir; onu
QUERYPROXY_CHAT_WEBHOOK_ALLOWED_HOSTS ile genişletin.
Slack Approve bir web formuna bağlantıyla yanıt veriyor
O tıklama bir admin override olurdu ve override’lar her kanalda yazılı bir gerekçe ister. Hiçbir şey onaylanmadı; bağlantıyı açın ve gerekçeyi doldurun.
İzleme ve dışa aktarım
/metrics 404, 401 ya da 400 yanıtı veriyor
404: kapalı.QUERYPROXY_METRICS_TOKENya daQUERYPROXY_METRICS_ALLOWED_IPSayarlayın.401: yanlış token ya da istemci adresi allowlist’te değil. Bir ters vekilin arkasında,TRUSTED_PROXIESayarlamadığınız sürece adres vekilin adresidir.400: scrape’inHostbaşlığıAPP_URL’in host’u değil veTRUSTED_HOSTSiçinde de değil. Scrape yapılandırmasındaHostbaşlığını ayarlayın ya da adı listeye ekleyin.
Bkz. İzleme.
SIEM olayları ulaşmıyor
- Doctor’ı çalıştırın;
siem_sinkskullanılmayacak bir sink’i adıyla söyler (16 karakterlik secret’ı olmayan bir webhook asla imzasız gönderilmez). - SIEM kuyruğu için bir işçi çalıştırın. Varsayılan, hazır işçinin hizmet
verdiği
default’tur; özel birQUERYPROXY_SIEM_QUEUEkendi işçisine ihtiyaç duyar. php artisan queue:failed’e bakın. Yeniden deneme hakkını tüketen bir teslim oraya düşer.
Teslim en az bir kez yapılır, bu yüzden alıcılar id üzerinden tekilleştirme
yapmalıdır.
Secret’lar ve açılış
Konteyner “Both X and X_FILE are set” ile çıkıyor
İkisinden yalnızca birini tanımlayın. null, (null) ya da (empty) olarak
ayarlanmış düz bir değişken ayarlanmamış sayılır. Mesaj değişkenin ve yolun
adını verir, değeri asla vermez.
Konteyner “X_FILE points at … which is not a readable file” ile çıkıyor
Secret’ı o yola bağlayın ve konteynerin çalıştığı kullanıcının okuyabileceği şekilde yapın. Boş dosya da reddedilir. Sondaki satır sonları kırpılır; başka hiçbir şey kırpılmaz.
Yeniden başlatmadan sonra saklanan kimlik bilgileri okunamıyor
APP_KEY değişti. Özgün anahtarı geri getirin ya da APP_PREVIOUS_KEYS içine
yazın. Bkz. Yedekleme ve geri yükleme.
Dosyadan okunan bir secret yine de yapılandırma cache’inde görünüyor
php artisan config:cache, dosyalardan okunan secret’lar dahil her yapılandırma
değerini bootstrap/cache/config.php içine düz metin olarak yazar. Cache her
zaman böyle çalışmıştır ve *_FILE’ın amacını kısmen boşa çıkarır. Image her
açılışta yapılandırmayı yeniden cache’ler. O yolu diğer kullanıcılara kapalı
tutun ve paylaşılan image’ların ve yedeklerin dışında bırakın.
Yükseltme ve veritabanı
Migration 1419 hatasıyla başarısız oluyor
MySQL ya da MariaDB denetim trigger’larını oluşturmayı reddetti. Migration
kullanıcısı TRIGGER yetkisine ve binary logging açıksa SUPER ya da
log_bin_trust_function_creators=1 değerine ihtiyaç duyar. Bkz.
Yükseltme.
audit:verify bir kopukluk bildiriyor
audit:verify ilk bozuk kaydı ve nedenini söyler: hash taşımayan, kendinden
öncekine bağlanmayan, hash’iyle eşleşmeyen bir kayıt; zinciri başlatmayan bir
ilk kayıt; yazılan kayıt sayısından farklı bir uzunluk ya da kaydedilmiş olandan
farklı bir zincir başı. Harekete geçmeden önce zinciri SIEM kopyanızla karşılaştırın;
bkz. Denetim zinciri ve SIEM dışa aktarımı.
Bir MySQL talebi sql_mode mesajıyla reddediliyor
Hedef oturumun sql_mode değeri, guard’ın farklı okuduğu NO_BACKSLASH_ESCAPES
ya da ANSI_QUOTES içeriyor. Bkz.
Yapılandırma.