Skip to content
This repository has been archived by the owner on Mar 30, 2023. It is now read-only.

Commit

Permalink
Add Azure Disk Encryption
Browse files Browse the repository at this point in the history
- Support both Key Encrypted Key and non- Key Encrypted Key encryption modes
- Introduce templates for master, client and data nodes to support the two encryption modes
- Introduce encrypt-vm template that encrypts the OS disk and attached data disks

For disk encryption to be applied:
1. The VM resource is created, with any attached data disks
2. The Encryption extension for the VM is created
3. The VM is updated with encryption settings from the Encryption extension

NOTES:

- There is no encryptionSettings on Data disks and specifying it returns a BadRequest. Looking at examples for Azure Disk Encryption, the encryptionSettings only get applied to the osDisk and the volumeType (OS, Data. All) determines which disks get encrypted.
- The dependency chain is set up to deploy the VM disk encryption extensions for VMs after all VM resources are created, and to update VM storageProfiles after all disk encryption extensions have run

TODO:

- return BitLocker secret for each encrypted VM

Closes #73
  • Loading branch information
russcam committed Feb 7, 2017
1 parent 84c441b commit e6b9027
Show file tree
Hide file tree
Showing 50 changed files with 6,793 additions and 59 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ communication before using in production.**

![Example UI Flow](images/ui.gif)

