Re: Internal key management system - Mailing list pgsql-hackers

From Fabien COELHO
Subject Re: Internal key management system
Date
Msg-id alpine.DEB.2.22.394.2006182258210.808159@pseudo
Whole thread Raw
In response to Re: Internal key management system  (Masahiko Sawada <masahiko.sawada@2ndquadrant.com>)
Responses Re: Internal key management system
List pgsql-hackers
Hello Masahiko-san,

> What I referred to "only one key" is KEK.

Ok, sorry, I misunderstood.

>>> Yeah, it depends on KMS, meaning we need different extensions for
>>> different KMS. A KMS might support an interface that creates key if not
>>> exist during GET but some KMS might support CREATE and GET separately.
>>
>> I disagree that it is necessary, but this is debatable. The KMS-side
>> interface code could take care of that, eg:
>>
>>    if command is "get X"
>>      if (X does not exist in KMS)
>>        create a new key stored in KMS, return it;
>>      else
>>        return KMS-stored key;
>>    ...
>>
>> So you can still have a "GET" only interface which adapts to the "final"
>> KMS. Basically, the glue code which implements the interface for the KMS
>> can include some logic to adapt to the KMS point of view.
>
> Is the above code is for the extension side, right?

Such a code could be in the command with which pg communicates (eg through 
its stdin/stdout, or whatever) to get keys.

pg talks to the command, the command can do anything, such as storing keys 
or communicating with an external service to retrieve them, anything 
really, that is the point.

I'm advocating defining the pg/command protocol, something along "GET xxx" 
as you wrote, and possibly provide a possible/reasonable command 
implementation, which would be part of the code you put in your patch, 
only it would be in the command instead of postgres.

> For example, if users want to use a cloud KMS, say AWS KMS, to store 
> DEKs and KEK they need an extension that is loaded to postgres and can 
> communicate with AWS KMS. I imagine that such extension needs to be 
> written in C,

Why? I could write it in bash, probably. Ok, maybe not so good for suid, 
but in principle it could be anything. I'd probably write it in C, though.

> the communication between the extension uses AWS KMS API, and the 
> communication between postgres core and the extension uses text 
> protocol.

I'm not sure of the word "extension" above. For me the postgres side could 
be an extension as in "CREATE EXTENSION". The command itself could be 
provided in the extension code, but would not be in the "CREATE 
EXTENSION", it would be something run independently.

> When postgres core needs a DEK identified by KEY-A, it asks 
> for the extension to get the DEK by passing something like “GET KEY-A” 
> message, and then the extension asks the existence of that key to AWK 
> KMS, creates if not exist and returns it to the postgres core. Is my 
> understanding right?

Yes. The command in the use-case you outline would just be an 
intermediary, but for another use-case it would do the storing. The point 
of aiming at extensibility if that from pg point of view the external 
commands provide keys, but what these commands really do to do this can be 
anything.

> When we have TDE feature in the future, we would also need to change
> frontend tools such as pg_waldump and pg_rewind that read database
> files so that they can read encrypted files. It means that these
> frond-end tools also somehow need to communicate with the external
> place to get DEKs in order to decrypt encrypted database files. In
> your idea, what do you think about how we can support it?

Hmmm. My idea was that the natural interface would be to get things 
through postgres. For a debug tool such as pg_waldump, probably it needs 
to be adapted if it needs to decrypt data to operate.

Now I'm not sure I understood, because of the DEK are managed by postgres 
in your patch, waldump and other external commands would have no access to 
the decrypted data anyway, so the issue would be the same?

With file-level encryption, obviously all commands which have to read and 
understand the files have to be adapted if they are to still work, which 
is another argument to have some interface rather than integrated 
server-side stuff, because these external commands would need to be able 
to get keys and use them as well.

Or I misunderstood something.

>> I'd like an extensible design to have anything in core. As I said in an
>> other mail, if you want to handle a somehow restricted use case, just
>> provide an external extension and do nothing in core, please. Put in core
>> something that people with a slightly different use case or auditor can
>> build on as well. The current patch makes a dozen hard-coded decisions
>> which it should not, IMHO.
>
> It might have confused you that I included key manager and encryption
> SQL functions to the patches but this key manager has been designed
> dedicated to only TDE.

