Per-column adoption flow for apps that already use Laravel's encrypted cast on a field and now want that specific column protected by Sealcraft instead. This is a column-scoped migration, not a whole-app migration -- the rest of your app keeps using Crypt / encrypted as usual.
Short version
- Back up the database
- Install Sealcraft, configure a KEK provider, run migrations
- Write a one-off Artisan command that reads each encrypted column via
Crypt::decryptand re-assigns via theEncryptedcast - Run during a maintenance window
- Keep
APP_KEYaround for at least one full backup cycle in case of rollback
The migration command
use App\Models\Patient;
use Illuminate\Support\Facades\Crypt;
class MigratePatientsToSealcraft extends Command
{
protected $signature = 'migrate:patients-to-sealcraft {--dry-run}';
public function handle(): int
{
Patient::query()->chunkById(500, function ($chunk): void {
foreach ($chunk as $patient) {
$plain = Crypt::decrypt($patient->getRawOriginal('ssn'));
if ($this->option('dry-run')) {
$this->line("Would migrate patient {$patient->id}");
continue;
}
$patient->ssn = $plain; // re-assignment triggers the Encrypted cast
$patient->save();
}
});
return self::SUCCESS;
}
}
Model config during migration
For the migration window, temporarily mark the column with both behaviors disabled:
- Remove the Laravel
'encrypted'cast (don't let it try to decrypt the new Sealcraft ciphertext) - Add the Sealcraft
Encrypted::classcast - Use
getRawOriginal()in the migration command to read the raw column before the cast kicks in
After migration
- Rotate
APP_KEYonly after you have a clean backup that no longer containsAPP_KEY-encrypted data - Run
sealcraft:auditto confirm every row has a DataKey - Run a
sealcraft:rotate-kekat the end to confirm all DEKs are wrapped under the current KEK version
Rollback
Keep APP_KEY and its backups until you are certain the migration is complete. If rollback is needed:
- Revert the cast back to
'encrypted' - Restore from the last pre-migration backup
APP_KEYstill works because you kept it
This is why step one is "back up the database."
Contributors
Thank you to everyone who has contributed to this package. Every pull request, bug report, and idea makes a difference.