---
title: "Správa kľúčov — Sentinel for Laravel | Roundly"
description: "Kruhy kľúčov, drivery a algoritmy; generovanie, import, rotácia, odvolanie a vyradenie kľúčov; stavy, uzly len na overovanie a import partnerov."
url: https://roundly-consulting.com/sk/open-source/navody/sentinel-for-laravel/sprava-klucov
language: sk
---

[Všetky balíky](https://roundly-consulting.com/sk/open-source.md)

[Sentinel for Laravel](https://roundly-consulting.com/sk/open-source/navody/sentinel-for-laravel.md)

# Správa kľúčov

Kľúče žijú v pomenovaných kruhoch: default pre pečate, denník a kontrolné body; http pre podpisy správ; vaše vlastné — napríklad kruh financial so silnejšími kľúčmi, ktorý pečať zvolí cez ring(); a kruhy pre MAC (napríklad logs), ktorých tajomstvá zdieľate s vlastnými odosielateľmi (pozri MAC pre vlastné služby). Id kľúča sa hľadá len v jeho kruhu a algoritmus vždy určuje kľúč — nikdy uložený riadok ani prijatý parameter.

| Driver | Odkiaľ sú kľúče | Rotácia |
| --- | --- | --- |
| config (kruh default) | SENTINEL\_KEY\_ID / SENTINEL\_KEY (+ SENTINEL\_PREVIOUS\_KEYS pre kľúče len na overovanie) | sentinel:key:rotate vypíše nové riadky env |
| database (kruh http) | Riadky sentinel\_keys: AES-256-GCM pod kľúčom odvodeným z APP\_KEY len pre obálky (nikdy nie aplikačný encrypter), každé pole viazané — upravený, skopírovaný či podstrčený riadok sa odmietne | sentinel:key:rotate uloží nový kľúč; starý je potom len na overovanie |
| `chain` | Drivery v poradí (vyhráva prvý podpisový kľúč) | podľa drivera |

## Algoritmy a materiál

| Algoritmus | Materiál | Pečate | HTTP |
| --- | --- | --- | --- |
| `hmac-sha256` | Koreňové tajomstvo 32–1024 bajtov; HKDF podkľúče 32 bajtov | áno | áno (surové zdieľané tajomstvo) |
| `hmac-sha384` | Koreň ≥ 32 bajtov; podkľúče 48 bajtov | áno | — |
| `hmac-sha512` | Koreň ≥ 32 bajtov; podkľúče 64 bajtov | áno | — |
| `ed25519` | 64-bajtový tajný kľúč libsodium / 32-bajtový verejný kľúč | áno | áno |
| `ecdsa-p256-sha256` | PKCS#8 / SPKI PEM, P-256 | áno | áno |
| `ecdsa-p384-sha384` | PKCS#8 / SPKI PEM, P-384 | áno | áno |

Materiál je vždy v tvare base64:<štandardné base64> — holý reťazec sa odmietne, čo blokuje heslá. Koreň HMAC má 32–1024 náhodných bajtov (nikdy PEM, nikdy jeden opakovaný bajt); Ed25519 je 64-bajtový tajný kľúč a/alebo 32-bajtový verejný kľúč; ECDSA je base64 textu PEM s krivkou overenou voči algoritmu. Materiál sa nikdy neobjaví vo výnimkách, logoch, udalostiach, about, var\_dump() ani v serializovaných dátach.

## API

```php
use RoundlyConsulting\Sentinel\Enums\Algorithm;
use RoundlyConsulting\Sentinel\Enums\KeyDestination;

Sentinel::keys()->rings();                                  // ['default', 'http']
Sentinel::keys()->all();                                    // KeyInfo of every key in every ring — never material
Sentinel::keys()->ring()->current();                        // KeyInfo of the default ring's signing key

$ring = Sentinel::keys()->ring('http');                     // KeyRingHandle; a kid of another ring is unknown here
$ring->name();                                              // 'http'
$ring->find('acme-2026-10');                                // ?KeyInfo
$ring->all();
$ring->generate(Algorithm::Ed25519, keyId: 'acme-2026-11', activatesAt: now()->addWeek());   // stored, pending until then
$ring->import('acme-2026-10', Algorithm::EcdsaP256Sha256, $pem, owner: $partner);
$ring->rotate();                                            // RotationResult: current, previous (now verify-only)
$ring->revoke('acme-2026-10', reason: 'Partner offboarded', actor: $admin);
$ring->retire('acme-2025-10');

$lines = Sentinel::keys()->ring()->generate(Algorithm::HmacSha256, destination: KeyDestination::Config)->envSnippet;
```

- Predvolené hodnoty sa líšia zámerne. generate() uloží kľúč do databázového úložiska kruhu (KeyDestination::Database; kruh bez neho vyhodí KeyDriverException::readOnly), kým KeyDestination::Config vráti riadky env v envSnippet a nič neuloží. sentinel:key:generate robí opak: riadky env, pokiaľ nezadáte --database.
- rotate() rotuje v úložisku, kde žije aktuálny podpisový kľúč; signs\_until predošlého kľúča sa nastaví na aktiváciu nového, takže sa prekrývajú bez medzery. Každý ďalší kľúč kruhu, ktorý by po tomto okamihu ešte mohol podpisovať — čakajúci kľúč z predošlej rotácie s activatesAt, kľúč pridaný súbežne —, dostane pod zámkami riadkov rovnaké signs\_until, takže naraz podpisuje práve jeden kľúč; KeyRotated::$previousKeyId uvedie kľúč, ktorý podpisoval v čase potvrdenia rotácie. Kruh, ktorý podpisuje kľúčom vlastného drivera, sa odmietne (KeyDriverException::customDriver): rotujte ho v jeho vlastnom úložisku — Sentinel materiál vlastného úložiska nikdy nevypíše.
- Label je platné UTF-8 s najviac 191 znakmi (KeyDriverException::invalidLabel) a od verzie 1.2 je viazaný v obálke kľúča v databáze.
- revoke() a retire() menia len kľúče v databáze. Kľúč z konfigurácie vyhodí KeyDriverException::notStoredInDatabase: odvoláte ho pridaním ring:kid do SENTINEL\_REVOKED\_KEYS a vyradíte odstránením zo zoznamu kľúčov kruhu len na overovanie — sentinel:key:revoke a sentinel:key:retire namiesto chyby vypíšu presne tento postup.
- Dôvod odvolania je povinný (1–1 000 znakov); retire() ukončí obdobie overovania kľúča okamžite, takže pečate, ktoré ho stále používajú, hlásia RetiredKey.

```php
use RoundlyConsulting\Sentinel\DataTransferObjects\GenerateKeyRequest;
use RoundlyConsulting\Sentinel\DataTransferObjects\RevokeKeyRequest;
use RoundlyConsulting\Sentinel\DataTransferObjects\RotateKeyRequest;

$key = Sentinel::generateKey(new GenerateKeyRequest('http', Algorithm::Ed25519, keyId: 'acme-2027-01', owner: $partner));
$rotation = Sentinel::rotateKey(new RotateKeyRequest('http'));
Sentinel::revokeKey(new RevokeKeyRequest('http', 'acme-2027-01', 'Partner offboarded', $admin));
Sentinel::retireKey('http', 'acme-2025-10');
Sentinel::listKeys('http');                                 // null = every ring
Sentinel::findKey('http', 'acme-2027-01');                  // ?KeyInfo
Sentinel::currentKey();                                     // null = keys.default_ring
```

## Naraz len jedna rotácia kruhu

Zámky riadkov pokrývajú len existujúce kľúče, preto databázová rotácia počas celej svojej transakcie drží aj zámok kruhu na pripojení kľúčov — bez tabuľky, bez migrácie — a dve súbežné prvé rotácie prázdneho kruhu už nikdy neuložia každá svoj podpisový kľúč:

| Engine | Zámok |
| --- | --- |
| PostgreSQL | pg\_advisory\_xact\_lock ako prvý príkaz transakcie po SET TRANSACTION ISOLATION LEVEL READ COMMITTED (snapshot REPEATABLE READ by vznikol ešte pred čakaním); uvoľní sa pri commite alebo rollbacku. |
| MySQL / MariaDB | GET\_LOCK('sentinel:keys:<crc32 databázy + kruhu>') pred transakciou, RELEASE\_LOCK po nej; čaká najviac innodb\_lock\_wait\_timeout, potom KeyDriverException (ringBusy). |
| SQLite | Žiadny — naraz zapisuje len jeden; prehraná transakcia zlyhá s „database is locked“, zopakuje sa a uvidí kľúč víťaza. |

Vo vašej vlastnej transakcii drží PostgreSQL zámok až do jej konca, no úroveň izolácie už zmeniť nevie: pri REPEATABLE READ rotujte mimo nej. Zámok zoraďuje len rotácie — generate() a import() pridávajú kľúče bez neho. Kruh, ktorému súbeh pred verziou 1.1.1 nechal dva podpisové kľúče, netreba opravovať: podpisuje novší, overujú oba a ďalšia rotácia oba zosadí. Ukáže to sentinel:key:list — viac než jeden aktívny kľúč bez signs\_until znamená, že je čas na rotáciu.

## Stavy

Stavy zodpovedajú NIST SP 800-57 — pending → active → verify-only → retired, plus revoked — a efektívny stav sa určuje v tomto poradí:

| Stav | Kedy | Podpisuje | Overuje |
| --- | --- | --- | --- |
| `Revoked` | ring:kid v keys.revoked (vždy vyhráva), alebo odvolaný | nie | nie |
| `Retired` | uplynulo verifies\_until, alebo vyradený | nie | nie (dôkazy v denníku sa stále overia) |
| `Pending` | activates\_at v budúcnosti | nie | nie |
| `VerifyOnly` | uplynulo signs\_until, kľúč previous v konfigurácii, alebo len verejný materiál | nie | áno |
| `Active` | inak | áno (so súkromným/tajným materiálom) | áno |

SENTINEL\_REVOKED\_KEYS (ring:kid,…) odvolá kľúč bez ohľadu na to, čo hovorí jeho driver — obnovený riadok v databáze odvolanie nikdy nezruší.

## Import kľúčov

Pridajte partnera za behu — bez nasadenia, s kľúčom viazaným na model partnera:

```php
$ring->import('acme-2026-10', Algorithm::Ed25519, $publicKeyPemOrBase64, owner: $partner, label: 'ACME');
Sentinel::importKey(new ImportKeyRequest('http', 'acme-2026-10', Algorithm::Ed25519, $pem, owner: $partner));
```

```bash
php artisan sentinel:key:import acme-2026-10 --ring=http --algorithm=ed25519 --file=acme.pem \
    --owner-type=partner --owner-id=7
```

import() uloží existujúci materiál do databázového úložiska kruhu: verejný kľúč partnera (Ed25519 surový alebo SPKI PEM, ECDSA PEM) alebo dohodnuté tajomstvo HMAC, viazaný na model vlastníka a len na overovanie — nikdy nepodpisuje, ani ako aktuálny kľúč kruhu, ani cez Http::withSignature() — pokiaľ nie je importovaný so signing: true (vlastný pár kľúčov presúvaný z prostredia do databázy; bez toho sa súkromný materiál odmietne). Stav, vlastník aj label sú viazané v zašifrovanej obálke — prepnutie stĺpca status alebo prepísanie labelu v SQL spôsobí, že riadok neprejde kontrolou integrity —, kid musí byť voľný v celom kruhu a odošle sa KeyImported.

## Rotácia

- Databázový kruh: rotate() vytvorí nový aktívny kľúč (voliteľne s neskoršou aktiváciou cez activatesAt); predošlý kľúč je po aktivácii nového len na overovanie. Staré pečate ostanú Intact, nové používajú nový kid.
- Kruh z konfigurácie: sentinel:key:rotate vypíše nové SENTINEL\_KEY\_ID / SENTINEL\_KEY a aktualizované SENTINEL\_PREVIOUS\_KEYS so starým kľúčom len na overovanie. Pri rotácii z kľúča Ed25519 či ECDSA na HMAC vypíše aj prázdne SENTINEL\_PUBLIC\_KEY= — použite ho, inak starý verejný kľúč ostane a kruh sa odmietne načítať (kľúč HMAC nemá verejnú polovicu).
- Potom presuňte staré pečate na nový kľúč cez sentinel:reseal — nikdy potichu nelegalizuje zmenu a --from-key= ho obmedzí na jeden starý kid.
- Kľúč vyraďte, keď ho už nič nepoužíva (sentinel:key:retire odmietne, kým ho pečate na ktoromkoľvek pripojení denníka používajú, pokiaľ nezadáte --force); kompromitovaný kľúč okamžite odvolajte.

## Drivery config a database

Driver config drží kľúče mimo databázy — odporúčané nastavenie pre pečate:

```bash
SENTINEL_KEY_ID=default-20261002-k3f9qa
SENTINEL_ALGORITHM=hmac-sha256
SENTINEL_KEY="base64:…"
SENTINEL_PUBLIC_KEY="base64:…"                  # asymmetric keys; alone = verify-only
SENTINEL_PREVIOUS_KEYS="default-20250901-a1b2c3|hmac-sha256|base64:…"   # verify-only, comma-separated
```

Driver database ukladá riadky sentinel\_keys, ktorých autoritatívna obálka je AES-256-GCM pod kľúčom odvodeným z APP\_KEY len pre obálky (s podporou rotácie cez APP\_PREVIOUS\_KEYS). Viaže každé pole — kruh, kid, algoritmus, materiál, verejný kľúč, stav, dátumy, vlastníka a od verzie 1.2 aj label — takže riadok, ktorého nešifrované stĺpce nesúhlasia s obálkou, vyvolá KeyIntegrityException, spustí KeyIntegrityViolated a považuje sa za neznámy. Kľúče v databáze sú len také bezpečné ako APP\_KEY, preto pre predvolený kruh uprednostnite driver config. chain číta svoje drivery v poradí — vyhráva prvý podpisový kľúč a odvolaný podpisový kľúč jedného úložiska (aj vlastného) sa preskočí v prospech ďalšieho.

## Viazanie labelu (prechod z 1.1)

Od verzie 1.2 je label kľúča v databáze viazaný v jeho obálke (sentinel.key/2) rovnako ako vlastník: prepísanie, vymazanie či pridanie labelu v SQL spôsobí, že kľúč neprejde kontrolou integrity. Sentinel 1.1 držal label len v obyčajnom stĺpci (sentinel.key/1). Po composer update tieto kľúče fungujú ďalej — nič sa nemigruje —, no ich labely ostanú neviazané, kým sa znovu nezapečatia:

| Nastavenie | Kľúč sentinel.key/1… |
| --- | --- |
| require\_bound\_label vypnuté (predvolené) | sa otvorí; label sa číta zo stĺpca, neviazaný |
| require\_bound\_label zapnuté | neprejde kontrolou integrity (KeyIntegrityViolated, považuje sa za neznámy) |

Každý zápis kľúča už prepečatí: generovanie, import, odvolanie, vyradenie aj zosadenie predošlého kľúča pri rotácii zapíšu sentinel.key/2 a naviažu label, ktorý riadok v tej chvíli drží. Zvyšok naviažete zámerne:

- Najprv nasaďte 1.2 na všetky uzly. Uzol s 1.1 obálku sentinel.key/2 neotvorí — každý kľúč, ktorý 1.2 zapíše či prepečatí, sa tam javí ako zlyhanie integrity, a preto ani niet návratu na 1.1.x, keď už 1.2 kľúče zapísala. Kým bežia uzly 1.1 a 1.2 vedľa seba, kľúče nezapisujte (generate, import, rotate, revoke, retire).
- Prepečaťte, na uzle, ktorý môže zapisovať do sentinel\_keys. Každý kľúč sa pred zápisom vypíše ako ring:kid → "label" — skontrolujte každý label: naviaže sa ten, ktorý riadok drží v čase prepečatenia, takže dôvera začína tu. Kľúč, ktorý neprejde kontrolou integrity, sa vypíše, nikdy sa neprepečatí a príkaz skončí kódom 1: skôr než budete pokračovať, zistite prečo. Opakované spustenie už nič neprepečatí (already bound).
- Zapnite striktný režim: SENTINEL\_REQUIRE\_BOUND\_LABEL=true. Odvtedy sa obálka sentinel.key/1 — obnovená zo starej zálohy, s prepísaným labelom — už neotvorí.

```bash
php artisan sentinel:key:reseal --dry-run     # what would be bound, nothing written
php artisan sentinel:key:reseal               # every ring that stores keys in the database
php artisan sentinel:key:reseal --ring=logs   # or one ring
```

sentinel:check to hlási ako key\_envelopes: varovanie, kým ostávajú kľúče sentinel.key/1 (počty po kruhoch, nikdy kid ani label — takže sentinel:check --strict skončí kódom 1, kým kľúče neprepečatíte), zlyhanie, ak je require\_bound\_label zapnuté a také kľúče ešte existujú, a ok, keď je každý kľúč viazaný. Nová inštalácia 1.2 kľúče sentinel.key/1 nemá a require\_bound\_label môže zapnúť hneď. Prepečatenie každý riadok znovu načíta pod jeho zámkom, takže súbežné odvolanie nikdy nezruší, a obálku zašifruje pod aktuálnym APP\_KEY.

## Uzly len na overovanie

Servery, ktoré majú overovať, no nikdy nepečatiť, nakonfigurujú len verejnú polovicu (SENTINEL\_KEY\_ID, SENTINEL\_ALGORITHM, SENTINEL\_PUBLIC\_KEY, bez SENTINEL\_KEY) a SENTINEL\_AUTO\_SEAL=false. Overia všetko; explicitné seal() vyhodí NoSigningKeyException.

## Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

[Ďalšie spôsoby podpory vrátane kryptomien](https://roundly-consulting.com/sk/podporte-nas.md)

Odoslaním daru súhlasíte s našimi [podmienkami prijímania darov](https://roundly-consulting.com/sk/podmienky-darov.md).

[Podporte našu open-source prácu (otvorí sa v novej karte)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Pridajte sa k nám na Patreone (otvorí sa v novej karte)](https://www.patreon.com/cw/roundly)

## Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.

[Ponuka do 48 hodín](https://roundly-consulting.com/sk/kontakt.md) [Prezrieť všetky balíky](https://roundly-consulting.com/sk/open-source/navody/sentinel-for-laravel.md)
