On 7/11/19 6:37 PM, Bruce Momjian wrote: > On Wed, Jul 10, 2019 at 12:26:24PM -0400, Bruce Momjian wrote: >> On Wed, Jul 10, 2019 at 08:31:17AM -0400, Joe Conway wrote: >>> Please see my other reply (and >>> https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf >>> appendix C as pointed out by Ryan downthread). >>> >>> At least in my mind, I trust a published specification from the >>> nation-state level over random blogs or wikipedia. If we can find some >>> equivalent published standards that contradict NIST we should discuss >>> it, but for my money I would prefer to stick with the NIST recommended >>> method to produce the IVs. >> >> So, we have had a flurry of activity on this thread in the past day, so >> let me summarize: > > Seems we have an updated approach:
I tried to keep up with this thread, and may have failed, but comments inline... > First, we need to store the symmetric encryption key in the data > directory, like we do for SSL certificates and private keys. (Crash > recovery needs access to this key, so we can't easily store it in a > database table.) We will pattern it after the GUC > ssl_passphrase_command. We will need to decide on a format for the > symmetric encryption key in the file so we can check that the supplied > passphrase properly unlocks the key. > > Our first implementation will encrypt the entire cluster. We can later > consider encryption per table or tablespace. It is unclear if > encrypting different parts of the system with different keys is useful > or feasible. (This is separate from key rotation.) I still object strongly to using a single key for the entire database. I think we can use a single key for WAL, but we need some way to split the heap so that multiple keys are used. If not by tablespace, then some other method. Regardless of the method to split the heap into different keys, I think there should be an option for some tables to not be encrypted. If we decide it must be all or nothing for the first implementation I guess I could live with it but would be very disappointed. The keys themselves should be in an file which is encrypted by a master key. Obtaining the master key should be pattern it after the GUC ssl_passphrase_command. > We will use CBC AES128 mode for tables/indexes, and CTR AES128 for WAL. > 8k pages will use the LSN as a nonce, which will be encrypted to > generate the initialization vector (IV). We will not encrypt the first > 16 bytes of each pages so the LSN can be used in this way. The WAL will > use the WAL file segment number as the nonce and the IV will be created > in the same way. I vote for AES 256 rather than 128. Did we determine that we no longer need table oid because LSNs are sufficiently unique? > wal_log_hints will be enabled automatically in encryption mode, like we > do for checksum mode, so we never encrypt different 8k pages with the > same IV. check > There will need to be a pg_control field to indicate that encryption is > in use. I didn't see that discussed but it makes sense. > Right now we don't support the online changing of a cluster's checksum > mode, so I suggest we create a utility like pg_checksums --enable to > allow offline key rotation. Once we get online checksum mode changing > ability, we can look into use that for encryption key rotation. Master key rotation should be trivial if we do it the way I discussed above. Rotating the individual heap and WAL keys would certainly be a bigger problem. Thinking out loud (and I believe somewhere in this massive thread someone else already said this), if we had a way to flag "key version" at the page level it seems like we could potentially rekey page-by-page while online, locking only one page at a time. We really only need to support 2 key versions and could ping-pong between them as they change. Or maybe this is a crazy idea. Joe -- Crunchy Data - http://crunchydata.com PostgreSQL Support for Secure Enterprises Consulting, Training, & Open Source Development