ObjectEncryption

= THIS PAGE IS OUT OF DATE =

The design on this page was never pursued. An effort to add encryption at rest was re-kindled about 2 years later and the result is a very different design. See the Swift spec for Encryption at Rest

= Object Encryption: Extending Swift =

OpenStack’s object storage system, Swift provides high availability and fault tolerance but for data at rest protection, client side encryption is required. Amazon and Google’s object storage systems provide transparent data encryption. Server side encryption with key management would make data protection more readily available, enable harnessing of any special hardware encryption support on the servers, make available a larger set of encryption algorithms and reduce client maintenance effort. Protecting data involves not only encryption support but also key management, the storing, protecting, and making the encryption keys readily available, without storing data and keys on the same device. We shall address thus both encryption and key management. Before we dig into the details, we take a brief look at the security model and design options and decisions to provide a phased support.

Security Model

 * Protection of data at rest: data encrypted and keys held in a separate location. Stealing the data disk still leaves the data protected.
 * Keys will also be encrypted, using a Master-key. One thing to keep safe as opposed to multiple keys. A notion similar to a safe deposit box requiring a bank key and a customer key to open.
 * Key Manager will not maintain mapping between keys to objects.
 * Authorization and access control support for key manager to protect from unauthorized use.
 * Protection from denial of service, either from malicious activity or natural disasters by way of key replication (akin to object replication and recovery in Swift).

Key Provider:

 * User (would rather not delegate trust, plans to use the same key for each object ..)
 * Auto-generation (either by the object storage system or key manager)

Key Scope:

 * Per object
 * Per project (within a domain)
 * Per domain

Key-Storage:

 * End-User
 * Key Manager

Key-Size

 * 128, 192, 256, shorter with padding

Encryption Algorithm

 * AES and its chaining variants
 * DES
 * RSA
 * And beyond …

Key Manager Access
Restricting access to the Key Manager to only OpenStack services would increase security. That is, no end user access.

Access Control
Keys inserted by a service only accessible by that service. Is there a use case to support a global access?

Master Key
Each OpenStack service that uses Key Manager to maintain its keys could have its own master key and use the same to encrypt a key string before passing it for storage to the Key Manager. The Master key could reside on a python key ring (currently it is included in common module in OpenStack and readily available to all packages). Benefits:

1.	Communication between the service and the key manager do not need to be further encrypted using ssl or https because they keys flying between them are at all times encrypted. The decrypted key string would at any time only reside on the service that seeks to save it or use.

2.	Keys used by different open stack services could reside in a single storage system but if one service were to be compromised, the keys from other services would still be safe.

3.	Further, should there be a desire to change a master key, only keys stored by that service need to be re-encrypted. The actual data that they were used to encrypt do not need to be re-encrypted.

Fault Tolerance and High Availability
Key Manager’s keys need to be accessible at the same level as the objects they encrypt which makes for have the keys stored on a Swift like Object Storage system. Our implementation will be based on this strategy.

Swift API Changes (vx.1)
1.	Put   (also   cli “upload)

“put” to take optional arguments should take optional args
 * a) encrypt=True|False, absence is the same as False

b•	enc-alg=AES-CBC ..|RSA|DES  (Mirantis selected AES-CBC)

c•	enc-key-size=128|192|256 .. default 256 (Mirantis selected 256)

d•	enc-key-string

e•	    (account, container, object-name == all the usual suspects same as before)

(To accommodate for domains and project names having to be only unique within a domain, there will be changes in Swift API semantics, in essence a unique project-id will be provided).

The encrypted object will be stored in Swift and the object meta data shall reflect these parameters. It shall further include a reference to its encryption key, key-id. Alternately a reference to an initialization vector will be provided, IV-id.

2.	Get  (also cli command)

enc-key-string

If an enc-key-string is provided, it is used to decrypt the retrieved object using the other meta data associated with the object. If enc-key-string is not provided, but the meta data indicates that it is encrypted, then key-id if it exists is used to decrypt the object. If IV-id is provided, then the project-id is used to retrieve the project specific key and this is used in conjunction with the IV string retrieved using IV-id to decrypt the object and return to the user.

3.	Put-key, arguments: key-string, project-id


 * a) Encrypt key-string using master key to get enc-key-string

b.	Create key-id using hash(DM5 or Sha)(project-id . enc-key-string

c.	Invoke Swift put using account=service-id (Swift|Cinder ..), enc-key-string and key-id from above, specify encrpt=false. (container could be “keys” or “project-id”)

4.	Create-key	project-id

Invokes Put-key after first generating a random key-string. Create key returns both the key-id and the unencrypted random key-string that was generated.

5.	Get-key key-id


 * a) Invokes a Swift get with account=service-id, container = keys or project-id, and key-id.

