diff --git a/bootstrapvz/providers/ec2/README.rst b/bootstrapvz/providers/ec2/README.rst index 3a6d797..1bd2c70 100644 --- a/bootstrapvz/providers/ec2/README.rst +++ b/bootstrapvz/providers/ec2/README.rst @@ -146,6 +146,30 @@ Example: name: ec2 amzn-driver-version: 1.5.0 +Encrypted volumes +~~~~~~~~~~~~~~~~~ + +Encrypted AMIs that can be used to launch instances with encrypted boot volume +are supported. Defining encryption key is optional and EC2 uses default +encryption key if one is not set. Encryption works only with EBS volumes. + +- ``encrypted:``: Default: False + Valid values: ``True``, ``False`` + ``optional`` +- ``kms_key_id:``: Default: EC2 default EBS encryption key + Valid values: arn of the KMS key + ``optional`` + +Example: + +.. code-block:: yaml + + --- + provider: + name: ec2 + encrypted: True + kms_key_id: arn:aws:kms:us-east-1:1234567890:key/00000000-0000-0000-0000-000000000000 + Image ~~~~~ diff --git a/bootstrapvz/providers/ec2/__init__.py b/bootstrapvz/providers/ec2/__init__.py index 9929987..0dd2856 100644 --- a/bootstrapvz/providers/ec2/__init__.py +++ b/bootstrapvz/providers/ec2/__init__.py @@ -25,6 +25,8 @@ def validate_manifest(data, validator, error): bootloader = data['system']['bootloader'] virtualization = data['provider']['virtualization'] + encrypted = data['provider'].get('encrypted', False) + kms_key_id = data['provider'].get('kms_key_id', None) backing = data['volume']['backing'] partition_type = data['volume']['partitions']['type'] enhanced_networking = data['provider']['enhanced_networking'] if 'enhanced_networking' in data['provider'] else None @@ -38,6 +40,12 @@ def validate_manifest(data, validator, error): if backing == 's3' and partition_type != 'none': error('S3 backed AMIs currently only work with unpartitioned volumes', ['system', 'bootloader']) + if backing != 'ebs' and encrypted: + error('Encryption is supported only on EBS volumes') + + if encrypted is False and kms_key_id is not None: + error('KMS Key Id can be set only when encryption is enabled') + if enhanced_networking == 'simple' and virtualization != 'hvm': error('Enhanced networking only works with HVM virtualization', ['provider', 'virtualization']) diff --git a/bootstrapvz/providers/ec2/ebsvolume.py b/bootstrapvz/providers/ec2/ebsvolume.py index 33e60e2..a4b4332 100644 --- a/bootstrapvz/providers/ec2/ebsvolume.py +++ b/bootstrapvz/providers/ec2/ebsvolume.py @@ -4,18 +4,26 @@ from bootstrapvz.base.fs.exceptions import VolumeError class EBSVolume(Volume): - def create(self, conn, zone, tags=[]): - self.fsm.create(connection=conn, zone=zone, tags=tags) + def create(self, conn, zone, tags=[], encrypted=False, kms_key_id=None): + self.fsm.create(connection=conn, zone=zone, tags=tags, encrypted=encrypted, kms_key_id=kms_key_id) def _before_create(self, e): self.conn = e.connection zone = e.zone tags = e.tags size = self.size.bytes.get_qty_in('GiB') - self.volume = self.conn.create_volume(Size=size, - AvailabilityZone=zone, - VolumeType='gp2', - TagSpecifications=[{'ResourceType': 'volume', 'Tags': tags}]) + + params = dict(Size=size, + AvailabilityZone=zone, + VolumeType='gp2', + TagSpecifications=[{'ResourceType': 'volume', 'Tags': tags}], + Encrypted=e.encrypted) + + if e.encrypted and e.kms_key_id: + params['KmsKeyId'] = e.kms_key_id + + self.volume = self.conn.create_volume(**params) + self.vol_id = self.volume['VolumeId'] waiter = self.conn.get_waiter('volume_available') waiter.wait(VolumeIds=[self.vol_id], diff --git a/bootstrapvz/providers/ec2/manifest-schema.yml b/bootstrapvz/providers/ec2/manifest-schema.yml index 2d9b217..c8a963b 100644 --- a/bootstrapvz/providers/ec2/manifest-schema.yml +++ b/bootstrapvz/providers/ec2/manifest-schema.yml @@ -27,6 +27,8 @@ properties: amzn-driver-version: type: string pattern: "^([0-9]+\\.?){3}$" + encrypted: { type: boolean } + kms_key_id: { type: string } required: [description, virtualization] system: type: object diff --git a/bootstrapvz/providers/ec2/tasks/ebs.py b/bootstrapvz/providers/ec2/tasks/ebs.py index c87a76e..90239eb 100644 --- a/bootstrapvz/providers/ec2/tasks/ebs.py +++ b/bootstrapvz/providers/ec2/tasks/ebs.py @@ -16,7 +16,12 @@ class Create(Task): formatted_tags = {k: v.format(**info.manifest_vars) for k, v in raw_tags.items()} tags = [{'Key': k, 'Value': v} for k, v in formatted_tags.items()] - info.volume.create(info._ec2['connection'], info._ec2['host']['availabilityZone'], tags) + # EBS volumes support encryption. KMS key id is optional and default key + # is used when it is not defined. + encrypted = info.manifest.data['provider'].get('encrypted', False) + kms_key_id = info.manifest.data['provider'].get('kms_key_id', None) + + info.volume.create(info._ec2['connection'], info._ec2['host']['availabilityZone'], tags=tags, encrypted=encrypted, kms_key_id=kms_key_id) class Attach(Task):