Stručně: Image Docker obsahuje PHP ve stavu okamžiku sestavení a zastarává i bez změny kódu. Kdo images sestavuje automaticky, časově řízeně i při bezpečnostních oznámeních, v pipeline kontroluje verzi PHP a nasazuje podle digestu, dostane záplaty jako proti PHP2Shell plánovaně do produkce. Zelený build sám o sobě není důkaz; počítá se verze v běžícím kontejneru.
Proč image bez změny kódu zastarávají
V mnoha týmech se build pipeline spouští, jen když někdo změní kód. Pro aplikaci je to logické. Pro bezpečnost je to problém, protože PHP v image pochází ze základního image podle tagu posledního buildu.
PHP2Shell to zviditelnilo. Opravené verze 8.5.12, 8.4.27, 8.3.36 a 8.2.35 vyšly 21. října 2026. Projekt, na kterém se v těch dnech nepracovalo, nedostal nový build a běžel dál se starým PHP, přestože základní image byl dávno aktualizován. Ruční cestu z této situace popisuje Záplatování PHP v kontejnerech Docker. Tento článek ukazuje, jak ji zautomatizovat.
Automatické nové sestavení imagí Docker: tři spouštěče
Robustní proces kombinuje několik spouštěčů, aby žádný nemusel nést vše sám.
| Spouštěč | Provedení | Na co dbát |
|---|---|---|
| Časový plán | časově řízený workflow, např. týdně | stáhne záplaty i bez změny kódu |
| Nový základní image | nástroj, který sleduje základní image a navrhuje změny | působí hlavně u pevných tagů verzí |
| Bezpečnostní oznámení | ruční spuštění pipeline provozním týmem | potřebuje jasně určenou odpovědnou osobu |
U GitHub Actions převzetí časového plánu zajišťuje událost schedule. Podle dokumentace GitHubu používá syntaxi cron s pěti poli, běží v UTC a jen na výchozí větvi. Plánované běhy se mohou při vysoké zátěži spouštět se zpožděním a ve veřejných repozitářích je GitHub po 60 dnech bez aktivity vypíná. Právě to druhé postihuje klidné projekty, tedy přesně ty, které automatické nové sestavení potřebují nejnaléhavěji.
Pro druhý spouštěč podporuje Dependabot podle dokumentace GitHubu ekosystém docker a navrhuje nové stavy základních imagí jako pull request. Dvě omezení byste měli znát. Za prvé musí někdo pull request zkontrolovat a sloučit, jinak zůstane ležet. Za druhé se u tagu větve jako php:8.3-fpm v Dockerfile nic nezmění, když se základní image sestaví znovu. Nástroj, který navrhuje textové změny, pak nemá co navrhovat. Právě proto je navíc potřeba časově řízené nové sestavení.
Třetí spouštěč zní banálně, v praxi však často ztroskotá na otázce, kdo ho spustí. Stanovte, kdo sleduje bezpečnostní oznámení k PHP a kdo smí pipeline spustit, i o víkendu. U PHP2Shell uplynul mezi předběžným oznámením a záplatou jen den.
Pipeline, která zachytí zastaralé PHP
Následující příklad pro GitHub Actions sestavuje image týdně a na požádání, kontroluje verzi PHP a skončí chybou, pokud je pod opraveným stavem. Registr, názvy a minimální verzi přizpůsobte.
name: php-image-rebuild
on:
schedule:
- cron: "0 3 * * 1" # pondělí 03:00 UTC
workflow_dispatch: {} # ruční spuštění při bezpečnostních oznámeních
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Image ohne Cache und mit frischem Basis-Image bauen
run: docker build --pull --no-cache -t app:${{ github.run_id }} .
- name: PHP-Version prüfen (Mindeststand des Zweigs 8.3)
run: |
docker run --rm app:${{ github.run_id }} php -v
docker run --rm app:${{ github.run_id }} \
php -r 'exit(version_compare(PHP_VERSION, "8.3.36", ">=") ? 0 : 1);'
Kontrola verze funguje u oficiálních imagí PHP, jejichž číslo verze udává skutečný stav. Používá-li váš image balíčky PHP z distribuce, zůstává číslo po backportu často stejné. Pak kontrolujte místo čísla changelog balíčku na čísla CVE, jak popisuje článek Doložení čísel CVE v changelogu balíčku.
Po kontrole následují v praxi tři další kroky: image prohledat na známé zranitelnosti, nahrát ho s datem a digestem do registru a digest předat nasazení. Které tagy a varianty se jako základ hodí, vysvětluje Oficiální image PHP pro Docker.
Od buildu k běžícímu kontejneru
Nejčastější omyl: Pipeline je zelená, takže je vše zaplatováno. Ve skutečnosti leží nový image jen v registru. Záplata se uplatní, až když je každý kontejner z nového image znovu vytvořen.
- Nasadit podle digestu: Nasazení odkazuje na digest nového image, nikoli na putující tag.
- Nejprve staging, pak produkce: Automatické testy na kopii zachytí zlomy způsobené novými základními imagemi.
- Ověřit v provozu: Po nasazení spustit
php -vv běžícím kontejneru a porovnat digest s buildem. - Omezit cestu zpět: Starý image zůstává krátce dostupný pro cestu zpět, obsahuje však zranitelné PHP.
V Kubernetes platí vlastní pravidla, například pro pull policy; najdete je v článku Záplatování PHP v Kubernetes.
Typické mezery v řetězci
- Cache buildu na runneru: Bez
--pulla--no-cachese znovu použije starý základní image. - Zrcadlo registru: Interní mezipaměť dodává ještě starý stav základního image.
- Vícestupňové buildy: Rozhoduje verze PHP posledního stupně, kontroluje se však často jen první.
- Vedlejší image: Workery front, kontejnery cron a interní nástroje mají vlastní pipeline, nebo žádnou.
- Pevně zapsané digesty: Jednou zafixovaný digest základního image se nikdy neaktualizuje, pokud ho žádný nástroj nesleduje.
Nové sestavení nahradí PHP, nikoli data. Škodlivý kód, který se před záplatou dostal do svazků, složek uploadu nebo do databáze, zůstává zachován a musí se zkontrolovat zvlášť.
Kdo zareaguje, když nové sestavení selže?
Automatické nové sestavení je tak dobré, jako reakce na jeho selhání. Pokud kontrola verze zareaguje nebo build skončí chybou kvůli změněnému základnímu image, musí si toho někdo všimnout. V mnoha týmech takové zprávy končí v poštovní schránce, kterou nikdo nečte, nebo v kanálu, kde jsou červené buildy dávno všedností.
Osvědčilo se jasné pravidlo: Selhané bezpečnostní nové sestavení je tiket s odpovědnou osobou a lhůtou, nikoli upozornění mezi mnoha jinými. Navíc u každého nasazeného image uchovávejte datum, digest a ověřenou verzi PHP. Tento seznam při příštím oznámení v minutách odpoví, které aplikace jsou dotčeny, a slouží vůči auditorům či pojišťovnám jako důkaz. Jak z toho vznikne trvalý postup, popisuje Správa záplat jako proces místo hašení požárů.
Jak konkrétně pomáhá PHP SOS?
- Zkontrolovat pipeline: Prohlédneme si vaše řetězce buildu a nasazení a ukážeme, kde může záplata uvíznout.
- Zautomatizovat nové sestavení: Zavedeme časově řízené buildy, kontrolu verze a nasazení podle digestu.
- Zachytit všechny image: Každému běžícímu kontejneru přiřadíme jeho pipeline, i vedlejším a starým imagím.
- Trvale spravovat: V rámci smlouvy o bezpečnostní údržbě sledujeme bezpečnostní oznámení a spouštíme nová sestavení.
Časté dotazy
Jak často by se měl image PHP znovu sestavovat?
Pevné číslo neexistuje. Osvědčil se pravidelný časově řízený build, například týdně, plus okamžitý build při bezpečnostních oznámeních. Rozhodující je, aby nová záplata nemusela čekat na další změnu kódu.
Stačí jako důkaz úspěšný build?
Ne. Build dokládá jen to, že existuje nový image. Záplata je účinná, až když jsou běžící kontejnery z tohoto image znovu vytvořeny a php -v v nich ukazuje opravenou verzi.
Proč se i po novém sestavení objevuje stará verze PHP?
Častými příčinami jsou cache buildu, která znovu používá starý základní image, zrcadlo registru se starým stavem nebo druhý řádek FROM ve vícestupňovém buildu. Sestavujte s --pull a --no-cache a zkontrolujte každý stupeň.
Může Dependabot aktualizovat základní image?
Podle dokumentace GitHubu Dependabot podporuje ekosystém Docker pro aktualizace verzí i bezpečnostní aktualizace. Změny základních imagí navrhuje jako pull request. Nové sestavení při nezměněném tagu to nenahrazuje.