Reputation: 653
In the AWS Java SDK 1.10.69, I can launch an instance and specify EBS volume mappings for the instance:
RunInstancesRequest runInstancesRequest = new RunInstancesRequest();
String userDataString = Base64.encodeBase64String(userData.toString().getBytes());
runInstancesRequest
.withImageId(machineImageId)
.withInstanceType(instanceType.toString())
.withMinCount(minCount)
.withMaxCount(maxCount)
.withKeyName(sshKeyName)
.withSecurityGroupIds(securityGroupIds)
.withSubnetId(subnetId)
.withUserData(userDataString)
.setEbsOptimized(true);
final EbsBlockDevice ebsBlockDevice = new EbsBlockDevice();
ebsBlockDevice.setDeleteOnTermination(true);
ebsBlockDevice.setVolumeType(VolumeType.Gp2);
ebsBlockDevice.setVolumeSize(256);
ebsBlockDevice.setEncrypted(true);
final BlockDeviceMapping mapping = new BlockDeviceMapping();
mapping.setDeviceName("/dev/sdb");
mapping.setEbs(ebsBlockDevice);
It seems that currently I can only enable / disable encryption on the volume, and not specify which KMS Customer Master Key to use for the volume.
Is there a way around this?
Upvotes: 3
Views: 613
Reputation: 21
Edit: See my other answer below (https://stackoverflow.com/a/47602790/7692970) for the much easier solution now available
To specify a Customer Master Key (CMK) for an EBS volume for an instance, you have to combine the RunInstancesRequest
with a CreateVolumeRequest
and an AttachVolumeRequest
. Otherwise, if you just specify true
for encryption on the EbsBlockDevice
it will use the default CMK.
First create the instance(s), without specifying the EBS volumes in the block device mapping of the RunInstancesRequest
, then separately create the volumes, then attach them.
CreateVolumeRequest
has withKmsKeyId()
/setKmsKeyId()
options.
For example, updating your code might look like:
RunInstancesRequest runInstancesRequest = new RunInstancesRequest();
String userDataString = Base64.encodeBase64String(userData.toString().getBytes());
runInstancesRequest
.withImageId(machineImageId)
.withInstanceType(instanceType.toString())
.withMinCount(minCount)
.withMaxCount(maxCount)
.withKeyName(sshKeyName)
.withSecurityGroupIds(securityGroupIds)
.withSubnetId(subnetId)
.withUserData(userDataString)
.setEbsOptimized(true);
RunInstancesResult runInstancesResult = ec2Client.runInstances(runInstancesRequest);
for (Instance instance : runInstancesResult.getReservation()) {
CreateVolumeRequest volumeRequest = new CreateVolumeRequest()
.withAvailabilityZone(instance.getPlacement().getAvailabilityZone())
.withKmsKeyId(/* CMK id or alias/yourkeyaliashere */)
.withEncrypted(true)
.withSize(256)
.withVolumeType(VolumeType.Gp2);
CreateVolumeResult volumeResult = ec2Client.createVolume(volumeRequest);
AttachVolumeRequest attachRequest = new AttachVolumeRequest()
.withDevice("/dev/sdb")
.withInstanceId(instance.getInstanceId())
.withVolumeId(volumeResult.getVolume().getVolumeId());
ec2Client.attachVolume(attachRequest);
}
Note: If you make use of the block device mapping in instance metadata, it does not get updated when you attach a volume to a running instance. To bring it up to date, you can stop/start the instance.
Upvotes: 2
Reputation: 21
Good news! AWS has just added the ability to specify CMK key ids in the block device mapping when launching instances.
This was added to the AWS Java SDK in version 1.11.237.
Therefore in your original code you now just add
ebsBlockDevice.setKmsKeyId(keyId);
where keyId can be a CMK alias (in the form alias/<alias name>
), key id (looks like 1234abcd-12ab-34cd-56ef-1234567890ab
) or full CMK ARN (arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab
).
Upvotes: 0