Replies: 4 comments 3 replies
|
For a normal PostgreSQL The most pgx-shaped path is to make the Go type for that column implement the interfaces that
Then configure sqlc to map that specific column to your custom Go type. That is the part that prevents accidental plaintext writes: generated code accepts
I would avoid wrapping/replacing Security caveat: keep the encryption envelope explicit in your type: version, nonce, ciphertext, authentication tag, and key ID if you rotate keys. Use randomized authenticated encryption unless you specifically need deterministic values for equality lookup, and treat deterministic encryption as a separate design choice with leakage tradeoffs. So my ranking would be: custom Go type plus sqlc column override plus |
Unfortunately this approach would run into the same issue as the other question (and the thing I want to avoid). I don't want each instance of of my custom type needs access to the encryption keys. I'm looking for a way to keep them as plain data holders and give pgx an a service that it'll use to encrypt/decrypt data in the process of reading and writing the data to postgres. |
|
That constraint changes the shape. If the values must stay plain data holders, then I would not use The important catch is dispatch scope. pgx chooses codecs from the type map by PostgreSQL type OID/name plus the Go value/target type. A plain For column-specific behavior, I would make the database type distinct, for example a domain over CREATE DOMAIN encrypted_bytea AS bytea;Then use that type only for encrypted columns, map those columns in sqlc to your plain Go holder type, and in pgx register a codec for the conn.TypeMap().RegisterType(&pgtype.Type{
Name: "encrypted_bytea",
OID: encryptedByteaOID,
Codec: EncryptedByteaCodec{keys: keyService},
})
conn.TypeMap().RegisterDefaultPgType(PlainSecret{}, "encrypted_bytea")Conceptually:
If you keep the column as ordinary So my updated ranking for your requirement would be: custom PostgreSQL domain/type plus pgx codec that owns the service first; global |
|
My initial thought is this would be best handled with a layer above pgx than directly in pgx. But if you really need to do it this way, then the |
Uh oh!
There was an error while loading. Please reload this page.
Let's say I have a table with a column that holds data encrypted by an application. Ideally I'd want both encryption and decryption to be handled in a middleware ish way so I can't accidentally forget to call the encryption methods and write clear text into that column. I'm also using sqlc in my project and most of the pgx code is generated. I haven't found a way to get sqlc to do something like this earlier question #2121
I found 3 approaches to get there, but not sure which one is lines up best with the way pgx is meant to be extended.
Option 1: Create a new postgres type, with a new OID, then register the type and a codec using
conn.TypeMap().RegisterType. It works, but requires creating a new type.Option 2: Register my encoder/decoder with
TryWrapEncodePlanFuncsandTryWrapScanPlanFuncs. This seems like the most likely approach, but would be good to confirm.Option 3: Wrap the existing
ByteaCodecwith my own implementation, handle the specific struct representing my encrypted column and pass everything else through to the default implementation. This one feels the sketchiest of the options, but would error quickly if I make a mistake and try to map a nonbyteacolumn to my struct.All reactions