b.	The encrypted key string retrieved above is decrypted using the service master key and the plain text key is returned.

Key-Manager API (v 1.0)
1.	Put   

Return success/failure and the key-id.

2.	Get   returns the encrypted-key-string

3.	Delete  deletes the entry

Swift Changes
Put Path

1.	If encryption is required, and the key string is provided, it shall be used.

2.	If no key string is provided, the system invokes create-key, and on success uses the random key-string generated to encrypt the object and annotate it by way of meta data with the encryption parameters including key-id. Create-key internally contacts key-manager and saves the random key generated.

3.	If a key-string is provided, the key-manager is bypassed and instead before put is attempted, the object is first encrypted. It is the responsibility of the get call to provide the appropriate decryption key.

4.	No change if encryption is not requested.

Get Path

If the retrieved object indicates Encrypt=true, then the encryption related meta data is used and the key-manger used to obtain the encrypted key string used to encrypt the retrieved object and the information used accordingly.

Delete Path

If each object has a distinct encryption key, then when an object is deleted, the key-manager may also delete the string saved against key-id or IV-id. How should we indicate whether we are using a common key that must not be deleted? General remarks: 1.	Encryption occurs on Swift which typically is doing more IO than compute, so this would better exploit the hardware resources on Swift.

2.	Additional network traffic to chat with the Key Manager to store and retrieve keys. Keys could be cached in the Swift node memory.

3.	SSL, HTTPS used for client communication with Swift is what protects the encryption key string in transit.

Concerns/Questions

1•	Data transfer overhead: Swift uses Rsync for file transfer during replication. Any encryption algorithm that uses some form of block cipher chaining or new initialization vector each time would result in the object representation changing drastically on each update. This would result in a larger network payload for transmission.

2•	More things that can fail:  With a key manager and an object storage system, there are two systems that can fail or be compromised, increasing the chance of things failing.

3•	Unauthorized key deletion: If we use a Swift based system to storing keys and insert tombstone records to mimic a legitimate deletion after breaking into a Swift storage node, yes, keys could indeed be deleted on a reaper task, but this would be no new security hazard from what Swift deals with today. Perhaps we could introduce a check that there was a logged request to delete a key before deleting a key.

4•	Wary of losing control of encryption key(s): Support the use case where the end user provides the encryption key (and stores a copy of their own key, and is responsible for maintaining safety of the key). The said key will not then be saved in the Key Manager.

5•	Caching: Should only cache encrypted data. But perhaps it does make sense to store in memory encrypted key-strings.

6•	Snap shots:  Any standard mechanism is fine. No change necessary, data is encrypted.

7•	Do we need an IV (initialization vector) for each object encrypted. Yes, if we take the common key for a project or domain approach. In this case the IV would need to be encrypted, and could be stored against a key-id. We could specify “compound-encryption” to imply use a master key in conjunction with the IV (accessed via the iv-id attached to the object meta-data).

8•	No re-keying in phase-1. Not addressing background tasks of object re-keying such as that mentioned in Mirantis blog.

Implementation versions
Phase 1: Develop stub Key Manager service and specify encryption parameters in the url

Key manager could just be a hash table in the first version to get all the APIs specified and implement, to get the plumbing correct. Support a single most popular encryption algorithm. This would fully implement object encryption.

Phase-2: Make Key Manager is Swift instance, with multiple zones for storage. This would support true HA and fault tolerance.

Phase-3: Support multiple encryption algorithms. For instance, volume encryption may prefer XTS, an encryption strategy that uses sector address.

Phase-4: Reaper routine to change a master key for a service

Intel's Interest
Intel X86 hardware in Westmere and beyond provides AES-NI, hardware support for encryption/decryption. These speed up encryption/decryption. Further, Intel provides open source libraries to speed computation further by parallelizing the operations (multibuffer) and interleaving them (function stitching). The references give pointers to white papers. Intel product generations are incorporating wider registers which enables further parallelization of cryptographic operations.

Future
Store user encryption preferences such as default key string, size, and encryption algorithm, to be passed along with the authentication token and used by Swift during object insertion. This would reduce put URL request lengths, while yet allowing flexibility in algorithm selection.

Glossary
Key-string: A string of bits used to encrypt data. Could be auto-generated or end-user provided.

Key-id: a unique ID used to index a key-string in the system. The key-id will be attached as meta data with the encrypted object.

Master-key: a key-string used to encrypt the keys (key-strings) before saving in the key manager, resides in a service end point such as Swift or Cinder or ..