You can view the UI in developer mode by [clicking here](https://portal.azure.com/#blade/Microsoft_Azure_Compute/CreateMultiVmWizardBlade/internal_bladeCallId/anything/internal_bladeCallerParams/{"initialData":{},"providerConfig":{"createUiDefinition":"https%3A%2F%2Fraw.luolix.top%2Felastic%2Fazure-marketplace%2Ffeature%2Fapplication-gateway%2Fsrc%2FcreateUiDefinition.json"}}). If you feel something is cached improperly use [this client unoptimized link instead](https://portal.azure.com/?clientOptimizations=false#blade/Microsoft_Azure_Compute/CreateMultiVmWizardBlade/internal_bladeCallId/anything/internal_bladeCallerParams/{"initialData":{},"providerConfig":{"createUiDefinition":"https%3A%2F%2Fraw.luolix.top%2Felastic%2Fazure-marketplace%2Ffeature%2Fapplication-gateway%2Fsrc%2FcreateUiDefinition.json"}})
You can view the UI in developer mode by [clicking here](https://portal.azure.com/#blade/Microsoft_Azure_Compute/CreateMultiVmWizardBlade/internal_bladeCallId/anything/internal_bladeCallerParams/{"initialData":{},"providerConfig":{"createUiDefinition":"https%3A%2F%2Fraw.luolix.top%2Felastic%2Fazure-marketplace%2Ffeature%2Fencryption%2Fsrc%2FcreateUiDefinition.json"}}). If you feel something is cached improperly use [this client unoptimized link instead](https://portal.azure.com/?clientOptimizations=false#blade/Microsoft_Azure_Compute/CreateMultiVmWizardBlade/internal_bladeCallId/anything/internal_bladeCallerParams/{"initialData":{},"providerConfig":{"createUiDefinition":"https%3A%2F%2Fraw.luolix.top%2Felastic%2Fazure-marketplace%2Ffeature%2Fencryption%2Fsrc%2FcreateUiDefinition.json"}})

## Reporting bugs

Expand Down Expand Up @@ -333,7 +333,7 @@ azure group create <name> <location>
4. Use our published template directly using `--template-uri`

```sh
azure group deployment create --template-uri https://raw.githubusercontent.com/elastic/azure-marketplace/feature/application-gateway/src/mainTemplate.json --parameters-file parameters/password.parameters.json -g name
azure group deployment create --template-uri https://raw.githubusercontent.com/elastic/azure-marketplace/feature/encryption/src/mainTemplate.json --parameters-file parameters/password.parameters.json -g name
```

or if your are executing commands from a clone of this repo using `--template-file`
Expand Down Expand Up @@ -366,7 +366,7 @@ Select-AzureRmSubscription -SubscriptionId "<subscriptionId>"

```powershell
$clusterParameters = @{
"artifactsBaseUrl"="https://raw.githubusercontent.com/elastic/azure-marketplace/feature/application-gateway/src"
"artifactsBaseUrl"="https://raw.githubusercontent.com/elastic/azure-marketplace/feature/encryption/src"
"esVersion" = "5.1.2"
"esClusterName" = "elasticsearch"
"location" = "ResourceGroup"
Expand All @@ -389,12 +389,12 @@ New-AzureRmResourceGroup -Name "<name>" -Location "<location>"
5. User our published template directly

```powershell
New-AzureRmResourceGroupDeployment -Name "<deployment name>" -ResourceGroupName "<name>" -TemplateUri "https://raw.githubusercontent.com/elastic/azure-marketplace/feature/application-gateway/src/mainTemplate.json" -TemplateParameterObject $clusterParameters
New-AzureRmResourceGroupDeployment -Name "<deployment name>" -ResourceGroupName "<name>" -TemplateUri "https://raw.githubusercontent.com/elastic/azure-marketplace/feature/encryption/src/mainTemplate.json" -TemplateParameterObject $clusterParameters
```

### Web based deploy

<a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.luolix.top%2Felastic%2Fazure-marketplace%2Ffeature%2Fapplication-gateway%2Fsrc%2FmainTemplate.json" target="_blank">
<a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.luolix.top%2Felastic%2Fazure-marketplace%2Ffeature%2Fencryption%2Fsrc%2FmainTemplate.json" target="_blank">
<img alt="Deploy to Azure" src="http://azuredeploy.net/deploybutton.png"/>
</a>

Expand Down
84 changes: 58 additions & 26 deletions build/tasks/generate-data-nodes-resources.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,89 @@ var replace = require('gulp-replace');

jsonfile.spaces = 2;

var resourceTemplate = require("../../src/datanodes/data-node-template.json");
var resourceTemplate = {
content: require("../../src/datanodes/data-nodes-template.json"),
suffix: "disk-resources"
};

var encryptedResourceTemplate = {
content: require("../../src/datanodes/data-nodes-encrypted-template.json"),
suffix: "disk-encrypted-resources"
};

var encryptedKekResourceTemplate = {
content: require("../../src/datanodes/data-nodes-encrypted-kek-template.json"),
suffix: "disk-encrypted-kek-resources"
};

var allowedValues = require('../allowedValues.json');
var resource = _(resourceTemplate.resources).find(function(r) { return r.type == "Microsoft.Resources/deployments"});
var dataDiskTemplate = resource.properties.parameters.dataDisks.value.disks[0];
var nthDisk = function(i) {
var d = _.cloneDeep(dataDiskTemplate);
d.lun = i;
d.name = d.name.replace(/_INDEX_/, i + 1);
d.vhd.uri = d.vhd.uri.replace(/_INDEX_/, i + 1);
return d;

var nthDisk = function(deploymentResource) {
return function(i) {
var disks = deploymentResource.properties.parameters.dataDisks.value.disks[0];
var d = _.cloneDeep(disks);
d.lun = i;
d.name = d.name.replace(/_INDEX_/, i + 1);
d.vhd.uri = d.vhd.uri.replace(/_INDEX_/, i + 1);
return d;
}
}

var dataNodeWithDataDisk = function (size, done) {
var t = _.cloneDeep(resourceTemplate);
var rr = _(t.resources).find(function(r) { return r.type == "Microsoft.Resources/deployments"});
var disks = _.range(size).map(nthDisk);
rr.properties.parameters.dataDisks["value"].disks = disks;
var dataNodeWithDataDisk = function (template, size, done) {
var t = _.cloneDeep(template.content);

var resource = "../src/datanodes/data-node-" + size + "disk-resources.json";
var deploymentResources = _(t.resources).filter(function(r) { return r.type == "Microsoft.Resources/deployments"}).value();

deploymentResources.forEach(function(rr) {
if (rr.properties.parameters.dataDisks) {
var mapDisks = nthDisk(rr);
var disks = _.range(size).map(mapDisks);
rr.properties.parameters.dataDisks["value"].disks = disks;
}
});


var resource = "../src/datanodes/data-nodes-" + size + template.suffix + ".json";
jsonfile.writeFile(resource, t, { flag: 'w' },function (err) {
done();
});
};
var dataNodeWithoutDataDisk = function (size, done) {
var t = _.cloneDeep(resourceTemplate);
var dataNodeWithoutDataDisk = function (template, size, done) {
var t = _.cloneDeep(template.content);
t.resources = _(t.resources).filter(r=>r.type != "Microsoft.Storage/storageAccounts").value();
var rr = _(t.resources).find(function(r) { return r.type == "Microsoft.Resources/deployments"});
rr.properties.parameters.dataDisks = null;
delete rr.properties.parameters.dataDisks;
rr.dependsOn = [rr.dependsOn[0]];
var deploymentResources = _(t.resources).filter(function(r) { return r.type == "Microsoft.Resources/deployments"}).value();

deploymentResources.forEach(function(rr) {
rr.properties.parameters.dataDisks = null;
delete rr.properties.parameters.dataDisks;
rr.dependsOn = [rr.dependsOn[0]];
});

delete t.variables.nodesPerStorageAccount;
delete t.variables.storageAccountPrefix;
delete t.variables.storageAccountPrefixCount;
delete t.variables.newStorageAccountNamePrefix;

var resource = "../src/datanodes/data-node-" + size + "disk-resources.json";
var resource = "../src/datanodes/data-nodes-" + size + template.suffix + ".json";
jsonfile.writeFile(resource, t, { flag: 'w' },function (err) {
done();
});
};

gulp.task("generate-data-nodes-resource", function(cb) {
var cbCalled = 0;
var templates = [resourceTemplate, encryptedResourceTemplate, encryptedKekResourceTemplate];
var done =function() {
cbCalled++;
if (cbCalled == allowedValues.dataDisks.length + 1) cb();
if (cbCalled == (allowedValues.dataDisks.length * templates.length) + templates.length)
cb();
};

allowedValues.dataDisks.forEach(function (size) {
dataNodeWithDataDisk(size, done);
templates.forEach(function (template) {
allowedValues.dataDisks.forEach(function (size) {
dataNodeWithDataDisk(template, size, done);
});
dataNodeWithoutDataDisk(template, 0, done);
});
dataNodeWithoutDataDisk(0, done);

});
2 changes: 1 addition & 1 deletion parameters/password.parameters.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"artifactsBaseUrl":{"value":"https://raw.githubusercontent.com/elastic/azure-marketplace/feature/application-gateway/src"},
"artifactsBaseUrl":{"value":"https://raw.githubusercontent.com/elastic/azure-marketplace/feature/encryption/src"},
"esVersion":{"value":"2.2.0"},
"esClusterName":{"value":"my-azure-cluster"},
"location":{"value":"ResourceGroup"},
Expand Down
2 changes: 1 addition & 1 deletion parameters/ssh.parameters.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"artifactsBaseUrl":{"value":"https://raw.githubusercontent.com/elastic/azure-marketplace/feature/application-gateway/src"},
"artifactsBaseUrl":{"value":"https://raw.githubusercontent.com/elastic/azure-marketplace/feature/encryption/src"},
"esVersion":{"value":"2.2.0"},
"esClusterName":{"value":"my-azure-cluster"},
"location":{"value":"ResourceGroup"},
Expand Down
8 changes: 8 additions & 0 deletions src/createUiDefinition.json
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,14 @@
"storageAccountType": "Default",
"dataNodesAreMasterEligible": "[steps('nodesStep').dataNodes.dataNodesAreMasterEligible]",
"vmHostNamePrefix": "[steps('nodesStep').vmHostNamePrefix]",
"vmDiskEncryption": "No",
"activeDirectoryClientId": "",
"activeDirectoryClientSecret": "",
"keyEncryptionKey": "No",
"keyEncryptionKeyUrl": "",
"keyVaultName": "",
"keyVaultResourceGroup": "",
"passphrase": "",
"vmSizeMasterNodes": "[steps('nodesStep').masterNodes.vmSizeMasterNodes]",
"vmClientNodeCount": "[steps('nodesStep').clientNodes.vmClientNodeCount]",
"vmSizeClientNodes": "[steps('nodesStep').clientNodes.vmSizeClientNodes]",
Expand Down
159 changes: 159 additions & 0 deletions src/datanodes/data-nodes-0disk-encrypted-kek-resources.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"templateBaseUrl": {
"type": "string",
"metadata": {
"description": "Base uri of resources"
}
},
"vm": {
"type": "object",
"metadata": {
"description": "vm configuration"
}
},
"storageSettings": {
"type": "object",
"metadata": {
"description": "Storage Account Settings"
}
},
"diskEncryptionSettings": {
"type": "object",
"metadata": {
"description": "The encryption settings for Azure Disk Encryption"
}
}
},
"variables": {
"namespace": "[parameters('vm').namespace]",
"avSetCount": "[add(div(sub(parameters('vm').count, 1), 100), 1)]"
},
"resources": [
{
"apiVersion": "2016-03-30",
"type": "Microsoft.Compute/availabilitySets",
"name": "[concat(variables('namespace'), copyindex(), '-av-set')]",
"location": "[parameters('vm').shared.location]",
"copy": {
"name": "[concat(variables('namespace'),'av-loop')]",
"count": "[variables('avSetCount')]"
},
"properties": {
"platformUpdateDomainCount": 20,
"platformFaultDomainCount": 3
}
},
{
"name": "[concat(variables('namespace'), copyindex(), '-vm-creation')]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-02-01",
"dependsOn": [
"[concat('Microsoft.Compute/availabilitySets/', variables('namespace'), mod(copyindex(),variables('avSetCount')), '-av-set')]"
],
"copy": {
"name": "[concat(variables('namespace'),'vm-creation-loop')]",
"count": "[parameters('vm').count]"
},
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('templateBaseUrl'), '/partials/vm.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"templateBaseUrl": {
"value": "[parameters('templateBaseUrl')]"
},
"vm": {
"value": "[parameters('vm')]"
},
"index": {
"value": "[copyindex()]"
},
"availabilitySet": {
"value": "[concat(variables('namespace'), mod(copyindex(),variables('avSetCount')), '-av-set')]"
}
}
}
},
{
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(variables('namespace'), copyindex(), '/', parameters('diskEncryptionSettings').extensionName)]",
"apiVersion": "2015-06-15",
"dependsOn": [
"[concat(variables('namespace'),'vm-creation-loop')]"
],
"location": "[parameters('vm').shared.location]",
"copy": {
"name": "[concat(variables('namespace'),'vm-encryption')]",
"count": "[parameters('vm').count]"
},
"properties": {
"protectedSettings": {
"AADClientSecret": "[parameters('diskEncryptionSettings').activeDirectoryClientSecret]",
"Passphrase": "[parameters('diskEncryptionSettings').passphrase]"
},
"publisher": "Microsoft.Azure.Security",
"settings": {
"AADClientID": "[parameters('diskEncryptionSettings').activeDirectoryClientId]",
"EncryptionOperation": "EnableEncryption",
"KeyEncryptionAlgorithm": "[parameters('diskEncryptionSettings').keyEncryptionAlgorithm]",
"KeyEncryptionKeyURL": "[parameters('diskEncryptionSettings').keyEncryptionKeyUrl]",
"KeyVaultURL": "[concat('https://', parameters('diskEncryptionSettings').keyVaultName, '.vault.azure.net/')]",
"SequenceVersion": "[parameters('diskEncryptionSettings').sequenceVersion]",
"VolumeType": "All"
},
"type": "[parameters('diskEncryptionSettings').extensionName]",
"typeHandlerVersion": "[parameters('diskEncryptionSettings').extensionVersion]"
}
},
{
"name": "[concat(variables('namespace'), copyindex(), '-vm-update')]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-02-01",
"dependsOn": [
"[concat(variables('namespace'),'vm-encryption')]"
],
"copy": {
"name": "[concat(variables('namespace'),'vm-update-loop')]",
"count": "[parameters('vm').count]"
},
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('templateBaseUrl'), '/partials/encrypt-vm.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"vm": {
"value": "[parameters('vm')]"
},
"index": {
"value": "[copyindex()]"
},
"diskEncryptionSettings": {
"value": {
"encryptionSettings": {
"diskEncryptionKey": {
"sourceVault": {
"id": "[parameters('diskEncryptionSettings').keyVaultResourceId]"
},
"secretUrl": "[reference(resourceId('Microsoft.Compute/virtualMachines/extensions', concat(variables('namespace'), copyindex()), parameters('diskEncryptionSettings').extensionName)).instanceView.statuses[0].message]"
},
"keyEncryptionKey": {
"sourceVault": {
"id": "[parameters('diskEncryptionSettings').keyVaultResourceId]"
},
"keyUrl": "[parameters('diskEncryptionSettings').keyEncryptionKeyUrl]"
}
}
}
}
}
}
}
]
}
Loading

0 comments on commit e6b9027

Please sign in to comment.