Feld-Verschlüsselung
Felder mit dem Tag encrypted werden von der Engine vor dem Schreiben
verschlüsselt (AES-256-GCM) und beim Lesen transparent entschlüsselt — auf
allen Backends identisch, die DB sieht nur Ciphertext (BYTEA/BLOB).
type ProviderAccount struct { ID orm.ID `orm:"pk"` Name string `orm:"index"` APIKey string `orm:"encrypted,required"`}
db, err := orm.Open(orm.Postgres(dsn), orm.Encryption(orm.StaticKey(keyFromKMS)), // Pflicht, sobald ein Model `encrypted` nutzt)Regeln:
orm.Encryption(provider)ist eineOpen-Option; ohne sie schlägtMigratebei Modellen mitencrypted-Feldern fehl.orm.StaticKey([]byte)(32 Bytes) ist der einfachste Provider; dasorm.KeyProvider-Interface (aktueller Schlüssel + Lookup per Key-ID) ist von Tag 1 rotationsfähig — jeder Ciphertext trägt die ID des benutzten Schlüssels, Rotation erfolgt lazy beim nächsten Schreiben.encryptedgilt fürstring- und[]byte-Felder (auch Pointer) und ist nicht kombinierbar mitpk/index/unique/json/version/default/enum/ref.- Verschlüsselte Felder sind nicht indizierbar, nicht filterbar und nicht sortierbar — die DB kann Ciphertext nicht sinnvoll vergleichen.
- v1-Umfang:
encryptedwirkt auf CRUD-Modellen. Auf EventSourced-Modellen wird es aktuell beiMigrateabgelehnt und folgt in einer späteren Version.
Beispiel: Schlüsselrotation
Abschnitt betitelt „Beispiel: Schlüsselrotation“StaticKey reicht für den Einstieg, ist aber ein einzelner Schlüssel ohne
Rotation. Für den Produktivbetrieb implementiert man orm.KeyProvider selbst
— zum Beispiel gegen ein KMS, das mehrere Schlüsselversionen kennt:
type kmsKeys struct{ kms *kms.Client }
// CurrentKey liefert den Schlüssel, mit dem NEU geschrieben wird.func (k kmsKeys) CurrentKey() (id string, key []byte, err error) { return k.kms.CurrentKeyID(), k.kms.Fetch(k.kms.CurrentKeyID()), nil}
// Key löst eine im Ciphertext gespeicherte Key-ID beim LESEN auf.func (k kmsKeys) Key(id string) ([]byte, error) { return k.kms.Fetch(id), nil}
db, err := orm.Open(orm.Postgres(dsn), orm.Encryption(kmsKeys{kms: kmsClient}),)Rotation braucht keinen Migrationsschritt: sobald das KMS eine neue
CurrentKeyID() liefert, verschlüsseln alle folgenden Schreibvorgänge damit.
Alte Zeilen bleiben lesbar, weil ihr Ciphertext die ursprüngliche Key-ID trägt
und Key(id) sie auflöst — Alt- und Neuschlüssel koexistieren, bis ein
Batch-Migrationsprozess (siehe Migration) die
Bestandszeilen bei Gelegenheit neu verschlüsselt.