Hello Bruce,

Hmmm. This seels to suggest that interacting with something outside should be an option.

Our goal is not to implement every possible security idea someone has,
because we will never finish, and the final result would be too complex
to be unable.

Sure. I'm trying to propose something both simple and extensible, so that other people could plug their own KMS if they are not fully satisfied with the way the internal pg KMS works, which IMHO should be the case if someone is motivated and paranoid enough to setup a KMS in the first place.

You will need to explain exactly why having a separate process has value over coding/user complexity, and you will need to get agreement from a sufficient number of people to move that idea forward.

ISTM that the value is simple: The whole KMS idea turns around a "KEK", which is a secret key which allows to unlock/retrieve/recompute many data keys, aka DEKs. Loosing the KEK basically means loosing all data keys, past, present and possibly future, depending on how the KEK/DEK mechanism operates internally.

So the thing you should not want is to lose your KEK.

Keeping it inside pg process means that any pg process compromision would result in the KEK to be compromised as well, while the whole point of doing this KMS business was to provide security by isolating realms of data encryption.

If you provide an interface instead, which I'm advocating, then where the KEK is does not concern pg, which has just to ask for DEKs. A compromise of pg would compromise local DEKs, but not the KEK "master key". The KEK may be somewhere on the same host, in another process, or possibly on another host, on some attached specialized quantum hardware inacessible to human beings. Postgres should not decide where the user should put its KEK, because it would depend on the threat model being addressed that you do not know.

From an implementation point of view, what I suggest is reasonably simple
and allows people to interface with the KMS of their choice, including one based on the patch, which would be a demos about what can be done, but other systems would be accessible just as well. The other software engineering aspect is that a KMS is a complex/sensitive thing, so reinventing our own and forcing it on users seems like a bad idea.

From what I understood from the code, the KEK is loaded into postgres process. That is what I'm disagreeing with, only needed DEK should be there.

One option would be to send the data needing to be encrypted to an
external command, and get the decrypted data back.  In that way, the KEK
is never on the Postgres server.  However, the API for doing such an
interface seems very complex and could lead to failures.

I was more thinking of an interface to retrieve DEKs, but to still keep encryption/decryption inside postgres, to limit traffic, but what you suggest could be a valid option, so maybe should be allowed.

I disagree with the implementation complexity, though.

Basically the protocol only function is sending "GET <opaque-key-identifier>" and retrieving a response which is either the DEK or an error, which looks like a manageable complexity. Attached a simplistic server-side implementation of that for illustration.

If you want externalized DEK as well, it would be sending "ENC/DEC <key-identifier> <data>" and the response is an error, or the translated data. Looks manageable as well. Allowing both approaches looks ok.

Obviously it requires some more thinking and design, but my point is that postgres should not hold a KEK, ever, nor presume how DEK are to be managed by a DMS, and that is not very difficult to achieve by putting it outside of pg and defining how interactions take place. Providing a reference/example implementation would be nice as well, and Masahiko-san code can be rewrapped quite easily.

--
Fabien.
#! /usr/bin/env python3
#
# This (powerful) code is public domain.

import sys
from hashlib import sha256 as H

# obviously the KEK should be retrieved from somewhere else
KEK = b"super secret default KEK"

while True:
    try: # parse GET 0xdeadbeef
        req = sys.stdin.readline())
        assert req[0:6] == "GET 0x" and req[-1] == "\n"
        hdata = bytes.fromhex(req[6:-1])
        print(f"DEK 0x{H(hdata + KEK).hexdigest()}")
    except Exception as e:
        print(f"ERR {e}")

Reply via email to