Hmmm. This is NOT AT ALL what the patch does. The documentation in your 
patch talks about "column level encryption", which is an application 
thing. Now you seem to say that it does not matter and can be removed 
because the use case is elsewhere.

> It might be better to remove both SQL interface
> and SQL key we discussed from the patch set as they are actually not
> necessary for TDE purposes.

The documentation part of the patch, at no point, talks about TDE 
(transparent data encryption), which is a file-level encryption as far as 
I understand it, i.e. whole files are encrypted.

I'm lost, because if you want to do that you cannot easily use 
padding/HMAC and so because they would change block sizes, and probably 
you would use CRT instead of CBC to be able to decrypt data selectively.

So you certainly succeeded in confusing me deeply:-)

> Aside from the security risk you mentioned, it was a natural design 
> decision for me that we have our key manager component in postgres core 
> that is responsible for managing encryption keys for our TDE.

The patch really needs a README to explain what it really does, and why, 
and how, and what is the thread model, what are the choices (there should 
be as few as possible), how it can/could be extended.

I've looked at the whole patch, and I could not find the place where files 
are actually encrypted/decrypted at a low level, that I would expect for 
file encryption implementation.

> To make the key manager and TDE simple as much as possible, we discussed 
> that we will have cluster-wide TDE and key manager that manages a few 
> encryption keys used by TDE (e.g. one key for table/index encryption and 
> another key for WAL encryption), as the first step.

Hmmm. Ok. So in fact all that is for TDE, *but* the patch does not do TDE, 
but provides a column-oriented SQL-level encryption, which is unrelated to 
your actual objective, which is to do file-level encryption in the end.

However, for TDE, it may that you cannot do it with a pg extension because 
for the extension to work the database must work, which would require some 
"data" files not to be encrypted in the first place. That seems like a 
good argument to actually have something in core.

Probably for TDE you only want the configuration file not to be encrypted.

I'd still advocate to have the key management system possibly outside of 
pg, and have pg interact with it to get keys when needed. Probably key ids 
would be the relative file names in that case. The approach of 
externalizing encryption/decryption would be totally impractical for 
performance reasons, though.

I see value in Cary Huang suggestion on the thread to have dynamically 
loaded functions implement an interface. That would at least allow to 
remove some hardcoded choices such as what cypher is actually used, key 
sizes, and so on. One possible implementation would be to manage things 
more or less internally as you do, another to fork an external command and 
talk with it to do the same.

However, I do not share the actual interface briefly outlined: I do not 
thinkpg should have to care about key management functions such as 
rotation, generation or derivation, storage… the interest of pg should be 
limited to retrieving the keys it needs. That does not mean such functions 
do not have security value and should not be implemented, I'd say that it 
should not be visible/hardcoded in the pg/kms interface, especially if
this interface is expected to be generic.

As I see it, a pg/kms C-level loadable interface would provide the 
following function:

// options would be supplied by a guc and allow to initialize the 
// interface with the relevant data, whatever the underlying 
// implementation needs.
error kms_init(char *options);

// associate opaque key identifier to a local id
error kms_key(local_id int, int key_id_len, byte *key_id);

or maybe something like:

// would return the local id attributed to the key
error/int kms_key(key_id_len, key_id);

// the actual functions should be clarified
// for TDE file-level, probably the encrypted length is the same as the 
// input, you cannot have padding, hmac or whatever added.
// for SQL app-level, the rules could be different
error kms_(en|de)crypt(local_id int, int mode, int len,
                        byte *in, byte *out);

// maybe
error kms_key_forget(local_id int);
error kms_destroy(…);

// maybe, to allow extensibility and genericity
// eg kms_command("rotate keys with new kek=123");
error kms_command(char *cmd);

I'm a little bit unsure that there should be only one KMS active ever, 
though: a file-level vs app-level encryption could have quite different 
constraints. Also, should the app-level encryption be able to access keys
loaded for file-level encryption?

-- 
Fabien.

pgsql-hackers by date:

Previous
From: Fujii Masao
Date:
Subject: Re: POC and rebased patch for CSN based snapshots
Next
From: Amit Kapila
Date:
Subject: Re: Global snapshots